Apply walks doc and stamps EnumSource + resolved Enum values on matching args and flags. Resolution failures are silent: the document continues to advertise enum_source even when no values are available, so consumers can fall back to invoking the dynamic command themselves. Apply is a no-op when r
(doc *Document)
| 111 | // Apply is a no-op when r is nil — callers may pass nil from |
| 112 | // Options.Resolver to disable dynamic resolution entirely. |
| 113 | func (r *Resolver) Apply(doc *Document) { |
| 114 | if r == nil || doc == nil { |
| 115 | return |
| 116 | } |
| 117 | |
| 118 | // Per-Apply cache: each enum_source resolved at most once even when |
| 119 | // many commands reference it (e.g. every `item` subcommand has a |
| 120 | // `collection` arg). |
| 121 | cache := make(map[string][]interface{}, len(r.Sources)) |
| 122 | resolve := func(src string) []interface{} { |
| 123 | if cached, ok := cache[src]; ok { |
| 124 | return cached |
| 125 | } |
| 126 | fn, ok := r.Sources[src] |
| 127 | if !ok { |
| 128 | cache[src] = nil |
| 129 | return nil |
| 130 | } |
| 131 | values, err := fn() |
| 132 | if err != nil { |
| 133 | values = nil |
| 134 | } |
| 135 | cache[src] = values |
| 136 | return values |
| 137 | } |
| 138 | |
| 139 | // Global flags: only the wildcard FlagEnumSources applies — there's |
| 140 | // no command path to scope a per-command binding against. |
| 141 | for name, f := range doc.GlobalFlags { |
| 142 | src, ok := r.FlagEnumSources[strings.ToLower(name)] |
| 143 | if !ok { |
| 144 | continue |
| 145 | } |
| 146 | f.EnumSource = src |
| 147 | values := resolve(src) |
| 148 | if len(values) > 0 && len(f.Enum) == 0 { |
| 149 | f.Enum = values |
| 150 | if f.Type == "string" { |
| 151 | f.Type = "enum" |
| 152 | } |
| 153 | } |
| 154 | doc.GlobalFlags[name] = f |
| 155 | } |
| 156 | |
| 157 | for path, cmd := range doc.Commands { |
| 158 | // Args: in-place via index since cmd.Args is a slice value |
| 159 | // inside the map's struct value. |
| 160 | for i := range cmd.Args { |
| 161 | src, ok := r.argSource(path, cmd.Args[i].Name) |
| 162 | if !ok { |
| 163 | continue |
| 164 | } |
| 165 | cmd.Args[i].EnumSource = src |
| 166 | values := resolve(src) |
| 167 | // Don't replace existing Enum values from alternation / |
| 168 | // ValidArgs — those are the authoritative spec for that arg |
| 169 | // and dynamic resolution is only meant to fill the gap. |
| 170 | if len(values) > 0 && len(cmd.Args[i].Enum) == 0 { |