package commandkit import ( "errors" "fmt" ) // ErrFlagInput identifies a missing required captured flag selected for an input. var ErrFlagInput = errors.New("required flag input is missing") // ErrFlagWiring identifies an invalid captured binding or destination. var ErrFlagWiring = errors.New("flag wiring is invalid") // FlagValues stores invocation-local values prepared for captured flags. type FlagValues[I any] struct { values map[*bindingIdentity]preparedValue[I] } // CaptureFlags adapts flags declared for I into flags on Outer. The returned // flags preserve the original identities and store prepared values in target. func CaptureFlags[Outer, I any](flags []Flag[I], target func(*Outer) *FlagValues[I]) []Flag[Outer] { captured := make([]Flag[Outer], len(flags)) for index, original := range flags { inner := original identity := newBindingIdentity() binding := flagBinding[Outer]{ identity: identity, meta: inner.binding.meta, defaultText: inner.binding.defaultText, repeated: inner.binding.repeated, boolean: inner.binding.boolean, } if target != nil && inner.binding.identity != nil && inner.binding.valid && inner.binding.prepare != nil { binding.valid = true binding.prepare = func(raw []string) (preparedValue[Outer], error) { prepared, err := inner.binding.prepare(raw) if err != nil { return preparedValue[Outer]{}, err } return preparedValue[Outer]{ identity: identity, supplied: prepared.supplied, apply: func(outer *Outer) { store := target(outer) if store == nil { return } if store.values == nil { store.values = make(map[*bindingIdentity]preparedValue[I]) } store.values[inner.binding.identity] = prepared }, }, nil } } captured[index] = Flag[Outer]{binding: binding} } return captured } // ApplyTo applies selected captured flags to an initialized destination. // Repeated core-owned values are copied for each application. func (values FlagValues[I]) ApplyTo(target *I, selected ...Flag[I]) error { if target == nil { return fmt.Errorf("%w: destination is nil", ErrFlagWiring) } for _, flag := range selected { binding := flag.binding if binding.identity == nil { return fmt.Errorf("%w: selected flag has no identity", ErrFlagWiring) } prepared, exists := values.values[binding.identity] if !exists { return fmt.Errorf("%w: flag --%s was not captured", ErrFlagWiring, binding.meta.Name) } if binding.meta.Required && !prepared.supplied { return fmt.Errorf("flag --%s: %w", binding.meta.Name, ErrFlagInput) } prepared.apply(target) } return nil } func classifyInputError(err error) Outcome { if errors.Is(err, ErrFlagWiring) { return Failure(err) } return Usage(err) }