Skip to content

Commit 300cba8

Browse files
authored
feat: Allow ignoring fields from embedded structs (#499)
If a field in a struct is ignored with `kong:"-"`, any embedded fields with the same name are also ignored. This allows an outer struct to remove flags from an embedded struct by redefining it and adding a kong ignore tag.
1 parent 3b9af5b commit 300cba8

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

build.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,16 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro
5454
if v.Kind() != reflect.Struct {
5555
return out, nil
5656
}
57+
ignored := map[string]bool{}
5758
for i := 0; i < v.NumField(); i++ {
5859
ft := v.Type().Field(i)
5960
fv := v.Field(i)
6061
tag, err := parseTag(v, ft)
6162
if err != nil {
6263
return nil, err
6364
}
64-
if tag.Ignored {
65+
if tag.Ignored || ignored[ft.Name] {
66+
ignored[ft.Name] = true
6567
continue
6668
}
6769
// Assign group if it's not already set.
@@ -106,9 +108,27 @@ func flattenedFields(v reflect.Value, ptag *Tag) (out []flattenedField, err erro
106108
}
107109
out = append(out, sub...)
108110
}
111+
out = removeIgnored(out, ignored)
109112
return out, nil
110113
}
111114

115+
func removeIgnored(fields []flattenedField, ignored map[string]bool) []flattenedField {
116+
j := 0
117+
for i := 0; i < len(fields); i++ {
118+
if ignored[fields[i].field.Name] {
119+
continue
120+
}
121+
if i != j {
122+
fields[j] = fields[i]
123+
}
124+
j++
125+
}
126+
if j != len(fields) {
127+
fields = fields[:j]
128+
}
129+
return fields
130+
}
131+
112132
// Build a Node in the Kong data model.
113133
//
114134
// "v" is the value to create the node from, "typ" is the output Node type.

kong_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,43 @@ func TestExcludedField(t *testing.T) {
856856
assert.Error(t, err)
857857
}
858858

859+
func TestExcludeEmbeddedField(t *testing.T) {
860+
type Embedded struct {
861+
Flag string
862+
Excluded string
863+
}
864+
type Embedded2 struct {
865+
Flag2 string
866+
Excluded string
867+
}
868+
var cli struct {
869+
Embedded
870+
Excluded string `kong:"-"`
871+
Embedded2
872+
}
873+
var cli2 struct {
874+
Embedded Embedded `kong:"embed"`
875+
Excluded string `kong:"-"`
876+
Embedded2 Embedded2 `kong:"embed"`
877+
}
878+
879+
p := mustNew(t, &cli)
880+
_, err := p.Parse([]string{"--flag=foo"})
881+
assert.NoError(t, err)
882+
_, err = p.Parse([]string{"--flag-2=foo"})
883+
assert.NoError(t, err)
884+
_, err = p.Parse([]string{"--excluded=foo"})
885+
assert.Error(t, err)
886+
887+
p = mustNew(t, &cli2)
888+
_, err = p.Parse([]string{"--flag=foo"})
889+
assert.NoError(t, err)
890+
_, err = p.Parse([]string{"--flag-2=foo"})
891+
assert.NoError(t, err)
892+
_, err = p.Parse([]string{"--excluded=foo"})
893+
assert.Error(t, err)
894+
}
895+
859896
func TestUnnamedFieldEmbeds(t *testing.T) {
860897
type Embed struct {
861898
Flag string

0 commit comments

Comments
 (0)