-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfield_describer.go
101 lines (87 loc) · 2 KB
/
field_describer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package fangs
import (
"fmt"
"reflect"
"github.com/spf13/pflag"
)
// FieldDescriber a struct implementing this interface will have DescribeFields called when Summarize is called
type FieldDescriber interface {
DescribeFields(descriptions FieldDescriptionSet)
}
// FieldDescriptionSet accepts field descriptions
type FieldDescriptionSet interface {
Add(ptr any, description string)
}
// FieldDescriptionSetProvider implements both DescriptionProvider and FieldDescriptionSet
type FieldDescriptionSetProvider interface {
DescriptionProvider
FieldDescriptionSet
}
type directDescriber struct {
flagRefs flagRefs
}
var _ FieldDescriptionSetProvider = (*directDescriber)(nil)
func NewDirectDescriber() FieldDescriptionSetProvider {
return &directDescriber{
flagRefs: flagRefs{},
}
}
func NewFieldDescriber(cfgs ...any) DescriptionProvider {
d := NewDirectDescriber()
for _, v := range cfgs {
addFieldDescriptions(d, reflect.ValueOf(v))
}
return d
}
func (d *directDescriber) Add(ptr any, description string) {
v := reflect.ValueOf(ptr)
if !isPtr(v.Type()) {
panic(fmt.Sprintf("Add() requires a pointer, but got: %#v", ptr))
}
p := v.Pointer()
d.flagRefs[p] = &pflag.Flag{
Usage: description,
}
}
func (d *directDescriber) GetDescription(v reflect.Value, _ reflect.StructField) string {
if v.CanAddr() {
v = v.Addr()
}
if isPtr(v.Type()) {
f := d.flagRefs[v.Pointer()]
if f != nil {
return f.Usage
}
}
return ""
}
func addFieldDescriptions(d FieldDescriptionSet, v reflect.Value) {
t := v.Type()
for isPtr(t) && v.CanInterface() {
o := v.Interface()
if p, ok := o.(FieldDescriber); ok && !isPromotedMethod(o, "DescribeFields") {
p.DescribeFields(d)
}
t = t.Elem()
v = v.Elem()
}
if !isStruct(t) {
return
}
for i := 0; i < v.NumField(); i++ {
f := t.Field(i)
if !includeField(f) {
continue
}
v := v.Field(i)
t := v.Type()
if isPtr(t) {
v = v.Elem()
t = t.Elem()
}
if !v.CanAddr() || !isStruct(t) {
continue
}
addFieldDescriptions(d, v.Addr())
}
}