@crustjs/core 0.3.1 → 0.3.3
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-CDq_hxre.js} +9 -217
- package/dist/tooling.d.ts +5 -1
- package/dist/tooling.js +2 -1
- package/package.json +4 -2
- package/dist/artifacts-D8Jlug-a.d.ts +0 -870
|
@@ -1,870 +0,0 @@
|
|
|
1
|
-
//#region ../utils/src/json.d.ts
|
|
2
|
-
/** Any value representable in a JSON document. */
|
|
3
|
-
type JsonValue = string | number | boolean | null | readonly JsonValue[] | JsonObject;
|
|
4
|
-
interface JsonObject {
|
|
5
|
-
[key: string]: JsonValue;
|
|
6
|
-
}
|
|
7
|
-
/** Preserve a type when all of its properties are recursively JSON-compatible. */
|
|
8
|
-
type JsonCompatible<T> = T extends JsonValue ? T : T extends ((...arguments_: never[]) => void) ? never : T extends readonly unknown[] ? { [K in keyof T]: JsonCompatible<T[K]>; } : T extends object ? { [K in keyof T]: JsonCompatible<T[K]>; } : never;
|
|
9
|
-
//#endregion
|
|
10
|
-
//#region ../utils/src/primitive.d.ts
|
|
11
|
-
/** Supported primitive type literals shared by Crust packages. */
|
|
12
|
-
type BaseValueType = "string" | "number" | "boolean";
|
|
13
|
-
//#endregion
|
|
14
|
-
//#region ../utils/src/schema.d.ts
|
|
15
|
-
/** The Standard Typed types interface. */
|
|
16
|
-
interface StandardSchemaTypes<Input = unknown, Output = Input> {
|
|
17
|
-
/** The input type of the schema. */
|
|
18
|
-
readonly input: Input;
|
|
19
|
-
/** The output type of the schema. */
|
|
20
|
-
readonly output: Output;
|
|
21
|
-
}
|
|
22
|
-
/** The result interface if validation succeeds. */
|
|
23
|
-
interface StandardSchemaSuccessResult<Output> {
|
|
24
|
-
/** The typed output value. */
|
|
25
|
-
readonly value: Output;
|
|
26
|
-
/** A falsy value for `issues` indicates success. */
|
|
27
|
-
readonly issues?: undefined;
|
|
28
|
-
}
|
|
29
|
-
/** The result interface if validation fails. */
|
|
30
|
-
interface StandardSchemaFailureResult {
|
|
31
|
-
/** The issues of failed validation. */
|
|
32
|
-
readonly issues: ReadonlyArray<StandardSchemaIssue>;
|
|
33
|
-
}
|
|
34
|
-
/** The result interface of the validate function. */
|
|
35
|
-
type StandardSchemaResult<Output> = StandardSchemaSuccessResult<Output> | StandardSchemaFailureResult;
|
|
36
|
-
/** The issue interface of the failure output. */
|
|
37
|
-
interface StandardSchemaIssue {
|
|
38
|
-
/** The error message of the issue. */
|
|
39
|
-
readonly message: string;
|
|
40
|
-
/** The path of the issue, if any. */
|
|
41
|
-
readonly path?: ReadonlyArray<PropertyKey | StandardSchemaPathSegment> | undefined;
|
|
42
|
-
}
|
|
43
|
-
/** The path segment interface of the issue. */
|
|
44
|
-
interface StandardSchemaPathSegment {
|
|
45
|
-
/** The key representing a path segment. */
|
|
46
|
-
readonly key: PropertyKey;
|
|
47
|
-
}
|
|
48
|
-
/** The Standard Schema properties interface. */
|
|
49
|
-
interface StandardSchemaProps<Input = unknown, Output = Input> {
|
|
50
|
-
/** The version number of the standard. */
|
|
51
|
-
readonly version: 1;
|
|
52
|
-
/** The vendor name of the schema library. */
|
|
53
|
-
readonly vendor: string;
|
|
54
|
-
/** Inferred types associated with the schema. */
|
|
55
|
-
readonly types?: StandardSchemaTypes<Input, Output> | undefined;
|
|
56
|
-
/** Validates unknown input values. */
|
|
57
|
-
readonly validate: (value: StandardSchemaTypes["input"]) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* A Standard Schema-compatible schema object.
|
|
61
|
-
*
|
|
62
|
-
* Any schema library implementing the Standard Schema v1 spec
|
|
63
|
-
* (Zod, Effect, Valibot, ArkType, etc.) produces objects matching this type.
|
|
64
|
-
*/
|
|
65
|
-
type StandardSchema<Input = unknown, Output = Input> = {
|
|
66
|
-
/** The Standard Schema properties. */
|
|
67
|
-
readonly "~standard": StandardSchemaProps<Input, Output>;
|
|
68
|
-
};
|
|
69
|
-
/** Infer the output type produced by a Standard Schema on success. */
|
|
70
|
-
type InferOutput<S extends StandardSchema> = NonNullable<S["~standard"]["types"]>["output"];
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/identity.d.ts
|
|
73
|
-
declare const brand: unique symbol;
|
|
74
|
-
/** Stable identity shared by Extensions and documentation section renderers. */
|
|
75
|
-
type ExtensionId = string & {
|
|
76
|
-
readonly [brand]: true;
|
|
77
|
-
};
|
|
78
|
-
/** Mint an Extension identity from any non-blank, trimmed string. */
|
|
79
|
-
declare function defineExtensionId(id: string): ExtensionId;
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region src/validation/shared.d.ts
|
|
82
|
-
type Awaitable<T> = T | Promise<T>;
|
|
83
|
-
type Simplify<T> = { [K in keyof T]: T[K]; };
|
|
84
|
-
type MergeContext<A, B> = A & B;
|
|
85
|
-
/** Provider replacement is last-write-wins; an open name may leave any earlier value in place. */
|
|
86
|
-
type MergeProviders<A, B> = keyof A extends never ? B : keyof B extends never ? A : string extends keyof B ? Record<string, A[keyof A] | B[string]> : [keyof A & keyof B] extends [never] ? A & B : Omit<A, keyof B> & B;
|
|
87
|
-
/**
|
|
88
|
-
* Extract the narrowed canonical `name` literal from a definition.
|
|
89
|
-
* Open name domains carry no spelling proof; attachment must retain
|
|
90
|
-
* their uncertainty rather than treating this absence as an empty namespace.
|
|
91
|
-
*/
|
|
92
|
-
type DefName<T> = T extends {
|
|
93
|
-
name: infer N extends string;
|
|
94
|
-
} ? IsClosedName<N> extends true ? N : never : never;
|
|
95
|
-
/**
|
|
96
|
-
* Statically known `name` members of a definition (or definition union), for spelling grammar.
|
|
97
|
-
* Filtered per variant: combining names first would let an open variant's `string` absorb
|
|
98
|
-
* a literal sibling before {@link ClosedMembers} can see it.
|
|
99
|
-
*/
|
|
100
|
-
type DefNameMembers<T> = T extends {
|
|
101
|
-
name: infer N extends string;
|
|
102
|
-
} ? ClosedMembers<N> : never;
|
|
103
|
-
type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
|
|
104
|
-
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true;
|
|
105
|
-
/**
|
|
106
|
-
* `true` only for a single statically known fixed-length tuple whose members
|
|
107
|
-
* are not unions. A conditionally assembled collection (`cond ? [a] : [b]` or
|
|
108
|
-
* `[cond ? a : b]`) infers as a union at the tuple or member level, and a
|
|
109
|
-
* variable-length array (`const xs: (typeof a)[]`) may be empty or partially
|
|
110
|
-
* populated at runtime; such contributions must stay runtime-only.
|
|
111
|
-
*/
|
|
112
|
-
type IsStaticTuple<Cs extends readonly unknown[]> = number extends Cs["length"] ? false : IsUnion<Cs> extends true ? false : true extends { [I in keyof Cs]: IsUnion<Cs[I]>; }[number] ? false : true;
|
|
113
|
-
/** Whether a fixed tuple has one closed canonical name per slot. */
|
|
114
|
-
type HasClosedNames<Ds extends readonly unknown[]> = number extends Ds["length"] ? false : IsUnion<Ds> extends true ? false : false extends { [I in keyof Ds]: Ds[I] extends {
|
|
115
|
-
name: infer N extends string;
|
|
116
|
-
} ? IsUnion<N> extends true ? false : IsClosedName<N> : false; }[number] ? false : true;
|
|
117
|
-
/** Brand statically known spelling collisions while allowing open names. */
|
|
118
|
-
type CollisionBrand<S extends string, Existing extends string, Key extends string, Before extends string, After extends string> = string extends S | Existing ? {} : [S & Existing] extends [never] ? {} : { readonly [K in Key]: `${Before}"${S & Existing}"${After}`; };
|
|
119
|
-
/**
|
|
120
|
-
* The statically known members of a name union; open members stay runtime-owned.
|
|
121
|
-
* Only for local spelling grammar: a literal beside an open template is still
|
|
122
|
-
* independently invalid, but must never become key or collision evidence.
|
|
123
|
-
*/
|
|
124
|
-
type ClosedMembers<N extends string> = N extends unknown ? IsClosedName<N> extends true ? N : never : never;
|
|
125
|
-
/** Brand a statically known empty literal member while allowing widened and generic names. */
|
|
126
|
-
type EmptyLiteralNameBrand<Name extends string, Err> = "" extends ClosedMembers<Name> ? Err : {};
|
|
127
|
-
/**
|
|
128
|
-
* Brand a definition whose custom parser can return a Promise — parse results
|
|
129
|
-
* are consumed synchronously during argv parsing. `Extract` keeps the check
|
|
130
|
-
* union-aware (a sometimes-async `cond ? Promise.resolve(x) : x` parser is
|
|
131
|
-
* caught) while `any`-returning parsers stay unbranded.
|
|
132
|
-
*/
|
|
133
|
-
type AsyncParseBrand<T> = T extends {
|
|
134
|
-
parse?: (...args: never[]) => infer R;
|
|
135
|
-
} ? Extract<R, Promise<unknown>> extends never ? {} : {
|
|
136
|
-
readonly FIX_ASYNC_PARSE: "parse must be synchronous; do async work in run()";
|
|
137
|
-
} : {};
|
|
138
|
-
/** Brand literal defaults that fall outside a literal `choices` tuple. */
|
|
139
|
-
type DefaultWithinChoicesBrand<T> = T extends {
|
|
140
|
-
choices: readonly (infer Choice extends string)[];
|
|
141
|
-
default: infer Default;
|
|
142
|
-
} ? string extends Choice ? {} : Default extends readonly string[] ? string extends Default[number] ? {} : Exclude<Default[number], Choice> extends never ? {} : {
|
|
143
|
-
readonly FIX_DEFAULT_CHOICE: "default must be one of choices";
|
|
144
|
-
} : Default extends string ? string extends Default ? {} : Exclude<Default, Choice> extends never ? {} : {
|
|
145
|
-
readonly FIX_DEFAULT_CHOICE: "default must be one of choices";
|
|
146
|
-
} : {} : {};
|
|
147
|
-
/** Finite literal domains have required record keys; infinite templates and branded strings do not.
|
|
148
|
-
* Distribute first so a finite union member cannot hide an open member's index signature.
|
|
149
|
-
*/
|
|
150
|
-
type IsClosedName<N extends string> = false extends (N extends unknown ? ({} extends Record<N, true> ? false : true) : never) ? false : true;
|
|
151
|
-
/** Reject independently provable invalid local values, including members of uncertain definitions. */
|
|
152
|
-
type LocalValueBrand<T> = UnionToIntersection<T extends unknown ? AsyncParseBrand<T> & DefaultWithinChoicesBrand<T> : never>;
|
|
153
|
-
//#endregion
|
|
154
|
-
//#region src/command/snapshot.d.ts
|
|
155
|
-
/**
|
|
156
|
-
* Serializable projection of a positional argument definition.
|
|
157
|
-
*
|
|
158
|
-
* Carries everything help/man/tooling surfaces need; `parse` functions and
|
|
159
|
-
* schemas never cross the boundary.
|
|
160
|
-
*
|
|
161
|
-
* Fields with `undefined` values are dropped entirely (see `freezeCompact`),
|
|
162
|
-
* so absent means "not declared".
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
165
|
-
* For `{ name: "port", type: "number", default: 3000 }`:
|
|
166
|
-
* ```ts
|
|
167
|
-
* { name: "port", type: "number", default: 3000 }
|
|
168
|
-
* // `required`/`variadic` keys absent — not declared on the def
|
|
169
|
-
* ```
|
|
170
|
-
*/
|
|
171
|
-
interface ArgSnapshot {
|
|
172
|
-
/** Argument name as defined, e.g. `"file"`. */
|
|
173
|
-
readonly name: string;
|
|
174
|
-
/** Value type (`"string"`, `"number"`, …); absent for schema-backed args. */
|
|
175
|
-
readonly type?: ValueType;
|
|
176
|
-
/** Human-readable description for help text. */
|
|
177
|
-
readonly description?: string;
|
|
178
|
-
/** `true` when parsing fails if the argument is missing. */
|
|
179
|
-
readonly required?: boolean;
|
|
180
|
-
/** `true` when the argument collects all remaining positionals into an array. */
|
|
181
|
-
readonly variadic?: boolean;
|
|
182
|
-
/** Static enum of accepted values, e.g. `["json", "text"]`. */
|
|
183
|
-
readonly choices?: readonly string[];
|
|
184
|
-
/** Declared default value; `URL` defaults are serialized to their `href` string. */
|
|
185
|
-
readonly default?: unknown;
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Serializable projection of a flag definition. The flag's canonical name is
|
|
189
|
-
* the key it sits under in {@link CommandSnapshot.flags}, not a field here.
|
|
190
|
-
*
|
|
191
|
-
* @example
|
|
192
|
-
* For `{ verbose: { type: "boolean", short: "v", default: false } }`:
|
|
193
|
-
* ```ts
|
|
194
|
-
* snapshot.flags.verbose
|
|
195
|
-
* // => { type: "boolean", short: "v", default: false, negatable: true }
|
|
196
|
-
* ```
|
|
197
|
-
*/
|
|
198
|
-
interface FlagSnapshot {
|
|
199
|
-
/** Value type, e.g. `"boolean"`, `"string"`, `"number"`. */
|
|
200
|
-
readonly type: ValueType;
|
|
201
|
-
/** Human-readable description for help text. */
|
|
202
|
-
readonly description?: string;
|
|
203
|
-
/** Single-character short alias without the dash, e.g. `"v"` for `-v`. */
|
|
204
|
-
readonly short?: string;
|
|
205
|
-
/** Additional aliases without dashes; one-character aliases accept one or two dashes. */
|
|
206
|
-
readonly aliases?: readonly string[];
|
|
207
|
-
/** `true` when parsing fails if the flag is not provided. */
|
|
208
|
-
readonly required?: boolean;
|
|
209
|
-
/** `true` when the flag can repeat and collects values into an array. */
|
|
210
|
-
readonly multiple?: boolean;
|
|
211
|
-
/** `true` when the flag accepts generated `--no-<name>` spellings. */
|
|
212
|
-
readonly negatable: boolean;
|
|
213
|
-
/** `true` when a boolean flag opted out of the `--no-<name>` spelling. */
|
|
214
|
-
readonly noNegate?: boolean;
|
|
215
|
-
/** Static enum of accepted values, e.g. `["debug", "info", "error"]`. */
|
|
216
|
-
readonly choices?: readonly string[];
|
|
217
|
-
/** Declared default value; `URL` defaults are serialized to their `href` string. */
|
|
218
|
-
readonly default?: unknown;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* A readonly, serializable description of a command, exposed across public
|
|
222
|
-
* API boundaries (Command Action context, Extension hooks, and
|
|
223
|
-
* `COMMAND_NOT_FOUND` error details) instead of internal command nodes.
|
|
224
|
-
*
|
|
225
|
-
* `flags` contains the effective (Context-owned + local merged) flags — the same
|
|
226
|
-
* set the parser accepts for the command.
|
|
227
|
-
*
|
|
228
|
-
* @example
|
|
229
|
-
* ```ts
|
|
230
|
-
* defineCommand("add", (cmd) =>
|
|
231
|
-
* cmd
|
|
232
|
-
* .args({ name: "name", type: "string", required: true })
|
|
233
|
-
* .flags({ name: "force", type: "boolean", short: "f" })
|
|
234
|
-
* .action(() => {}),
|
|
235
|
-
* );
|
|
236
|
-
* // snapshots to:
|
|
237
|
-
* // {
|
|
238
|
-
* // meta: { name: "add" },
|
|
239
|
-
* // hasAction: true,
|
|
240
|
-
* // args: [{ name: "name", type: "string", required: true }],
|
|
241
|
-
* // flags: { force: { type: "boolean", short: "f", negatable: true } },
|
|
242
|
-
* // subCommands: {},
|
|
243
|
-
* // }
|
|
244
|
-
* ```
|
|
245
|
-
*/
|
|
246
|
-
interface CommandSnapshot {
|
|
247
|
-
/** Command metadata, including routing and presentation options. */
|
|
248
|
-
readonly meta: Readonly<CommandMeta>;
|
|
249
|
-
/** Whether the command defines a Command Action */
|
|
250
|
-
readonly hasAction: boolean;
|
|
251
|
-
/** Positional argument snapshots in declaration order. */
|
|
252
|
-
readonly args: readonly ArgSnapshot[];
|
|
253
|
-
/** Effective flags keyed by canonical flag name. */
|
|
254
|
-
readonly flags: Readonly<Record<string, FlagSnapshot>>;
|
|
255
|
-
/** Direct subcommand snapshots keyed by canonical name (includes hidden ones). */
|
|
256
|
-
readonly subCommands: Readonly<Record<string, CommandSnapshot>>;
|
|
257
|
-
}
|
|
258
|
-
//#endregion
|
|
259
|
-
//#region src/parsing/parser.d.ts
|
|
260
|
-
type RunInputValue = URL | JsonValue | readonly RunInputValue[];
|
|
261
|
-
interface RunInputPayload {
|
|
262
|
-
readonly args?: Readonly<Record<string, RunInputValue | undefined>>;
|
|
263
|
-
readonly flags?: Readonly<Record<string, RunInputValue | undefined>>;
|
|
264
|
-
readonly raw?: readonly string[];
|
|
265
|
-
}
|
|
266
|
-
//#endregion
|
|
267
|
-
//#region src/types.d.ts
|
|
268
|
-
/** Injectable output callbacks threaded through one invocation. */
|
|
269
|
-
interface InvocationIO {
|
|
270
|
-
/** Write a line of standard output (injectable text callback) */
|
|
271
|
-
stdout: (text: string) => void;
|
|
272
|
-
/** Write a line of diagnostic output (injectable text callback) */
|
|
273
|
-
stderr: (text: string) => void;
|
|
274
|
-
}
|
|
275
|
-
/**
|
|
276
|
-
* Supported type literals for args and flags.
|
|
277
|
-
*
|
|
278
|
-
* Extends `BaseValueType` (`"string" | "number" | "boolean"`) with three
|
|
279
|
-
* formatted built-ins:
|
|
280
|
-
*
|
|
281
|
-
* - `"url"` — the raw value is parsed via `new URL()` into a {@link URL}
|
|
282
|
-
* - `"path"` — the raw value is expanded (`~`) and resolved against
|
|
283
|
-
* `process.cwd()` into an absolute `string`
|
|
284
|
-
* - `"json"` — the raw value is parsed via `JSON.parse()` into `unknown`
|
|
285
|
-
*/
|
|
286
|
-
type ValueType = BaseValueType | "url" | "path" | "json";
|
|
287
|
-
/** Resolve a {@link ValueType} literal to its runtime TypeScript type. */
|
|
288
|
-
type Resolve<T extends ValueType> = {
|
|
289
|
-
string: string;
|
|
290
|
-
number: number;
|
|
291
|
-
boolean: boolean;
|
|
292
|
-
url: URL;
|
|
293
|
-
path: string;
|
|
294
|
-
json: unknown;
|
|
295
|
-
}[T];
|
|
296
|
-
/**
|
|
297
|
-
* Resolve the inferred runtime type for a flag/arg definition.
|
|
298
|
-
*
|
|
299
|
-
* When the def declares a `parse` escape hatch (only allowed on `"string"`
|
|
300
|
-
* variants), the inferred type is `ReturnType<typeof parse>`. Optional parsers
|
|
301
|
-
* also retain the unparsed output branch. String defs
|
|
302
|
-
* with a literal `choices` tuple narrow to the union of those literals.
|
|
303
|
-
* Otherwise it delegates to {@link Resolve} on the declared `type`.
|
|
304
|
-
*/
|
|
305
|
-
type ResolveBaseType<F> = "parse" extends keyof F ? F["parse"] extends (infer Parse) ? Parse extends ((raw: string) => infer R) ? R : ResolveUnparsedType<F> : never : ResolveUnparsedType<F>;
|
|
306
|
-
type ResolveUnparsedType<F> = F extends {
|
|
307
|
-
type: "string";
|
|
308
|
-
choices: readonly (infer C extends string)[];
|
|
309
|
-
} ? C : F extends {
|
|
310
|
-
type: infer T extends ValueType;
|
|
311
|
-
} ? Resolve<T> : never;
|
|
312
|
-
/** Shared fields present on every positional argument definition */
|
|
313
|
-
interface ArgDefBase {
|
|
314
|
-
/** The argument name (used as the key in the parsed result and in help text) */
|
|
315
|
-
name: string;
|
|
316
|
-
/** Human-readable description for help text */
|
|
317
|
-
description?: string;
|
|
318
|
-
/**
|
|
319
|
-
* When `true`, the parser throws if the argument is not provided.
|
|
320
|
-
*
|
|
321
|
-
* For variadic args without a default, the validated output is a nonempty tuple.
|
|
322
|
-
*/
|
|
323
|
-
required?: true;
|
|
324
|
-
/** Not supported with core value options — see {@link SchemaArgDef} */
|
|
325
|
-
schema?: never;
|
|
326
|
-
/**
|
|
327
|
-
* When `true`, collects all remaining positional values into an array.
|
|
328
|
-
*
|
|
329
|
-
* The validated output is always an array, never `undefined`.
|
|
330
|
-
* Required core variadics without defaults infer `[T, ...T[]]` after
|
|
331
|
-
* required validation; other core variadics infer `T[]`.
|
|
332
|
-
*/
|
|
333
|
-
variadic?: true;
|
|
334
|
-
}
|
|
335
|
-
/** A positional argument whose value is a string */
|
|
336
|
-
interface StringArgDef<ParseOutput = unknown> extends ArgDefBase {
|
|
337
|
-
type: "string";
|
|
338
|
-
/** Default string value when the argument is not provided */
|
|
339
|
-
default?: string;
|
|
340
|
-
/**
|
|
341
|
-
* Static enum of valid values for this argument.
|
|
342
|
-
*
|
|
343
|
-
* Checked for argv and structured invocation input before `parse` runs.
|
|
344
|
-
* Typed input also proves membership statically. Passing a value outside
|
|
345
|
-
* `choices` throws `CrustError("PARSE", …)` before any `parse` transform
|
|
346
|
-
* is applied. Also consumed by shell-completion extensions
|
|
347
|
-
* (e.g. `@crustjs/extensions`) to emit value candidates.
|
|
348
|
-
*
|
|
349
|
-
* Only available on string-typed args; not supported on number/boolean.
|
|
350
|
-
*
|
|
351
|
-
* @example
|
|
352
|
-
* { name: "target", type: "string", choices: ["browser", "bun", "node"] }
|
|
353
|
-
*/
|
|
354
|
-
choices?: readonly string[];
|
|
355
|
-
/**
|
|
356
|
-
* Custom synchronous parser for the raw argv string. Runs after `choices`
|
|
357
|
-
* validation and per element for variadic args. Its return type becomes the
|
|
358
|
-
* argument's inferred runtime type; declared defaults are parsed too.
|
|
359
|
-
*
|
|
360
|
-
* @example
|
|
361
|
-
* { name: "port", type: "string", parse: (s) => Number(s) }
|
|
362
|
-
*/
|
|
363
|
-
parse?: (raw: string) => ParseOutput;
|
|
364
|
-
}
|
|
365
|
-
/** A positional argument whose value is a number */
|
|
366
|
-
interface NumberArgDef extends ArgDefBase {
|
|
367
|
-
type: "number";
|
|
368
|
-
choices?: never;
|
|
369
|
-
/** Default number value when the argument is not provided */
|
|
370
|
-
default?: number;
|
|
371
|
-
/** Not supported on number args — use `type: "string"` with `parse`. */
|
|
372
|
-
parse?: never;
|
|
373
|
-
}
|
|
374
|
-
/** A positional argument whose value is a boolean */
|
|
375
|
-
interface BooleanArgDef extends ArgDefBase {
|
|
376
|
-
type: "boolean";
|
|
377
|
-
choices?: never;
|
|
378
|
-
/** Default boolean value when the argument is not provided */
|
|
379
|
-
default?: boolean;
|
|
380
|
-
/** Not supported on boolean args — use `type: "string"` with `parse`. */
|
|
381
|
-
parse?: never;
|
|
382
|
-
}
|
|
383
|
-
/** A positional argument whose value is a {@link URL} */
|
|
384
|
-
interface UrlArgDef extends ArgDefBase {
|
|
385
|
-
type: "url";
|
|
386
|
-
choices?: never;
|
|
387
|
-
/** Default URL value when the argument is not provided */
|
|
388
|
-
default?: URL;
|
|
389
|
-
/** Not supported on url args — use `type: "string"` with `parse`. */
|
|
390
|
-
parse?: never;
|
|
391
|
-
}
|
|
392
|
-
/** A positional argument whose value is an absolute filesystem path */
|
|
393
|
-
interface PathArgDef extends ArgDefBase {
|
|
394
|
-
type: "path";
|
|
395
|
-
choices?: never;
|
|
396
|
-
/** Default path string when the argument is not provided */
|
|
397
|
-
default?: string;
|
|
398
|
-
/** Not supported on path args — use `type: "string"` with `parse`. */
|
|
399
|
-
parse?: never;
|
|
400
|
-
}
|
|
401
|
-
/** A positional argument whose value is JSON parsed to `unknown` */
|
|
402
|
-
interface JsonArgDef extends ArgDefBase {
|
|
403
|
-
type: "json";
|
|
404
|
-
choices?: never;
|
|
405
|
-
/** Default parsed JSON value when the argument is not provided */
|
|
406
|
-
default?: unknown;
|
|
407
|
-
/** Not supported on json args — use `type: "string"` with `parse`. */
|
|
408
|
-
parse?: never;
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* A positional argument validated by a Standard Schema (exclusive mode).
|
|
412
|
-
*
|
|
413
|
-
* The schema receives the raw string token (`string | undefined` when the
|
|
414
|
-
* argument is absent; `string[]` for variadic args) and exclusively owns
|
|
415
|
-
* coercion, defaults, requiredness, choices, and validation. Its inferred
|
|
416
|
-
* output type reaches the Command Action. Core value options (`type`,
|
|
417
|
-
* `default`, `required`, `choices`, `parse`) cannot be mixed in.
|
|
418
|
-
*/
|
|
419
|
-
interface SchemaArgDef {
|
|
420
|
-
/** The argument name (used as the key in the parsed result and in help text) */
|
|
421
|
-
name: string;
|
|
422
|
-
/** Human-readable description for help text */
|
|
423
|
-
description?: string;
|
|
424
|
-
/** When `true`, collects all remaining raw tokens into a `string[]` for the schema */
|
|
425
|
-
variadic?: true;
|
|
426
|
-
/** Standard Schema that owns coercion, defaults, requiredness, and validation */
|
|
427
|
-
schema: StandardSchema;
|
|
428
|
-
type?: never;
|
|
429
|
-
required?: never;
|
|
430
|
-
default?: never;
|
|
431
|
-
choices?: never;
|
|
432
|
-
parse?: never;
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Defines a single positional argument for a CLI command.
|
|
436
|
-
*
|
|
437
|
-
* Discriminated by `type` for type-safe `default` values. Boolean toggle
|
|
438
|
-
* fields (`required`, `variadic`) only accept `true`.
|
|
439
|
-
*
|
|
440
|
-
* @example
|
|
441
|
-
* ```ts
|
|
442
|
-
* const args = [
|
|
443
|
-
* { name: "port", type: "number", description: "Port number", default: 3000 },
|
|
444
|
-
* { name: "name", type: "string", required: true },
|
|
445
|
-
* { name: "files", type: "string", variadic: true },
|
|
446
|
-
* ] as const satisfies ArgsDef;
|
|
447
|
-
* ```
|
|
448
|
-
*/
|
|
449
|
-
type ArgDef = StringArgDef | NumberArgDef | BooleanArgDef | UrlArgDef | PathArgDef | JsonArgDef | SchemaArgDef;
|
|
450
|
-
/** Ordered tuple of positional argument definitions */
|
|
451
|
-
type ArgsDef = readonly ArgDef[];
|
|
452
|
-
/** Shared fields present on every flag definition */
|
|
453
|
-
interface FlagDefBase {
|
|
454
|
-
/** Human-readable description for help text */
|
|
455
|
-
description?: string;
|
|
456
|
-
/** Single-character short alias (e.g. `"v"` → `-v`) */
|
|
457
|
-
short?: string;
|
|
458
|
-
/** Additional aliases (e.g. `["out"]` → `--out`); one-character aliases also accept one dash. */
|
|
459
|
-
aliases?: readonly string[];
|
|
460
|
-
/** When `true`, the parser throws if the flag is not provided */
|
|
461
|
-
required?: true;
|
|
462
|
-
/** Not supported with core value options — see {@link SchemaStringFlagDef} */
|
|
463
|
-
schema?: never;
|
|
464
|
-
}
|
|
465
|
-
/** Base for single-value flags — `multiple` must be omitted */
|
|
466
|
-
interface SingleFlagBase extends FlagDefBase {
|
|
467
|
-
/** Must be omitted for single-value flags — set to `true` for multi-value */
|
|
468
|
-
multiple?: never;
|
|
469
|
-
}
|
|
470
|
-
/** Base for multi-value flags — `multiple` is required as `true` */
|
|
471
|
-
interface MultiFlagBase extends FlagDefBase {
|
|
472
|
-
/** Collect repeated values into an array */
|
|
473
|
-
multiple: true;
|
|
474
|
-
}
|
|
475
|
-
type StringFlagFields<Default, ParseOutput> = {
|
|
476
|
-
/** Default string value, or string array for a multi-value flag. */
|
|
477
|
-
default?: Default;
|
|
478
|
-
/**
|
|
479
|
-
* Static enum of valid values for this flag.
|
|
480
|
-
*
|
|
481
|
-
* Checked for argv and structured invocation input before `parse` runs.
|
|
482
|
-
* Typed input also proves membership statically. Passing a value outside
|
|
483
|
-
* `choices` throws `CrustError("PARSE", …)` before any `parse` transform
|
|
484
|
-
* is applied. Also consumed by shell-completion extensions.
|
|
485
|
-
*/
|
|
486
|
-
choices?: readonly string[];
|
|
487
|
-
/**
|
|
488
|
-
* Custom synchronous parser for the raw argv string. For multi-value
|
|
489
|
-
* flags it runs once per occurrence. The return type becomes the flag's
|
|
490
|
-
* inferred runtime value type.
|
|
491
|
-
*/
|
|
492
|
-
parse?: (raw: string) => ParseOutput;
|
|
493
|
-
noNegate?: never;
|
|
494
|
-
};
|
|
495
|
-
type TypedFlagFields<T extends Exclude<ValueType, "string">, Default> = {
|
|
496
|
-
/** Default value, or value array for a multi-value flag. */
|
|
497
|
-
default?: Default;
|
|
498
|
-
choices?: never;
|
|
499
|
-
/** Only boolean flags support generated-negation opt-out. */
|
|
500
|
-
noNegate?: T extends "boolean" ? true : never;
|
|
501
|
-
/** Use `type: "string"` with `parse` for custom parsing. */
|
|
502
|
-
parse?: never;
|
|
503
|
-
};
|
|
504
|
-
type CoreFlagFields<T extends ValueType, Default, ParseOutput> = T extends "string" ? StringFlagFields<Default, ParseOutput> : T extends Exclude<ValueType, "string"> ? TypedFlagFields<T, Default> : never;
|
|
505
|
-
/** A single-value core flag for the declared value type. */
|
|
506
|
-
type TypedFlagDef<T extends ValueType, ParseOutput = unknown> = SingleFlagBase & {
|
|
507
|
-
type: T;
|
|
508
|
-
} & CoreFlagFields<T, Resolve<T>, ParseOutput>;
|
|
509
|
-
/** A repeatable core flag for the declared value type. */
|
|
510
|
-
type TypedMultiFlagDef<T extends ValueType, ParseOutput = unknown> = MultiFlagBase & {
|
|
511
|
-
type: T;
|
|
512
|
-
} & CoreFlagFields<T, readonly Resolve<T>[], ParseOutput>;
|
|
513
|
-
/** Shared fields for schema-backed flags (exclusive mode) */
|
|
514
|
-
interface SchemaFlagBase extends Omit<FlagDefBase, "schema" | "required"> {
|
|
515
|
-
/** Standard Schema that owns coercion, defaults, requiredness, and validation */
|
|
516
|
-
schema: StandardSchema;
|
|
517
|
-
required?: never;
|
|
518
|
-
default?: never;
|
|
519
|
-
choices?: never;
|
|
520
|
-
parse?: never;
|
|
521
|
-
}
|
|
522
|
-
/**
|
|
523
|
-
* A schema-backed flag that consumes a value token (`--flag value`).
|
|
524
|
-
* The schema receives the raw string (`string | undefined`, or
|
|
525
|
-
* `string[] | undefined` with `multiple: true`) and exclusively owns coercion,
|
|
526
|
-
* defaults, requiredness, and validation. `type` declares token consumption only.
|
|
527
|
-
*/
|
|
528
|
-
interface SchemaStringFlagDef extends SchemaFlagBase {
|
|
529
|
-
type: "string";
|
|
530
|
-
/** When `true`, the schema receives `string[]` when present, or `undefined` when omitted. */
|
|
531
|
-
multiple?: true;
|
|
532
|
-
noNegate?: never;
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* A schema-backed toggle flag (no value token). The schema receives the raw
|
|
536
|
-
* `boolean | undefined` (or `boolean[] | undefined` with `multiple: true`).
|
|
537
|
-
*/
|
|
538
|
-
interface SchemaBooleanFlagDef extends SchemaFlagBase {
|
|
539
|
-
type: "boolean";
|
|
540
|
-
/** When `true`, the schema receives `boolean[]` when present, or `undefined` when omitted. */
|
|
541
|
-
multiple?: true;
|
|
542
|
-
/** When `true`, reject `--no-{name}` (and negated aliases) at parse time and hide the generated help label */
|
|
543
|
-
noNegate?: true;
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Defines a single named flag for a CLI command.
|
|
547
|
-
*
|
|
548
|
-
* Discriminated by `type` and `multiple` for type-safe `default` values.
|
|
549
|
-
* Boolean toggle fields (`required`, `multiple`) only accept `true`.
|
|
550
|
-
*
|
|
551
|
-
* @example
|
|
552
|
-
* ```ts
|
|
553
|
-
* const flags = {
|
|
554
|
-
* verbose: { type: "boolean", description: "Enable verbose logging", short: "v" },
|
|
555
|
-
* port: { type: "number", description: "Port number", default: 3000 },
|
|
556
|
-
* files: { type: "string", multiple: true, default: ["index.ts"] },
|
|
557
|
-
* } satisfies FlagsDef;
|
|
558
|
-
* ```
|
|
559
|
-
*/
|
|
560
|
-
type FlagDef = { [T in ValueType]: TypedFlagDef<T> | TypedMultiFlagDef<T>; }[ValueType] | SchemaStringFlagDef | SchemaBooleanFlagDef;
|
|
561
|
-
/** Record mapping flag names to their definitions */
|
|
562
|
-
type FlagsDef = Record<string, FlagDef>;
|
|
563
|
-
/**
|
|
564
|
-
* A flag definition that carries its own name — the authoring shape
|
|
565
|
-
* produced by `defineFlag(name, def)` or written inline as an object
|
|
566
|
-
* literal (`{ name: "dry-run", type: "boolean" }`) and attached with the
|
|
567
|
-
* variadic `.flags(...defs)`.
|
|
568
|
-
*/
|
|
569
|
-
type NamedFlagDef = FlagDef & {
|
|
570
|
-
readonly name: string;
|
|
571
|
-
};
|
|
572
|
-
/**
|
|
573
|
-
* Derive the internal `FlagsDef` record from a tuple of named flag
|
|
574
|
-
* definitions: each definition's `name` literal becomes a key, its value
|
|
575
|
-
* the definition without `name`.
|
|
576
|
-
*
|
|
577
|
-
* The `extends infer R extends FlagsDef` step defers evaluation so the
|
|
578
|
-
* result satisfies `FlagsDef` in generic positions.
|
|
579
|
-
*/
|
|
580
|
-
type FlagWithoutName<D> = D extends unknown ? Omit<D, "name"> : never;
|
|
581
|
-
type NamedFlagsRecord<Defs extends readonly NamedFlagDef[]> = { [K in Defs[number]["name"]]: FlagWithoutName<Extract<Defs[number], {
|
|
582
|
-
name: K;
|
|
583
|
-
}>>; } extends (infer R extends FlagsDef) ? R : never;
|
|
584
|
-
/**
|
|
585
|
-
* Merges two flag sets as a flat intersection.
|
|
586
|
-
*
|
|
587
|
-
* Statically known shared keys are branded at compile time (`DuplicateNameBrand`,
|
|
588
|
-
* `ExistingFlagCollisionBrand`, `ProvideChecks`). A plain intersection stays
|
|
589
|
-
* flat in the checker — chained `.flags()`/`.provide()` calls cost constant
|
|
590
|
-
* instantiation depth, where per-call merge layers (mapped type or
|
|
591
|
-
* `Simplify<Omit & …>`) nested and hit TS2589 at ~47 / ~31 chained calls.
|
|
592
|
-
*/
|
|
593
|
-
type MergeFlags<Base extends FlagsDef, Override extends FlagsDef> = Base & Override;
|
|
594
|
-
/**
|
|
595
|
-
* Infer the resolved type for a single ArgDef:
|
|
596
|
-
*
|
|
597
|
-
* - **variadic** → `[primitive, ...primitive[]]` when required without a default,
|
|
598
|
-
* otherwise `primitive[]` (always an array, never `undefined`)
|
|
599
|
-
* - **required** or **has default** → `primitive` (non-optional)
|
|
600
|
-
* - otherwise → `primitive | undefined`
|
|
601
|
-
*
|
|
602
|
-
* Required core variadics without defaults resolve to nonempty tuples.
|
|
603
|
-
* Schema-backed and default-backed arguments retain their own output contracts.
|
|
604
|
-
*/
|
|
605
|
-
type InferArgValue<A extends ArgDef> = A extends {
|
|
606
|
-
schema: infer S extends StandardSchema;
|
|
607
|
-
} ? InferOutput<S> : A extends {
|
|
608
|
-
variadic: true;
|
|
609
|
-
} ? A extends {
|
|
610
|
-
required: true;
|
|
611
|
-
default?: never;
|
|
612
|
-
} ? [ResolveBaseType<A>, ...ResolveBaseType<A>[]] : ResolveBaseType<A>[] : ("variadic" extends keyof A ? true extends A["variadic"] ? ResolveBaseType<A>[] : never : never) | (A extends {
|
|
613
|
-
required: true;
|
|
614
|
-
} ? ResolveBaseType<A> : A extends {
|
|
615
|
-
default: infer Default;
|
|
616
|
-
} ? undefined extends Default ? ResolveBaseType<A> | undefined : ResolveBaseType<A> : ResolveBaseType<A> | undefined);
|
|
617
|
-
type DuplicateArgNames<A extends readonly ArgDef[], Seen extends string = never, Duplicates extends string = never> = A extends readonly [infer Head extends ArgDef, ...infer Tail extends readonly ArgDef[]] ? DuplicateArgNames<Tail, Seen | Head["name"], Duplicates | (Head["name"] & Seen)> : Duplicates;
|
|
618
|
-
type InferDuplicateArgs<A extends readonly ArgDef[]> = A extends readonly [infer Head extends ArgDef, ...infer Tail extends readonly ArgDef[]] ? { [K in Head["name"]]: InferArgValue<Head>; } & InferDuplicateArgs<Tail> : {};
|
|
619
|
-
/**
|
|
620
|
-
* Convert a literal ArgsDef tuple into resolved values keyed by argument name.
|
|
621
|
-
*
|
|
622
|
-
* Tuples with rest elements (`number extends A["length"]`) opt out to `{}`;
|
|
623
|
-
* the builder only produces fixed tuples. Unions of tuples distribute through
|
|
624
|
-
* `InferArgs`'s naked conditional, so each member is inferred separately.
|
|
625
|
-
*/
|
|
626
|
-
type InferArgsTuple<A extends readonly ArgDef[]> = number extends A["length"] ? {} : [DuplicateArgNames<A>] extends [never] ? { [D in A[number] as D["name"]]: InferArgValue<D>; } : InferDuplicateArgs<A>;
|
|
627
|
-
/**
|
|
628
|
-
* Maps an ArgsDef tuple to resolved arg types keyed by each arg's `name`.
|
|
629
|
-
*
|
|
630
|
-
* @example
|
|
631
|
-
* ```ts
|
|
632
|
-
* type Result = InferArgs<readonly [
|
|
633
|
-
* { name: "port"; type: "number"; default: 3000 },
|
|
634
|
-
* { name: "name"; type: "string"; required: true },
|
|
635
|
-
* { name: "files"; type: "string"; variadic: true },
|
|
636
|
-
* ]>;
|
|
637
|
-
* // Result = { port: number; name: string; files: string[] }
|
|
638
|
-
* ```
|
|
639
|
-
*/
|
|
640
|
-
type InferArgs<A> = A extends ArgsDef ? Simplify<InferArgsTuple<A>> : Record<string, never>;
|
|
641
|
-
/**
|
|
642
|
-
* Infer the resolved type for a single FlagDef:
|
|
643
|
-
*
|
|
644
|
-
* - **multiple** → wraps the resolved type in an array
|
|
645
|
-
* - **required** or **has default** → `primitive` (non-optional)
|
|
646
|
-
* - otherwise → `primitive | undefined`
|
|
647
|
-
*/
|
|
648
|
-
type InferFlagValue<F extends FlagDef> = F extends {
|
|
649
|
-
schema: infer S extends StandardSchema;
|
|
650
|
-
} ? InferOutput<S> : F extends {
|
|
651
|
-
multiple: true;
|
|
652
|
-
} ? F extends {
|
|
653
|
-
required: true;
|
|
654
|
-
} ? ResolveBaseType<F>[] : F extends {
|
|
655
|
-
default: readonly unknown[];
|
|
656
|
-
} ? ResolveBaseType<F>[] : ResolveBaseType<F>[] | undefined : F extends {
|
|
657
|
-
required: true;
|
|
658
|
-
} ? ResolveBaseType<F> : F extends {
|
|
659
|
-
default: infer Default;
|
|
660
|
-
} ? undefined extends Default ? ResolveBaseType<F> | undefined : ResolveBaseType<F> : ResolveBaseType<F> | undefined;
|
|
661
|
-
/**
|
|
662
|
-
* Maps a full FlagsDef record to resolved flag types.
|
|
663
|
-
*
|
|
664
|
-
* @example
|
|
665
|
-
* ```ts
|
|
666
|
-
* type Result = InferFlags<{
|
|
667
|
-
* verbose: { type: "boolean" };
|
|
668
|
-
* port: { type: "number", default: 3000 };
|
|
669
|
-
* }>;
|
|
670
|
-
* // Result = { verbose: boolean | undefined; port: number }
|
|
671
|
-
* ```
|
|
672
|
-
*/
|
|
673
|
-
type InferFlags<F> = F extends FlagsDef ? { [K in keyof F]: InferFlagValue<F[K]>; } : Record<string, never>;
|
|
674
|
-
type InputBaseValue<D> = true extends IsUnion<D> | IsUnion<D[keyof D & "type"]> ? never : D extends {
|
|
675
|
-
type: "boolean";
|
|
676
|
-
} ? "noNegate" extends keyof D ? true extends D["noNegate"] ? true : boolean : boolean : D extends {
|
|
677
|
-
schema: StandardSchema;
|
|
678
|
-
} ? D extends {
|
|
679
|
-
type: "boolean";
|
|
680
|
-
} ? boolean : string : D extends {
|
|
681
|
-
type: "json";
|
|
682
|
-
} ? JsonValue : "choices" extends keyof D ? Exclude<D["choices"], undefined> extends (infer Choices extends readonly string[]) ? [Choices] extends [never] ? D extends {
|
|
683
|
-
type: infer T extends ValueType;
|
|
684
|
-
} ? Resolve<T> : never : IsStaticTuple<Choices> extends true ? IsClosedName<Choices[number]> extends true ? Choices[number] : never : never : never : D extends {
|
|
685
|
-
parse: (raw: string) => infer _ParseOutput;
|
|
686
|
-
} ? string : D extends {
|
|
687
|
-
type: infer T extends ValueType;
|
|
688
|
-
} ? Resolve<T> : never;
|
|
689
|
-
type InputArgValue<D extends ArgDef, Value = InputBaseValue<D>> = [Value] extends [never] ? never : D extends {
|
|
690
|
-
variadic: true;
|
|
691
|
-
} ? RequiredArgNames<[D]> extends never ? Value[] : [Value, ...Value[]] : "variadic" extends keyof D ? true extends D["variadic"] ? never : Value : Value;
|
|
692
|
-
type InputFlagValue<D, Value = InputBaseValue<D>> = [Value] extends [never] ? never : D extends {
|
|
693
|
-
multiple: true;
|
|
694
|
-
} ? Value[] : "multiple" extends keyof D ? true extends D["multiple"] ? never : Value : Value;
|
|
695
|
-
type RequiredArgNames<A extends ArgsDef> = A[number] extends (infer D) ? D extends {
|
|
696
|
-
name: infer N extends string;
|
|
697
|
-
} ? "required" extends keyof D ? true extends D["required"] ? D extends {
|
|
698
|
-
default: infer Default;
|
|
699
|
-
} ? undefined extends Default ? N : never : N : never : never : never : never;
|
|
700
|
-
type InputArgsPrefixes<Remaining extends ArgsDef, Supplied = {}, Prefixes = never> = Remaining extends readonly [infer Head extends ArgDef, ...infer Tail extends ArgsDef] ? InputArgsPrefixes<Tail, Supplied & { [K in Head["name"]]: InputArgValue<Head>; }, Prefixes | (RequiredArgNames<Remaining> extends never ? Simplify<Supplied & { [D in Remaining[number] as D["name"]]?: never; }> : never)> : Prefixes | Simplify<Supplied>;
|
|
701
|
-
/** Supplied positional values form a prefix; defaults do not fill input gaps. */
|
|
702
|
-
type InputArgs<A extends ArgsDef> = number extends A["length"] ? never : IsUnion<A> extends true ? never : IsClosedName<A[number]["name"]> extends true ? InputArgsPrefixes<A> : never;
|
|
703
|
-
type RequiredFlagName<D, K> = D extends unknown ? "required" extends keyof D ? true extends D["required"] ? D extends {
|
|
704
|
-
default: infer Default;
|
|
705
|
-
} ? undefined extends Default ? K : never : K : never : never : never;
|
|
706
|
-
type RequiredFlagNames<F extends FlagsDef> = { [K in keyof F]-?: RequiredFlagName<F[K], K>; }[keyof F];
|
|
707
|
-
/** Flag values accepted by typed programmatic invocation before parsing/validation. */
|
|
708
|
-
type KnownFlags<F extends FlagsDef> = { [K in keyof F as string extends K ? never : K]: F[K]; };
|
|
709
|
-
type InputFlags<F extends FlagsDef> = IsUnion<F> extends true ? never : Simplify<{ [K in RequiredFlagNames<KnownFlags<F>>]-?: InputFlagValue<KnownFlags<F>[K]>; } & { [K in Exclude<keyof KnownFlags<F>, RequiredFlagNames<KnownFlags<F>>>]?: InputFlagValue<KnownFlags<F>[K]>; }> & (string extends keyof F ? NonNullable<RunInputPayload["flags"]> : {});
|
|
710
|
-
type SectionConsumer = ExtensionId | {
|
|
711
|
-
readonly id: ExtensionId;
|
|
712
|
-
};
|
|
713
|
-
type Audience<C> = {
|
|
714
|
-
readonly only: C;
|
|
715
|
-
readonly except?: never;
|
|
716
|
-
} | {
|
|
717
|
-
readonly except: C;
|
|
718
|
-
readonly only?: never;
|
|
719
|
-
} | {
|
|
720
|
-
readonly only?: never;
|
|
721
|
-
readonly except?: never;
|
|
722
|
-
};
|
|
723
|
-
type SectionAudience = Audience<readonly [SectionConsumer, ...SectionConsumer[]]>;
|
|
724
|
-
type SectionContent = {
|
|
725
|
-
readonly title: string;
|
|
726
|
-
readonly body: string;
|
|
727
|
-
};
|
|
728
|
-
/** A plain-text documentation section accepted from command and Extension authors. */
|
|
729
|
-
type CommandSectionInput = SectionContent & SectionAudience;
|
|
730
|
-
/** Typed dynamic audiences may be empty until their consuming operation checks them. */
|
|
731
|
-
type RuntimeCommandSectionInput = SectionContent & Audience<readonly SectionConsumer[]>;
|
|
732
|
-
/** A validated documentation section rendered after built-in command documentation. */
|
|
733
|
-
type CommandSection = SectionContent & Audience<readonly [ExtensionId, ...ExtensionId[]]>;
|
|
734
|
-
/** Metadata describing a CLI command */
|
|
735
|
-
interface CommandMeta {
|
|
736
|
-
/** The command name (used in help text and routing) */
|
|
737
|
-
name: string;
|
|
738
|
-
/** Human-readable description for help text */
|
|
739
|
-
description?: string;
|
|
740
|
-
/** Application version exposed to Extensions and tooling on the root command. */
|
|
741
|
-
version?: string;
|
|
742
|
-
/** Custom usage string (overrides auto-generated usage) */
|
|
743
|
-
usage?: string;
|
|
744
|
-
/** Plain-text sections rendered after built-in command documentation. */
|
|
745
|
-
sections?: readonly CommandSection[];
|
|
746
|
-
/**
|
|
747
|
-
* Alternative names that resolve to the same command.
|
|
748
|
-
*
|
|
749
|
-
* Each entry is a sibling-level alternative for `name`. For example,
|
|
750
|
-
* `defineCommand("issue", { aliases: ["issues", "i"] }, recipe)` makes
|
|
751
|
-
* `cli issue`, `cli issues`, and `cli i` all route to the same command node.
|
|
752
|
-
*
|
|
753
|
-
* **Conflict policy.** Alias strings must not collide with this command's
|
|
754
|
-
* own canonical `name`, with any sibling's `name`, or with any sibling's
|
|
755
|
-
* own alias. TypeScript reports statically known collisions. Each alias
|
|
756
|
-
* must also be a non-empty string with no
|
|
757
|
-
* whitespace and must not start with `-`.
|
|
758
|
-
*
|
|
759
|
-
* **Display contract.** Help output renders the canonical name with
|
|
760
|
-
* aliases inline as `name (a, b, c)`. The canonical `name` is what
|
|
761
|
-
* appears in `commandPath`, error messages, and suggestions from
|
|
762
|
-
* `didYouMean` — it does not depend on which alias the user typed.
|
|
763
|
-
*
|
|
764
|
-
* @example
|
|
765
|
-
* defineCommand("issue", { aliases: ["issues", "i"] }, recipe)
|
|
766
|
-
*/
|
|
767
|
-
aliases?: readonly string[];
|
|
768
|
-
/**
|
|
769
|
-
* When `true`, omit this command from every tooling surface that
|
|
770
|
-
* enumerates the command tree for users:
|
|
771
|
-
*
|
|
772
|
-
* - `help` rendered output (subcommand list + USAGE token)
|
|
773
|
-
* - `@crustjs/man` generated man pages (`SUBCOMMANDS` section)
|
|
774
|
-
* - `completion` candidate lists (recursively — hidden
|
|
775
|
-
* subcommands and their descendants never appear in generated
|
|
776
|
-
* bash/zsh/fish scripts)
|
|
777
|
-
* - `didYouMean` typo suggestions and "Available commands"
|
|
778
|
-
* list (so internal names never surface in error UX)
|
|
779
|
-
* - `skill` manifests
|
|
780
|
-
*
|
|
781
|
-
* The command is **only hidden from listings**: routing in
|
|
782
|
-
* `@crustjs/core` does not consult `meta.hidden`, so it stays fully
|
|
783
|
-
* invocable by direct name (or alias). The intended use case is
|
|
784
|
-
* internal/runtime commands like a `__complete` shell-completion
|
|
785
|
-
* entrypoint. Marking a user-facing command `hidden` is supported but
|
|
786
|
-
* unusual.
|
|
787
|
-
*
|
|
788
|
-
* **Scope: commands only.** There is no analogous `hidden` field on
|
|
789
|
-
* `FlagDef` or `ArgDef`; flags and positional arguments always surface
|
|
790
|
-
* in help, completion, and man output. If you need a flag that does
|
|
791
|
-
* not advertise itself, the workaround is to register it as an Extension
|
|
792
|
-
* flags entry without a description (omit `description`),
|
|
793
|
-
* which suppresses its description body but still lists the spelling
|
|
794
|
-
* — there is intentionally no full hide mechanism at the flag layer.
|
|
795
|
-
*
|
|
796
|
-
* Tooling contract: any renderer or generator that walks
|
|
797
|
-
* `subCommands` to produce a user-facing listing should skip nodes
|
|
798
|
-
* where `meta.hidden === true`.
|
|
799
|
-
*
|
|
800
|
-
* @example
|
|
801
|
-
* meta: { name: "__complete", hidden: true, description: "Internal" }
|
|
802
|
-
*/
|
|
803
|
-
hidden?: boolean;
|
|
804
|
-
}
|
|
805
|
-
/** Raw token shapes a Standard Schema receives before it runs. */
|
|
806
|
-
type RawSchemaFlagInput = string | boolean | readonly (string | boolean)[] | undefined;
|
|
807
|
-
/** One flag value after syntax parsing and before required/schema validation. */
|
|
808
|
-
type RawFlagValue<D extends FlagDef> = D extends {
|
|
809
|
-
schema: StandardSchema;
|
|
810
|
-
} ? RawSchemaFlagInput : InferFlagValue<D> | undefined;
|
|
811
|
-
/** Positional counterpart of {@link RawFlagValue}. */
|
|
812
|
-
type RawArgValue<D extends ArgDef> = D extends {
|
|
813
|
-
schema: StandardSchema;
|
|
814
|
-
} ? D extends {
|
|
815
|
-
variadic: true;
|
|
816
|
-
} ? string[] : string | undefined : D extends {
|
|
817
|
-
variadic: true;
|
|
818
|
-
} ? ResolveBaseType<D>[] | undefined : InferArgValue<D> | undefined;
|
|
819
|
-
/** Runtime-erased syntax-parsed flag value. */
|
|
820
|
-
type ParsedFlagValue = RawFlagValue<FlagDef>;
|
|
821
|
-
/** Runtime-erased syntax-parsed positional value. */
|
|
822
|
-
type ParsedArgValue = RawArgValue<ArgDef>;
|
|
823
|
-
type RawParsedFlags<F extends FlagsDef> = { [K in keyof F]: RawFlagValue<F[K]>; };
|
|
824
|
-
type RawParsedArgs<A extends ArgsDef> = number extends A["length"] ? Record<string, ParsedArgValue> : { [D in A[number] as D["name"]]: RawArgValue<D>; };
|
|
825
|
-
/** A declared default on any argument or flag definition. */
|
|
826
|
-
type DeclaredDefault = (ArgDef | FlagDef)["default"];
|
|
827
|
-
/** Syntax-parsed input, before required and Standard Schema validation. */
|
|
828
|
-
interface ParseResult<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef> {
|
|
829
|
-
args: RawParsedArgs<A>;
|
|
830
|
-
flags: RawParsedFlags<F>;
|
|
831
|
-
/** Positionals before `--` that were not consumed by a declared argument. */
|
|
832
|
-
excessArgs: string[];
|
|
833
|
-
/** Arguments after the `--` separator. */
|
|
834
|
-
rawArgs: string[];
|
|
835
|
-
}
|
|
836
|
-
/** Fully validated input returned by the schema boundary. */
|
|
837
|
-
interface ValidatedInput<A extends ArgsDef = ArgsDef, F extends FlagsDef = FlagsDef> {
|
|
838
|
-
args: InferArgs<A>;
|
|
839
|
-
flags: InferFlags<F>;
|
|
840
|
-
}
|
|
841
|
-
//#endregion
|
|
842
|
-
//#region ../utils/src/artifacts.d.ts
|
|
843
|
-
/**
|
|
844
|
-
* Set by `crust build` while it prepares the Command Snapshot: the absolute
|
|
845
|
-
* entry-isolated directory Extension build hooks write into. Core reads it
|
|
846
|
-
* to run the hooks; `resolveArtifactDir` reads it so sections evaluated during
|
|
847
|
-
* that run see the artifacts being built instead of the wiped `.crust/root`.
|
|
848
|
-
*/
|
|
849
|
-
declare const BUILD_OUT_DIR_ENV = "CRUST_INTERNAL_BUILD_OUT_DIR";
|
|
850
|
-
/**
|
|
851
|
-
* Absolute path of a build artifact or `crust.include` directory shipped with
|
|
852
|
-
* this CLI. `name` is a top-level directory name such as `"skills"`.
|
|
853
|
-
*
|
|
854
|
-
* The artifact path is computed from how the CLI is running — never probed:
|
|
855
|
-
* - Compiled executable (Bun or Deno): `<dir of the executable>/<name>`, which
|
|
856
|
-
* is a platform package's `bin/` or wherever the binary was placed.
|
|
857
|
-
* - Crust-built Node bundle: `<name>` next to the bundle's `bin/` directory,
|
|
858
|
-
* i.e. `.crust/root/<name>` in place and `<installed root>/<name>` after install.
|
|
859
|
-
* - Snapshot preparation inside `crust build`: `<build output dir>/<name>`, the
|
|
860
|
-
* artifacts earlier Extension build hooks wrote in this same build.
|
|
861
|
-
* - Source (`bun run`, `node`, `deno run`): `.crust/root/<name>` under the
|
|
862
|
-
* nearest package root of the real `process.argv[1]` entrypoint (following source
|
|
863
|
-
* links) — the output of the last `crust build`.
|
|
864
|
-
*
|
|
865
|
-
* @throws {Error} when `name` is not a single path segment, or in source mode
|
|
866
|
-
* when the entrypoint cannot be resolved or has no enclosing `package.json`.
|
|
867
|
-
*/
|
|
868
|
-
declare function resolveArtifactDir(name: string): string;
|
|
869
|
-
//#endregion
|
|
870
|
-
export { FlagSnapshot as A, IsUnion as B, SectionAudience as C, RunInputPayload as D, ValueType as E, DefNameMembers as F, ExtensionId as G, MergeContext as H, EmptyLiteralNameBrand as I, JsonValue as J, defineExtensionId as K, HasClosedNames as L, ClosedMembers as M, CollisionBrand as N, ArgSnapshot as O, DefName as P, IsClosedName as R, RuntimeCommandSectionInput as S, ValidatedInput as T, MergeProviders as U, LocalValueBrand as V, UnionToIntersection as W, NamedFlagDef as _, CommandMeta as a, ParsedArgValue as b, DeclaredDefault as c, InferArgs as d, InferFlags as f, MergeFlags as g, InvocationIO as h, ArgsDef as i, Awaitable as j, CommandSnapshot as k, FlagDef as l, InputFlags as m, resolveArtifactDir as n, CommandSection as o, InputArgs as p, JsonCompatible as q, ArgDef as r, CommandSectionInput as s, BUILD_OUT_DIR_ENV as t, FlagsDef as u, NamedFlagsRecord as v, SectionConsumer as w, ParsedFlagValue as x, ParseResult as y, IsStaticTuple as z };
|