@@ -169,11 +169,11 @@ options: {
169169
170170So a redeclaration of the same name with the same type is silent. What the CLI
171171still warns about at registration is a redeclaration that changes what the
172- spelling * means * :
172+ spelling _ means _ :
173173
174174- a declared option whose name matches a CLI-wide one but whose type differs —
175175 ` verbose: stringOption() ` against the CLI's boolean ` --verbose ` ;
176- - an alias that belongs to a * different * CLI-wide option — `output:
176+ - an alias that belongs to a _ different _ CLI-wide option — `output:
177177stringOption({ alias: "p" })` steals ` --path`'s shorthand. Restating an
178178 option's own shorthand (` path: stringOption({ alias: "p" }) ` ) is fine.
179179
@@ -449,6 +449,40 @@ top of `run`; nothing else changes. "Once per invocation" means once across
449449` canExecute ` , ` run ` and ` postRun ` together — whichever of them the CLI reaches
450450first triggers it, and the rest reuse the value.
451451
452+ When several commands share a setup, or a helper outside the definition takes
453+ the services as a parameter, lift it into a named function and derive the type
454+ from it instead of writing the shape out by hand:
455+
456+ ``` ts
457+ export function setupWidgetAddCommand() {
458+ const projectData = inject (ProjectData );
459+ projectData .initializeProjectData ();
460+ return { projectData , widgets: inject (WidgetService ) };
461+ }
462+ export type IWidgetAddCommandServices = ReturnType <
463+ typeof setupWidgetAddCommand
464+ >;
465+
466+ export function canAddWidget(services : IWidgetAddCommandServices ): boolean {
467+ return !! services .projectData .projectDir ;
468+ }
469+
470+ export default defineCommand ({
471+ name: " widget|add" ,
472+ arguments: " any" ,
473+ setup: setupWidgetAddCommand ,
474+ canExecute : (ctx , services ) => canAddWidget (services ),
475+ async run(ctx , { widgets }) {
476+ await widgets .add (ctx .args );
477+ },
478+ });
479+ ```
480+
481+ Leave the setup function's return type off: the alias reads what the body
482+ infers, so annotating the function with the alias makes the pair circular. Read
483+ a setup curried over a parameter — ` setupX(platform) ` returning the setup
484+ itself — through its inner function, ` ReturnType<ReturnType<typeof setupX>> ` .
485+
452486` run ` 's return value, and ` postRun `
453487-----------------------------------
454488
@@ -504,7 +538,7 @@ all — or the definition itself, which it defines on your behalf, so registerin
504538a command is one call. Either way the definition is validated before it reaches
505539the registry. It claims every name the definition declares, through the
506540` CommandRegistry ` the target injector provides, and returns a
507- ` DeferredCommandResult ` — see * The owner is ambient * below. The command instance
541+ ` DeferredCommandResult ` — see _ The owner is ambient _ below. The command instance
508542is built by a factory on first resolution and cached.
509543
510544Pass providers as the second argument to scope the command to a child injector
@@ -523,7 +557,7 @@ That is how one definition serves several commands that differ only in data —
523557the platform each one targets — instead of one command subclassing another.
524558
525559** Which injector it registers against is not a parameter.** It is the injector
526- of the current injection context — see * The owner is ambient * below — and the
560+ of the current injection context — see _ The owner is ambient _ below — and the
527561CLI's own injector outside one. To register against some other injector, run
528562the call in its context:
529563
@@ -722,16 +756,16 @@ A definition is compiled into an ordinary `ICommand`, so nothing downstream —
722756the registry, the router, hooks, help, analytics — knows the difference. The
723757mapping is:
724758
725- | Definition | ` ICommand ` |
726- | --------------------------------- | --------------------------------------------------- |
727- | ` options ` | ` dashedOptions ` |
728- | ` run ` | ` execute ` , wrapped in an injection context |
729- | ` arguments ` , ` canExecute ` | ` canExecute ` : policy enforced, then the refinement |
730- | ` setup ` | — run inside ` canExecute ` /` execute ` , memoised |
731- | ` postRun ` | ` postCommandAction ` , with ` run ` 's return value |
732- | ` allowUnknownOptions ` | ` skipOptionsValidation ` |
733- | — | ` allowedParameters ` , always ` [] ` |
734- | ` disableAnalytics ` , ` enableHooks ` | passed through unchanged |
759+ | Definition | ` ICommand ` |
760+ | --------------------------------- | -------------------------------------------------- |
761+ | ` options ` | ` dashedOptions ` |
762+ | ` run ` | ` execute ` , wrapped in an injection context |
763+ | ` arguments ` , ` canExecute ` | ` canExecute ` : policy enforced, then the refinement |
764+ | ` setup ` | — run inside ` canExecute ` /` execute ` , memoised |
765+ | ` postRun ` | ` postCommandAction ` , with ` run ` 's return value |
766+ | ` allowUnknownOptions ` | ` skipOptionsValidation ` |
767+ | — | ` allowedParameters ` , always ` [] ` |
768+ | ` disableAnalytics ` , ` enableHooks ` | passed through unchanged |
735769
736770The compiled command always exposes ` canExecute ` , because ` CommandsService `
737771stops consulting ` allowedParameters ` as soon as a command has one — the adapter
0 commit comments