@@ -19,6 +19,8 @@ package fieldpath
1919import (
2020 "sort"
2121 "strings"
22+
23+ "sigs.k8s.io/structured-merge-diff/v4/schema"
2224)
2325
2426// Set identifies a set of fields.
@@ -110,6 +112,30 @@ func (s *Set) RecursiveDifference(s2 *Set) *Set {
110112 }
111113}
112114
115+ // EnsureNamedFieldsAreMembers returns a Set that contains all the
116+ // fields in s, as well as all the named fields that are typically not
117+ // included. For example, a set made of "a.b.c" will end-up also owning
118+ // "a" if it's a named fields but not "a.b" if it's a map.
119+ func (s * Set ) EnsureNamedFieldsAreMembers (sc * schema.Schema , tr schema.TypeRef ) * Set {
120+ members := PathElementSet {
121+ members : make (sortedPathElements , 0 , s .Members .Size ()+ len (s .Children .members )),
122+ }
123+ atom , _ := sc .Resolve (tr )
124+ members .members = append (members .members , s .Members .members ... )
125+ for _ , node := range s .Children .members {
126+ // Only insert named fields.
127+ if node .pathElement .FieldName != nil && atom .Map != nil {
128+ if _ , has := atom .Map .FindField (* node .pathElement .FieldName ); has {
129+ members .Insert (node .pathElement )
130+ }
131+ }
132+ }
133+ return & Set {
134+ Members : members ,
135+ Children : * s .Children .EnsureNamedFieldsAreMembers (sc , tr ),
136+ }
137+ }
138+
113139// Size returns the number of members of the set.
114140func (s * Set ) Size () int {
115141 return s .Members .Size () + s .Children .Size ()
@@ -391,6 +417,31 @@ func (s *SetNodeMap) RecursiveDifference(s2 *Set) *SetNodeMap {
391417 return out
392418}
393419
420+ // EnsureNamedFieldsAreMembers returns a set that contains all the named fields along with the leaves.
421+ func (s * SetNodeMap ) EnsureNamedFieldsAreMembers (sc * schema.Schema , tr schema.TypeRef ) * SetNodeMap {
422+ out := make (sortedSetNode , 0 , s .Size ())
423+ atom , _ := sc .Resolve (tr )
424+ for _ , member := range s .members {
425+ tr := schema.TypeRef {}
426+ if member .pathElement .FieldName != nil && atom .Map != nil {
427+ tr = atom .Map .ElementType
428+ if sf , ok := atom .Map .FindField (* member .pathElement .FieldName ); ok {
429+ tr = sf .Type
430+ }
431+ } else if member .pathElement .Key != nil && atom .List != nil {
432+ tr = atom .List .ElementType
433+ }
434+ out = append (out , setNode {
435+ pathElement : member .pathElement ,
436+ set : member .set .EnsureNamedFieldsAreMembers (sc , tr ),
437+ })
438+ }
439+
440+ return & SetNodeMap {
441+ members : out ,
442+ }
443+ }
444+
394445// Iterate calls f for each PathElement in the set.
395446func (s * SetNodeMap ) Iterate (f func (PathElement )) {
396447 for _ , n := range s .members {
0 commit comments