@crustjs/core 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context-Cud9frNp.d.ts +2059 -0
- package/dist/index.d.ts +3 -1287
- package/dist/index.js +2 -1
- package/dist/{invocation-CIvHShiW.js → invocation-B17RvTLb.js} +5 -216
- package/dist/tooling.d.ts +2 -1
- package/dist/tooling.js +2 -1
- package/package.json +4 -2
- package/dist/artifacts-D8Jlug-a.d.ts +0 -870
package/dist/index.d.ts
CHANGED
|
@@ -1,1289 +1,5 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
|
|
3
|
-
type ArgNames<A extends readonly object[]> = DefName<A[number]>;
|
|
4
|
-
type DuplicateArgBrand<A, Existing extends string> = CollisionBrand<DefName<A>, Existing, "FIX_DUPLICATE_ARG", "Argument name ", " is already defined">;
|
|
5
|
-
type EmptyArgNameError = {
|
|
6
|
-
readonly FIX_EMPTY_NAME: "Argument names must be non-empty";
|
|
7
|
-
};
|
|
8
|
-
/** Reject empty argument names, including empty members of a name union. */
|
|
9
|
-
type EmptyArgNameBrand<Name extends string> = EmptyLiteralNameBrand<Name, EmptyArgNameError>;
|
|
10
|
-
type EmptyArgDefinitionNameBrand<A> = EmptyArgNameBrand<DefNameMembers<A>>;
|
|
11
|
-
type ArgChecks<A, Existing extends string> = A & DuplicateArgBrand<A, Existing> & LocalValueBrand<A> & EmptyArgDefinitionNameBrand<A>;
|
|
12
|
-
/**
|
|
13
|
-
* Per-arg validation tuple type. Resolves to `A` when the constraints are
|
|
14
|
-
* satisfied: only the last arg is variadic, names are unique, and custom
|
|
15
|
-
* parsers are synchronous. Invalid definitions receive a branded property.
|
|
16
|
-
*
|
|
17
|
-
* Generalized to work with any ordered tuple of object-typed definitions.
|
|
18
|
-
* Uses `readonly object[]` to avoid TypeScript's weak type detection
|
|
19
|
-
* (all-optional constraint rejection).
|
|
20
|
-
*
|
|
21
|
-
* ```
|
|
22
|
-
* Property 'FIX_VARIADIC_POSITION' is missing in type '{ name: "files"; ... variadic: true }'
|
|
23
|
-
* but required in type
|
|
24
|
-
* '{ readonly FIX_VARIADIC_POSITION: "Only the last positional argument can be variadic" }'.
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
type ValidateVariadicArgs<A extends readonly object[], Existing extends string = never> = A extends readonly [infer Head, ...infer Tail extends readonly object[]] ? Tail extends readonly [unknown, ...unknown[]] ? Head extends {
|
|
28
|
-
variadic: true;
|
|
29
|
-
} ? readonly [ArgChecks<Head, Existing> & {
|
|
30
|
-
readonly FIX_VARIADIC_POSITION: "Only the last positional argument can be variadic";
|
|
31
|
-
}, ...ValidateVariadicArgs<Tail, Existing | DefName<Head>>] : readonly [ArgChecks<Head, Existing>, ...ValidateVariadicArgs<Tail, Existing | DefName<Head>>] : readonly [ArgChecks<Head, Existing>] : { [I in keyof A]: ArgChecks<A[I], Existing>; };
|
|
32
|
-
type BrandVariadicPosition<A extends readonly object[]> = { [I in keyof A]: A[I] & {
|
|
33
|
-
readonly FIX_VARIADIC_POSITION: "Only the last positional argument can be variadic";
|
|
34
|
-
}; };
|
|
35
|
-
type AppendArgsChecks<A extends ArgsDef, NewA extends ArgsDef> = A extends readonly [...unknown[], infer Last] ? Last extends {
|
|
36
|
-
variadic: true;
|
|
37
|
-
} ? BrandVariadicPosition<ValidateVariadicArgs<NewA, ArgNames<A>>> : ValidateVariadicArgs<NewA, ArgNames<A>> : ValidateVariadicArgs<NewA>;
|
|
38
|
-
/** Conditional collections and uncertain canonical identities cannot promise every alternative output key. */
|
|
39
|
-
type AttachedArgs<A extends ArgsDef> = HasClosedNames<A> extends true ? A : ArgsDef;
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region src/validation/commands.brands.d.ts
|
|
42
|
-
/** Preserve configured aliases; only a genuinely absent field proves an empty set. */
|
|
43
|
-
type AliasesOf<C> = C extends {
|
|
44
|
-
readonly aliases: infer A extends readonly string[];
|
|
45
|
-
} ? A : "aliases" extends keyof C ? readonly string[] : readonly [];
|
|
46
|
-
type NarrowAliases<A extends readonly string[]> = IsClosedName<A[number]> extends true ? A[number] : never;
|
|
47
|
-
type AliasMembers<A extends readonly string[]> = ClosedMembers<A[number]>;
|
|
48
|
-
type AliasShapeError<Name extends string, Alias extends string> = Alias extends "" ? `Subcommand "${Name}" has an invalid alias: must be a non-empty string` : Alias extends `${string} ${string}` | `${string}\t${string}` | `${string}\n${string}` | `${string}\r${string}` | `${string}\v${string}` | `${string}\f${string}` ? `Subcommand "${Name}" alias "${Alias}" must not contain whitespace` : Alias extends `-${string}` ? `Subcommand "${Name}" alias "${Alias}" must not start with "-" (reserved for flags)` : string extends Name ? never : Alias extends Name ? `Subcommand "${Name}" alias "${Alias}" must not equal its own canonical name` : never;
|
|
49
|
-
type AliasShapeErrors<Name extends string, C> = AliasMembers<AliasesOf<C>> extends (infer Alias) ? Alias extends string ? AliasShapeError<Name, Alias> : never : never;
|
|
50
|
-
type AliasShapeBrand<Name extends string, C> = [AliasShapeErrors<Name, C>] extends [never] ? {} : {
|
|
51
|
-
readonly FIX_ALIAS_SHAPE: AliasShapeErrors<Name, C>;
|
|
52
|
-
};
|
|
53
|
-
type RootVersionBrand<C> = "version" extends keyof C ? {
|
|
54
|
-
readonly FIX_ROOT_VERSION: "Command config \"version\" belongs on the root Crust constructor";
|
|
55
|
-
} : {};
|
|
56
|
-
/** Brand command config containing statically known invalid metadata. */
|
|
57
|
-
type ValidateCommandConfig<Name extends string, C> = AliasShapeBrand<Name, C> & RootVersionBrand<C>;
|
|
58
|
-
type EmptyNameError = {
|
|
59
|
-
readonly FIX_EMPTY_NAME: "Command name must be a non-empty string";
|
|
60
|
-
};
|
|
61
|
-
type TrimWhitespace = " " | "\t" | "\n" | "\r" | "\v" | "\f" | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | " " | "
" | "
" | " " | " " | " " | "";
|
|
62
|
-
type BlankName<Name extends string> = Name extends `${TrimWhitespace}${infer Tail}` ? BlankName<Tail> : Name extends "" ? true : false;
|
|
63
|
-
/** Runtime checks own open members; every statically known member is validated, even beside an open one. */
|
|
64
|
-
type CommandNameBrand<Name extends string> = true extends BlankName<ClosedMembers<Name>> ? EmptyNameError : "__proto__" extends ClosedMembers<Name> ? {
|
|
65
|
-
readonly FIX_RESERVED_NAME: "Command name \"__proto__\" is reserved";
|
|
66
|
-
} : {};
|
|
67
|
-
type DefinitionAliases<D> = CommandDefinitionData<D> extends {
|
|
68
|
-
readonly _aliases?: infer A extends readonly string[];
|
|
69
|
-
} ? A : readonly string[];
|
|
70
|
-
/** All statically known canonical and alias spellings carried by a command definition. */
|
|
71
|
-
type CommandDefinitionSpellings<D> = D extends unknown ? D extends {
|
|
72
|
-
name: infer N extends string;
|
|
73
|
-
} ? IsUnion<N> extends true ? never : DefName<D> extends (infer Name extends string) ? [Name] extends [never] ? never : Name | NarrowAliases<DefinitionAliases<D>> : never : never : never;
|
|
74
|
-
type SelfAliasBrand<D> = UnionToIntersection<D extends unknown ? DefNameMembers<D> & AliasMembers<DefinitionAliases<D>> extends (infer Dup extends string) ? [Dup] extends [never] ? {} : {
|
|
75
|
-
readonly FIX_ALIAS_SHAPE: `Command "${Dup}" must not list its own canonical name as an alias`;
|
|
76
|
-
} : never : never>;
|
|
77
|
-
type CommandCollisionBrand<Spellings extends string, Existing extends string> = CollisionBrand<Spellings, Existing, "FIX_COMMAND_COLLISION", "Command name or alias ", " collides with a sibling command">;
|
|
78
|
-
/**
|
|
79
|
-
* Validate definitions against existing siblings and definitions earlier in
|
|
80
|
-
* the same `.add()` call. Widened names opt out because their spellings are
|
|
81
|
-
* not statically knowable; their literal aliases opt out with them
|
|
82
|
-
* (see {@link CommandDefinitionSpellings}).
|
|
83
|
-
*/
|
|
84
|
-
type ValidateCommandDefinitions<Ds extends readonly unknown[], Existing extends string = never> = Ds extends readonly [infer Head, ...infer Tail] ? CommandDefinitionSpellings<Head> extends (infer Spellings extends string) ? readonly [Head & CommandCollisionBrand<Spellings, Existing> & CommandNameBrand<DefNameMembers<Head>> & SelfAliasBrand<Head>, ...ValidateCommandDefinitions<Tail, Existing | Spellings>] : never : Ds;
|
|
85
|
-
type ExtensionCommandDefs<E> = [E] extends [never] ? readonly [] : DefiningOf<E> extends {
|
|
86
|
-
readonly commands?: infer Cs extends readonly unknown[];
|
|
87
|
-
} ? Cs : readonly [];
|
|
88
|
-
/** An uncertain command collection opens only the child namespace. */
|
|
89
|
-
type ExtensionCommandSpellings<E> = AttachedCommandSpellings<ExtensionCommandDefs<E>>;
|
|
90
|
-
type ExtensionsCommandSpellings<Es extends readonly unknown[]> = IsStaticTuple<Es> extends true ? { [I in keyof Es]: ExtensionCommandSpellings<Es[I]>; }[number] : ExtensionCommandDefs<Es[number]>[number] extends never ? never : string;
|
|
91
|
-
type ExtensionCommandCollisionBrand<E, Existing extends string> = CollisionBrand<ExtensionCommandSpellings<E>, Existing, "FIX_COMMAND_COLLISION", "Extension command ", " collides with an existing command">;
|
|
92
|
-
/**
|
|
93
|
-
* Validate each Extension's contributed command spellings against existing
|
|
94
|
-
* root commands and against Extensions earlier in the same `.extend()` call.
|
|
95
|
-
* Runtime preparation resolves collisions last-write-wins, so a statically
|
|
96
|
-
* known collision would silently retype `run()` against a command that
|
|
97
|
-
* dispatch replaces.
|
|
98
|
-
*/
|
|
99
|
-
type ValidateExtensionCommands<Es extends readonly unknown[], Existing extends string> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ExtensionCommandCollisionBrand<H, Existing>, ...ValidateExtensionCommands<T, Existing | ExtensionCommandSpellings<H>>] : Es;
|
|
100
|
-
/** Local metadata checks; unrelated description/version/usage text has no grammar. */
|
|
101
|
-
type SectionTextBrand<S> = S extends {
|
|
102
|
-
title: infer T extends string;
|
|
103
|
-
body: infer B extends string;
|
|
104
|
-
} ? true extends BlankName<T> | BlankName<B> ? {
|
|
105
|
-
readonly FIX_SECTION_TEXT: "Section title/body must be nonblank";
|
|
106
|
-
} : Extract<T, `${string}\r${string}` | `${string}\n${string}`> extends never ? {} : {
|
|
107
|
-
readonly FIX_SECTION_TEXT: "Section title must be a single line";
|
|
108
|
-
} : {};
|
|
109
|
-
type SectionAudienceBrand<S> = S extends {
|
|
110
|
-
only: readonly [];
|
|
111
|
-
} | {
|
|
112
|
-
except: readonly [];
|
|
113
|
-
} ? {
|
|
114
|
-
readonly FIX_SECTION_AUDIENCE: "Section audience must be nonempty";
|
|
115
|
-
} : {};
|
|
116
|
-
type LocalSectionsBrand<C> = "sections" extends keyof C ? C extends {
|
|
117
|
-
sections: infer S extends readonly unknown[];
|
|
118
|
-
} ? {
|
|
119
|
-
readonly sections: { [I in keyof S]: S[I] & UnionToIntersection<SectionTextBrand<S[I]>> & UnionToIntersection<SectionAudienceBrand<S[I]>>; };
|
|
120
|
-
} : {} : {};
|
|
121
|
-
type LocalCommandConfigBrand<N extends string, C> = ValidateCommandConfig<N, C> & LocalSectionsBrand<C>;
|
|
122
|
-
type AttachedCommandSpellings<Ds extends readonly unknown[]> = [Ds] extends [readonly []] ? never : IsStaticTuple<Ds> extends true ? HasClosedNames<Ds> extends true ? false extends { [I in keyof Ds]: IsClosedName<DefinitionAliases<Ds[I]>[number]>; }[number] ? string : CommandDefinitionSpellings<Ds[number]> : string : string;
|
|
123
|
-
//#endregion
|
|
124
|
-
//#region src/validation/contexts.brands.d.ts
|
|
125
|
-
/** Canonical names claimed by more than one instance in the same `.provide()` call. */
|
|
126
|
-
type DuplicateContextNames<Cs extends readonly AnyContextInstance[], Seen extends string = never> = Cs extends readonly [infer Head, ...infer Tail extends readonly AnyContextInstance[]] ? (DefName<Head> & Seen) | DuplicateContextNames<Tail, Seen | DefName<Head>> : never;
|
|
127
|
-
type DuplicateContextBrand<C, Existing extends string> = CollisionBrand<DefName<C>, Existing, "FIX_DUPLICATE_CONTEXT", "Context ", " is already provided on this command path">;
|
|
128
|
-
/**
|
|
129
|
-
* Brand instances whose name is already provided on this builder chain or
|
|
130
|
-
* repeated within the same `.provide()` call. The accumulated Context value
|
|
131
|
-
* map doubles as the name registry (its keys are the provided names), so no
|
|
132
|
-
* separate accumulator is needed. Wrappers generic over the builder type
|
|
133
|
-
* use `any`, which opts out via the
|
|
134
|
-
* `string extends keyof Ctx` guard instead of deferring. Widened names opt
|
|
135
|
-
* out via `DefName`; a parent-provided Context is not in the definition's
|
|
136
|
-
* `Ctx` and therefore cannot be checked at this call site.
|
|
137
|
-
*/
|
|
138
|
-
type ValidateContextNames<Ctx extends ContextMap, Cs extends readonly AnyContextInstance[], Existing extends string = string extends keyof Ctx ? never : keyof Ctx & string, Dups extends string = DuplicateContextNames<Cs>> = { [I in keyof Cs]: Cs[I] & DuplicateContextBrand<Cs[I], Existing | Dups>; };
|
|
139
|
-
type InstanceNames<P extends readonly unknown[]> = P extends readonly [infer H, ...infer T extends readonly unknown[]] ? DefName<H> | InstanceNames<T> : never;
|
|
140
|
-
/** Statically known names of an Extension's provided Contexts; widened Extensions opt out. */
|
|
141
|
-
type ExtensionProvidedNames<E> = DefiningOf<E> extends {
|
|
142
|
-
readonly provides?: infer P extends readonly unknown[];
|
|
143
|
-
} ? InstanceNames<P> : never;
|
|
144
|
-
type ExtensionContextBrand<E, Existing extends string> = CollisionBrand<ExtensionProvidedNames<E>, Existing, "FIX_DUPLICATE_CONTEXT", "Extension-provided Context ", " is already provided on this command path">;
|
|
145
|
-
type ValidateExtensionProvidesWorker<Es extends readonly unknown[], Existing extends string> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ExtensionContextBrand<H, Existing>, ...ValidateExtensionProvidesWorker<T, Existing | ExtensionProvidedNames<H>>] : Es;
|
|
146
|
-
/**
|
|
147
|
-
* Brand Extensions whose provided Context names replace one already on the
|
|
148
|
-
* command path (or one provided by an earlier Extension in the same call).
|
|
149
|
-
* The resolver is last-write-wins, so a silent replacement would hand actions
|
|
150
|
-
* bound before `.extend()` a value of a different static type.
|
|
151
|
-
*/
|
|
152
|
-
type ValidateExtensionProvides<Es extends readonly unknown[], Ctx extends ContextMap> = ValidateExtensionProvidesWorker<Es, string extends keyof Ctx ? never : keyof Ctx & string>;
|
|
153
|
-
type ProvidedDepsOf<C> = IsAny<C> extends true ? {} : IsAny<ContextDepsOf<C>> extends true ? {} : string extends keyof ContextDepsOf<C> ? {} : ContextDepsOf<C>;
|
|
154
|
-
type MissingDependencyBrand<C, Known extends string> = Exclude<keyof ProvidedDepsOf<C> & string, Known> extends (infer Missing extends string) ? [Missing] extends [never] ? {} : {
|
|
155
|
-
readonly FIX_MISSING_DEPENDENCY: `Context "${DefName<C>}" uses Context "${Missing}" which is not provided on this command path`;
|
|
156
|
-
} : never;
|
|
157
|
-
type MismatchedDependencyNames<Deps, KnownValues> = keyof Deps extends never ? never : KnownValues extends unknown ? { [K in keyof Deps & keyof KnownValues & string]: IsAny<KnownValues[K]> extends true ? never : IsAny<Deps[K]> extends true ? never : [unknown, string] extends [KnownValues[K], keyof KnownValues] ? never : KnownValues[K] extends Deps[K] ? never : K; }[keyof Deps & keyof KnownValues & string] : never;
|
|
158
|
-
type MismatchedDependencyBrand<C, KnownValues> = MismatchedDependencyNames<ProvidedDepsOf<C>, KnownValues> extends (infer Mismatched extends string) ? [Mismatched] extends [never] ? {} : {
|
|
159
|
-
readonly FIX_DEPENDENCY_TYPE: `Context "${DefName<C>}" uses Context "${Mismatched}" whose provided value does not satisfy the declared dependency type`;
|
|
160
|
-
} : never;
|
|
161
|
-
/** Brand provided instances whose transitive dependency closure is unsatisfied. */
|
|
162
|
-
type ValidateContextDeps<Ctx extends ContextMap, Cs extends readonly AnyContextInstance[], Known extends string = (keyof Ctx & string) | DefName<Cs[number]>, KnownValues extends ContextMap = Ctx & ContextsOutput<Cs>> = { [I in keyof Cs]: Cs[I] & MissingDependencyBrand<Cs[I], Known> & MismatchedDependencyBrand<Cs[I], KnownValues>; };
|
|
163
|
-
/** Dependency closure carried by command definitions and Extensions. */
|
|
164
|
-
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
165
|
-
type DeclaredDepsOf<T> = IsAny<T> extends true ? Record<string, ContextValue> : CommandDefinitionData<DefiningOf<T>> extends {
|
|
166
|
-
readonly _deps?: infer D extends ContextMap;
|
|
167
|
-
} ? IsAny<D> extends true ? Record<string, ContextValue> : D : {};
|
|
168
|
-
/** Missing-dependency brand shared by `ValidateDeclaredDeps` and inline `.command()`. */
|
|
169
|
-
type MissingDeclaredDependencyBrand<T, Known extends string> = string extends keyof DeclaredDepsOf<T> ? {} : Exclude<keyof DeclaredDepsOf<T> & string, Known> extends (infer Missing extends string) ? [Missing] extends [never] ? {} : {
|
|
170
|
-
readonly FIX_MISSING_DEPENDENCY: `Uses Context "${Missing}" which is not provided`;
|
|
171
|
-
} : never;
|
|
172
|
-
/** Brand sealed units whose declared dependencies are absent at a composition site. */
|
|
173
|
-
type ValidateDeclaredDeps<Ctx extends ContextMap, Items extends readonly unknown[]> = { [I in keyof Items]: Items[I] & MissingDeclaredDependencyBrand<Items[I], keyof Ctx & string> & DeclaredDependencyValuesBrand<DeclaredDepsOf<Items[I]>, Ctx>; };
|
|
174
|
-
/** Callback values stay TypeScript-owned, including at dynamic composition. */
|
|
175
|
-
type DeclaredDependencyValuesBrand<Deps, Values> = MismatchedDependencyNames<Deps, Values> extends (infer Names extends string) ? [Names] extends [never] ? {} : {
|
|
176
|
-
readonly FIX_DEPENDENCY_TYPE: `Provided Context "${Names}" does not satisfy its declared value type`;
|
|
177
|
-
} : never;
|
|
178
|
-
/** Structural provider copies retain their defining name. */
|
|
179
|
-
type KnownContextInstances<Cs extends readonly AnyContextInstance[]> = { [I in keyof Cs]: Cs[I] & Pick<DefiningOf<Cs[I]>, "name">; };
|
|
180
|
-
//#endregion
|
|
181
|
-
//#region src/validation/flags.brands.d.ts
|
|
182
|
-
/** Brand an incoming definition when one of its spellings is already claimed. */
|
|
183
|
-
type ExistingFlagCollisionBrand<F, Existing extends string> = CollisionBrand<DefName<F> | ExtractAllAliases<F>, Existing, "FIX_ALIAS_COLLISION", "Flag spelling ", " collides with an existing flag">;
|
|
184
|
-
/**
|
|
185
|
-
* Every statically known canonical, short, and long-alias member, including literals
|
|
186
|
-
* beside an open member. Spelling grammar only: collision evidence stays with
|
|
187
|
-
* {@link ExtractAllAliases}, which must not leak literals out of an open domain.
|
|
188
|
-
* Each field is filtered on its own so a `string`-typed field cannot absorb a
|
|
189
|
-
* sibling field's invalid literal before the filter runs.
|
|
190
|
-
*/
|
|
191
|
-
type SpellingMembers<F> = DefNameMembers<F> | ClosedMembers<F extends {
|
|
192
|
-
short: infer S extends string;
|
|
193
|
-
} ? S : never> | ClosedMembers<F extends {
|
|
194
|
-
aliases: infer A extends readonly string[];
|
|
195
|
-
} ? A[number] : never>;
|
|
196
|
-
/** Reject `__proto__`, which mutates the prototype of plain-object flag registries. */
|
|
197
|
-
type ReservedSpellingBrand<F> = "__proto__" extends SpellingMembers<F> ? {
|
|
198
|
-
readonly FIX_RESERVED_SPELLING: "Flag spelling \"__proto__\" is reserved";
|
|
199
|
-
} : {};
|
|
200
|
-
type EmptySpellingError = {
|
|
201
|
-
readonly FIX_EMPTY_SPELLING: "Flag names and aliases must be non-empty strings";
|
|
202
|
-
};
|
|
203
|
-
/** Reject empty flag names, including an empty member of a name union beside an open member. */
|
|
204
|
-
type EmptyFlagSpellingBrand<Name extends string> = EmptyLiteralNameBrand<Name, EmptySpellingError>;
|
|
205
|
-
/** Reject empty spellings: their CLI tokens (`--`, `-`) are unparseable, so the flag can never be supplied. */
|
|
206
|
-
type EmptySpellingBrand<F> = "" extends SpellingMembers<F> ? EmptySpellingError : {};
|
|
207
|
-
type RepeatedAliases<Aliases extends readonly string[], Seen extends string> = Aliases extends readonly [infer Head extends string, ...infer Tail extends readonly string[]] ? (Head & Seen) | RepeatedAliases<Tail, Seen | Head> : never;
|
|
208
|
-
type OwnAliasesBrand<F> = F extends {
|
|
209
|
-
aliases: infer Aliases extends readonly string[];
|
|
210
|
-
} ? RepeatedAliases<Aliases, ExtractShort<F>> extends (infer Duplicate extends string) ? [Duplicate] extends [never] ? {} : {
|
|
211
|
-
readonly FIX_ALIAS_COLLISION: "Flag repeats one of its own spellings";
|
|
212
|
-
} : never : {};
|
|
213
|
-
type InvalidShort<S extends string> = S extends `${infer _First}${infer Rest}` ? Rest extends "" ? never : S : S;
|
|
214
|
-
type ShortLengthBrand<F> = F extends {
|
|
215
|
-
short: infer Short extends string;
|
|
216
|
-
} ? string extends Short ? {} : [InvalidShort<Short>] extends [never] ? {} : {
|
|
217
|
-
readonly FIX_SHORT_LENGTH: "Short flags must be one character";
|
|
218
|
-
} : {};
|
|
219
|
-
/**
|
|
220
|
-
* Extract the `short` alias literal from a flag definition.
|
|
221
|
-
* Resolves to `never` when the field is absent or its spelling domain is open.
|
|
222
|
-
*/
|
|
223
|
-
type ExtractShort<F> = F extends {
|
|
224
|
-
short: infer S;
|
|
225
|
-
} ? S extends string ? IsClosedName<S> extends true ? S : never : never : never;
|
|
226
|
-
/**
|
|
227
|
-
* Extract alias string literals from the `aliases` array of a flag definition.
|
|
228
|
-
* Resolves to `never` when the field is absent or its element domain is open.
|
|
229
|
-
*/
|
|
230
|
-
type ExtractLongAliases<F> = F extends {
|
|
231
|
-
aliases: infer A;
|
|
232
|
-
} ? A extends readonly string[] ? IsClosedName<A[number]> extends true ? A[number] : never : never : never;
|
|
233
|
-
/**
|
|
234
|
-
* Extract all alias identifiers (short + long) from a flag definition.
|
|
235
|
-
*
|
|
236
|
-
* Generalized to work with any shape; values without `short`/`aliases`
|
|
237
|
-
* fields resolve to `never`.
|
|
238
|
-
*
|
|
239
|
-
* Closed-name proof excludes open domains from literal collision evidence.
|
|
240
|
-
* Attachment separately keeps their spelling namespace open.
|
|
241
|
-
*/
|
|
242
|
-
type ExtractAllAliases<F> = ExtractShort<F> | ExtractLongAliases<F>;
|
|
243
|
-
/** All narrowed canonical, short, and long-alias spellings in a flags record. */
|
|
244
|
-
type SpellingsOf<F extends FlagsDef> = string extends keyof F ? never : (keyof F & string) | { [K in keyof F & string]: ExtractAllAliases<F[K]>; }[keyof F & string];
|
|
245
|
-
type NoPrefixBrand<S extends string> = [Extract<S, `no-${string}`>] extends [never] ? {} : {
|
|
246
|
-
readonly FIX_NO_PREFIX: "Names must not start with no-";
|
|
247
|
-
};
|
|
248
|
-
type ContextOwnedFlags<C> = C extends unknown ? DefiningOf<C> extends {
|
|
249
|
-
readonly _ownedFlags?: infer OF extends FlagsDef;
|
|
250
|
-
} ? OF : {} : never;
|
|
251
|
-
type ContextFlagCollisionBrand<C, Existing extends string> = CollisionBrand<LocalSpellingsOf<ContextOwnedFlags<C>>, Existing, "FIX_ALIAS_COLLISION", "Flag spelling ", " collides with an existing flag">;
|
|
252
|
-
/** Declared flag literals carried by an Extension's `_flagDefs` phantom; widened Extensions opt out. */
|
|
253
|
-
type ExtensionFlagDefsOf<E> = [E] extends [never] ? readonly [] : DefiningOf<E> extends {
|
|
254
|
-
readonly _flagDefs?: infer D extends readonly NamedFlagDef[];
|
|
255
|
-
} ? D : readonly NamedFlagDef[];
|
|
256
|
-
/** All statically known owned-flag spellings across a tuple of Context instances. */
|
|
257
|
-
type ProvidedContextSpellings<P extends readonly unknown[]> = P extends readonly [infer H, ...infer T extends readonly unknown[]] ? LocalSpellingsOf<ContextOwnedFlags<H>> | ProvidedContextSpellings<T> : [P[number]] extends [never] ? never : LocalSpellingsOf<ContextOwnedFlags<P[number]>>;
|
|
258
|
-
/** All statically known flag spellings an Extension contributes: declared flags plus provided Context-owned flags. */
|
|
259
|
-
type ExtensionSpellings<E> = AttachedSpellings<ExtensionFlagDefsOf<E>> | ([E] extends [never] ? never : DefiningOf<E> extends {
|
|
260
|
-
readonly provides?: infer P extends readonly unknown[];
|
|
261
|
-
} ? ProvidedContextSpellings<P> : never);
|
|
262
|
-
type ExtensionFlagCollisionBrand<E, Existing extends string> = CollisionBrand<ExtensionSpellings<E>, Existing, "FIX_ALIAS_COLLISION", "Extension flag spelling ", " collides with an existing flag">;
|
|
263
|
-
/**
|
|
264
|
-
* Validate each Extension's contributed flag spellings against accumulated
|
|
265
|
-
* existing spellings and against Extensions earlier in the same `.extend()`
|
|
266
|
-
* call. Extensions must not override application flags: a silent overwrite
|
|
267
|
-
* would retype an already-bound action's flag at parse time.
|
|
268
|
-
*/
|
|
269
|
-
type ValidateExtensionFlags<Es extends readonly unknown[], Existing extends string> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ExtensionFlagCollisionBrand<H, Existing>, ...ValidateExtensionFlags<T, Existing | ExtensionSpellings<H>>] : Es;
|
|
270
|
-
type ShapeSpellings<S> = 0 extends 1 & S ? string : S extends {
|
|
271
|
-
readonly flags: infer F extends FlagsDef;
|
|
272
|
-
readonly children: infer C;
|
|
273
|
-
} ? LocalSpellingsOf<F> | TreeSpellings<C> : never;
|
|
274
|
-
/** Every flag spelling reachable in a compile-time command tree (`Record<spelling, CommandShape>`), recursively. */
|
|
275
|
-
type TreeSpellings<Tree> = 0 extends 1 & Tree ? string : string extends keyof Tree ? string : Tree extends object ? { [K in keyof Tree]: ShapeSpellings<Tree[K]>; }[keyof Tree] : never;
|
|
276
|
-
type DefinitionSpellings<D> = CommandDefinitionData<D> extends {
|
|
277
|
-
readonly _shape?: infer S;
|
|
278
|
-
} ? ShapeSpellings<S> : never;
|
|
279
|
-
/** Flag spellings contributed by a tuple of command definitions. */
|
|
280
|
-
type DefinitionTreeSpellings<Ds extends readonly unknown[]> = DefinitionSpellings<Ds[number]>;
|
|
281
|
-
/**
|
|
282
|
-
* Extension-collision brand over a built command shape. Shared by `.add()`
|
|
283
|
-
* (via {@link ValidateDefinitionFlags}) and inline `.command()`, whose recipe
|
|
284
|
-
* builder exposes a shape instead of a definition tuple.
|
|
285
|
-
*/
|
|
286
|
-
type ShapeFlagCollisionBrand<S, Ext extends string> = CollisionBrand<ShapeSpellings<S>, Ext, "FIX_ALIAS_COLLISION", "Flag spelling ", " collides with a registered Extension flag">;
|
|
287
|
-
type DefinitionFlagCollisionBrand<D, Ext extends string> = CommandDefinitionData<D> extends {
|
|
288
|
-
readonly _shape?: infer S;
|
|
289
|
-
} ? ShapeFlagCollisionBrand<S, Ext> : {};
|
|
290
|
-
/**
|
|
291
|
-
* Validate an added definition tree's flag spellings against already-registered
|
|
292
|
-
* Extension flags. Recursive Extension flags inject into every node at prepare
|
|
293
|
-
* time, so a colliding local flag would be silently retyped for its action.
|
|
294
|
-
*/
|
|
295
|
-
type ValidateDefinitionFlags<Ds extends readonly unknown[], Ext extends string> = { [I in keyof Ds]: Ds[I] & DefinitionFlagCollisionBrand<Ds[I], Ext>; };
|
|
296
|
-
/** Union of every statically known flag spelling contributed by a tuple of Extensions. */
|
|
297
|
-
type ExtensionsSpellings<Es extends readonly unknown[]> = Es extends readonly [infer H, ...infer T extends readonly unknown[]] ? ExtensionSpellings<H> | ExtensionsSpellings<T> : ExtensionSpellings<Es[number]> extends never ? never : string;
|
|
298
|
-
/**
|
|
299
|
-
* Validate Context-owned flags against accumulated existing spellings and
|
|
300
|
-
* against instances earlier in the same `.provide(a(), b())` call. Without
|
|
301
|
-
* the batch check a same-call collision silently resolves last-write-wins,
|
|
302
|
-
* and a required flag shadowed by a peer's alias becomes impossible to supply.
|
|
303
|
-
*/
|
|
304
|
-
type ProvideChecks<Sp extends string, Cs extends readonly unknown[]> = Cs extends readonly [infer H, ...infer T extends readonly unknown[]] ? readonly [H & ContextFlagCollisionBrand<H, Sp>, ...ProvideChecks<Sp | LocalSpellingsOf<ContextOwnedFlags<H>>, T>] : Cs;
|
|
305
|
-
/** Whether canonical and alias spellings form a closed, fixed local namespace. */
|
|
306
|
-
type HasClosedFlagSpellings<F> = F extends {
|
|
307
|
-
name: infer N extends string;
|
|
308
|
-
} ? false extends IsClosedName<N> | ("short" extends keyof F ? F extends {
|
|
309
|
-
short: infer S extends string;
|
|
310
|
-
} ? IsClosedName<S> : false : true) | ("aliases" extends keyof F ? F extends {
|
|
311
|
-
aliases: infer A extends readonly string[];
|
|
312
|
-
} ? false extends IsStaticTuple<A> | IsClosedName<A[number]> ? false : true : false : true) ? false : true : false;
|
|
313
|
-
type LocalFlagBrand<F> = UnionToIntersection<F extends unknown ? LocalFlagBranchBrand<F> : never>;
|
|
314
|
-
type LocalFlagBranchBrand<F> = LocalValueBrand<F> & OwnAliasesBrand<F> & ShortLengthBrand<F> & ReservedSpellingBrand<F> & EmptySpellingBrand<F> & NoPrefixBrand<SpellingMembers<F>> & ([DefName<F> & ExtractAllAliases<F>] extends [never] ? {} : {
|
|
315
|
-
readonly FIX_ALIAS_COLLISION: "Flag repeats one of its own spellings";
|
|
316
|
-
});
|
|
317
|
-
/** Validate provable local fields and destination relations without inventing names for open inputs. */
|
|
318
|
-
type ValidateLocalFlagDefs<Defs extends readonly NamedFlagDef[], Existing extends string> = Defs & UnionToIntersection<LocalFlagTupleChecks<Defs, Existing>>;
|
|
319
|
-
type LocalFlagTupleChecks<Defs extends readonly NamedFlagDef[], Existing extends string, Errors = {}> = Defs extends readonly [infer Head extends NamedFlagDef, ...infer Tail extends readonly NamedFlagDef[]] ? LocalFlagTupleChecks<Tail, Existing | DefName<Head> | ExtractAllAliases<Head>, Errors & LocalFlagBrand<Head> & ExistingFlagCollisionBrand<Head, Existing>> : Defs extends readonly [] ? Errors : Errors & LocalFlagBrand<Defs[number]>;
|
|
320
|
-
/** An open collection is not an empty or guaranteed-present flag record. */
|
|
321
|
-
type KnownNamedFlag<D> = D extends NamedFlagDef ? HasClosedNames<readonly [D]> extends true ? D : never : never;
|
|
322
|
-
type AttachedFlags<Defs extends readonly NamedFlagDef[]> = HasClosedNames<Defs> extends true ? NamedFlagsRecord<Defs> : IsStaticTuple<Defs> extends true ? FlagsDef & NamedFlagsRecord<readonly KnownNamedFlag<Defs[number]>[]> : FlagsDef;
|
|
323
|
-
type AttachedSpellings<Defs extends readonly NamedFlagDef[]> = IsStaticTuple<Defs> extends true ? false extends { [I in keyof Defs]: HasClosedFlagSpellings<Defs[I]>; }[number] ? string : SpellingsOf<NamedFlagsRecord<Defs>> : string;
|
|
324
|
-
type LocalFlagNameBrand<N extends string> = EmptyFlagSpellingBrand<N> & ReservedSpellingBrand<{
|
|
325
|
-
name: N;
|
|
326
|
-
}> & NoPrefixBrand<N>;
|
|
327
|
-
/** Broad structural builder holders must not default their spelling state to empty. */
|
|
328
|
-
type LocalSpellingsOf<F extends FlagsDef> = string extends keyof F ? string : true extends { [K in keyof F]: HasClosedFlagSpellings<F[K] & {
|
|
329
|
-
name: K;
|
|
330
|
-
}> extends false ? true : false; }[keyof F] ? string : SpellingsOf<F>;
|
|
331
|
-
//#endregion
|
|
332
|
-
//#region src/command/crust.d.ts
|
|
333
|
-
/**
|
|
334
|
-
* The runtime context object passed to the Command Action defined with
|
|
335
|
-
* `.action()`.
|
|
336
|
-
*
|
|
337
|
-
* Generic parameters:
|
|
338
|
-
* - `A` — positional argument definitions tuple
|
|
339
|
-
* - `F` — the effective (Context-owned + local merged) flag definitions
|
|
340
|
-
*/
|
|
341
|
-
interface CrustCommandContext<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef, Ctx extends ContextMap = {}> extends InvocationIO {
|
|
342
|
-
/** Resolved positional arguments, keyed by arg name */
|
|
343
|
-
args: InferArgs<A>;
|
|
344
|
-
/** Resolved flags, keyed by flag name */
|
|
345
|
-
flags: InferFlags<F>;
|
|
346
|
-
/** Lazy Context values available on this command path. */
|
|
347
|
-
ctx: ContextBag<Ctx>;
|
|
348
|
-
/** Raw arguments that appeared after the `--` separator */
|
|
349
|
-
rawArgs: string[];
|
|
350
|
-
/** Readonly, serializable snapshot of the resolved command */
|
|
351
|
-
command: CommandSnapshot;
|
|
352
|
-
/** Readonly snapshot of the application root, including Extension contributions */
|
|
353
|
-
rootCommand: CommandSnapshot;
|
|
354
|
-
}
|
|
355
|
-
declare const commandProviders: unique symbol;
|
|
356
|
-
/** Compile-time description of one command's programmatic input and action result. */
|
|
357
|
-
interface CommandShape<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef, Children extends object = {}, Result = unknown, Providers extends Record<string, ContextValue> = Record<string, ContextValue>> {
|
|
358
|
-
readonly [commandProviders]?: Providers;
|
|
359
|
-
readonly args: A;
|
|
360
|
-
readonly flags: F;
|
|
361
|
-
readonly children: Children;
|
|
362
|
-
readonly result: Result;
|
|
363
|
-
}
|
|
364
|
-
/** Captured invocation after lifecycle cleanup. */
|
|
365
|
-
type RunOutcome<Result> = {
|
|
366
|
-
readonly stdout: string;
|
|
367
|
-
readonly stderr: string;
|
|
368
|
-
} & ({
|
|
369
|
-
readonly status: "completed";
|
|
370
|
-
readonly result: Result;
|
|
371
|
-
} | {
|
|
372
|
-
readonly status: "finished";
|
|
373
|
-
readonly by: ExtensionId;
|
|
374
|
-
} | {
|
|
375
|
-
readonly status: "failed";
|
|
376
|
-
readonly error: unknown;
|
|
377
|
-
});
|
|
378
|
-
/** Compile-time command tree accumulated by `.add()`. */
|
|
379
|
-
type CommandTree = Record<string, CommandShape>;
|
|
380
|
-
/** Every valid path through a command tree, including the root path (`[]`). */
|
|
381
|
-
type CommandPath<Tree extends object, Depth extends readonly unknown[] = readonly []> = Depth["length"] extends 15 ? readonly string[] : string extends keyof Tree ? readonly string[] : readonly [] | { [K in keyof Tree & string]: Tree[K] extends CommandShape ? readonly [K, ...CommandPath<Tree[K]["children"], readonly [...Depth, unknown]>] : never; }[keyof Tree & string];
|
|
382
|
-
type KnownCommandPath<Path extends readonly string[], Tree> = string extends keyof Tree ? Path : IsStaticTuple<Path> extends true ? string extends Path[number] ? never : Path : never;
|
|
383
|
-
/** Resolve the command shape at a typed path. */
|
|
384
|
-
type CommandShapeAt<Shape extends CommandShape, Path extends readonly string[]> = Path extends readonly [infer Head, ...infer Tail extends readonly string[]] ? Head extends keyof Shape["children"] ? Shape["children"][Head] extends (infer Child extends CommandShape) ? CommandShapeAt<Child, Tail> : never : string extends Head ? CommandShape : never : Path extends readonly [] ? Shape : CommandShape;
|
|
385
|
-
type RunSection<Name extends string, Values> = keyof Values extends never ? { [K in Name]?: never; } : {} extends Values ? { [K in Name]?: Values; } : { [K in Name]: Values; };
|
|
386
|
-
/** Structured values bound directly against the selected command's definitions; no argv is produced. */
|
|
387
|
-
type RunInput<Shape extends CommandShape> = RunSection<"args", ArgsDef extends Shape["args"] ? NonNullable<RunInputPayload["args"]> : InputArgs<Shape["args"]>> & RunSection<"flags", FlagsDef extends Shape["flags"] ? NonNullable<RunInputPayload["flags"]> : InputFlags<Shape["flags"]>> & {
|
|
388
|
-
readonly raw?: readonly string[];
|
|
389
|
-
};
|
|
390
|
-
type CompatibleRunValue<Expected, Actual> = Actual extends Expected ? Actual extends object ? Expected extends unknown ? Actual extends Expected ? Actual & { [K in Exclude<keyof Actual, keyof Expected>]: never; } & { [K in keyof Actual & keyof Expected]: CompatibleRunValue<Expected[K], Actual[K]>; } : never : never : Actual : JsonValue extends Expected ? Actual extends JsonCompatible<Actual> ? Actual : never : Expected extends unknown ? CompatibleRunBranch<Expected, Actual> : never;
|
|
391
|
-
type CompatibleRunBranch<Expected, Actual> = Actual extends Expected ? Actual : Expected extends readonly (infer Item)[] ? JsonValue extends Item ? Actual extends (Expected extends readonly [unknown, ...unknown[]] ? readonly [unknown, ...unknown[]] : readonly unknown[]) ? Actual extends JsonCompatible<Actual> ? Actual : never : never : never : Actual extends object ? string extends keyof Expected ? { [K in keyof Actual]: CompatibleRunValue<Exclude<Expected[K & keyof Expected], undefined>, Actual[K]>; } : { [K in keyof Expected]: K extends keyof Actual ? CompatibleRunValue<Exclude<Expected[K], undefined>, Actual[K]> : Expected[K]; } & { [K in Exclude<keyof Actual, keyof Expected>]: never; } : never;
|
|
392
|
-
type CompatibleRunInput<Shape extends CommandShape, Input> = CompatibleRunValue<RunInput<Shape>, Input>;
|
|
393
|
-
type RunInputArguments<Shape extends CommandShape> = {} extends RunInput<Shape> ? readonly [input?: RunInput<Shape>] : readonly [input: RunInput<Shape>];
|
|
394
|
-
type RunArguments<Shape extends CommandShape> = readonly [...RunInputArguments<Shape>, io?: Partial<InvocationIO>];
|
|
395
|
-
/**
|
|
396
|
-
* Typed invoker bound to one command in an app, returned by {@link Crust.at}.
|
|
397
|
-
*
|
|
398
|
-
* `run` accepts the same structured input and IO as `Crust.run` with the path
|
|
399
|
-
* already applied, so a handle can be re-exported as a plain typed function.
|
|
400
|
-
*/
|
|
401
|
-
interface CommandHandle<Shape extends CommandShape> {
|
|
402
|
-
/** The typed path this handle was created with (`[]` selects the root). */
|
|
403
|
-
readonly path: readonly string[];
|
|
404
|
-
run(...args: RunArguments<Shape>): Promise<RunOutcome<Shape["result"]>>;
|
|
405
|
-
run<const Input>(input: Input, ...validation: [Input] extends [CompatibleRunInput<Shape, Input>] ? readonly [io?: Partial<InvocationIO>] : readonly [invalidInput: never]): Promise<RunOutcome<Shape["result"]>>;
|
|
406
|
-
}
|
|
407
|
-
/** Static configuration for a reusable command definition. */
|
|
408
|
-
interface CommandConfig extends Omit<CommandMeta, "name" | "sections" | "version"> {
|
|
409
|
-
/** Plain-text sections rendered after built-in command documentation. */
|
|
410
|
-
readonly sections?: readonly RuntimeCommandSectionInput[];
|
|
411
|
-
}
|
|
412
|
-
/** Static metadata accepted by the root command constructor. */
|
|
413
|
-
type RootCommandMeta = Pick<CommandMeta, "description" | "version" | "usage"> & {
|
|
414
|
-
/** Plain-text sections rendered after built-in command documentation. */
|
|
415
|
-
readonly sections?: readonly RuntimeCommandSectionInput[];
|
|
416
|
-
};
|
|
417
|
-
type AnyCommandDefinitionBuilder = Crust<any, any, any, any, any, any, any, any, any, any, any, "recipe">;
|
|
418
|
-
type CommandRecipe<Builder extends AnyCommandDefinitionBuilder = AnyCommandDefinitionBuilder> = (command: CommandDefinitionBuilder<{}, [], {}, never, never>) => Builder;
|
|
419
|
-
declare const commandDefinitionInternal: unique symbol;
|
|
420
|
-
interface CommandDefinitionInternal {
|
|
421
|
-
readonly name: string;
|
|
422
|
-
readonly recipe: (command: AnyCommandDefinitionBuilder) => AnyCommandDefinitionBuilder;
|
|
423
|
-
readonly meta: Omit<CommandMeta, "name">;
|
|
424
|
-
}
|
|
425
|
-
type CommandInputShape<S extends CommandShape> = {
|
|
426
|
-
readonly args: S["args"];
|
|
427
|
-
readonly flags: S["flags"];
|
|
428
|
-
readonly providers: S[typeof commandProviders];
|
|
429
|
-
readonly children: { [K in keyof S["children"]]: S["children"][K] extends CommandShape ? CommandInputShape<S["children"][K]> : never; };
|
|
430
|
-
};
|
|
431
|
-
interface CommandDefinition<Name extends string = string, Aliases extends readonly string[] = readonly string[], Shape extends CommandShape = CommandShape, Deps extends ContextMap = {}> {
|
|
432
|
-
/** The subcommand name this definition is added under */
|
|
433
|
-
readonly name: Name;
|
|
434
|
-
/** The same definition under a different name; configured aliases travel with it. */
|
|
435
|
-
as<const N extends string>(name: N & CommandNameBrand<N> & ValidateCommandConfig<N, {
|
|
436
|
-
aliases: Aliases;
|
|
437
|
-
}>): CommandDefinition<N, Aliases, Shape, Deps>;
|
|
438
|
-
/** @internal */
|
|
439
|
-
readonly [commandDefinitionInternal]: CommandDefinitionInternal & {
|
|
440
|
-
readonly _aliases?: Aliases;
|
|
441
|
-
readonly _shape?: Shape;
|
|
442
|
-
readonly _deps?: Deps;
|
|
443
|
-
readonly proof?: [Shape] extends [never] ? unknown : string extends keyof Shape["flags"] | keyof Deps ? unknown : (state: [CommandInputShape<Shape>, Deps]) => void;
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
/** @internal */
|
|
447
|
-
type CommandDefinitionData<D> = D extends {
|
|
448
|
-
readonly [commandDefinitionInternal]: infer Data;
|
|
449
|
-
} ? Data : D;
|
|
450
|
-
type AppendedArgs<A extends ArgsDef, NewA extends ArgsDef> = readonly [...A, ...AttachedArgs<NewA>];
|
|
451
|
-
/** Configure-only capability of {@link Crust} passed to command recipes. */
|
|
452
|
-
type CommandDefinitionBuilder<Flags extends FlagsDef = {}, A extends ArgsDef = ArgsDef, Ctx extends ContextMap = {}, Sibs extends string = never, Sp extends string = LocalSpellingsOf<Flags>, Tree extends object = {}, CtxFlags extends FlagsDef = {}, Result = void, Deps extends ContextMap = {}, Providers extends Record<string, ContextValue> = {}> = Crust<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSpellings<never, never, {}, never, Deps, Providers>, Result, {}, string, "recipe">;
|
|
453
|
-
type ShapeOfBuilder<B> = [B] extends [never] ? CommandShape<[], {}, {}, never, {}> : B extends {
|
|
454
|
-
readonly _recipeTypes: {
|
|
455
|
-
shape: infer S extends CommandShape;
|
|
456
|
-
};
|
|
457
|
-
} ? S : never;
|
|
458
|
-
type DepsOfBuilder<B> = UnionToIntersection<B extends {
|
|
459
|
-
readonly _recipeTypes: {
|
|
460
|
-
deps: infer Deps extends ContextMap;
|
|
461
|
-
};
|
|
462
|
-
} ? Deps : {}> extends (infer Merged extends ContextMap) ? Merged : {};
|
|
463
|
-
type DefinitionShapeForSpelling<D, Spelling extends string> = D extends unknown ? CommandDefinitionData<D> extends {
|
|
464
|
-
readonly _shape?: infer Shape extends CommandShape;
|
|
465
|
-
} ? Spelling extends CommandDefinitionSpellings<D> ? Shape : never : never : never;
|
|
466
|
-
type ShapeWithInheritedFlags<S, CF extends FlagsDef> = keyof CF extends never ? S : S extends CommandShape<infer SA, infer SF, infer SC, infer SR, infer P> ? CommandShape<SA, MergeFlags<CF, SF>, { [K in keyof SC]: ShapeWithInheritedFlags<SC[K], CF>; }, SR, P> : never;
|
|
467
|
-
type DefinitionsTree<Ds extends readonly CommandDefinition<any, any, any, any>[], CtxFlags extends FlagsDef = {}> = string extends AttachedCommandSpellings<Ds> ? Record<string, CommandShape> & KnownDefinitionTree<Ds, CtxFlags> : { [K in CommandDefinitionSpellings<Ds[number]>]: ShapeWithInheritedFlags<DefinitionShapeForSpelling<Ds[number], K>, CtxFlags>; };
|
|
468
|
-
type KnownDefinitionTree<Ds extends readonly unknown[], CF extends FlagsDef> = IsUnion<Ds> extends true ? {} : Ds extends readonly [infer H, ...infer T] ? (IsUnion<H> extends true ? {} : { [K in CommandDefinitionSpellings<H>]: ShapeWithInheritedFlags<DefinitionShapeForSpelling<H, K>, CF>; }) & KnownDefinitionTree<T, CF> : {};
|
|
469
|
-
type ExtensionCheckAt<Checks, I> = I extends keyof Checks ? Checks[I] : never;
|
|
470
|
-
type ExtensionCommands<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? readonly [...ExtensionCommandDefs<H>, ...ExtensionCommands<T>] : ExtensionCommandDefs<Es[number]>[number] extends never ? readonly [] : readonly CommandDefinition<any, any, any, any>[];
|
|
471
|
-
type ExtensionProviders<E> = [E] extends [never] ? [] : DefiningOf<E> extends {
|
|
472
|
-
provides?: infer P extends readonly AnyContextInstance[];
|
|
473
|
-
} ? P : [];
|
|
474
|
-
type ExtensionOwnDefs<E> = [E] extends [never] ? [] : DefiningOf<E> extends {
|
|
475
|
-
_flagDefs?: infer F extends readonly NamedFlagDef[];
|
|
476
|
-
} ? F : [];
|
|
477
|
-
type ExtensionFlags<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? AttachedFlags<ExtensionOwnDefs<H>> & ContextsOwnedFlags<ExtensionProviders<H>> & ExtensionFlags<T> : ExtensionOwnDefs<Es[number]>[number] extends never ? keyof ContextsOwnedFlags<ExtensionProviders<Es[number]>> extends never ? {} : FlagsDef : FlagsDef;
|
|
478
|
-
type RecursiveFlagsOf<E> = ExtensionOwnDefs<E>[number] extends never ? {} : true extends { [K in keyof ExtensionOwnDefs<E>]: ExtensionOwnDefs<E>[K] extends (infer D extends NamedFlagDef) ? D extends {
|
|
479
|
-
readonly recursive: false;
|
|
480
|
-
} ? false : IsClosedName<D["name"]> extends false ? true : IsUnion<D["name"]> extends true ? true : D extends {
|
|
481
|
-
recursive: infer R;
|
|
482
|
-
} ? boolean extends R ? true : false : false : false; }[number] ? FlagsDef : IsStaticTuple<ExtensionOwnDefs<E>> extends true ? { [D in ExtensionOwnDefs<E>[number] as D extends {
|
|
483
|
-
readonly recursive: infer R;
|
|
484
|
-
} ? [R] extends [false] ? never : D["name"] : D["name"]]: Omit<D, "name">; } : FlagsDef;
|
|
485
|
-
type RecursiveExtensionFlags<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? RecursiveFlagsOf<H> & ContextsOwnedFlags<ExtensionProviders<H>> & RecursiveExtensionFlags<T> : ExtensionFlags<Es>;
|
|
486
|
-
type TreeWithInheritedFlags<Tree, F extends FlagsDef> = { [K in keyof Tree]: ShapeWithInheritedFlags<Tree[K], F>; };
|
|
487
|
-
type ReplacementTree<Tree, D extends CommandDefinition<any, any, any, any>, CF extends FlagsDef> = CommandDefinitionData<D> extends {
|
|
488
|
-
readonly _aliases?: infer Aliases extends readonly string[];
|
|
489
|
-
} ? IsClosedName<Aliases[number]> extends false ? Record<string, CommandShape> & { [K in D["name"]]: ShapeWithInheritedFlags<DefinitionShapeForSpelling<D, K>, CF>; } : Omit<Tree, CommandDefinitionSpellings<D>> & { [K in CommandDefinitionSpellings<D>]: K extends D["name"] ? ShapeWithInheritedFlags<DefinitionShapeForSpelling<D, K>, CF> : K extends keyof Tree ? CommandShape : ShapeWithInheritedFlags<DefinitionShapeForSpelling<D, K>, CF>; } : Record<string, CommandShape>;
|
|
490
|
-
type ReplacedTree<Tree, Commands extends readonly unknown[], CF extends FlagsDef> = Commands extends readonly [infer H extends CommandDefinition<any, any, any, any>, ...infer T extends readonly unknown[]] ? ReplacedTree<IsClosedName<H["name"]> extends false ? Record<string, CommandShape> : true extends IsUnion<H> | IsUnion<H["name"]> ? Record<string, CommandShape> : ReplacementTree<Tree, H, CF>, T, CF> : number extends Commands["length"] ? Record<string, CommandShape> : Tree;
|
|
491
|
-
type ReplacedExtensionTree<Tree, Es extends readonly AnyExtension[], CF extends FlagsDef> = Es extends readonly [infer H extends AnyExtension, ...infer T extends readonly AnyExtension[]] ? ReplacedExtensionTree<ReplacedTree<Tree, ExtensionCommandDefs<H>, CF>, T, CF> : ExtensionCommandDefs<Es[number]>[number] extends never ? Tree : Record<string, CommandShape>;
|
|
492
|
-
type ExtendedTree<Tree, Es extends readonly AnyExtension[], RecursiveFlags extends FlagsDef, InheritedFlags extends FlagsDef> = keyof RecursiveFlags extends never ? ReplacedExtensionTree<Tree, Es, InheritedFlags> : TreeWithInheritedFlags<ReplacedExtensionTree<Tree, Es, InheritedFlags>, RecursiveFlags>;
|
|
493
|
-
/**
|
|
494
|
-
* Define a reusable, inert command under a required name.
|
|
495
|
-
*
|
|
496
|
-
* The recipe runs once per `.add()`, receiving a fresh builder.
|
|
497
|
-
*
|
|
498
|
-
* Static metadata belongs in `config`. Use `.as(name)`
|
|
499
|
-
* to add one definition under a different name; configured aliases travel with it.
|
|
500
|
-
*/
|
|
501
|
-
export declare function defineCommand<const Name extends string, Builder extends AnyCommandDefinitionBuilder>(name: Name & CommandNameBrand<Name>, recipe: CommandRecipe<Builder>): CommandDefinition<Name, readonly [], ShapeOfBuilder<Builder>, DepsOfBuilder<Builder>>;
|
|
502
|
-
export declare function defineCommand<const Name extends string, const C extends CommandConfig, Builder extends AnyCommandDefinitionBuilder>(name: Name & CommandNameBrand<Name>, config: C & LocalCommandConfigBrand<Name, C>, recipe: CommandRecipe<Builder>): CommandDefinition<Name, AliasesOf<C>, ShapeOfBuilder<Builder>, DepsOfBuilder<Builder>>;
|
|
503
|
-
/**
|
|
504
|
-
* Chainable builder for defining CLI commands with full type inference.
|
|
505
|
-
*
|
|
506
|
-
* Generic parameters:
|
|
507
|
-
* - `Flags` — flags defined locally or installed by provided Contexts
|
|
508
|
-
* - `A` — positional argument definitions
|
|
509
|
-
* - `Ctx` — provided Context values
|
|
510
|
-
* - `Sibs` — sibling command names and aliases already registered
|
|
511
|
-
* - `Sp` — accumulated flag spellings used for collision checks
|
|
512
|
-
* - `Tree` — command shapes accumulated by `.add()` for typed `run()`
|
|
513
|
-
* - `CtxFlags` — Context-owned flags accumulated by `.provide()` and recursive
|
|
514
|
-
* Extension flags accumulated by `.extend()`, inherited by the shapes of
|
|
515
|
-
* definitions added afterwards
|
|
516
|
-
* - `Result` — awaited return type of this command's action
|
|
517
|
-
* - `Meta` — authored root metadata available to Extension requirements
|
|
518
|
-
* - `Caps` — root application or configure-only recipe capabilities
|
|
519
|
-
*
|
|
520
|
-
* @example
|
|
521
|
-
* ```ts
|
|
522
|
-
* const app = new Crust("my-cli")
|
|
523
|
-
* .flags({ name: "verbose", type: "boolean", short: "v" })
|
|
524
|
-
* .args({ name: "file", type: "string", required: true })
|
|
525
|
-
* .action(({ args, flags }) => {
|
|
526
|
-
* console.log(args.file, flags.verbose);
|
|
527
|
-
* });
|
|
528
|
-
* ```
|
|
529
|
-
*/
|
|
530
|
-
type CollisionSpellings<Extensions extends string = never, Tree extends string = never, Demands extends ContextMap = {}, Pending extends string = never, RecipeDeps extends ContextMap = {}, Providers extends Record<string, ContextValue> = {}, ActionDeps extends ContextMap = {}> = {
|
|
531
|
-
readonly actionDeps: ActionDeps;
|
|
532
|
-
readonly pending: Pending;
|
|
533
|
-
readonly demands: Demands;
|
|
534
|
-
readonly extension: Extensions;
|
|
535
|
-
readonly tree: Tree;
|
|
536
|
-
readonly recipeDeps: RecipeDeps;
|
|
537
|
-
readonly providers: Providers;
|
|
538
|
-
};
|
|
539
|
-
type AnyCollisionSpellings = {
|
|
540
|
-
readonly actionDeps?: ContextMap;
|
|
541
|
-
readonly pending: string;
|
|
542
|
-
readonly demands: ContextMap;
|
|
543
|
-
readonly extension: string;
|
|
544
|
-
readonly tree: string;
|
|
545
|
-
readonly recipeDeps?: ContextMap;
|
|
546
|
-
readonly providers?: Record<string, ContextValue>;
|
|
547
|
-
};
|
|
548
|
-
type RecipeDepsOf<S extends AnyCollisionSpellings> = S extends {
|
|
549
|
-
readonly recipeDeps: infer Deps extends ContextMap;
|
|
550
|
-
} ? Deps : {};
|
|
551
|
-
type ProvidersOf<S extends AnyCollisionSpellings> = S extends {
|
|
552
|
-
readonly providers: infer Providers extends Record<string, ContextValue>;
|
|
553
|
-
} ? Providers : {};
|
|
554
|
-
/** Obligations of this node's stored action, never inherited by descendants. */
|
|
555
|
-
type ActionDepsOf<S extends AnyCollisionSpellings> = S extends {
|
|
556
|
-
readonly actionDeps: infer Deps extends ContextMap;
|
|
557
|
-
} ? Deps : {};
|
|
558
|
-
type AfterFlags<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Defs extends readonly NamedFlagDef[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<MergeFlags<Flags, AttachedFlags<Defs>>, A, Ctx, Sibs, Sp | AttachedSpellings<Defs>, Tree, CtxFlags, CollisionSp, Result, Meta, string, Caps>;
|
|
559
|
-
type AfterArgs<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, NewA extends ArgsDef, Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<Flags, AppendedArgs<A, NewA>, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Meta, string, Caps>;
|
|
560
|
-
type AfterUse<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Fs extends readonly AnyContextFactory[], Meta extends RootCommandMeta | undefined> = Crust<Flags, A, MergeContext<Ctx, ContextDependencies<Fs>>, Sibs, Sp, Tree, CtxFlags, CollisionSpellings<CollisionSp["extension"], CollisionSp["tree"], CollisionSp["demands"], CollisionSp["pending"], MergeContext<RecipeDepsOf<CollisionSp>, ContextDependencies<Fs>>, ProvidersOf<CollisionSp>, ActionDepsOf<CollisionSp>>, Result, Meta, string, "recipe">;
|
|
561
|
-
type AfterProvide<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Cs extends readonly AnyContextInstance[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<MergeFlags<Flags, ContextsOwnedFlags<Cs>>, A, MergeProviders<Ctx, ContextsOutput<Cs>>, Sibs, Sp | LocalSpellingsOf<ContextsOwnedFlags<Cs>>, Tree, MergeFlags<CtxFlags, ContextsOwnedFlags<Cs>>, CollisionSpellings<CollisionSp["extension"], CollisionSp["tree"], CollisionSp["demands"], CollisionSp["pending"], RecipeDepsOf<CollisionSp>, MergeProviders<ProvidersOf<CollisionSp>, ContextsOutput<Cs>>, ActionDepsOf<CollisionSp>>, Result, Meta, string, Caps>;
|
|
562
|
-
type AfterAction<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, R, Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, Omit<CollisionSp, "actionDeps"> & {
|
|
563
|
-
readonly actionDeps: Ctx;
|
|
564
|
-
}, Awaited<R>, Meta, string, Caps>;
|
|
565
|
-
type AfterExtend<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Es extends readonly AnyExtension[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<MergeFlags<Flags, ExtensionFlags<Es>>, A, MergeProviders<Ctx, ExtensionsProvidesOutput<Es>>, Sibs | ExtensionsCommandSpellings<Es>, Sp | ExtensionsSpellings<Es>, ExtendedTree<Tree, Es, RecursiveExtensionFlags<Es>, CtxFlags>, MergeFlags<CtxFlags, RecursiveExtensionFlags<Es>>, CollisionSpellings<CollisionSp["extension"] | ExtensionsSpellings<Es>, CollisionSp["tree"] | DefinitionTreeSpellings<ExtensionCommands<Es>>, CollisionSp["demands"] & ExtensionDemandValues<Es>, CollisionSp["pending"] | DefinitionTreeSpellings<ExtensionCommands<Es>>, RecipeDepsOf<CollisionSp>, MergeProviders<ProvidersOf<CollisionSp>, ExtensionsProvidesOutput<Es>>, ActionDepsOf<CollisionSp>>, Result, Meta, string, Caps>;
|
|
566
|
-
type AfterAdd<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextMap, Sibs extends string, Sp extends string, Tree extends object, CtxFlags extends FlagsDef, CollisionSp extends AnyCollisionSpellings, Result, Ds extends readonly CommandDefinition<any, any, any, any>[], Meta extends RootCommandMeta | undefined, Caps extends "app" | "recipe"> = Crust<Flags, A, Ctx, Sibs | AttachedCommandSpellings<Ds>, Sp, Tree & DefinitionsTree<Ds, CtxFlags>, CtxFlags, CollisionSpellings<CollisionSp["extension"], CollisionSp["tree"] | DefinitionTreeSpellings<Ds>, CollisionSp["demands"], CollisionSp["pending"], RecipeDepsOf<CollisionSp>, ProvidersOf<CollisionSp>, ActionDepsOf<CollisionSp>>, Result, Meta, string, Caps>;
|
|
567
|
-
type ExtensionDemandValues<Es extends readonly AnyExtension[]> = UnionToIntersection<DefiningOf<Es[number]> extends {
|
|
568
|
-
readonly _hookDeps?: infer H extends ContextMap;
|
|
569
|
-
} ? H : Record<string, ContextValue>> extends (infer D extends ContextMap) ? D : {};
|
|
570
|
-
type DescendantShapeValuesBrand<S, Deps> = S extends CommandShape ? DeclaredDependencyValuesBrand<Deps, NonNullable<S[typeof commandProviders]>> & DescendantValuesBrand<S["children"], Deps> : {};
|
|
571
|
-
type DescendantValuesBrand<Tree, Deps> = keyof Deps extends never ? {} : UnionToIntersection<Tree extends unknown ? keyof Tree extends never ? {} : { [K in keyof Tree]: DescendantShapeValuesBrand<Tree[K], Deps>; }[keyof Tree] : never>;
|
|
572
|
-
type DefinitionDescendantValuesBrand<Ds extends readonly CommandDefinition<any, any, any, any>[], Deps> = DescendantValuesBrand<DefinitionsTree<Ds>, Deps>;
|
|
573
|
-
type ValidateInlineCommandDeps<Ctx extends ContextMap, B> = MissingDeclaredDependencyBrand<{
|
|
574
|
-
readonly _deps?: DepsOfBuilder<B>;
|
|
575
|
-
}, keyof Ctx & string> & DeclaredDependencyValuesBrand<DepsOfBuilder<B>, Ctx>;
|
|
576
|
-
/** Completed applications expose inspection and invocation, not authoring after erasure. */
|
|
577
|
-
type AnyCrust = Pick<Crust<FlagsDef, ArgsDef, Record<string, ContextValue>, string, string, CommandTree, FlagsDef, AnyCollisionSpellings, unknown, RootCommandMeta>, "_types" | "run" | "execute" | "snapshot">;
|
|
578
|
-
type DefinedRootMetaKeys<Meta extends RootCommandMeta | undefined> = { [K in RootMetaKey]: [Meta] extends [Required<Pick<RootCommandMeta, K>>] ? K : never; }[RootMetaKey];
|
|
579
|
-
export declare class Crust<Flags extends FlagsDef = {}, A extends ArgsDef = [], Ctx extends ContextMap = {}, Sibs extends string = never, Sp extends string = LocalSpellingsOf<Flags>, Tree extends object = {}, CtxFlags extends FlagsDef = {}, CollisionSp extends AnyCollisionSpellings = CollisionSpellings, Result = void, const out Meta extends RootCommandMeta | undefined = {}, const Name extends string = string, Caps extends "app" | "recipe" = "app"> {
|
|
580
|
-
private readonly _contextProof;
|
|
581
|
-
/** @internal — recipe state, without structural inference through builder methods. */
|
|
582
|
-
readonly _recipeTypes: {
|
|
583
|
-
readonly shape: CommandShape<A, Flags, Tree, Result, ProvidersOf<CollisionSp>>;
|
|
584
|
-
readonly deps: RecipeDepsOf<CollisionSp>;
|
|
585
|
-
readonly proof?: (state: [CommandInputShape<CommandShape<A, Flags, Tree, Result, ProvidersOf<CollisionSp>>>, RecipeDepsOf<CollisionSp>]) => void;
|
|
586
|
-
};
|
|
587
|
-
/** Supported type-level seam exposing the application's inferred command types. */
|
|
588
|
-
readonly _types: {
|
|
589
|
-
flags: Flags;
|
|
590
|
-
args: A;
|
|
591
|
-
ctx: Ctx;
|
|
592
|
-
tree: Tree;
|
|
593
|
-
shape: CommandShape<A, Flags, Tree, Result>;
|
|
594
|
-
readonly rootMeta: Meta;
|
|
595
|
-
readonly caps: Caps;
|
|
596
|
-
};
|
|
597
|
-
/** @internal */
|
|
598
|
-
_node: CommandNode;
|
|
599
|
-
/** @internal — Recipe-builder lineage anchor, unique per materialization and preserved by clones */
|
|
600
|
-
_ancestorOwnedFlags: FlagsDef;
|
|
601
|
-
/**
|
|
602
|
-
* Create a new root command builder.
|
|
603
|
-
*
|
|
604
|
-
* @param name - The command name.
|
|
605
|
-
* @param metadata - Optional root description, version, usage, and documentation sections.
|
|
606
|
-
*/
|
|
607
|
-
constructor(nameInput: (Name & CommandNameBrand<Name>) & ({} extends Meta ? {} : {
|
|
608
|
-
readonly FIX_ROOT_META: "This root requires metadata";
|
|
609
|
-
}));
|
|
610
|
-
constructor(nameInput: Name & CommandNameBrand<Name>, meta: Meta & (undefined | (RootCommandMeta & LocalSectionsBrand<NoInfer<NonNullable<Meta>>> & { [K in Exclude<keyof Meta, RootMetaKey>]: never; })));
|
|
611
|
-
/** @internal — Clone this builder with a new node, preserving generics. */
|
|
612
|
-
_clone<Out = this>(nodeOverrides: Partial<CommandNode>): Out;
|
|
613
|
-
/**
|
|
614
|
-
* Define local flags for this command from named flag definitions
|
|
615
|
-
* (created with `defineFlag(name, def)` or written inline as
|
|
616
|
-
* `{ name: "dry-run", type: "boolean" }`).
|
|
617
|
-
*
|
|
618
|
-
* Repeated `.flags()` calls accumulate local flags. Returns a new builder
|
|
619
|
-
* with the combined local flag types. The original builder is not mutated.
|
|
620
|
-
*
|
|
621
|
-
* @param defs - Named flag definitions
|
|
622
|
-
* @returns A new `Crust` instance with the given flags
|
|
623
|
-
*/
|
|
624
|
-
flags<const Defs extends readonly NamedFlagDef[], _Union extends this = never>(...defs: ValidateLocalFlagDefs<Defs, Sp>): AfterFlags<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Defs, Meta, Caps>;
|
|
625
|
-
/**
|
|
626
|
-
* Define positional arguments for this command; argument order is the
|
|
627
|
-
* order they are passed (created with `defineArg(name, def)` or written
|
|
628
|
-
* inline).
|
|
629
|
-
*
|
|
630
|
-
* Repeated `.args()` calls append in call order. Returns a new builder with
|
|
631
|
-
* the combined args types. The original builder is not mutated.
|
|
632
|
-
*
|
|
633
|
-
* @param defs - Positional argument definitions, in positional order
|
|
634
|
-
* @returns A new `Crust` instance with the combined args
|
|
635
|
-
*/
|
|
636
|
-
args<const NewA extends ArgsDef, _Union extends this = never>(...defs: NewA & AppendArgsChecks<A, NewA>): AfterArgs<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, NewA, Meta, Caps>;
|
|
637
|
-
/**
|
|
638
|
-
* Declare Contexts this command consumes without supplying their values.
|
|
639
|
-
* Factory references are retained while setup stays lazy.
|
|
640
|
-
*/
|
|
641
|
-
use<const Fs extends readonly [AnyContextFactory, ...AnyContextFactory[]] = never>(this: {
|
|
642
|
-
readonly _types: {
|
|
643
|
-
readonly caps: "recipe";
|
|
644
|
-
};
|
|
645
|
-
}, ...factories: Fs & DeclaredDependencyValuesBrand<ContextDependencies<Fs>, ProvidersOf<CollisionSp>>): AfterUse<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Fs, Meta>;
|
|
646
|
-
/**
|
|
647
|
-
* Attach Contexts — named command dependencies — to this command.
|
|
648
|
-
*
|
|
649
|
-
* Contexts are inherited by descendant commands and constructed lazily when
|
|
650
|
-
* their `ctx` property is accessed. Dependency order within one call does not
|
|
651
|
-
* affect construction. Disposable values are released in
|
|
652
|
-
* reverse construction order after post-run hooks. TypeScript rejects known Context-owned flag collisions, including pending
|
|
653
|
-
* Extension commands. Consuming operations throw `DEFINITION` for actual collisions.
|
|
654
|
-
*
|
|
655
|
-
*/
|
|
656
|
-
provide<const Cs extends readonly AnyContextInstance[] = never>(...instances: KnownContextInstances<Cs> & ProvideChecks<Sp | CollisionSp["pending"], Cs> & ValidateContextNames<Caps extends "recipe" ? ProvidersOf<CollisionSp> : Ctx, Cs> & ValidateContextDeps<Ctx, Cs> & DeclaredDependencyValuesBrand<CollisionSp["demands"] & RecipeDepsOf<CollisionSp> & ActionDepsOf<CollisionSp>, ContextsOutput<NoInfer<Cs>>>): AfterProvide<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Cs, Meta, Caps>;
|
|
657
|
-
/**
|
|
658
|
-
* Define the Command Action — the function that implements this
|
|
659
|
-
* command's behavior after its inputs are ready.
|
|
660
|
-
*
|
|
661
|
-
* The action receives a {@link CrustCommandContext} with `args` typed from
|
|
662
|
-
* `.args()` and `flags` typed from the accumulated `Flags`.
|
|
663
|
-
*
|
|
664
|
-
* Calling `.action()` again replaces the command behavior and its Context obligations
|
|
665
|
-
* on the new builder. Later local providers must satisfy the bound Context value types;
|
|
666
|
-
* descendants may shadow independently. The original builder is not mutated.
|
|
667
|
-
*
|
|
668
|
-
* @param action - The Command Action function
|
|
669
|
-
* @returns A new `Crust` instance with the action registered
|
|
670
|
-
*/
|
|
671
|
-
action<R>(action: (ctx: NoInfer<CrustCommandContext<A, Flags, Ctx>>) => R): AfterAction<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, R, Meta, Caps>;
|
|
672
|
-
/**
|
|
673
|
-
* Register one or more CLI Extensions on the application root.
|
|
674
|
-
*
|
|
675
|
-
* Extensions are application-wide: they own the flags and commands they
|
|
676
|
-
* contribute. Repeated calls accumulate Extensions in registration order,
|
|
677
|
-
* except that registering an `ExtensionId` again keeps only the last
|
|
678
|
-
* registration — its contributions and providers replace the earlier ones
|
|
679
|
-
* and its hooks run once, at the later position. ID deduplication is
|
|
680
|
-
* runtime-only, so removed paths can remain statically visible and reject
|
|
681
|
-
* with `COMMAND_NOT_FOUND`. Canonical replacements use the new
|
|
682
|
-
* shape; open replacements and ambiguous aliases have unknown results.
|
|
683
|
-
* Required root metadata keys are checked against the constructor's inferred
|
|
684
|
-
* metadata by TypeScript, not at runtime.
|
|
685
|
-
* Recipe builders cannot call this root-only method.
|
|
686
|
-
*/
|
|
687
|
-
extend<const Es extends readonly Extension<any, any, any, any, DefinedRootMetaKeys<Meta>>[], _Union extends this = never>(this: {
|
|
688
|
-
readonly _types: {
|
|
689
|
-
readonly caps: "app";
|
|
690
|
-
};
|
|
691
|
-
}, ...extensions: Es & { [I in keyof Es]: (ExtensionCommandDefs<Es[I]> extends ValidateDefinitionFlags<ExtensionCommandDefs<Es[I]>, LocalSpellingsOf<CtxFlags>> ? {} : {
|
|
692
|
-
readonly FIX_ALIAS_COLLISION: "Extension command flags collide with inherited Context flags";
|
|
693
|
-
}) & ValidateDeclaredDeps<MergeProviders<Ctx, ExtensionsProvidesOutput<Es>>, Es>[I] & DeclaredDependencyValuesBrand<CollisionSp["demands"], MergeProviders<Ctx, ExtensionsProvidesOutput<Es>>> & DescendantValuesBrand<Tree, ExtensionDemandValues<Es>> & DefinitionDescendantValuesBrand<ExtensionCommands<Es>, CollisionSp["demands"] & ExtensionDemandValues<Es>> & ExtensionCheckAt<ValidateExtensionFlags<Es, Sp | CollisionSp["tree"] | DefinitionTreeSpellings<ExtensionCommands<Es>>>, I> & ExtensionCheckAt<ValidateExtensionCommands<Es, Sibs>, I> & ExtensionCheckAt<ValidateExtensionProvides<Es, Ctx>, I>; }): AfterExtend<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Es, Meta, Caps>;
|
|
694
|
-
/**
|
|
695
|
-
* Materialize and register inert reusable command definitions, each
|
|
696
|
-
* under its own carried name (use `.as(name)` to rename).
|
|
697
|
-
*
|
|
698
|
-
*/
|
|
699
|
-
add<const Ds extends readonly CommandDefinition<any, any, any, any>[] = never>(...definitions: Ds & ValidateCommandDefinitions<Ds, Sibs> & ValidateDeclaredDeps<Ctx, Ds> & DefinitionDescendantValuesBrand<Ds, CollisionSp["demands"]> & ValidateDefinitionFlags<Ds, CollisionSp["extension"] | LocalSpellingsOf<CtxFlags>>): AfterAdd<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, Ds, Meta, Caps>;
|
|
700
|
-
/**
|
|
701
|
-
* Define an app-local leaf subcommand inline (root-only sugar for
|
|
702
|
-
* `.add(defineCommand(name, recipe))`).
|
|
703
|
-
*
|
|
704
|
-
* The recipe builder is seeded with the Contexts and Context-owned flags
|
|
705
|
-
* accumulated on this builder so far — the call site. Contexts provided
|
|
706
|
-
* after `.command()` are not visible to it, matching the positional runtime
|
|
707
|
-
* semantics of `.provide()`. Extract to `defineCommand` when a command needs
|
|
708
|
-
* its own file, reuse, or a package. Recipe builders cannot call this
|
|
709
|
-
* root-only method.
|
|
710
|
-
*/
|
|
711
|
-
command<const N extends string, B extends AnyCommandDefinitionBuilder>(this: {
|
|
712
|
-
readonly _types: {
|
|
713
|
-
readonly caps: "app";
|
|
714
|
-
};
|
|
715
|
-
}, name: N & CommandNameBrand<N> & CommandCollisionBrand<N, Sibs>, recipe: ((command: CommandDefinitionBuilder<{}, [], Ctx, never, LocalSpellingsOf<CtxFlags>, {}, CtxFlags>) => B & ShapeFlagCollisionBrand<ShapeOfBuilder<B>, CollisionSp["extension"]> & ValidateInlineCommandDeps<Ctx, NoInfer<B>>) & NoInfer<DescendantValuesBrand<{
|
|
716
|
-
child: ShapeOfBuilder<B>;
|
|
717
|
-
}, CollisionSp["demands"]>>): AfterAdd<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, readonly [CommandDefinition<N, readonly [], ShapeOfBuilder<B>, DepsOfBuilder<B>>], Meta, Caps>;
|
|
718
|
-
private _addDefinitions;
|
|
719
|
-
/**
|
|
720
|
-
* Prepare a frozen Command Snapshot for tooling such as man-page, skill,
|
|
721
|
-
* and build generators.
|
|
722
|
-
*
|
|
723
|
-
* Materializes Extension contributions and command definitions without
|
|
724
|
-
* calling Command Actions.
|
|
725
|
-
*/
|
|
726
|
-
snapshot(this: {
|
|
727
|
-
readonly _types: {
|
|
728
|
-
readonly caps: "app";
|
|
729
|
-
};
|
|
730
|
-
}): Promise<CommandSnapshot>;
|
|
731
|
-
/**
|
|
732
|
-
* Programmatically invoke a typed command, quietly capturing its output.
|
|
733
|
-
* Returns completed, finished, or failed after cleanup without presenting errors.
|
|
734
|
-
* Use {@link execute} as the streaming terminal adapter.
|
|
735
|
-
*
|
|
736
|
-
* @param path - Typed path to the command to invoke (`[]` selects the root)
|
|
737
|
-
* @param input - Structured argument, flag, and raw values
|
|
738
|
-
* @param io - Optional `stdout(text)` / `stderr(text)` callbacks, also
|
|
739
|
-
* exposed to Command Actions and Extensions
|
|
740
|
-
*/
|
|
741
|
-
run<const Path extends CommandPath<Tree>>(this: {
|
|
742
|
-
readonly _types: {
|
|
743
|
-
readonly caps: "app";
|
|
744
|
-
};
|
|
745
|
-
}, path: Path & KnownCommandPath<Path, Tree>, ...args: RunArguments<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>>): Promise<RunOutcome<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>["result"]>>;
|
|
746
|
-
run<const Path extends CommandPath<Tree>, const Input>(this: {
|
|
747
|
-
readonly _types: {
|
|
748
|
-
readonly caps: "app";
|
|
749
|
-
};
|
|
750
|
-
}, path: Path & KnownCommandPath<Path, Tree>, input: Input, ...validation: [Input] extends [CompatibleRunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, NoInfer<Path>>, Input>] ? readonly [io?: Partial<InvocationIO>] : readonly [invalidInput: never]): Promise<RunOutcome<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>["result"]>>;
|
|
751
|
-
/**
|
|
752
|
-
* Bind a typed command path into a reusable {@link CommandHandle}.
|
|
753
|
-
*
|
|
754
|
-
* Validates the path eagerly against the prepared command tree, so an
|
|
755
|
-
* unknown path throws `COMMAND_NOT_FOUND` here rather than on the first
|
|
756
|
-
* `handle.run()`. The handle is bound to this builder's tree; commands added
|
|
757
|
-
* afterwards belong to the new builder returned by `.add()`.
|
|
758
|
-
*
|
|
759
|
-
* @param path - Typed path to the command to bind (`[]` selects the root)
|
|
760
|
-
* @throws {CrustError} COMMAND_NOT_FOUND when the path does not name a command
|
|
761
|
-
*/
|
|
762
|
-
at<const Path extends CommandPath<Tree>>(this: {
|
|
763
|
-
readonly _types: {
|
|
764
|
-
readonly caps: "app";
|
|
765
|
-
};
|
|
766
|
-
}, path: Path & KnownCommandPath<Path, Tree>): CommandHandle<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>>;
|
|
767
|
-
/**
|
|
768
|
-
* Parse `process.argv`, resolve subcommands, run Extension hooks, and
|
|
769
|
-
* execute the matched Command Action.
|
|
770
|
-
*
|
|
771
|
-
* This is the terminal CLI boundary — call it on the root builder. It
|
|
772
|
-
* renders a failure once (through Extension `onError` hooks, ending in
|
|
773
|
-
* Core's default renderer), sets `process.exitCode` (`1`, or
|
|
774
|
-
* `130` for an `AbortError` cancellation), and resolves to the exit code.
|
|
775
|
-
*
|
|
776
|
-
* @param options - Optional overrides (e.g. custom `argv` and captured
|
|
777
|
-
* `io` for in-process testing of exit codes and
|
|
778
|
-
* rendered failures)
|
|
779
|
-
* @returns The terminal exit code (`0`, `1`, or `130` for cancellation)
|
|
780
|
-
*/
|
|
781
|
-
execute(this: {
|
|
782
|
-
readonly _types: {
|
|
783
|
-
readonly caps: "app";
|
|
784
|
-
};
|
|
785
|
-
}, options?: {
|
|
786
|
-
argv?: string[];
|
|
787
|
-
io?: Partial<InvocationIO>;
|
|
788
|
-
}): Promise<number>;
|
|
789
|
-
}
|
|
790
|
-
//#endregion
|
|
791
|
-
//#region src/errors.d.ts
|
|
792
|
-
/** A value thrown by user code crossing a Core error boundary. */
|
|
793
|
-
type CaughtError = unknown;
|
|
794
|
-
/** Details for a subcommand token that could not be resolved. */
|
|
795
|
-
interface CommandNotFoundErrorDetails {
|
|
796
|
-
/** Unrecognized subcommand token. */
|
|
797
|
-
input: string;
|
|
798
|
-
/** Canonical names of visible available child commands. */
|
|
799
|
-
available: string[];
|
|
800
|
-
/** Canonical path to the command whose child could not be resolved. */
|
|
801
|
-
commandPath: string[];
|
|
802
|
-
/** Readonly, serializable snapshot of the parent command. */
|
|
803
|
-
parentCommand: CommandSnapshot;
|
|
804
|
-
}
|
|
805
|
-
/** Aggregated Standard Schema and required-value validation failures. */
|
|
806
|
-
interface ValidationErrorDetails {
|
|
807
|
-
/** Issues normalized under `args.<name>` or `flags.<name>`. */
|
|
808
|
-
issues: readonly {
|
|
809
|
-
readonly message: string;
|
|
810
|
-
readonly path: string;
|
|
811
|
-
}[];
|
|
812
|
-
}
|
|
813
|
-
/** Details for argv syntax or built-in value parsing failures. */
|
|
814
|
-
interface ParseErrorDetails {
|
|
815
|
-
readonly flag?: string;
|
|
816
|
-
readonly argument?: string;
|
|
817
|
-
/** Retained for compatibility; Core no longer populates this field. */
|
|
818
|
-
readonly value?: string;
|
|
819
|
-
readonly reason?: string;
|
|
820
|
-
}
|
|
821
|
-
/** Details for runtime recipe, Extension, Context, and documentation failures. */
|
|
822
|
-
interface DefinitionErrorDetails {
|
|
823
|
-
readonly subject?: "command" | "context" | "extension" | "flag" | "argument";
|
|
824
|
-
readonly name?: string;
|
|
825
|
-
readonly reason?: string;
|
|
826
|
-
}
|
|
827
|
-
interface CrustErrorDetailsMap {
|
|
828
|
-
DEFINITION: DefinitionErrorDetails | undefined;
|
|
829
|
-
VALIDATION: ValidationErrorDetails | undefined;
|
|
830
|
-
PARSE: ParseErrorDetails | undefined;
|
|
831
|
-
COMMAND_NOT_FOUND: CommandNotFoundErrorDetails;
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* All possible error codes emitted by Crust.
|
|
835
|
-
*
|
|
836
|
-
* - `DEFINITION` — Runtime recipe, Extension, Context, or documentation definition failure
|
|
837
|
-
* - `VALIDATION` — Missing required arguments or flags
|
|
838
|
-
* - `PARSE` — Argv parsing failures (unknown flags, type coercion)
|
|
839
|
-
* - `COMMAND_NOT_FOUND` — Unrecognised subcommand at the current level
|
|
840
|
-
*
|
|
841
|
-
* @example
|
|
842
|
-
* ```ts
|
|
843
|
-
* const outcome = await app.run(path, input);
|
|
844
|
-
* if (outcome.status === "failed") {
|
|
845
|
-
* const err = outcome.error;
|
|
846
|
-
* if (err instanceof CrustError) {
|
|
847
|
-
* switch (err.code) {
|
|
848
|
-
* case "VALIDATION":
|
|
849
|
-
* console.error(err.message);
|
|
850
|
-
* showHelp(cmd);
|
|
851
|
-
* break;
|
|
852
|
-
* case "PARSE":
|
|
853
|
-
* console.error(err.message);
|
|
854
|
-
* break;
|
|
855
|
-
* }
|
|
856
|
-
* }
|
|
857
|
-
* }
|
|
858
|
-
* ```
|
|
859
|
-
*/
|
|
860
|
-
type CrustErrorCode = keyof CrustErrorDetailsMap;
|
|
861
|
-
type CrustErrorDetails<C extends CrustErrorCode> = CrustErrorDetailsMap[C];
|
|
862
|
-
interface CrustErrorJson<C extends CrustErrorCode> {
|
|
863
|
-
code: C;
|
|
864
|
-
message: string;
|
|
865
|
-
details: CrustErrorDetails<C>;
|
|
866
|
-
}
|
|
867
|
-
/**
|
|
868
|
-
* A typed error for runtime recipe, Extension, Context, documentation, argv, and validation failures.
|
|
869
|
-
*
|
|
870
|
-
* Every `CrustError` carries a {@link CrustErrorCode} that identifies the specific
|
|
871
|
-
* failure, enabling programmatic error handling without fragile message parsing.
|
|
872
|
-
*
|
|
873
|
-
* @example
|
|
874
|
-
* ```ts
|
|
875
|
-
* import { CrustError } from "@crustjs/core";
|
|
876
|
-
*
|
|
877
|
-
* const outcome = await app.run(["deploy"], { args: { target: "prod" } });
|
|
878
|
-
* if (outcome.status === "failed") {
|
|
879
|
-
* const err = outcome.error;
|
|
880
|
-
* if (err instanceof CrustError) {
|
|
881
|
-
* console.error(`[${err.code}] ${err.message}`);
|
|
882
|
-
* }
|
|
883
|
-
* }
|
|
884
|
-
* ```
|
|
885
|
-
*/
|
|
886
|
-
export declare class CrustError<C extends CrustErrorCode = CrustErrorCode> extends Error {
|
|
887
|
-
/** Machine-readable error code for programmatic handling */
|
|
888
|
-
readonly code: C;
|
|
889
|
-
/** Structured payload for programmatic handling */
|
|
890
|
-
readonly details: CrustErrorDetails<C>;
|
|
891
|
-
/** Optional wrapped original error/value */
|
|
892
|
-
override cause?: unknown;
|
|
893
|
-
constructor(code: C, message: string, ...details: undefined extends CrustErrorDetails<C> ? [] | [CrustErrorDetails<C>] : [CrustErrorDetails<C>]);
|
|
894
|
-
is<T extends CrustErrorCode>(code: T): this is CrustError<T>;
|
|
895
|
-
withCause(cause: unknown): this;
|
|
896
|
-
toJSON(): CrustErrorJson<C>;
|
|
897
|
-
}
|
|
898
|
-
//#endregion
|
|
899
|
-
//#region src/api/extension.d.ts
|
|
900
|
-
declare const finishedBrand: unique symbol;
|
|
901
|
-
/** Opaque token returned by {@link ExtensionContext.finish} to end an invocation successfully. */
|
|
902
|
-
interface Finished {
|
|
903
|
-
readonly [finishedBrand]: true;
|
|
904
|
-
}
|
|
905
|
-
type InvocationOutcome = {
|
|
906
|
-
readonly status: "completed";
|
|
907
|
-
} | {
|
|
908
|
-
readonly status: "finished";
|
|
909
|
-
readonly by: ExtensionId;
|
|
910
|
-
} | {
|
|
911
|
-
readonly status: "failed";
|
|
912
|
-
readonly error: unknown;
|
|
913
|
-
readonly by?: ExtensionId;
|
|
914
|
-
};
|
|
915
|
-
/** Authored root metadata fields an Extension may require. */
|
|
916
|
-
type RootMetaKey = keyof RootCommandMeta;
|
|
917
|
-
type RootCommandSnapshot<K extends RootMetaKey> = CommandSnapshot & {
|
|
918
|
-
readonly meta: Readonly<Required<Pick<CommandMeta, K>>>;
|
|
919
|
-
};
|
|
920
|
-
/** One file a build hook produces; `path` is POSIX-relative to the build output directory. */
|
|
921
|
-
interface BuildFile {
|
|
922
|
-
readonly path: string;
|
|
923
|
-
readonly content: string | Uint8Array;
|
|
924
|
-
}
|
|
925
|
-
/** Files returned by a build hook; build tooling writes them into the build output directory. */
|
|
926
|
-
type BuildArtifacts = readonly BuildFile[];
|
|
927
|
-
/** Files written for each Extension build hook, in hook execution order. */
|
|
928
|
-
interface BuildReport {
|
|
929
|
-
readonly extensions: readonly {
|
|
930
|
-
readonly id: ExtensionId;
|
|
931
|
-
readonly files: readonly string[];
|
|
932
|
-
}[];
|
|
933
|
-
}
|
|
934
|
-
/**
|
|
935
|
-
* Build-time context passed to an Extension's artifact generator. It deliberately
|
|
936
|
-
* carries no output directory: build tooling owns that tree, so every shipped file
|
|
937
|
-
* is a returned {@link BuildFile} and the {@link BuildReport} is exact.
|
|
938
|
-
*/
|
|
939
|
-
interface ExtensionBuildContext<MetaKeys extends RootMetaKey = never> {
|
|
940
|
-
/**
|
|
941
|
-
* Frozen snapshot prepared before this hook starts. It does not include this hook's own
|
|
942
|
-
* outputs; later-registered hooks receive refreshed snapshots.
|
|
943
|
-
*/
|
|
944
|
-
readonly snapshot: RootCommandSnapshot<MetaKeys>;
|
|
945
|
-
}
|
|
946
|
-
/**
|
|
947
|
-
* Readonly invocation view passed to Extension hooks.
|
|
948
|
-
*
|
|
949
|
-
* Commands cross this boundary as readonly, serializable
|
|
950
|
-
* {@link CommandSnapshot}s — never as internal command nodes.
|
|
951
|
-
*
|
|
952
|
-
* Examples below assume the `tool deploy api --trace -- --dry-run` invocation.
|
|
953
|
-
*/
|
|
954
|
-
interface ExtensionContext<Defs extends readonly NamedExtensionFlagDef[] = [], Deps extends ContextMap = {}, MetaKeys extends RootMetaKey = never> extends Readonly<InvocationIO> {
|
|
955
|
-
/**
|
|
956
|
-
* Complete argv passed to the application, including routed command names.
|
|
957
|
-
* For typed `run()` this is the command path only; structured values are never rendered as argv.
|
|
958
|
-
*
|
|
959
|
-
* @example `["deploy", "api", "--trace", "--", "--dry-run"]`
|
|
960
|
-
*/
|
|
961
|
-
readonly argv: readonly string[];
|
|
962
|
-
/**
|
|
963
|
-
* Snapshot of the application root, including Extension-contributed flags/commands.
|
|
964
|
-
*
|
|
965
|
-
* @example
|
|
966
|
-
* ```ts
|
|
967
|
-
* ctx.rootCommand.meta.name; // "tool"
|
|
968
|
-
* Object.keys(ctx.rootCommand.subCommands); // ["deploy"]
|
|
969
|
-
* ```
|
|
970
|
-
*/
|
|
971
|
-
readonly rootCommand: RootCommandSnapshot<MetaKeys>;
|
|
972
|
-
/**
|
|
973
|
-
* Snapshot of the resolved command (the root when routing failed).
|
|
974
|
-
*
|
|
975
|
-
* @example
|
|
976
|
-
* ```ts
|
|
977
|
-
* ctx.command.meta.name; // "deploy"
|
|
978
|
-
* ctx.command.args; // [{ name: "target", type: "string", required: true }]
|
|
979
|
-
* ```
|
|
980
|
-
*/
|
|
981
|
-
readonly command: CommandSnapshot;
|
|
982
|
-
/**
|
|
983
|
-
* Canonical names from the application root through the resolved command.
|
|
984
|
-
*
|
|
985
|
-
* @example `["tool", "deploy"]`
|
|
986
|
-
*/
|
|
987
|
-
readonly commandPath: readonly string[];
|
|
988
|
-
/**
|
|
989
|
-
* Bound positional values for the resolved command, before validation: parsed from
|
|
990
|
-
* argv tokens for `execute()`, taken as-is from the structured input for typed `run()`
|
|
991
|
-
* (URL/JSON values keep their identity).
|
|
992
|
-
*
|
|
993
|
-
* @example `{ target: "api" }`
|
|
994
|
-
*/
|
|
995
|
-
readonly args: Readonly<Record<string, ParsedArgValue>>;
|
|
996
|
-
/**
|
|
997
|
-
* Bound own flags plus unknown flags from the resolved command, before validation;
|
|
998
|
-
* parsed from argv tokens for `execute()`, taken as-is from the structured input for typed `run()`.
|
|
999
|
-
*
|
|
1000
|
-
* @example `{ trace: true }`
|
|
1001
|
-
*/
|
|
1002
|
-
readonly flags: Readonly<InferExtensionFlags<Defs> & Record<string, ParsedFlagValue>>;
|
|
1003
|
-
/**
|
|
1004
|
-
* Positional values that appeared after the `--` separator, or the `raw` array passed to typed `run()`.
|
|
1005
|
-
*
|
|
1006
|
-
* @example `["--dry-run"]`
|
|
1007
|
-
*/
|
|
1008
|
-
readonly rawArgs: readonly string[];
|
|
1009
|
-
/** Declared Contexts, constructed lazily on first property access. */
|
|
1010
|
-
readonly ctx: ContextBag<Deps>;
|
|
1011
|
-
/**
|
|
1012
|
-
* End the invocation successfully before validation, Context construction, and the action.
|
|
1013
|
-
*
|
|
1014
|
-
* @example
|
|
1015
|
-
* ```ts
|
|
1016
|
-
* preRun(ctx) {
|
|
1017
|
-
* if (ctx.flags.help === true) return ctx.finish();
|
|
1018
|
-
* }
|
|
1019
|
-
* ```
|
|
1020
|
-
*/
|
|
1021
|
-
readonly finish: () => Finished;
|
|
1022
|
-
}
|
|
1023
|
-
interface ExtensionHooks<Defs extends readonly NamedExtensionFlagDef[] = [], Deps extends ContextMap = {}, MetaKeys extends RootMetaKey = never> {
|
|
1024
|
-
/**
|
|
1025
|
-
* Runs after routing and input binding (argv parsing for `execute()`, structured
|
|
1026
|
-
* binding for typed `run()`), before validation, in `.extend()` order.
|
|
1027
|
-
* Return `ctx.finish()` to end the invocation successfully; later pre-run hooks,
|
|
1028
|
-
* validation, schemas, Contexts, and the Command Action do not run.
|
|
1029
|
-
*/
|
|
1030
|
-
readonly preRun?: (ctx: ExtensionContext<Defs, Deps, MetaKeys>) => Awaitable<void | Finished>;
|
|
1031
|
-
/**
|
|
1032
|
-
* Runs after the invocation settles, in reverse `.extend()` order. This is the
|
|
1033
|
-
* `finally` slot for cleanup and post-run side effects.
|
|
1034
|
-
*/
|
|
1035
|
-
readonly postRun?: (ctx: ExtensionContext<Defs, Deps, MetaKeys>, outcome: InvocationOutcome) => Awaitable<void>;
|
|
1036
|
-
/**
|
|
1037
|
-
* Renders a failure in `execute()` only. Return true when rendered to stop the
|
|
1038
|
-
* chain; falsy values delegate to the next Extension and then Core's renderer.
|
|
1039
|
-
* A hook that throws ends the chain: remaining hooks are skipped and Core's
|
|
1040
|
-
* default renderer reports the original failure.
|
|
1041
|
-
*
|
|
1042
|
-
* Receives the base context: routing or syntax-parse failures render with a
|
|
1043
|
-
* fallback context whose `flags` are empty, so owned-flag inference would lie here.
|
|
1044
|
-
*/
|
|
1045
|
-
readonly onError?: (error: CaughtError, ctx: ExtensionContext<[], Deps, MetaKeys>) => Awaitable<boolean | void>;
|
|
1046
|
-
}
|
|
1047
|
-
/**
|
|
1048
|
-
* A flag owned by an Extension. `recursive` (default `true`) contributes the
|
|
1049
|
-
* flag to every command in the application; set `false` for a root-only flag.
|
|
1050
|
-
*/
|
|
1051
|
-
type ExtensionFlagDef = FlagDef & {
|
|
1052
|
-
readonly recursive?: boolean;
|
|
1053
|
-
};
|
|
1054
|
-
/** A named flag definition accepted by {@link defineExtension}. */
|
|
1055
|
-
type NamedExtensionFlagDef = NamedFlagDef & {
|
|
1056
|
-
readonly recursive?: boolean;
|
|
1057
|
-
};
|
|
1058
|
-
type SchemaToken<F> = F extends {
|
|
1059
|
-
type: "boolean";
|
|
1060
|
-
} ? boolean : string;
|
|
1061
|
-
type InferPreSchemaExtensionFlag<F extends ExtensionFlagDef> = F extends {
|
|
1062
|
-
schema: unknown;
|
|
1063
|
-
} ? (F extends {
|
|
1064
|
-
multiple: true;
|
|
1065
|
-
} ? never : SchemaToken<F>) | ("multiple" extends keyof F ? true extends F["multiple"] ? SchemaToken<F>[] : never : never) | undefined : F extends {
|
|
1066
|
-
required: true;
|
|
1067
|
-
} ? F extends {
|
|
1068
|
-
default: unknown;
|
|
1069
|
-
} ? InferFlags<{
|
|
1070
|
-
value: F;
|
|
1071
|
-
}>["value"] : InferFlags<{
|
|
1072
|
-
value: F;
|
|
1073
|
-
}>["value"] | undefined : InferFlags<{
|
|
1074
|
-
value: F;
|
|
1075
|
-
}>["value"];
|
|
1076
|
-
type InferExtensionFlag<F> = F extends ExtensionFlagDef ? InferPreSchemaExtensionFlag<F> | ("recursive" extends keyof F ? (false extends F["recursive"] ? undefined : never) : never) : never;
|
|
1077
|
-
/** Infer pre-validation hook values; uncertain collections claim no typed ownership. */
|
|
1078
|
-
type InferExtensionFlags<Defs extends readonly NamedExtensionFlagDef[]> = IsStaticTuple<Defs> extends true ? HasClosedNames<Defs> extends true ? { [K in keyof NamedFlagsRecord<Defs>]: InferExtensionFlag<NamedFlagsRecord<Defs>[K]>; } : Record<string, ParsedFlagValue> : Record<string, ParsedFlagValue>;
|
|
1079
|
-
/** A documentation section an Extension contributes to one command path. */
|
|
1080
|
-
type ExtensionSectionContribution = RuntimeCommandSectionInput & {
|
|
1081
|
-
readonly command: readonly string[];
|
|
1082
|
-
};
|
|
1083
|
-
type CommandDefinitionsDependencies<Commands extends readonly CommandDefinition<any, any, any, any>[]> = Commands extends readonly [infer H extends CommandDefinition<any, any, any, any>, ...infer T extends readonly CommandDefinition<any, any, any, any>[]] ? ([H] extends [never] ? {} : DeclaredDepsOf<H>) & CommandDefinitionsDependencies<T> : Commands extends readonly [] ? {} : Record<string, ContextValue>;
|
|
1084
|
-
interface ExtensionConfig<Defs extends readonly NamedExtensionFlagDef[] = readonly NamedExtensionFlagDef[], Uses extends readonly AnyContextFactory[] = readonly AnyContextFactory[], Provides extends readonly AnyContextInstance[] = readonly AnyContextInstance[], Commands extends readonly CommandDefinition<any, any, any, any>[] = readonly CommandDefinition<any, any, any, any>[], MetaKeys extends RootMetaKey = never> {
|
|
1085
|
-
readonly flags?: Defs;
|
|
1086
|
-
readonly commands?: Commands;
|
|
1087
|
-
readonly uses?: Uses;
|
|
1088
|
-
readonly provides?: Provides;
|
|
1089
|
-
readonly sections?: (snapshot: RootCommandSnapshot<MetaKeys>) => readonly ExtensionSectionContribution[];
|
|
1090
|
-
readonly build?: (ctx: ExtensionBuildContext<MetaKeys>) => Awaitable<BuildArtifacts>;
|
|
1091
|
-
readonly hooks?: ExtensionHooks<Defs, ContextDependencies<Uses>, MetaKeys>;
|
|
1092
|
-
}
|
|
1093
|
-
type ValidateExtensionConfig<Defs extends readonly NamedExtensionFlagDef[], Provides extends readonly AnyContextInstance[], Commands extends readonly CommandDefinition<any, any, any, any>[], Uses extends readonly AnyContextFactory[]> = {
|
|
1094
|
-
readonly uses?: Uses;
|
|
1095
|
-
readonly commands?: ValidateCommandDefinitions<Commands>;
|
|
1096
|
-
readonly flags?: ValidateLocalFlagDefs<Defs, ProvidedContextSpellings<Provides>>;
|
|
1097
|
-
readonly provides?: KnownContextInstances<Provides> & ProvideChecks<never, Provides>;
|
|
1098
|
-
};
|
|
1099
|
-
declare const extensionHookProof: unique symbol;
|
|
1100
|
-
interface Extension<Deps extends ContextMap = ContextMap, Provides extends readonly AnyContextInstance[] = readonly AnyContextInstance[], FlagDefs extends readonly NamedExtensionFlagDef[] = readonly NamedExtensionFlagDef[], Commands extends readonly CommandDefinition<any, any, any, any>[] = readonly CommandDefinition<any, any, any, any>[], out MetaKeys extends RootMetaKey = never, HookDeps extends ContextMap = Deps> extends Defining<Extension<Deps, Provides, FlagDefs, Commands, MetaKeys, HookDeps>> {
|
|
1101
|
-
/** @internal Hook demands are distinct from command/provider attachment dependencies. */
|
|
1102
|
-
readonly _hookDeps?: HookDeps;
|
|
1103
|
-
readonly [extensionHookProof]?: (deps: HookDeps) => void;
|
|
1104
|
-
readonly id: ExtensionId;
|
|
1105
|
-
readonly flags?: Readonly<Record<string, ExtensionFlagDef>>;
|
|
1106
|
-
/** @internal — phantom carrying declared flag literals for extend-time collision checks */
|
|
1107
|
-
readonly _flagDefs?: FlagDefs;
|
|
1108
|
-
readonly commands?: Commands;
|
|
1109
|
-
readonly uses: readonly AnyContextFactory[];
|
|
1110
|
-
readonly provides?: Provides;
|
|
1111
|
-
readonly sections?: (snapshot: RootCommandSnapshot<MetaKeys>) => readonly ExtensionSectionContribution[];
|
|
1112
|
-
readonly build?: (ctx: ExtensionBuildContext<MetaKeys>) => Awaitable<BuildArtifacts>;
|
|
1113
|
-
readonly hooks?: ExtensionHooks<any, Deps, MetaKeys>;
|
|
1114
|
-
readonly _deps?: Deps;
|
|
1115
|
-
}
|
|
1116
|
-
/** @internal Broad Extension constraint; contravariance requires the full metadata key set. */
|
|
1117
|
-
type AnyExtension = Extension<any, any, any, any, RootMetaKey>;
|
|
1118
|
-
type ExtensionProvidesOutput<E> = DefiningOf<E> extends Extension<any, infer Provides, any, any, RootMetaKey> ? ContextsOutput<Provides> : {};
|
|
1119
|
-
type ExtensionsProvidesOutput<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? MergeProviders<ExtensionProvidesOutput<H>, ExtensionsProvidesOutput<T>> : Es extends readonly [] ? {} : Es[number] extends Extension<any, infer P, any, any, RootMetaKey> ? P[number] extends never ? {} : Record<string, ContextValue> : {};
|
|
1120
|
-
/**
|
|
1121
|
-
* A callable Extension constructor whose identity is also a section consumer.
|
|
1122
|
-
* Contribution parameters default to closed sets. Use `ContextMap`,
|
|
1123
|
-
* `readonly AnyContextInstance[]`, `readonly NamedExtensionFlagDef[]`, or
|
|
1124
|
-
* `readonly CommandDefinition<any, any, any, any>[]` to keep a namespace open.
|
|
1125
|
-
*/
|
|
1126
|
-
type ExtensionFactory<Args extends readonly unknown[] = [], Deps extends ContextMap = {}, Provides extends readonly AnyContextInstance[] = [], Defs extends readonly NamedExtensionFlagDef[] = [], Commands extends readonly CommandDefinition<any, any, any, any>[] = [], MetaKeys extends RootMetaKey = never, HookDeps extends ContextMap = Deps> = ((...args: Args) => Extension<Deps, Provides, Defs, Commands, MetaKeys, HookDeps>) & {
|
|
1127
|
-
readonly id: ExtensionId;
|
|
1128
|
-
};
|
|
1129
|
-
/** Curried Extension definer: explicit metadata keys leave all other types inferred. */
|
|
1130
|
-
interface DefineExtensionWith<MetaKeys extends RootMetaKey> {
|
|
1131
|
-
<Args extends readonly unknown[], const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, factory: (...args: Args) => ExtensionConfig<Defs, Uses, Provides, Commands, MetaKeys> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): ExtensionFactory<Args, ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, MetaKeys, ContextDependencies<Uses>>;
|
|
1132
|
-
<const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, config?: ExtensionConfig<Defs, Uses, Provides, Commands, MetaKeys> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): Extension<ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, MetaKeys, ContextDependencies<Uses>>;
|
|
1133
|
-
}
|
|
1134
|
-
/**
|
|
1135
|
-
* Define an Extension, or a factory that builds one from config on each call.
|
|
1136
|
-
*
|
|
1137
|
-
* Extensions apply to the whole application and own the flags and commands
|
|
1138
|
-
* they contribute. Factories expose the same identity for section audiences.
|
|
1139
|
-
* `defineExtension<"version">()(id, configOrFactory)` declares required root
|
|
1140
|
-
* metadata keys without preventing inference of flags, Contexts, or commands.
|
|
1141
|
-
*/
|
|
1142
|
-
export declare function defineExtension<MetaKeys extends RootMetaKey = never>(): DefineExtensionWith<MetaKeys>;
|
|
1143
|
-
export declare function defineExtension<Args extends readonly unknown[], const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, factory: (...args: Args) => ExtensionConfig<Defs, Uses, Provides, Commands> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): ExtensionFactory<Args, ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, never, ContextDependencies<Uses>>;
|
|
1144
|
-
export declare function defineExtension<const Defs extends readonly NamedExtensionFlagDef[] = [], const Uses extends readonly AnyContextFactory[] = [], const Provides extends readonly AnyContextInstance[] = [], const Commands extends readonly CommandDefinition<any, any, any, any>[] = []>(id: ExtensionId, config?: ExtensionConfig<Defs, Uses, Provides, Commands> & ValidateExtensionConfig<Defs, Provides, Commands, Uses>): Extension<ContextDependencies<Uses> & ContextsDependencies<Provides> & CommandDefinitionsDependencies<Commands>, Provides, Defs, Commands, never, ContextDependencies<Uses>>;
|
|
1145
|
-
//#endregion
|
|
1146
|
-
//#region src/parsing/spellings.d.ts
|
|
1147
|
-
interface FlagSpelling {
|
|
1148
|
-
canonicalName: string;
|
|
1149
|
-
def: FlagDef;
|
|
1150
|
-
kind: "canonical" | "short" | "alias";
|
|
1151
|
-
negatable: boolean;
|
|
1152
|
-
}
|
|
1153
|
-
//#endregion
|
|
1154
|
-
//#region src/command/node.d.ts
|
|
1155
|
-
/** Runtime-erased Command Action; typed builders and run() own the specific result contract. */
|
|
1156
|
-
type CommandAction = (ctx: CrustCommandContext) => unknown;
|
|
1157
|
-
interface CommandContext {
|
|
1158
|
-
instance: AnyContextInstance;
|
|
1159
|
-
extensionId?: ExtensionId;
|
|
1160
|
-
}
|
|
1161
|
-
/**
|
|
1162
|
-
* Internal representation of a single node in the command tree.
|
|
1163
|
-
*
|
|
1164
|
-
* Built by the `Crust` builder class; not part of the public API.
|
|
1165
|
-
* Each node carries its own local flags, the pre-computed effective
|
|
1166
|
-
* (Context-owned + local merged) flags, positional args, subcommands,
|
|
1167
|
-
* extensions, and the Command Action.
|
|
1168
|
-
*/
|
|
1169
|
-
interface CommandNode {
|
|
1170
|
-
/** Command metadata (name, description, usage) */
|
|
1171
|
-
meta: CommandMeta;
|
|
1172
|
-
/** Flags defined directly on this command via `.flags()` */
|
|
1173
|
-
localFlags: FlagsDef;
|
|
1174
|
-
/** Accumulated flags owned by Contexts provided on this command path */
|
|
1175
|
-
ownedFlags: FlagsDef;
|
|
1176
|
-
/** Context-owned and local flags merged for parsing */
|
|
1177
|
-
effectiveFlags: FlagsDef;
|
|
1178
|
-
/** Cached canonical/short/alias table for the effective flags. */
|
|
1179
|
-
flagSpellings: Map<string, FlagSpelling>;
|
|
1180
|
-
/** Positional argument definitions */
|
|
1181
|
-
args: ArgsDef;
|
|
1182
|
-
/** Named subcommands keyed by name */
|
|
1183
|
-
subCommands: Record<string, CommandNode>;
|
|
1184
|
-
/** Contexts available to this command in provide order (construction order is pull-driven). */
|
|
1185
|
-
contexts: CommandContext[];
|
|
1186
|
-
/** Declared command demands; validated when recipes are materialized. */
|
|
1187
|
-
demands: readonly AnyContextFactory[];
|
|
1188
|
-
/** Extensions registered via `.extend()` (root builder only) */
|
|
1189
|
-
extensions: Extension[];
|
|
1190
|
-
/** The Command Action */
|
|
1191
|
-
run?: CommandAction;
|
|
1192
|
-
}
|
|
1193
|
-
//#endregion
|
|
1194
|
-
//#region src/api/context.d.ts
|
|
1195
|
-
/** Upper bound for phantom name-to-value context maps. */
|
|
1196
|
-
type ContextMap = object;
|
|
1197
|
-
declare const defining: unique symbol;
|
|
1198
|
-
declare const contextProof: unique symbol;
|
|
1199
|
-
/** @internal Immutable defining data retained through public structural copies. */
|
|
1200
|
-
interface Defining<T> {
|
|
1201
|
-
readonly [defining]: T;
|
|
1202
|
-
}
|
|
1203
|
-
/** @internal */
|
|
1204
|
-
type DefiningOf<T> = T extends Defining<unknown> ? T[typeof defining] : T;
|
|
1205
|
-
/**
|
|
1206
|
-
* Adapter hook: the Context sources a bag was built from, exposed as a
|
|
1207
|
-
* non-enumerable symbol property. Reading it never starts construction.
|
|
1208
|
-
*/
|
|
1209
|
-
export declare const contextSources: unique symbol;
|
|
1210
|
-
/** Lazy, invocation-scoped Context values. Reading a property starts construction. */
|
|
1211
|
-
type ContextBag<Deps extends ContextMap = {}> = { readonly [K in keyof Deps]: Promise<Deps[K]>; } & {
|
|
1212
|
-
readonly [contextSources]?: readonly (AnyContextFactory | AnyContextInstance)[];
|
|
1213
|
-
};
|
|
1214
|
-
interface ContextConfig {
|
|
1215
|
-
readonly flags?: readonly NamedFlagDef[];
|
|
1216
|
-
readonly uses?: readonly AnyContextFactory[];
|
|
1217
|
-
}
|
|
1218
|
-
type ValidateContextConfig<R extends ContextConfig> = {
|
|
1219
|
-
readonly flags?: R["flags"] extends readonly NamedFlagDef[] ? ValidateLocalFlagDefs<R["flags"], never> : "flags" extends keyof R ? {} : never;
|
|
1220
|
-
readonly uses?: R["uses"] extends readonly AnyContextFactory[] ? R["uses"] : "uses" extends keyof R ? {} : never;
|
|
1221
|
-
};
|
|
1222
|
-
interface ContextSetupInput<OF extends FlagsDef = FlagsDef> extends InvocationIO {
|
|
1223
|
-
readonly flags: InferFlags<OF>;
|
|
1224
|
-
readonly ctx: ContextBag<ContextMap>;
|
|
1225
|
-
readonly defer: (cleanup: () => void | PromiseLike<void>) => void;
|
|
1226
|
-
}
|
|
1227
|
-
interface ContextInstance<Name extends string = string, Value = unknown, OF extends FlagsDef = FlagsDef, Deps extends ContextMap = Record<string, ContextValue>> extends Defining<ContextInstance<Name, Value, OF, Deps>> {
|
|
1228
|
-
readonly [contextProof]?: string extends keyof OF | keyof Deps ? unknown : (state: [OF, Deps]) => void;
|
|
1229
|
-
readonly name: Name;
|
|
1230
|
-
readonly ownedFlags: FlagsDef;
|
|
1231
|
-
/** @internal — declared direct dependency factories */
|
|
1232
|
-
readonly uses: readonly AnyContextFactory[];
|
|
1233
|
-
/** @internal defining factory, for adapters that identify Contexts by factory */
|
|
1234
|
-
readonly factory: AnyContextFactory;
|
|
1235
|
-
setup(input: ContextSetupInput<OF>): Awaitable<Value>;
|
|
1236
|
-
readonly _ownedFlags?: OF;
|
|
1237
|
-
/** @internal — phantom carrying the transitive dependency closure */
|
|
1238
|
-
readonly _deps?: Deps;
|
|
1239
|
-
}
|
|
1240
|
-
/** @internal Existential registry constraint; never evidence for trusted attachment. */
|
|
1241
|
-
type AnyContextInstance = ContextInstance<string, unknown, any, any>;
|
|
1242
|
-
/** Whatever a Context setup produces, erased at the runtime registry. */
|
|
1243
|
-
type ContextValue = Awaited<ReturnType<AnyContextInstance["setup"]>>;
|
|
1244
|
-
interface ContextSetup<Options, OF extends FlagsDef = {}, Deps extends ContextMap = {}> extends InvocationIO {
|
|
1245
|
-
readonly options: Options;
|
|
1246
|
-
readonly flags: InferFlags<OF>;
|
|
1247
|
-
readonly ctx: ContextBag<Deps>;
|
|
1248
|
-
/**
|
|
1249
|
-
* Registers cleanup on the invocation's disposal stack: callbacks run after
|
|
1250
|
-
* post-run hooks in reverse registration order. Throws once setup has settled.
|
|
1251
|
-
*/
|
|
1252
|
-
readonly defer: (cleanup: () => void | PromiseLike<void>) => void;
|
|
1253
|
-
}
|
|
1254
|
-
interface ContextFactory<Name extends string, Options, Value, OF extends FlagsDef = {}, Deps extends ContextMap = {}> extends Defining<ContextFactory<Name, Options, Value, OF, Deps>> {
|
|
1255
|
-
(options: Options): ContextInstance<Name, Value, OF, Deps>;
|
|
1256
|
-
readonly contextName: Name;
|
|
1257
|
-
/** @internal — declared direct dependency factories */
|
|
1258
|
-
readonly uses: readonly AnyContextFactory[];
|
|
1259
|
-
of(value: Value): ContextInstance<Name, Value, OF, {}>;
|
|
1260
|
-
readonly _deps?: Deps;
|
|
1261
|
-
}
|
|
1262
|
-
type AnyContextFactory = ContextFactory<string, any, any, any, any>;
|
|
1263
|
-
type NamedOutput<Name extends string, Value> = IsClosedName<Name> extends false ? Record<string, Awaited<Value>> : IsUnion<Name> extends true ? Record<string, Awaited<Value>> : { [K in Name]: Awaited<Value>; };
|
|
1264
|
-
type ContextOutput<C> = C extends AnyContextInstance ? DefiningOf<C> extends ContextInstance<infer Name, infer Value, any, any> ? NamedOutput<Name, Value> : never : never;
|
|
1265
|
-
type ContextsOutput<Cs extends readonly AnyContextInstance[]> = IsStaticTuple<Cs> extends true ? Cs extends readonly [infer H, ...infer T extends readonly AnyContextInstance[]] ? MergeProviders<ContextOutput<H>, ContextsOutput<T>> : {} : Cs[number] extends never ? {} : Record<string, ContextOutput<Cs[number]> extends (infer O) ? O extends unknown ? O[keyof O] : never : never>;
|
|
1266
|
-
type ContextsOwnedFlags<Cs extends readonly AnyContextInstance[]> = IsStaticTuple<Cs> extends true ? Cs extends readonly [infer H, ...infer T extends readonly AnyContextInstance[]] ? MergeFlags<ContextOwnedFlags<H>, ContextsOwnedFlags<T>> : {} : keyof UnionToIntersection<ContextOwnedFlags<Cs[number]>> extends never ? {} : FlagsDef;
|
|
1267
|
-
type FactoryOutput<F> = F extends AnyContextFactory ? DefiningOf<F> extends ContextFactory<infer Name, any, infer Value, any, any> ? NamedOutput<Name, Value> : never : never;
|
|
1268
|
-
type FactoriesOutput<Fs extends readonly AnyContextFactory[]> = Fs extends readonly [infer H, ...infer T extends readonly AnyContextFactory[]] ? FactoryOutput<H> & FactoriesOutput<T> : {};
|
|
1269
|
-
type FactoryDeps<F> = F extends AnyContextFactory ? DefiningOf<F> extends ContextFactory<any, any, any, any, infer Deps> ? Deps : {} : {};
|
|
1270
|
-
type FactoriesDeps<Fs extends readonly AnyContextFactory[]> = Fs extends readonly [infer H, ...infer T extends readonly AnyContextFactory[]] ? FactoryDeps<H> & FactoriesDeps<T> : {};
|
|
1271
|
-
type ContextDependencies<Uses extends readonly AnyContextFactory[]> = IsStaticTuple<Uses> extends true ? FactoriesOutput<Uses> & FactoriesDeps<Uses> : Record<string, ContextValue>;
|
|
1272
|
-
type ContextDepsOf<C> = C extends AnyContextInstance ? DefiningOf<C> extends {
|
|
1273
|
-
readonly _deps?: infer Deps extends ContextMap;
|
|
1274
|
-
} ? Deps : {} : {};
|
|
1275
|
-
type ContextsDependencies<Cs extends readonly AnyContextInstance[]> = Cs extends readonly [infer H, ...infer T extends readonly AnyContextInstance[]] ? ContextDepsOf<H> & ContextsDependencies<T> : {};
|
|
1276
|
-
type OwnedFlagsOf<R extends ContextConfig> = R extends {
|
|
1277
|
-
flags: infer F extends readonly NamedFlagDef[];
|
|
1278
|
-
} ? AttachedFlags<F> : "flags" extends keyof R ? FlagsDef : {};
|
|
1279
|
-
type UsesOf<R extends ContextConfig> = R extends {
|
|
1280
|
-
uses: infer Uses extends readonly AnyContextFactory[];
|
|
1281
|
-
} ? Uses : "uses" extends keyof R ? readonly AnyContextFactory[] : readonly [];
|
|
1282
|
-
/** Define a named, lazy command dependency. Declared `uses` are exposed on `ctx`. */
|
|
1283
|
-
export declare function defineContext<Name extends string, Value, Options = void>(name: Name, setup: (input: ContextSetup<Options>) => Awaitable<Value>): ContextFactory<Name, Options, Value>;
|
|
1284
|
-
export declare function defineContext<Name extends string, const R extends ContextConfig, Value, Options = void>(name: Name, config: R & ValidateContextConfig<R> & ContextConfig, setup: (input: ContextSetup<Options, OwnedFlagsOf<R>, ContextDependencies<UsesOf<R>>>) => Awaitable<Value>): ContextFactory<Name, Options, Value, OwnedFlagsOf<R>, ContextDependencies<UsesOf<R>>>;
|
|
1285
|
-
type FactoryValueOf<F extends AnyContextFactory> = F extends ContextFactory<any, any, infer Value, any, any> ? Awaited<Value> : never;
|
|
1286
|
-
//#endregion
|
|
1
|
+
import { $ as CrustErrorDetailsMap, A as ValueType, At as defineExtensionId, B as ExtensionFlagDef, C as NamedFlagDef, Ct as FlagSnapshot, D as SectionAudience, Dt as LocalValueBrand, E as ParsedFlagValue, Et as EmptyArgNameBrand, F as Extension, G as InvocationOutcome, H as ExtensionSectionContribution, I as ExtensionBuildContext, J as defineExtension, K as NamedExtensionFlagDef, L as ExtensionConfig, M as BuildFile, N as BuildReport, O as SectionConsumer, Ot as MergeContext, P as DefineExtensionWith, Q as CrustErrorDetails, R as ExtensionContext, S as MergeFlags, St as CommandSnapshot, T as ParsedArgValue, Tt as LocalFlagNameBrand, U as Finished, V as ExtensionHooks, W as InferExtensionFlags, X as CrustError, Y as CommandNotFoundErrorDetails, Z as CrustErrorCode, _ as FlagDef, _t as RunInput, a as ContextInstance, at as CommandConfig, b as InputFlags, bt as defineCommand, c as FactoryValueOf, ct as CommandHandle, d as ArgDef, dt as CommandShapeAt, et as CrustErrorJson, f as ArgsDef, ft as CommandTree, gt as RunArguments, h as CommandSectionInput, ht as RootCommandMeta, i as ContextFactory, it as AnyCrust, j as BuildArtifacts, k as ValidatedInput, kt as ExtensionId, l as contextSources, lt as CommandPath, m as CommandSection, mt as CrustCommandContext, n as ContextBag, nt as ParseErrorDetails, o as ContextMap, ot as CommandDefinition, p as CommandMeta, pt as Crust, q as RootMetaKey, r as ContextConfig, rt as ValidationErrorDetails, s as ContextSetup, st as CommandDefinitionBuilder, t as AnyContextFactory, tt as DefinitionErrorDetails, u as defineContext, ut as CommandShape, v as FlagsDef, vt as RunInputArguments, w as ParseResult, wt as LocalFlagBrand, x as InvocationIO, xt as ArgSnapshot, y as InputArgs, yt as RunOutcome, z as ExtensionFactory } from "./context-Cud9frNp.js";
|
|
2
|
+
import { resolveArtifactDir } from "@crustjs/utils/artifacts";
|
|
1287
3
|
//#region src/api/flags.d.ts
|
|
1288
4
|
/** Distribute `Omit<_, "name">` over the {@link ArgDef} union. */
|
|
1289
5
|
type OmitName<T> = T extends {
|
|
@@ -1304,4 +20,4 @@ export declare function defineFlag<const N extends string, const D extends FlagD
|
|
|
1304
20
|
/** Define and own one positional argument; layout belongs to its consuming command. */
|
|
1305
21
|
export declare function defineArg<const N extends string, const D extends UnnamedArgDef>(name: N & EmptyArgNameBrand<N>, def: D & LocalValueBrand<D>): Named<N, D>;
|
|
1306
22
|
//#endregion
|
|
1307
|
-
export { type AnyContextFactory, type AnyCrust, type ArgDef, type ArgSnapshot, type ArgsDef, type BuildArtifacts, type BuildFile, type BuildReport, type CommandConfig, type CommandDefinition, type CommandDefinitionBuilder, type CommandHandle, type CommandMeta, type CommandNotFoundErrorDetails, type CommandPath, type CommandSection, type CommandSectionInput, type CommandShape, type CommandShapeAt, type CommandSnapshot, type CommandTree, type ContextBag, type ContextConfig, type ContextFactory, type ContextInstance, type ContextMap, type ContextSetup, type CrustCommandContext, type CrustErrorCode, type CrustErrorDetails, type CrustErrorDetailsMap, type CrustErrorJson, type DefineExtensionWith, type DefinitionErrorDetails, type Extension, type ExtensionBuildContext, type ExtensionConfig, type ExtensionContext, type ExtensionFactory, type ExtensionFlagDef, type ExtensionHooks, type ExtensionId, type ExtensionSectionContribution, type FactoryValueOf, type Finished, type FlagDef, type FlagSnapshot, type FlagsDef, type InferExtensionFlags, type InputArgs, type InputFlags, type InvocationIO, type InvocationOutcome, type MergeContext, type MergeFlags, type NamedExtensionFlagDef, type NamedFlagDef, type ParseErrorDetails, type ParseResult, type ParsedArgValue, type ParsedFlagValue, type RootCommandMeta, type RootMetaKey, type RunArguments, type RunInput, type RunInputArguments, type RunOutcome, type SectionAudience, type SectionConsumer, type UnnamedArgDef, type ValidatedInput, type ValidationErrorDetails, type ValueType, defineExtensionId, resolveArtifactDir };
|
|
23
|
+
export { type AnyContextFactory, type AnyCrust, type ArgDef, type ArgSnapshot, type ArgsDef, type BuildArtifacts, type BuildFile, type BuildReport, type CommandConfig, type CommandDefinition, type CommandDefinitionBuilder, type CommandHandle, type CommandMeta, type CommandNotFoundErrorDetails, type CommandPath, type CommandSection, type CommandSectionInput, type CommandShape, type CommandShapeAt, type CommandSnapshot, type CommandTree, type ContextBag, type ContextConfig, type ContextFactory, type ContextInstance, type ContextMap, type ContextSetup, Crust, type CrustCommandContext, CrustError, type CrustErrorCode, type CrustErrorDetails, type CrustErrorDetailsMap, type CrustErrorJson, type DefineExtensionWith, type DefinitionErrorDetails, type Extension, type ExtensionBuildContext, type ExtensionConfig, type ExtensionContext, type ExtensionFactory, type ExtensionFlagDef, type ExtensionHooks, type ExtensionId, type ExtensionSectionContribution, type FactoryValueOf, type Finished, type FlagDef, type FlagSnapshot, type FlagsDef, type InferExtensionFlags, type InputArgs, type InputFlags, type InvocationIO, type InvocationOutcome, type MergeContext, type MergeFlags, type NamedExtensionFlagDef, type NamedFlagDef, type ParseErrorDetails, type ParseResult, type ParsedArgValue, type ParsedFlagValue, type RootCommandMeta, type RootMetaKey, type RunArguments, type RunInput, type RunInputArguments, type RunOutcome, type SectionAudience, type SectionConsumer, type UnnamedArgDef, type ValidatedInput, type ValidationErrorDetails, type ValueType, contextSources, defineCommand, defineContext, defineExtension, defineExtensionId, resolveArtifactDir };
|