TraverseStringsFunc runs the given function on every string in the given value by traversing it recursively. If the given value is a string, the function will run on a copy of the string and return it. If the value is a struct, map or a slice, the function will recursively call itself for each field
(v T, fn func(v string) (string, error))
| 71 | // field or element of the struct, map or slice until all strings inside the |
| 72 | // struct or slice are replaced. |
| 73 | func TraverseStringsFunc[T any](v T, fn func(v string) (string, error)) (T, error) { |
| 74 | original := reflect.ValueOf(v) |
| 75 | if original.Kind() == reflect.Invalid || !original.IsValid() { |
| 76 | return v, nil |
| 77 | } |
| 78 | copy := reflect.New(original.Type()).Elem() |
| 79 | |
| 80 | var traverseFunc func(copy, v reflect.Value) error |
| 81 | traverseFunc = func(copy, v reflect.Value) error { |
| 82 | switch v.Kind() { |
| 83 | |
| 84 | case reflect.Pointer: |
| 85 | // Unwrap the pointer |
| 86 | originalValue := v.Elem() |
| 87 | // If the pointer is nil, do nothing |
| 88 | if !originalValue.IsValid() { |
| 89 | return nil |
| 90 | } |
| 91 | // Create an empty copy from the original value's type |
| 92 | copy.Set(reflect.New(originalValue.Type())) |
| 93 | // Unwrap the newly created pointer and call traverseFunc recursively |
| 94 | if err := traverseFunc(copy.Elem(), originalValue); err != nil { |
| 95 | return err |
| 96 | } |
| 97 | |
| 98 | case reflect.Interface: |
| 99 | // Unwrap the interface |
| 100 | originalValue := v.Elem() |
| 101 | if !originalValue.IsValid() { |
| 102 | return nil |
| 103 | } |
| 104 | // Create an empty copy from the original value's type |
| 105 | copyValue := reflect.New(originalValue.Type()).Elem() |
| 106 | // Unwrap the newly created pointer and call traverseFunc recursively |
| 107 | if err := traverseFunc(copyValue, originalValue); err != nil { |
| 108 | return err |
| 109 | } |
| 110 | copy.Set(copyValue) |
| 111 | |
| 112 | case reflect.Struct: |
| 113 | // Loop over each field and call traverseFunc recursively |
| 114 | for i := range v.NumField() { |
| 115 | if err := traverseFunc(copy.Field(i), v.Field(i)); err != nil { |
| 116 | return err |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | case reflect.Slice: |
| 121 | // Create an empty copy from the original value's type |
| 122 | copy.Set(reflect.MakeSlice(v.Type(), v.Len(), v.Cap())) |
| 123 | // Loop over each element and call traverseFunc recursively |
| 124 | for i := range v.Len() { |
| 125 | if err := traverseFunc(copy.Index(i), v.Index(i)); err != nil { |
| 126 | return err |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | case reflect.Map: |
no test coverage detected
searching dependent graphs…