@crustjs/core 0.4.1 → 0.5.1
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.
|
@@ -223,7 +223,7 @@ type ValidateContextNames<Ctx extends ContextMap, Cs extends readonly AnyContext
|
|
|
223
223
|
type InstanceNames<P extends readonly unknown[]> = P extends readonly [infer H, ...infer T extends readonly unknown[]] ? DefName<H> | InstanceNames<T> : never;
|
|
224
224
|
/** Statically known names of an Extension's provided Contexts; widened Extensions opt out. */
|
|
225
225
|
type ExtensionProvidedNames<E> = DefiningOf<E> extends {
|
|
226
|
-
readonly
|
|
226
|
+
readonly provide?: infer P extends readonly unknown[];
|
|
227
227
|
} ? InstanceNames<P> : never;
|
|
228
228
|
type ExtensionContextBrand<E, Existing extends string> = CollisionBrand<ExtensionProvidedNames<E>, Existing, "FIX_DUPLICATE_CONTEXT", "Extension-provided Context ", " is already provided on this command path">;
|
|
229
229
|
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;
|
|
@@ -246,9 +246,10 @@ type MismatchedDependencyBrand<C, KnownValues> = MismatchedDependencyNames<Provi
|
|
|
246
246
|
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>; };
|
|
247
247
|
/** Dependency closure carried by command definitions and Extensions. */
|
|
248
248
|
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
249
|
-
type
|
|
249
|
+
type DeclaredDepsOfMember<T> = IsAny<T> extends true ? Record<string, ContextValue> : CommandDefinitionData<DefiningOf<T>> extends {
|
|
250
250
|
readonly _deps?: infer D extends ContextMap;
|
|
251
251
|
} ? IsAny<D> extends true ? Record<string, ContextValue> : D : {};
|
|
252
|
+
type DeclaredDepsOf<T> = (T extends unknown ? (deps: DeclaredDepsOfMember<T>) => void : never) extends ((deps: infer Deps extends ContextMap) => void) ? Deps : {};
|
|
252
253
|
/** Missing-dependency brand shared by `ValidateDeclaredDeps` and inline `.command()`. */
|
|
253
254
|
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] ? {} : {
|
|
254
255
|
readonly FIX_MISSING_DEPENDENCY: `Uses Context "${Missing}" which is not provided`;
|
|
@@ -341,7 +342,7 @@ type ExtensionFlagDefsOf<E> = [E] extends [never] ? readonly [] : DefiningOf<E>
|
|
|
341
342
|
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]>>;
|
|
342
343
|
/** All statically known flag spellings an Extension contributes: declared flags plus provided Context-owned flags. */
|
|
343
344
|
type ExtensionSpellings<E> = AttachedSpellings<ExtensionFlagDefsOf<E>> | ([E] extends [never] ? never : DefiningOf<E> extends {
|
|
344
|
-
readonly
|
|
345
|
+
readonly provide?: infer P extends readonly unknown[];
|
|
345
346
|
} ? ProvidedContextSpellings<P> : never);
|
|
346
347
|
type ExtensionFlagCollisionBrand<E, Existing extends string> = CollisionBrand<ExtensionSpellings<E>, Existing, "FIX_ALIAS_COLLISION", "Extension flag spelling ", " collides with an existing flag">;
|
|
347
348
|
/**
|
|
@@ -578,12 +579,13 @@ type RunOutcome<Result> = {
|
|
|
578
579
|
type CommandTree = Record<string, CommandShape>;
|
|
579
580
|
/** Every valid path through a command tree, including the root path (`[]`). */
|
|
580
581
|
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];
|
|
581
|
-
type
|
|
582
|
+
type CommandPathContinuations<Path extends readonly string[], Tree extends object, Prefix extends readonly string[] = readonly []> = Path extends readonly [infer Head extends string, ...infer Tail extends readonly string[]] ? readonly [...Prefix, Head] extends CommandPath<Tree> ? CommandPathContinuations<Tail, Tree, readonly [...Prefix, Head]> : Extract<CommandPath<Tree>, readonly [...Prefix, ...string[]]> : Extract<CommandPath<Tree>, readonly [...Prefix, ...string[]]>;
|
|
583
|
+
type KnownCommandPath<Path extends readonly string[], Tree extends object> = string extends keyof Tree ? Path : IsStaticTuple<Path> extends true ? string extends Path[number] ? never : [Path] extends [CommandPath<Tree>] ? Path : CommandPathContinuations<Path, Tree> : number extends Path["length"] ? CommandPath<Tree> : never;
|
|
582
584
|
/** Resolve the command shape at a typed path. */
|
|
583
585
|
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;
|
|
584
|
-
type RunSection<Name extends string, Values> = keyof Values extends never ? {
|
|
586
|
+
type RunSection<Name extends string, Values> = keyof Values extends never ? {} : {} extends Values ? { [K in Name]?: Values; } : { [K in Name]: Values; };
|
|
585
587
|
/** Structured values bound directly against the selected command's definitions; no argv is produced. */
|
|
586
|
-
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"]>> & {
|
|
588
|
+
type RunInput<Shape extends CommandShape> = RunSection<"args", ArgsDef extends Shape["args"] ? NonNullable<RunInputPayload["args"]> : InputArgs<Shape["args"]>> & RunSection<"flags", FlagsDef extends Shape["flags"] ? [keyof Shape["flags"]] extends [never] ? {} : NonNullable<RunInputPayload["flags"]> : InputFlags<Shape["flags"]>> & {
|
|
587
589
|
readonly raw?: readonly string[];
|
|
588
590
|
};
|
|
589
591
|
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;
|
|
@@ -591,6 +593,14 @@ type CompatibleRunBranch<Expected, Actual> = Actual extends Expected ? Actual :
|
|
|
591
593
|
type CompatibleRunInput<Shape extends CommandShape, Input> = CompatibleRunValue<RunInput<Shape>, Input>;
|
|
592
594
|
type RunInputArguments<Shape extends CommandShape> = {} extends RunInput<Shape> ? readonly [input?: RunInput<Shape>] : readonly [input: RunInput<Shape>];
|
|
593
595
|
type RunArguments<Shape extends CommandShape> = readonly [...RunInputArguments<Shape>, options?: InvocationOptions];
|
|
596
|
+
type KeysOf<T> = T extends unknown ? keyof T : never;
|
|
597
|
+
type UnknownRunKeys<Actual, Known> = { [K in keyof Actual as string extends K ? never : number extends K ? never : K extends Known ? never : K]: Actual[K] extends undefined ? Actual[K] : never; };
|
|
598
|
+
type ClosedRunInput<Shape extends CommandShape, Input> = Input extends unknown ? UnknownRunKeys<Input, keyof RunInput<Shape>> & { [K in keyof Input as K extends ("args" | "flags") & keyof RunInput<Shape> ? K : never]: UnknownRunKeys<NonNullable<Input[K]>, KeysOf<NonNullable<RunInput<Shape>[K & keyof RunInput<Shape>]>>>; } : never;
|
|
599
|
+
type CheckedRunInput<Shape extends CommandShape, Input> = [Input] extends [ClosedRunInput<Shape, Input>] ? NonNullable<RunInputArguments<Shape>[0]> : Input & NoInfer<ClosedRunInput<Shape, Input>>;
|
|
600
|
+
type OmittableRunInput<Shape extends CommandShape> = {} extends RunInput<Shape> ? undefined : never;
|
|
601
|
+
type RunWithoutInputThis<Shape extends CommandShape, This> = [Shape] extends [never] ? This : {} extends RunInput<Shape> ? This : This & {
|
|
602
|
+
readonly FIX_MISSING_INPUT: "Pass the command's required arguments or flags";
|
|
603
|
+
};
|
|
594
604
|
/**
|
|
595
605
|
* Typed invoker bound to one command in an app, returned by {@link Crust.at}.
|
|
596
606
|
*
|
|
@@ -600,7 +610,8 @@ type RunArguments<Shape extends CommandShape> = readonly [...RunInputArguments<S
|
|
|
600
610
|
interface CommandHandle<Shape extends CommandShape> {
|
|
601
611
|
/** The typed path this handle was created with (`[]` selects the root). */
|
|
602
612
|
readonly path: readonly string[];
|
|
603
|
-
run(
|
|
613
|
+
run(this: RunWithoutInputThis<Shape, unknown>): Promise<RunOutcome<Shape["result"]>>;
|
|
614
|
+
run<const Input extends RunInput<Shape> | OmittableRunInput<Shape> = RunInput<Shape>>(input: CheckedRunInput<Shape, Input> | OmittableRunInput<Shape>, options?: InvocationOptions): Promise<RunOutcome<Shape["result"]>>;
|
|
604
615
|
run<const Input>(input: Input, ...validation: [Input] extends [CompatibleRunInput<Shape, Input>] ? readonly [options?: InvocationOptions] : readonly [invalidInput: never]): Promise<RunOutcome<Shape["result"]>>;
|
|
605
616
|
}
|
|
606
617
|
/** Static configuration for a reusable command definition. */
|
|
@@ -668,7 +679,7 @@ type KnownDefinitionTree<Ds extends readonly unknown[], CF extends FlagsDef> = I
|
|
|
668
679
|
type ExtensionCheckAt<Checks, I> = I extends keyof Checks ? Checks[I] : never;
|
|
669
680
|
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>[];
|
|
670
681
|
type ExtensionProviders<E> = [E] extends [never] ? [] : DefiningOf<E> extends {
|
|
671
|
-
|
|
682
|
+
provide?: infer P extends readonly AnyContextInstance[];
|
|
672
683
|
} ? P : [];
|
|
673
684
|
type ExtensionOwnDefs<E> = [E] extends [never] ? [] : DefiningOf<E> extends {
|
|
674
685
|
_flagDefs?: infer F extends readonly NamedFlagDef[];
|
|
@@ -763,9 +774,8 @@ type AfterAction<Flags extends FlagsDef, A extends ArgsDef, Ctx extends ContextM
|
|
|
763
774
|
}, Awaited<R>, Meta, string, Caps>;
|
|
764
775
|
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>;
|
|
765
776
|
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>;
|
|
766
|
-
type
|
|
767
|
-
|
|
768
|
-
} ? H : Record<string, ContextValue>> extends (infer D extends ContextMap) ? D : {};
|
|
777
|
+
type ExtensionHookDemand<E> = E extends AnyExtension ? (deps: NonNullable<DefiningOf<E>["_hookDeps"]>) => void : never;
|
|
778
|
+
type ExtensionDemandValues<Es extends readonly AnyExtension[]> = ExtensionHookDemand<Es[number]> extends ((deps: infer D extends ContextMap) => void) ? D : {};
|
|
769
779
|
type DescendantShapeValuesBrand<S, Deps> = S extends CommandShape ? DeclaredDependencyValuesBrand<Deps, NonNullable<S[typeof commandProviders]>> & DescendantValuesBrand<S["children"], Deps> : {};
|
|
770
780
|
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>;
|
|
771
781
|
type DefinitionDescendantValuesBrand<Ds extends readonly CommandDefinition<any, any, any, any>[], Deps> = DescendantValuesBrand<DefinitionsTree<Ds>, Deps>;
|
|
@@ -851,6 +861,8 @@ declare class Crust<Flags extends FlagsDef = {}, A extends ArgsDef = [], Ctx ext
|
|
|
851
861
|
* reverse construction order after post-run hooks. TypeScript rejects known Context-owned flag collisions, including pending
|
|
852
862
|
* Extension commands. Consuming operations throw `DEFINITION` for actual collisions.
|
|
853
863
|
*
|
|
864
|
+
* Context `sections` document only this command, never descendants. Preparation throws
|
|
865
|
+
* `DEFINITION` when one repeats a section title already on this command.
|
|
854
866
|
*/
|
|
855
867
|
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>;
|
|
856
868
|
/**
|
|
@@ -897,21 +909,17 @@ declare class Crust<Flags extends FlagsDef = {}, A extends ArgsDef = [], Ctx ext
|
|
|
897
909
|
*/
|
|
898
910
|
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>;
|
|
899
911
|
/**
|
|
900
|
-
* Define
|
|
901
|
-
*
|
|
912
|
+
* Define a subcommand inline (sugar for `.add(defineCommand(name, recipe))`),
|
|
913
|
+
* on the root or inside another command's recipe.
|
|
902
914
|
*
|
|
903
915
|
* The recipe builder is seeded with the Contexts and Context-owned flags
|
|
904
|
-
* accumulated on this builder so far — the call site.
|
|
905
|
-
*
|
|
906
|
-
*
|
|
907
|
-
*
|
|
908
|
-
*
|
|
916
|
+
* accumulated on this builder so far — the call site. In a recipe, those are
|
|
917
|
+
* its `.use()` and `.provide()` Contexts. Contexts provided after `.command()`
|
|
918
|
+
* are not visible to it, matching the positional runtime semantics of
|
|
919
|
+
* `.provide()`. Extract to `defineCommand` when a command needs its own file
|
|
920
|
+
* or reuse.
|
|
909
921
|
*/
|
|
910
|
-
command<const N extends string, B extends AnyCommandDefinitionBuilder>(
|
|
911
|
-
readonly _types: {
|
|
912
|
-
readonly caps: "app";
|
|
913
|
-
};
|
|
914
|
-
}, 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<{
|
|
922
|
+
command<const N extends string, B extends AnyCommandDefinitionBuilder>(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<{
|
|
915
923
|
child: ShapeOfBuilder<B>;
|
|
916
924
|
}, CollisionSp["demands"]>>): AfterAdd<Flags, A, Ctx, Sibs, Sp, Tree, CtxFlags, CollisionSp, Result, readonly [CommandDefinition<N, readonly [], ShapeOfBuilder<B>, DepsOfBuilder<B>>], Meta, Caps>;
|
|
917
925
|
private _addDefinitions;
|
|
@@ -938,16 +946,21 @@ declare class Crust<Flags extends FlagsDef = {}, A extends ArgsDef = [], Ctx ext
|
|
|
938
946
|
* exposed to Command Actions and Extensions) and an
|
|
939
947
|
* `AbortSignal` that cancels the invocation
|
|
940
948
|
*/
|
|
941
|
-
run<const Path extends
|
|
949
|
+
run<const Path extends readonly string[]>(this: RunWithoutInputThis<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>, {
|
|
942
950
|
readonly _types: {
|
|
943
951
|
readonly caps: "app";
|
|
944
952
|
};
|
|
945
|
-
}
|
|
946
|
-
run<const Path extends
|
|
953
|
+
}>, path: KnownCommandPath<Path, Tree>): Promise<RunOutcome<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>["result"]>>;
|
|
954
|
+
run<const Path extends readonly string[], const Input extends RunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>> | OmittableRunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>> = RunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>>>(this: {
|
|
947
955
|
readonly _types: {
|
|
948
956
|
readonly caps: "app";
|
|
949
957
|
};
|
|
950
|
-
}, path:
|
|
958
|
+
}, path: KnownCommandPath<Path, Tree>, input: CheckedRunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>, Input> | OmittableRunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>>, options?: InvocationOptions): Promise<RunOutcome<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>["result"]>>;
|
|
959
|
+
run<const Path extends readonly string[], const Input>(this: {
|
|
960
|
+
readonly _types: {
|
|
961
|
+
readonly caps: "app";
|
|
962
|
+
};
|
|
963
|
+
}, path: KnownCommandPath<Path, Tree>, input: Input, ...validation: [Input] extends [CompatibleRunInput<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, NoInfer<Path>>, Input>] ? readonly [options?: InvocationOptions] : readonly [invalidInput: never]): Promise<RunOutcome<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>["result"]>>;
|
|
951
964
|
/**
|
|
952
965
|
* Bind a typed command path into a reusable {@link CommandHandle}.
|
|
953
966
|
*
|
|
@@ -959,11 +972,11 @@ declare class Crust<Flags extends FlagsDef = {}, A extends ArgsDef = [], Ctx ext
|
|
|
959
972
|
* @param path - Typed path to the command to bind (`[]` selects the root)
|
|
960
973
|
* @throws {CrustError} COMMAND_NOT_FOUND when the path does not name a command
|
|
961
974
|
*/
|
|
962
|
-
at<const Path extends
|
|
975
|
+
at<const Path extends readonly string[]>(this: {
|
|
963
976
|
readonly _types: {
|
|
964
977
|
readonly caps: "app";
|
|
965
978
|
};
|
|
966
|
-
}, path:
|
|
979
|
+
}, path: KnownCommandPath<Path, Tree>): CommandHandle<CommandShapeAt<CommandShape<A, Flags, Tree, Result>, Path>>;
|
|
967
980
|
/**
|
|
968
981
|
* Parse `process.argv`, resolve subcommands, run Extension hooks, and
|
|
969
982
|
* execute the matched Command Action.
|
|
@@ -1021,11 +1034,25 @@ interface DefinitionErrorDetails {
|
|
|
1021
1034
|
readonly name?: string;
|
|
1022
1035
|
readonly reason?: string;
|
|
1023
1036
|
}
|
|
1037
|
+
/** One environment variable that failed; its value is never recorded. */
|
|
1038
|
+
interface EnvIssue {
|
|
1039
|
+
/** Variable name as declared. */
|
|
1040
|
+
readonly name: string;
|
|
1041
|
+
/** Declared expectation, e.g. `"number"` or `"one of: debug, info"`. */
|
|
1042
|
+
readonly expected: string;
|
|
1043
|
+
/** Whether the variable was unset or held a value that failed parsing or validation. */
|
|
1044
|
+
readonly received: "missing" | "invalid";
|
|
1045
|
+
}
|
|
1046
|
+
/** Every missing or invalid variable of one `@crustjs/env` definition. */
|
|
1047
|
+
interface EnvErrorDetails {
|
|
1048
|
+
readonly issues: readonly EnvIssue[];
|
|
1049
|
+
}
|
|
1024
1050
|
interface CrustErrorDetailsMap {
|
|
1025
1051
|
DEFINITION: DefinitionErrorDetails | undefined;
|
|
1026
1052
|
VALIDATION: ValidationErrorDetails | undefined;
|
|
1027
1053
|
PARSE: ParseErrorDetails | undefined;
|
|
1028
1054
|
COMMAND_NOT_FOUND: CommandNotFoundErrorDetails;
|
|
1055
|
+
ENV: EnvErrorDetails;
|
|
1029
1056
|
}
|
|
1030
1057
|
/**
|
|
1031
1058
|
* All possible error codes emitted by Crust.
|
|
@@ -1034,6 +1061,7 @@ interface CrustErrorDetailsMap {
|
|
|
1034
1061
|
* - `VALIDATION` — Missing required arguments or flags
|
|
1035
1062
|
* - `PARSE` — Argv parsing failures (unknown flags, type coercion)
|
|
1036
1063
|
* - `COMMAND_NOT_FOUND` — Unrecognised subcommand at the current level
|
|
1064
|
+
* - `ENV` — Missing or invalid `@crustjs/env` variables (values redacted)
|
|
1037
1065
|
*
|
|
1038
1066
|
* @example
|
|
1039
1067
|
* ```ts
|
|
@@ -1284,67 +1312,100 @@ type ExtensionSectionContribution = RuntimeCommandSectionInput & {
|
|
|
1284
1312
|
readonly command: readonly string[];
|
|
1285
1313
|
};
|
|
1286
1314
|
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>;
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
readonly uses?: Uses;
|
|
1291
|
-
readonly provides?: Provides;
|
|
1292
|
-
readonly sections?: (snapshot: RootCommandSnapshot<MetaKeys>) => readonly ExtensionSectionContribution[];
|
|
1293
|
-
readonly build?: (ctx: ExtensionBuildContext<MetaKeys>) => Awaitable<BuildArtifacts>;
|
|
1294
|
-
readonly hooks?: ExtensionHooks<Defs, ContextDependencies<Uses>, MetaKeys>;
|
|
1295
|
-
}
|
|
1296
|
-
type ValidateExtensionConfig<Defs extends readonly NamedExtensionFlagDef[], Provides extends readonly AnyContextInstance[], Commands extends readonly CommandDefinition<any, any, any, any>[], Uses extends readonly AnyContextFactory[]> = {
|
|
1297
|
-
readonly uses?: Uses;
|
|
1298
|
-
readonly commands?: ValidateCommandDefinitions<Commands>;
|
|
1299
|
-
readonly flags?: ValidateLocalFlagDefs<Defs, ProvidedContextSpellings<Provides>>;
|
|
1300
|
-
readonly provides?: KnownContextInstances<Provides> & ProvideChecks<never, Provides>;
|
|
1301
|
-
};
|
|
1315
|
+
type ExtensionDeps<Use extends readonly AnyContextFactory[], Provide extends readonly AnyContextInstance[], Commands extends readonly CommandDefinition<any, any, any, any>[]> = ContextDependencies<Use> & ContextsDependencies<Provide> & CommandDefinitionsDependencies<Commands>;
|
|
1316
|
+
/** Flag spellings an Extension already owns: declared flags plus provided Context-owned flags. */
|
|
1317
|
+
type DeclaredSpellings<Defs extends readonly NamedExtensionFlagDef[], Provide extends readonly AnyContextInstance[]> = AttachedSpellings<Defs> | ProvidedContextSpellings<Provide>;
|
|
1302
1318
|
declare const extensionHookProof: unique symbol;
|
|
1303
|
-
|
|
1319
|
+
/**
|
|
1320
|
+
* @internal Sealed runtime record behind an {@link Extension} handle. Runtime
|
|
1321
|
+
* consumers read it through `definingOf`, so structural copies of a handle keep
|
|
1322
|
+
* the declaration proofs `.extend()` checks.
|
|
1323
|
+
*/
|
|
1324
|
+
interface ExtensionData<Deps extends ContextMap = ContextMap, Provide 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> {
|
|
1304
1325
|
/** @internal Hook demands are distinct from command/provider attachment dependencies. */
|
|
1305
1326
|
readonly _hookDeps?: HookDeps;
|
|
1306
1327
|
readonly [extensionHookProof]?: (deps: HookDeps) => void;
|
|
1307
1328
|
readonly id: ExtensionId;
|
|
1308
|
-
readonly flags
|
|
1329
|
+
readonly flags: Readonly<Record<string, ExtensionFlagDef>>;
|
|
1309
1330
|
/** @internal — phantom carrying declared flag literals for extend-time collision checks */
|
|
1310
1331
|
readonly _flagDefs?: FlagDefs;
|
|
1311
|
-
readonly commands
|
|
1312
|
-
readonly
|
|
1313
|
-
readonly
|
|
1332
|
+
readonly commands: Commands;
|
|
1333
|
+
readonly use: readonly AnyContextFactory[];
|
|
1334
|
+
readonly provide: Provide;
|
|
1314
1335
|
readonly sections?: (snapshot: RootCommandSnapshot<MetaKeys>) => readonly ExtensionSectionContribution[];
|
|
1315
1336
|
readonly build?: (ctx: ExtensionBuildContext<MetaKeys>) => Awaitable<BuildArtifacts>;
|
|
1316
|
-
readonly hooks
|
|
1337
|
+
readonly hooks: ExtensionHooks<any, Deps, MetaKeys>;
|
|
1317
1338
|
readonly _deps?: Deps;
|
|
1318
1339
|
}
|
|
1340
|
+
/**
|
|
1341
|
+
* An Extension handle accepted by `.extend()`. Contribution parameters default to
|
|
1342
|
+
* open sets; holders keep the private dependency and hook-demand proofs.
|
|
1343
|
+
*/
|
|
1344
|
+
interface Extension<Deps extends ContextMap = ContextMap, Provide 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<ExtensionData<Deps, Provide, FlagDefs, Commands, MetaKeys, HookDeps>> {
|
|
1345
|
+
readonly id: ExtensionId;
|
|
1346
|
+
}
|
|
1319
1347
|
/** @internal Broad Extension constraint; contravariance requires the full metadata key set. */
|
|
1320
1348
|
type AnyExtension = Extension<any, any, any, any, RootMetaKey>;
|
|
1321
|
-
type ExtensionProvidesOutput<E> = DefiningOf<E> extends
|
|
1322
|
-
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
|
|
1349
|
+
type ExtensionProvidesOutput<E> = DefiningOf<E> extends ExtensionData<any, infer Provide, any, any, RootMetaKey> ? ContextsOutput<Provide> : {};
|
|
1350
|
+
type ExtensionsProvidesOutput<Es extends readonly AnyExtension[]> = Es extends readonly [infer H, ...infer T extends readonly AnyExtension[]] ? MergeProviders<ExtensionProvidesOutput<H>, ExtensionsProvidesOutput<T>> : Es extends readonly [] ? {} : DefiningOf<Es[number]> extends ExtensionData<any, infer P, any, any, RootMetaKey> ? P[number] extends never ? {} : Record<string, ContextValue> : {};
|
|
1323
1351
|
/**
|
|
1324
1352
|
* A callable Extension constructor whose identity is also a section consumer.
|
|
1325
1353
|
* Contribution parameters default to closed sets. Use `ContextMap`,
|
|
1326
1354
|
* `readonly AnyContextInstance[]`, `readonly NamedExtensionFlagDef[]`, or
|
|
1327
1355
|
* `readonly CommandDefinition<any, any, any, any>[]` to keep a namespace open.
|
|
1328
1356
|
*/
|
|
1329
|
-
type ExtensionFactory<Args extends readonly unknown[] = [], Deps extends ContextMap = {},
|
|
1357
|
+
type ExtensionFactory<Args extends readonly unknown[] = [], Deps extends ContextMap = {}, Provide 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, Provide, Defs, Commands, MetaKeys, HookDeps>) & {
|
|
1330
1358
|
readonly id: ExtensionId;
|
|
1331
1359
|
};
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1360
|
+
type ExtensionFactoryOf<Args extends readonly unknown[], E> = E extends Defining<ExtensionData<infer Deps, infer Provide, infer Defs, infer Commands, infer MetaKeys, infer HookDeps>> ? ExtensionFactory<Args, Deps, Provide, Defs, Commands, MetaKeys, HookDeps> : never;
|
|
1361
|
+
type ExtensionHook<Name extends keyof ExtensionHooks, Use extends readonly AnyContextFactory[], Defs extends readonly NamedExtensionFlagDef[], MetaKeys extends RootMetaKey> = NonNullable<ExtensionHooks<Defs, ContextDependencies<Use>, MetaKeys>[Name]>;
|
|
1362
|
+
/**
|
|
1363
|
+
* Immutable fluent Extension authoring handle returned by {@link defineExtension}.
|
|
1364
|
+
* Every method returns a new handle. Collection methods (`use`, `provide`,
|
|
1365
|
+
* `flags`, `add`) append; lifecycle setters (`preRun`, `postRun`, `onError`,
|
|
1366
|
+
* `sections`, `build`) replace the previous callback. Callbacks are typed by the
|
|
1367
|
+
* declarations made before them.
|
|
1368
|
+
*/
|
|
1369
|
+
interface ExtensionBuilder<Use extends readonly AnyContextFactory[] = [], Provide extends readonly AnyContextInstance[] = [], Defs extends readonly NamedExtensionFlagDef[] = [], Commands extends readonly CommandDefinition<any, any, any, any>[] = [], MetaKeys extends RootMetaKey = never> extends Extension<ExtensionDeps<Use, Provide, Commands>, Provide, Defs, Commands, MetaKeys, ContextDependencies<Use>> {
|
|
1370
|
+
/**
|
|
1371
|
+
* Declare Contexts the hooks read from `ctx`. This consumes only: the
|
|
1372
|
+
* application (or `.provide()`) must supply each Context.
|
|
1373
|
+
*/
|
|
1374
|
+
use<const Fs extends readonly [AnyContextFactory, ...AnyContextFactory[]]>(...factories: Fs): ExtensionBuilder<readonly [...Use, ...Fs], Provide, Defs, Commands, MetaKeys>;
|
|
1375
|
+
/**
|
|
1376
|
+
* Provide Contexts application-wide, regardless of chain position. Provided
|
|
1377
|
+
* Contexts are not exposed to this Extension's hooks unless also declared with `.use()`.
|
|
1378
|
+
*/
|
|
1379
|
+
provide<const Cs extends readonly AnyContextInstance[]>(...instances: KnownContextInstances<Cs> & ProvideChecks<DeclaredSpellings<Defs, Provide>, Cs>): ExtensionBuilder<Use, readonly [...Provide, ...Cs], Defs, Commands, MetaKeys>;
|
|
1380
|
+
/** Own flags; `recursive` (default `true`) contributes a flag to every command. */
|
|
1381
|
+
flags<const Fs extends readonly NamedExtensionFlagDef[]>(...defs: ValidateLocalFlagDefs<Fs, DeclaredSpellings<Defs, Provide>>): ExtensionBuilder<Use, Provide, readonly [...Defs, ...Fs], Commands, MetaKeys>;
|
|
1382
|
+
/** Contribute root commands; they replace same-named application commands. */
|
|
1383
|
+
add<const Ds extends readonly CommandDefinition<any, any, any, any>[]>(...definitions: Ds & ValidateCommandDefinitions<Ds, AttachedCommandSpellings<Commands>>): ExtensionBuilder<Use, Provide, Defs, readonly [...Commands, ...Ds], MetaKeys>;
|
|
1384
|
+
/** See {@link ExtensionHooks.preRun}. */
|
|
1385
|
+
preRun(hook: ExtensionHook<"preRun", Use, Defs, MetaKeys>): ExtensionBuilder<Use, Provide, Defs, Commands, MetaKeys>;
|
|
1386
|
+
/** See {@link ExtensionHooks.postRun}. */
|
|
1387
|
+
postRun(hook: ExtensionHook<"postRun", Use, Defs, MetaKeys>): ExtensionBuilder<Use, Provide, Defs, Commands, MetaKeys>;
|
|
1388
|
+
/** See {@link ExtensionHooks.onError}. */
|
|
1389
|
+
onError(hook: ExtensionHook<"onError", Use, Defs, MetaKeys>): ExtensionBuilder<Use, Provide, Defs, Commands, MetaKeys>;
|
|
1390
|
+
/** Contribute documentation sections computed from the prepared root snapshot. */
|
|
1391
|
+
sections(contribute: (snapshot: RootCommandSnapshot<MetaKeys>) => readonly ExtensionSectionContribution[]): ExtensionBuilder<Use, Provide, Defs, Commands, MetaKeys>;
|
|
1392
|
+
/** Generate build artifacts; build tooling writes the returned files. */
|
|
1393
|
+
build(generate: (ctx: ExtensionBuildContext<MetaKeys>) => Awaitable<BuildArtifacts>): ExtensionBuilder<Use, Provide, Defs, Commands, MetaKeys>;
|
|
1394
|
+
/**
|
|
1395
|
+
* Make a configurable Extension: each call passes this handle and the call
|
|
1396
|
+
* arguments to `define`, which must return an Extension with this handle's id.
|
|
1397
|
+
*/
|
|
1398
|
+
factory<Args extends readonly unknown[], E extends AnyExtension>(define: (extension: ExtensionBuilder<Use, Provide, Defs, Commands, MetaKeys>, ...args: Args) => E): ExtensionFactoryOf<Args, E>;
|
|
1336
1399
|
}
|
|
1337
1400
|
/**
|
|
1338
|
-
*
|
|
1401
|
+
* Start an immutable fluent Extension definition.
|
|
1339
1402
|
*
|
|
1340
1403
|
* Extensions apply to the whole application and own the flags and commands
|
|
1341
|
-
* they contribute.
|
|
1342
|
-
*
|
|
1343
|
-
*
|
|
1404
|
+
* they contribute. `defineExtension<"version">(id)` requires root metadata keys
|
|
1405
|
+
* without preventing inference of flags, Contexts, or commands; chain
|
|
1406
|
+
* `.factory()` for a configurable Extension whose identity is a section consumer.
|
|
1344
1407
|
*/
|
|
1345
|
-
declare function defineExtension<MetaKeys extends RootMetaKey = never>():
|
|
1346
|
-
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>>;
|
|
1347
|
-
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>>;
|
|
1408
|
+
declare function defineExtension<MetaKeys extends RootMetaKey = never>(id: ExtensionId): ExtensionBuilder<[], [], [], [], MetaKeys>;
|
|
1348
1409
|
//#endregion
|
|
1349
1410
|
//#region src/parsing/spellings.d.ts
|
|
1350
1411
|
/**
|
|
@@ -1392,10 +1453,12 @@ interface CommandNode {
|
|
|
1392
1453
|
subCommands: Record<string, CommandNode>;
|
|
1393
1454
|
/** Contexts available to this command in provide order (construction order is pull-driven). */
|
|
1394
1455
|
contexts: CommandContext[];
|
|
1456
|
+
/** Contexts `.provide()`d on this command itself; preparation installs their sections here. */
|
|
1457
|
+
providedContexts: readonly AnyContextInstance[];
|
|
1395
1458
|
/** Declared command demands; validated when recipes are materialized. */
|
|
1396
1459
|
demands: readonly AnyContextFactory[];
|
|
1397
1460
|
/** Extensions registered via `.extend()` (root builder only) */
|
|
1398
|
-
extensions:
|
|
1461
|
+
extensions: ExtensionData[];
|
|
1399
1462
|
/** The Command Action */
|
|
1400
1463
|
run?: CommandAction;
|
|
1401
1464
|
}
|
|
@@ -1407,6 +1470,22 @@ interface RunInputPayload {
|
|
|
1407
1470
|
readonly flags?: Readonly<Record<string, RunInputValue | undefined>>;
|
|
1408
1471
|
readonly raw?: readonly string[];
|
|
1409
1472
|
}
|
|
1473
|
+
/** Environment variables consulted by `FlagDef.env`; `process.env` on the terminal path. */
|
|
1474
|
+
type FlagEnvironment = Readonly<Record<string, string | undefined>>;
|
|
1475
|
+
/**
|
|
1476
|
+
* Resolve flags from their `env` bindings alone, as {@link parseArgs} does for an
|
|
1477
|
+
* empty argv: `env.delimiter` splitting, `choices`, `parse`, built-in coercion,
|
|
1478
|
+
* defaults, requiredness, then Standard Schemas. Flags without `env` resolve
|
|
1479
|
+
* to their defaults.
|
|
1480
|
+
*
|
|
1481
|
+
* @param flags - Flag definitions keyed by result name; each `env.name` selects its variable
|
|
1482
|
+
* @param env - Raw variable text; only own properties are read
|
|
1483
|
+
* @throws {CrustError} `DEFINITION` for a definition `defineFlag` rejects (e.g. a
|
|
1484
|
+
* `__proto__` key or a default outside `choices`); `PARSE` or `VALIDATION` on the first
|
|
1485
|
+
* coercion or requiredness failure, or `VALIDATION` aggregating schema issues. Messages
|
|
1486
|
+
* may quote raw values.
|
|
1487
|
+
*/
|
|
1488
|
+
declare function parseFlagValues<F extends FlagsDef>(flags: F, env: FlagEnvironment): Promise<InferFlags<F>>;
|
|
1410
1489
|
//#endregion
|
|
1411
1490
|
//#region src/types.d.ts
|
|
1412
1491
|
/** Injectable output callbacks threaded through one invocation. */
|
|
@@ -2048,29 +2127,17 @@ declare const contextSources: unique symbol;
|
|
|
2048
2127
|
type ContextBag<Deps extends ContextMap = {}> = { readonly [K in keyof Deps]: Promise<Deps[K]>; } & {
|
|
2049
2128
|
readonly [contextSources]?: readonly (AnyContextFactory | AnyContextInstance)[];
|
|
2050
2129
|
};
|
|
2051
|
-
interface ContextConfig {
|
|
2052
|
-
readonly flags?: readonly NamedFlagDef[];
|
|
2053
|
-
readonly uses?: readonly AnyContextFactory[];
|
|
2054
|
-
}
|
|
2055
|
-
type ValidateContextConfig<R extends ContextConfig> = {
|
|
2056
|
-
readonly flags?: R["flags"] extends readonly NamedFlagDef[] ? ValidateLocalFlagDefs<R["flags"], never> : "flags" extends keyof R ? {} : never;
|
|
2057
|
-
readonly uses?: R["uses"] extends readonly AnyContextFactory[] ? R["uses"] : "uses" extends keyof R ? {} : never;
|
|
2058
|
-
};
|
|
2059
|
-
interface ContextSetupInput<OF extends FlagsDef = FlagsDef> extends InvocationIO {
|
|
2060
|
-
readonly signal: AbortSignal;
|
|
2061
|
-
readonly flags: InferFlags<OF>;
|
|
2062
|
-
readonly ctx: ContextBag<ContextMap>;
|
|
2063
|
-
readonly defer: (cleanup: () => void | PromiseLike<void>) => void;
|
|
2064
|
-
}
|
|
2065
2130
|
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>> {
|
|
2066
2131
|
readonly [contextProof]?: string extends keyof OF | keyof Deps ? unknown : (state: [OF, Deps]) => void;
|
|
2067
2132
|
readonly name: Name;
|
|
2068
2133
|
readonly ownedFlags: FlagsDef;
|
|
2134
|
+
/** Validated {@link ContextBuilder.sections}, frozen at declaration. */
|
|
2135
|
+
readonly sections: readonly CommandSection[];
|
|
2069
2136
|
/** @internal — declared direct dependency factories */
|
|
2070
|
-
readonly
|
|
2137
|
+
readonly use: readonly AnyContextFactory[];
|
|
2071
2138
|
/** @internal defining factory, for adapters that identify Contexts by factory */
|
|
2072
2139
|
readonly factory: AnyContextFactory;
|
|
2073
|
-
setup(input:
|
|
2140
|
+
setup(input: ContextSetup<OF, ContextMap>): Awaitable<Value>;
|
|
2074
2141
|
readonly _ownedFlags?: OF;
|
|
2075
2142
|
/** @internal — phantom carrying the transitive dependency closure */
|
|
2076
2143
|
readonly _deps?: Deps;
|
|
@@ -2079,8 +2146,8 @@ interface ContextInstance<Name extends string = string, Value = unknown, OF exte
|
|
|
2079
2146
|
type AnyContextInstance = ContextInstance<string, unknown, any, any>;
|
|
2080
2147
|
/** Whatever a Context setup produces, erased at the runtime registry. */
|
|
2081
2148
|
type ContextValue = Awaited<ReturnType<AnyContextInstance["setup"]>>;
|
|
2082
|
-
|
|
2083
|
-
|
|
2149
|
+
/** Invocation input passed to a Context's `.setup()` callback; factory options arrive as its second parameter. */
|
|
2150
|
+
interface ContextSetup<OF extends FlagsDef = {}, Deps extends ContextMap = {}> extends InvocationIO {
|
|
2084
2151
|
/** The invocation's cancellation signal; pass it to cancellable setup work. */
|
|
2085
2152
|
readonly signal: AbortSignal;
|
|
2086
2153
|
readonly flags: InferFlags<OF>;
|
|
@@ -2092,10 +2159,11 @@ interface ContextSetup<Options, OF extends FlagsDef = {}, Deps extends ContextMa
|
|
|
2092
2159
|
readonly defer: (cleanup: () => void | PromiseLike<void>) => void;
|
|
2093
2160
|
}
|
|
2094
2161
|
interface ContextFactory<Name extends string, Options, Value, OF extends FlagsDef = {}, Deps extends ContextMap = {}> extends Defining<ContextFactory<Name, Options, Value, OF, Deps>> {
|
|
2095
|
-
|
|
2162
|
+
/** Options may be omitted when their type accepts `undefined` (including no-option `void`). */
|
|
2163
|
+
(...options: undefined extends Options ? [options?: Options] : [options: Options]): ContextInstance<Name, Value, OF, Deps>;
|
|
2096
2164
|
readonly contextName: Name;
|
|
2097
2165
|
/** @internal — declared direct dependency factories */
|
|
2098
|
-
readonly
|
|
2166
|
+
readonly use: readonly AnyContextFactory[];
|
|
2099
2167
|
of(value: Value): ContextInstance<Name, Value, OF, {}>;
|
|
2100
2168
|
readonly _deps?: Deps;
|
|
2101
2169
|
}
|
|
@@ -2108,20 +2176,40 @@ type FactoryOutput<F> = F extends AnyContextFactory ? DefiningOf<F> extends Cont
|
|
|
2108
2176
|
type FactoriesOutput<Fs extends readonly AnyContextFactory[]> = Fs extends readonly [infer H, ...infer T extends readonly AnyContextFactory[]] ? FactoryOutput<H> & FactoriesOutput<T> : {};
|
|
2109
2177
|
type FactoryDeps<F> = F extends AnyContextFactory ? DefiningOf<F> extends ContextFactory<any, any, any, any, infer Deps> ? Deps : {} : {};
|
|
2110
2178
|
type FactoriesDeps<Fs extends readonly AnyContextFactory[]> = Fs extends readonly [infer H, ...infer T extends readonly AnyContextFactory[]] ? FactoryDeps<H> & FactoriesDeps<T> : {};
|
|
2111
|
-
type ContextDependencies<
|
|
2179
|
+
type ContextDependencies<Use extends readonly AnyContextFactory[]> = IsStaticTuple<Use> extends true ? FactoriesOutput<Use> & FactoriesDeps<Use> : Record<string, ContextValue>;
|
|
2112
2180
|
type ContextDepsOf<C> = C extends AnyContextInstance ? DefiningOf<C> extends {
|
|
2113
2181
|
readonly _deps?: infer Deps extends ContextMap;
|
|
2114
2182
|
} ? Deps : {} : {};
|
|
2115
2183
|
type ContextsDependencies<Cs extends readonly AnyContextInstance[]> = Cs extends readonly [infer H, ...infer T extends readonly AnyContextInstance[]] ? ContextDepsOf<H> & ContextsDependencies<T> : {};
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2184
|
+
/** Factory options inferred from a setup callback's optional second parameter. */
|
|
2185
|
+
type ContextOptionsOf<Args extends readonly unknown[]> = Args extends readonly [] ? void : Args[0];
|
|
2186
|
+
/**
|
|
2187
|
+
* Immutable fluent Context authoring handle returned by {@link defineContext}.
|
|
2188
|
+
* `use`, `flags`, and `sections` append and return a new handle; `setup` ends the chain and
|
|
2189
|
+
* returns the callable {@link ContextFactory}. Callbacks are typed by the
|
|
2190
|
+
* declarations made before them.
|
|
2191
|
+
*/
|
|
2192
|
+
interface ContextBuilder<Name extends string, Use extends readonly AnyContextFactory[] = [], Defs extends readonly NamedFlagDef[] = []> {
|
|
2193
|
+
/** Declare Contexts setup reads from `ctx`; consumers must provide their transitive closure. */
|
|
2194
|
+
use<const Fs extends readonly AnyContextFactory[]>(...factories: Fs): ContextBuilder<Name, readonly [...Use, ...Fs], Defs>;
|
|
2195
|
+
/** Own flags parsed wherever this Context is provided; setup reads them from `flags`. */
|
|
2196
|
+
flags<const Fs extends readonly NamedFlagDef[]>(...defs: ValidateLocalFlagDefs<Fs, AttachedSpellings<Defs>>): ContextBuilder<Name, Use, readonly [...Defs, ...Fs]>;
|
|
2197
|
+
/** Document only the providing command (the root for Extension-provided Contexts). */
|
|
2198
|
+
sections<const S extends readonly RuntimeCommandSectionInput[]>(...sections: S & LocalSectionsBrand<{
|
|
2199
|
+
sections: S;
|
|
2200
|
+
}>["sections"]): ContextBuilder<Name, Use, Defs>;
|
|
2201
|
+
/**
|
|
2202
|
+
* Finish the definition. `setup` runs lazily, once per invocation, when a
|
|
2203
|
+
* consumer first reads the Context. Annotate its optional second parameter to
|
|
2204
|
+
* accept factory options: `.setup((input, options: { url: string }) => …)`.
|
|
2205
|
+
*/
|
|
2206
|
+
setup<Value, Args extends readonly [options?: unknown] = []>(setup: (input: ContextSetup<AttachedFlags<Defs>, ContextDependencies<Use>>, ...args: Args) => Awaitable<Value>): ContextFactory<Name, ContextOptionsOf<Args>, Value, AttachedFlags<Defs>, ContextDependencies<Use>>;
|
|
2207
|
+
}
|
|
2208
|
+
/**
|
|
2209
|
+
* Start an immutable fluent Context definition: a named, lazy command
|
|
2210
|
+
* dependency. Chain `.use()`, `.flags()`, and `.sections()`, then `.setup()` for the factory.
|
|
2211
|
+
*/
|
|
2212
|
+
declare function defineContext<Name extends string>(name: Name): ContextBuilder<Name>;
|
|
2125
2213
|
type FactoryValueOf<F extends AnyContextFactory> = F extends ContextFactory<any, any, infer Value, any, any> ? Awaited<Value> : never;
|
|
2126
2214
|
//#endregion
|
|
2127
|
-
export {
|
|
2215
|
+
export { CrustError as $, SectionConsumer as A, LocalFlagNameBrand as At, ExtensionBuilder as B, InvocationOptions as C, RunInputArguments as Ct, ParsedArgValue as D, CommandSnapshot as Dt, ParseResult as E, ArgSnapshot as Et, BuildArtifacts as F, defineExtensionId as Ft, ExtensionSectionContribution as G, ExtensionFactory as H, BuildFile as I, InvocationOutcome as J, Finished as K, BuildReport as L, ValueType as M, LocalValueBrand as Mt, FlagEnvironment as N, MergeContext as Nt, ParsedFlagValue as O, FlagSnapshot as Ot, parseFlagValues as P, ExtensionId as Pt, CommandNotFoundErrorDetails as Q, Extension as R, InvocationIO as S, RunInput as St, NamedFlagDef as T, defineCommand as Tt, ExtensionFlagDef as U, ExtensionContext as V, ExtensionHooks as W, RootMetaKey as X, NamedExtensionFlagDef as Y, defineExtension as Z, ExecuteOptions as _, CommandTree as _t, ContextInstance as a, EnvErrorDetails as at, InputArgs as b, RootCommandMeta as bt, FactoryValueOf as c, ValidationErrorDetails as ct, ArgDef as d, CommandDefinition as dt, CrustErrorCode as et, ArgsDef as f, CommandDefinitionBuilder as ft, DeclaredDefault as g, CommandShapeAt as gt, CommandSectionInput as h, CommandShape as ht, ContextFactory as i, DefinitionErrorDetails as it, ValidatedInput as j, EmptyArgNameBrand as jt, SectionAudience as k, LocalFlagBrand as kt, contextSources as l, AnyCrust as lt, CommandSection as m, CommandPath as mt, ContextBag as n, CrustErrorDetailsMap as nt, ContextMap as o, EnvIssue as ot, CommandMeta as p, CommandHandle as pt, InferExtensionFlags as q, ContextBuilder as r, CrustErrorJson as rt, ContextSetup as s, ParseErrorDetails as st, AnyContextFactory as t, CrustErrorDetails as tt, defineContext as u, CommandConfig as ut, FlagDef as v, Crust as vt, MergeFlags as w, RunOutcome as wt, InputFlags as x, RunArguments as xt, FlagsDef as y, CrustCommandContext as yt, ExtensionBuildContext as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as CrustError, A as SectionConsumer, At as LocalFlagNameBrand, B as ExtensionBuilder, C as InvocationOptions, Ct as RunInputArguments, D as ParsedArgValue, Dt as CommandSnapshot, E as ParseResult, Et as ArgSnapshot, F as BuildArtifacts, Ft as defineExtensionId, G as ExtensionSectionContribution, H as ExtensionFactory, I as BuildFile, J as InvocationOutcome, K as Finished, L as BuildReport, M as ValueType, Mt as LocalValueBrand, Nt as MergeContext, O as ParsedFlagValue, Ot as FlagSnapshot, Pt as ExtensionId, Q as CommandNotFoundErrorDetails, R as Extension, S as InvocationIO, St as RunInput, T as NamedFlagDef, Tt as defineCommand, U as ExtensionFlagDef, V as ExtensionContext, W as ExtensionHooks, X as RootMetaKey, Y as NamedExtensionFlagDef, Z as defineExtension, _ as ExecuteOptions, _t as CommandTree, a as ContextInstance, at as EnvErrorDetails, b as InputArgs, bt as RootCommandMeta, c as FactoryValueOf, ct as ValidationErrorDetails, d as ArgDef, dt as CommandDefinition, et as CrustErrorCode, f as ArgsDef, ft as CommandDefinitionBuilder, gt as CommandShapeAt, h as CommandSectionInput, ht as CommandShape, i as ContextFactory, it as DefinitionErrorDetails, j as ValidatedInput, jt as EmptyArgNameBrand, k as SectionAudience, kt as LocalFlagBrand, l as contextSources, lt as AnyCrust, m as CommandSection, mt as CommandPath, n as ContextBag, nt as CrustErrorDetailsMap, o as ContextMap, ot as EnvIssue, p as CommandMeta, pt as CommandHandle, q as InferExtensionFlags, r as ContextBuilder, rt as CrustErrorJson, s as ContextSetup, st as ParseErrorDetails, t as AnyContextFactory, tt as CrustErrorDetails, u as defineContext, ut as CommandConfig, v as FlagDef, vt as Crust, w as MergeFlags, wt as RunOutcome, x as InputFlags, xt as RunArguments, y as FlagsDef, yt as CrustCommandContext, z as ExtensionBuildContext } from "./context-9ee4iljp.js";
|
|
2
2
|
import { resolveArtifactDir } from "@crustjs/utils/artifacts";
|
|
3
3
|
//#region src/api/flags.d.ts
|
|
4
4
|
/** Distribute `Omit<_, "name">` over the {@link ArgDef} union. */
|
|
@@ -20,4 +20,4 @@ export declare function defineFlag<const N extends string, const D extends FlagD
|
|
|
20
20
|
/** Define and own one positional argument; layout belongs to its consuming command. */
|
|
21
21
|
export declare function defineArg<const N extends string, const D extends UnnamedArgDef>(name: N & EmptyArgNameBrand<N>, def: D & LocalValueBrand<D>): Named<N, D>;
|
|
22
22
|
//#endregion
|
|
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
|
|
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 ContextBuilder, type ContextFactory, type ContextInstance, type ContextMap, type ContextSetup, Crust, type CrustCommandContext, CrustError, type CrustErrorCode, type CrustErrorDetails, type CrustErrorDetailsMap, type CrustErrorJson, type DefinitionErrorDetails, type EnvErrorDetails, type EnvIssue, type ExecuteOptions, type Extension, type ExtensionBuildContext, type ExtensionBuilder, 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 InvocationOptions, 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 };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as normalizeFlag, S as normalizeArg, _ as validateContextAvailability, a as runInvocation, b as validateCommandSections, c as cloneCommandNode, d as createCommandNode, f as registerFlag, g as definingOf, h as defineContext, i as resolveTypedPath, l as cloneFlagRegistry, m as contextSources, n as executeInvocation, o as snapshotCommand, p as defineExtension, r as prepareInvocation, u as installExtensionContexts, w as CrustError } from "./invocation-CD299Gic.js";
|
|
2
2
|
import { resolveArtifactDir } from "@crustjs/utils/artifacts";
|
|
3
3
|
//#region src/identity.ts
|
|
4
4
|
/** Mint an Extension identity from any non-blank, trimmed string. */
|
|
@@ -161,7 +161,8 @@ var Crust = class {
|
|
|
161
161
|
validateContextAvailability([...this._node.contexts.map(({ instance }) => instance), ...instances], instances);
|
|
162
162
|
const cloned = this._clone({
|
|
163
163
|
...cloneFlagRegistry(this._node),
|
|
164
|
-
contexts: [...this._node.contexts, ...instances.map((instance) => ({ instance }))]
|
|
164
|
+
contexts: [...this._node.contexts, ...instances.map((instance) => ({ instance }))],
|
|
165
|
+
providedContexts: [...this._node.providedContexts, ...instances]
|
|
165
166
|
});
|
|
166
167
|
for (const instance of instances) for (const [name, definition] of Object.entries(instance.ownedFlags)) registerFlag(cloned._node, name, definition, "owned");
|
|
167
168
|
return cloned;
|
|
@@ -187,7 +188,7 @@ var Crust = class {
|
|
|
187
188
|
const extensions = inputs.map(definingOf);
|
|
188
189
|
const activeExtensions = dedupeExtensions([...this._node.extensions, ...extensions]);
|
|
189
190
|
const node = installExtensionContexts(this._node, activeExtensions, new Set(extensions.map((extension) => extension.id)));
|
|
190
|
-
validateContextAvailability(node.contexts.map(({ instance }) => instance), activeExtensions.flatMap((extension) => [...extension.
|
|
191
|
+
validateContextAvailability(node.contexts.map(({ instance }) => instance), activeExtensions.flatMap((extension) => [...extension.use, ...extension.provide]));
|
|
191
192
|
return this._clone({
|
|
192
193
|
...node,
|
|
193
194
|
extensions: activeExtensions
|