@@ -7,13 +7,15 @@ import (
77 "sort"
88
99 "github.com/databricks/cli/libs/structs/structpath"
10+ "github.com/databricks/cli/libs/structs/structtag"
1011)
1112
1213// VisitFunc is invoked for every scalar (int, uint, float, string, bool) field encountered while walking v.
1314//
1415// path PathNode representing the JSON-style path to the field.
1516// val the field's value – if the field is a pointer to a scalar the pointer is *not* dereferenced; the
1617// callback receives either nil (for a nil pointer) or the concrete value.
18+ // field the reflect.StructField for struct fields, nil for map keys and array indices.
1719//
1820// NOTE: Fields lacking a json tag or tagged as "-" are ignored entirely.
1921// Composite kinds (struct, slice/array, map, interface, function, chan, etc.) are *not* visited, but the walk
@@ -23,13 +25,13 @@ import (
2325// The walk is depth-first and deterministic (map keys are sorted lexicographically).
2426//
2527// Example:
26- // err := structwalk.Walk(cfg, func(path *structpath.PathNode, v any) {
28+ // err := structwalk.Walk(cfg, func(path *structpath.PathNode, v any, field *reflect.StructField ) {
2729// fmt.Printf("%s = %v\n", path.String(), v)
2830// })
2931//
3032// ******************************************************************************************************
3133
32- type VisitFunc func (path * structpath.PathNode , val any )
34+ type VisitFunc func (path * structpath.PathNode , val any , field * reflect. StructField )
3335
3436// Walk validates that v is a struct or pointer to one and starts the recursive traversal.
3537func Walk (v any , visit VisitFunc ) error {
@@ -40,7 +42,7 @@ func Walk(v any, visit VisitFunc) error {
4042 if ! rv .IsValid () {
4143 return nil
4244 }
43- walkValue (nil , rv , visit )
45+ walkValue (nil , rv , nil , visit )
4446 return nil
4547}
4648
@@ -58,25 +60,25 @@ func isScalar(k reflect.Kind) bool {
5860 }
5961}
6062
61- func walkValue (path * structpath.PathNode , val reflect.Value , visit VisitFunc ) {
63+ func walkValue (path * structpath.PathNode , val reflect.Value , field * reflect. StructField , visit VisitFunc ) {
6264 kind := val .Kind ()
6365
6466 if isScalar (kind ) {
65- visit (path , val .Interface ())
67+ visit (path , val .Interface (), field )
6668 return
6769 }
6870
6971 switch kind {
7072 case reflect .Pointer :
71- walkValue (path , val .Elem (), visit )
73+ walkValue (path , val .Elem (), field , visit )
7274
7375 case reflect .Struct :
7476 walkStruct (path , val , visit )
7577
7678 case reflect .Slice , reflect .Array :
7779 for i := range val .Len () {
7880 node := structpath .NewIndex (path , i )
79- walkValue (node , val .Index (i ), visit )
81+ walkValue (node , val .Index (i ), nil , visit )
8082 }
8183
8284 case reflect .Map :
@@ -91,7 +93,7 @@ func walkValue(path *structpath.PathNode, val reflect.Value, visit VisitFunc) {
9193 for _ , ks := range keys {
9294 v := val .MapIndex (reflect .ValueOf (ks ))
9395 node := structpath .NewMapKey (path , ks )
94- walkValue (node , v , visit )
96+ walkValue (node , v , nil , visit )
9597 }
9698
9799 default :
@@ -114,17 +116,18 @@ func walkStruct(path *structpath.PathNode, s reflect.Value, visit VisitFunc) {
114116 }
115117
116118 node := structpath .NewStructField (path , sf .Tag , sf .Name )
117- if node .JSONTag ().Name () == "-" {
119+ jsonTag := structtag .JSONTag (sf .Tag .Get ("json" ))
120+ if jsonTag .Name () == "-" {
118121 continue // skip fields without json name
119122 }
120123
121124 fieldVal := s .Field (i )
122125 // Skip zero values with omitempty unless field is explicitly forced.
123- if node . JSONTag () .OmitEmpty () && fieldVal .IsZero () && ! slices .Contains (forced , sf .Name ) {
126+ if jsonTag .OmitEmpty () && fieldVal .IsZero () && ! slices .Contains (forced , sf .Name ) {
124127 continue
125128 }
126129
127- walkValue (node , fieldVal , visit )
130+ walkValue (node , fieldVal , & sf , visit )
128131 }
129132}
130133
0 commit comments