Document application-owned alias contracts
This commit is contained in:
74
command.go
74
command.go
@@ -10,21 +10,32 @@ import (
|
||||
"gitea.maximumdirect.net/eric/CommandKit/internal/commandpath"
|
||||
)
|
||||
|
||||
// Command is an opaque, reusable declaration captured by NewCommand, Group,
|
||||
// RootGroup, or an integration. Capture copies declaration slices but retains
|
||||
// callback and caller-owned object references. Installation validates the
|
||||
// declaration before changing an App registry.
|
||||
// Command is an opaque, reusable declaration of canonical commands and groups.
|
||||
// NewCommand, Group, RootGroup, and integration command factories return
|
||||
// Command values. Capture copies declaration slices but retains callback and
|
||||
// caller-owned object references. Installation validates the declaration
|
||||
// before changing an App registry.
|
||||
type Command struct{ record *commandRecord }
|
||||
|
||||
// Declaration is a captured command or application routing rule accepted by
|
||||
// New and App.Register. Only CommandKit declaration types implement it.
|
||||
// Declaration is a captured canonical command or application routing rule
|
||||
// accepted by New and App.Register. Use []Declaration when collecting both
|
||||
// kinds. Group and RootGroup children remain Commands; install routing rules
|
||||
// alongside the completed command tree through New or Register. Only
|
||||
// CommandKit declaration types implement Declaration.
|
||||
//
|
||||
// A zero Command, zero RoutingRule, nil declaration, or typed nil declaration
|
||||
// pointer is invalid. Use NoCommand to represent an intentionally absent
|
||||
// optional command.
|
||||
type Declaration interface {
|
||||
commandkitDeclaration()
|
||||
}
|
||||
|
||||
func (Command) commandkitDeclaration() {}
|
||||
|
||||
// RoutingRule is an opaque, reusable command or flag alias declaration.
|
||||
// RoutingRule is an opaque, reusable command or flag alias declaration. Alias,
|
||||
// FlagAlias, and FlagAliasFor capture routing rules eagerly and retain any
|
||||
// construction issues for New or App.Register to report. Identical duplicate
|
||||
// mappings are accepted; competing targets for the same source are errors.
|
||||
type RoutingRule struct{ record *routingRuleRecord }
|
||||
|
||||
func (RoutingRule) commandkitDeclaration() {}
|
||||
@@ -236,9 +247,11 @@ func (c typedCommand[I]) prepare(flagValues, flagSpellings [][]string, operands
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewCommand captures a typed command declaration without constructing its
|
||||
// input or running callbacks. Construction issues are retained and reported
|
||||
// when the declaration is installed. The returned declaration can be reused.
|
||||
// NewCommand captures a typed canonical command declaration without
|
||||
// constructing its input or running callbacks. It copies the spec's flags,
|
||||
// arguments, and children slices. Construction issues are retained and
|
||||
// reported when the declaration is installed; NewCommand itself does not
|
||||
// return an error. The returned declaration can be reused across Apps.
|
||||
func NewCommand[I any](spec CommandSpec[I]) Command {
|
||||
return captureCommand(spec, nil)
|
||||
}
|
||||
@@ -260,25 +273,29 @@ func captureCommand[I any](spec CommandSpec[I], privateRun func(commandExecution
|
||||
return Command{record: record}
|
||||
}
|
||||
|
||||
// Group captures a non-runnable command group and a copy of its relative child
|
||||
// slice. Child declarations remain reusable and are not recursively copied.
|
||||
// Group captures a non-runnable canonical command group and a copy of its
|
||||
// relative Command child slice. Child declarations remain reusable and are not
|
||||
// recursively copied. Routing rules cannot be children; install them alongside
|
||||
// the root command tree through New or App.Register.
|
||||
func Group(name, summary string, children ...Command) Command {
|
||||
record := &commandRecord{name: name, summary: summary, children: append([]Command(nil), children...)}
|
||||
captureComposition(record)
|
||||
return Command{record: record}
|
||||
}
|
||||
|
||||
// RootGroup captures a group that may only be installed at the application root.
|
||||
// Installation rejects it below any other command, including through wrappers.
|
||||
// RootGroup captures a group that may only be installed at the application
|
||||
// root. Installation rejects it below any other command, including through
|
||||
// wrappers. Its children are canonical Commands; install routing rules at the
|
||||
// application root separately.
|
||||
func RootGroup(name, summary string, children ...Command) Command {
|
||||
command := Group(name, summary, children...)
|
||||
command.record.rootOnly = true
|
||||
return command
|
||||
}
|
||||
|
||||
// WithError returns a new declaration that also retains a non-nil err for
|
||||
// installation. Earlier declaration and child errors remain available, and
|
||||
// wrapped error identity is preserved. A nil err returns command unchanged.
|
||||
// WithError returns a new Command declaration that also retains a non-nil err
|
||||
// for installation. Earlier declaration and child errors remain available,
|
||||
// and wrapped error identity is preserved. A nil err returns command unchanged.
|
||||
func WithError(command Command, err error) Command {
|
||||
if err == nil {
|
||||
return command
|
||||
@@ -294,14 +311,17 @@ func WithError(command Command, err error) Command {
|
||||
return Command{record: &record}
|
||||
}
|
||||
|
||||
// NoCommand explicitly represents an absent optional declaration. Installation
|
||||
// skips it, but reports errors attached to it; a zero Command is invalid and is
|
||||
// not an absence marker.
|
||||
// NoCommand explicitly represents an absent optional command declaration.
|
||||
// Installation skips it, but reports errors attached to it; a zero Command is
|
||||
// invalid and is not an absence marker. Routing rules have no absence marker.
|
||||
func NoCommand() Command { return Command{record: &commandRecord{absent: true}} }
|
||||
|
||||
// Alias captures a command-path alias from path to target. Paths are
|
||||
// whitespace-separated sequences of command names; construction issues are
|
||||
// retained for New or App.Register to report.
|
||||
// whitespace-separated sequences of command names relative to the application
|
||||
// root. The target must resolve to a canonical command or group; aliases do not
|
||||
// add operands or transform flag values. Construction issues are retained for
|
||||
// New or App.Register to report. Identical mappings are accepted, while
|
||||
// different targets for the same source path are installation errors.
|
||||
func Alias(path, target string) RoutingRule {
|
||||
record := &routingRuleRecord{
|
||||
kind: commandAliasRule,
|
||||
@@ -314,7 +334,10 @@ func Alias(path, target string) RoutingRule {
|
||||
}
|
||||
|
||||
// FlagAlias captures an application-wide flag spelling alias. Spellings must
|
||||
// be one long flag name or one individual short spelling.
|
||||
// be one long flag name or one individual short spelling. The mapping applies
|
||||
// wherever its canonical target flag is available and contributes nothing on
|
||||
// commands without that flag. Identical mappings are accepted; different
|
||||
// targets for the same source spelling in this scope are installation errors.
|
||||
func FlagAlias(spelling, target string) RoutingRule {
|
||||
record := &routingRuleRecord{
|
||||
kind: globalFlagAliasRule,
|
||||
@@ -327,7 +350,10 @@ func FlagAlias(spelling, target string) RoutingRule {
|
||||
}
|
||||
|
||||
// FlagAliasFor captures a flag spelling alias scoped to a canonical command
|
||||
// path.
|
||||
// path, not an alias path. The command and canonical target flag must be
|
||||
// available in the complete installation. Scoped mappings take precedence over
|
||||
// application-wide mappings with the same source spelling. Identical mappings
|
||||
// are accepted; competing targets in the same scope are installation errors.
|
||||
func FlagAliasFor(commandPath, spelling, target string) RoutingRule {
|
||||
record := &routingRuleRecord{
|
||||
kind: scopedFlagAliasRule,
|
||||
|
||||
Reference in New Issue
Block a user