Resolve alias declaration API and shared path handling

This commit is contained in:
2026-10-19 13:48:07 +00:00
parent 55330d2817
commit c6c4b01902

View File

@@ -1,9 +1,8 @@
# Application-owned aliases
Status: command- and flag-alias directions accepted; implementation has not
started. Consumer registration conventions are selected; the installer declaration
type and remaining routing details are open. This roadmap records
the target and work needed before implementation.
Status: command- and flag-alias behavior and consumer API direction accepted;
implementation has not started. OD-1 through OD-6 are resolved. This roadmap
records the target and work needed before implementation.
## Purpose and ownership
@@ -60,6 +59,47 @@ Commands and aliases use the same installation boundary through `New` and
aliases as separate routing records internally. No separate alias-registration
API is needed.
### Installation types and composition
Introduce a common `Declaration` interface with an unexported marker method.
CommandKit supplies its implementations through public factories. `Command`
represents canonical commands; a separate opaque `RoutingRule` represents
aliases. Both satisfy `Declaration`:
```text
Declaration
├── Command → canonical command tree
└── RoutingRule → alias routing layer
```
The selected installation signatures are:
```go
func New(identity Identity, declarations ...Declaration) (*App, error)
func (a *App) Register(declarations ...Declaration) error
```
`NewCommand`, `Group`, and integration command factories return `Command`.
`Alias`, `FlagAlias`, and `FlagAliasFor` return `RoutingRule`. The common
installation boundary validates relationships across the layers atomically;
installation directs each declaration to its corresponding registry. Routing
rules reference canonical commands without becoming command nodes or owning
handlers. Preserve eager capture and retained construction errors for both
declaration kinds, without introducing deferred installation callbacks.
`Group`, `RootGroup`, and command children continue to accept only `Command`.
Install routing rules alongside the completed canonical tree through `New` or
`Register`. Alias paths remain relative to the application root; moving a
command beneath a group does not silently rebase an alias.
Use ordinary `[]Declaration` slices for reusable collections containing commands
and routing rules. Command-only helpers may return `Command` or `[]Command`.
Go does not allow expanding `[]Command` into `...Declaration`; callers assembling
installation collections should use `[]Declaration` or convert their elements.
No additional bundle abstraction is selected.
### Consumer declarations
Use space-separated strings for command paths, interpreted as sequences of
command names without shell quoting or expansion. Application-wide flag aliases
use `FlagAlias`; command-scoped aliases use `FlagAliasFor` with an explicit
@@ -75,14 +115,12 @@ app, err := commandkit.New(
)
```
This illustrates planned APIs. The declaration type accepted by the installer
still needs design; aliases remain routing records rather than fabricated
canonical command nodes. Later registration uses the same model and validation.
These are planned APIs. Later registration uses the same model and validation.
Accept identical duplicate alias mappings as harmless, including when reusable
helpers contribute them. Identity includes the alias kind, source, target, and
scope where applicable. Different-target command mappings for the same source
remain errors; overlap between flag scopes is addressed under OD-6.
remain errors; flag scope precedence is specified below.
Alias support lives entirely in core and works with built-in commands,
application commands, optional integrations, or any combination. Validation
@@ -91,6 +129,35 @@ dependency is required for alias support. Core continues to supply help and
version automatically, including for applications whose other commands are
entirely application-defined.
### Shared path handling
Centralize path parsing, component validation, comparison, and formatting in
shared internal helpers with a common structured path representation. Alias
validation, routing, help lookup, and invocation metadata use those primitives.
Keep the routing and canonical command models distinct while sharing path
operations.
Declaration factories tokenize command-path strings on whitespace, accepting
leading, trailing, and repeated whitespace, then validate each component using
the canonical command-name rules. Reject empty paths and invalid components.
Normalize equivalent paths before duplicate detection. Quotes and backslashes
receive no shell interpretation; paths cannot contain flag assignments or
operand templates. Capture parsed paths once when constructing declarations.
CLI arguments are already tokenized. Preserve those boundaries: an argument
containing `list collections` is one argument, not two command components.
Do not trim or split incoming operands or flag values. Invocation routing
identifies the command portion of the supplied tokens and carries structured
paths through alias resolution and canonical selection. Format paths for
presentation when needed, avoiding repeated string joining and parsing through
alias chains.
Convert inputs at their appropriate boundaries and reuse the result where
practical. Parsing once per query is an implementation objective, not a permanent
allocation or parsing guarantee. Use an internal path package if sharing across
core and the backend adapter warrants it; otherwise private core helpers and a
path type suffice. No additional public path package is selected.
## Selected command-alias behavior
### Paths and resolution
@@ -222,8 +289,15 @@ the selected public metadata.
Consumers can use the canonical path to identify the operation consistently
and the entered path for logging and diagnostics. CommandKit dispatch and
bindings continue to use the canonical target. Exact accessor names and path
representation remain API design details under OD-1.
bindings continue to use the canonical target. Expose the paths through these
accessors, returning normalized, space-separated strings:
```go
func (inv Invocation) EnteredPath() string
func (inv Invocation) CanonicalPath() string
```
Strings provide read-only values and match the declaration path representation.
Support both help forms:
@@ -415,7 +489,7 @@ canonical binding.
## Work needed from the baseline
1. Finalize the installer declaration type and open routing details with consumer examples
1. Prepare consumer examples for the selected declaration types and shared path handling,
covering a command shortcut, a synonym inside an integration namespace, and
a group shortcut, an application-wide help flag alias, and a command-scoped
flag alias reached through a command shortcut.
@@ -423,8 +497,9 @@ canonical binding.
command and flag ownership in an ADR. Keep exact API, matching, and presentation
details in their appropriate contracts. No relaxation of canonical namespace
ownership is selected.
3. Extend installation to validate aliases and commands against the complete
candidate batch, preserving retained errors and atomicity. Keep aliases
3. Implement the selected declaration types and shared path primitives. Extend
installation to validate aliases and commands against the complete candidate
batch, preserving retained errors and atomicity. Keep aliases
independent of optional-library dependencies and backend-specific exports.
4. Integrate command and flag alias resolution with canonical routing, help, and
invocation identity. Use canonical flag metadata and the existing parser to
@@ -448,17 +523,4 @@ Completion means consumers can declare alternate command paths and flag
spellings with minimal wiring and invoke canonical behavior and help through
them while canonical ownership and binding semantics stay intact. Installation
rejects conflicts with canonical commands and applicable flags in either
registration order. Remaining public API details are listed below.
## Open Decisions
### OD-1: Installer declaration type and composition details
The shared installation API, path strings, explicit flag scopes, identical
duplicate handling, and core-only availability are selected above. What public
declaration type lets `New` and `App.Register` accept commands and aliases
together? How do collections of reusable declarations and group composition
interact with application-root alias paths? What exact whitespace parsing and
path validation rules accompany the selected string representation? What
accessor names and representation expose the selected read-only entered and
canonical invocation paths?
registration order.