@kidd-cli/core 0.3.0 → 0.4.0
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/README.md +2 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +228 -39
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +15 -3
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +45 -6
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/http.d.ts +1 -1
- package/dist/{types-CTvrsrnD.d.ts → types-U73X_oQ_.d.ts} +59 -9
- package/dist/{types-CTvrsrnD.d.ts.map → types-U73X_oQ_.d.ts.map} +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ await cli({
|
|
|
28
28
|
name: 'my-app',
|
|
29
29
|
version: '1.0.0',
|
|
30
30
|
commands: { greet },
|
|
31
|
+
help: { header: 'my-app - a friendly CLI' },
|
|
31
32
|
})
|
|
32
33
|
```
|
|
33
34
|
|
|
@@ -45,9 +46,7 @@ cli({
|
|
|
45
46
|
commands: { deploy, migrate },
|
|
46
47
|
middleware: [requireAuth()],
|
|
47
48
|
config: { schema: MyConfigSchema },
|
|
48
|
-
|
|
49
|
-
apiKey: { env: 'API_KEY', required: true },
|
|
50
|
-
},
|
|
49
|
+
help: { header: 'my-app - deploy and migrate with ease' },
|
|
51
50
|
})
|
|
52
51
|
```
|
|
53
52
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { defineConfig } from "@kidd-cli/config";
|
|
1
|
+
import { a as Command, c as CommandsConfig, d as MiddlewareEnv, f as MiddlewareFn, i as CliOptions, l as InferVariables, n as AutoloadOptions, o as CommandDef, p as Context, r as CliHelpOptions, s as CommandMap, t as ArgsDef, u as Middleware } from "./types-U73X_oQ_.js";
|
|
3
2
|
import { z } from "zod";
|
|
3
|
+
import { defineConfig } from "@kidd-cli/config";
|
|
4
4
|
|
|
5
5
|
//#region src/cli.d.ts
|
|
6
6
|
/**
|
|
@@ -21,6 +21,10 @@ declare function cli<TSchema extends z.ZodType = z.ZodType>(options: CliOptions<
|
|
|
21
21
|
* enabling TypeScript to extract and intersect `Variables` from each middleware
|
|
22
22
|
* element onto the handler's `ctx` type.
|
|
23
23
|
*
|
|
24
|
+
* When `def.commands` is a structured {@link CommandsConfig}, the factory
|
|
25
|
+
* normalizes it into flat `commands` and `order` fields on the output
|
|
26
|
+
* `Command` object so downstream consumers never need to handle the grouped form.
|
|
27
|
+
*
|
|
24
28
|
* @param def - Command definition including description, args schema, middleware, and handler.
|
|
25
29
|
* @returns A resolved Command object for registration in the command map.
|
|
26
30
|
*/
|
|
@@ -113,5 +117,5 @@ declare function decorateContext<TKey extends string, TValue>(ctx: Context, key:
|
|
|
113
117
|
*/
|
|
114
118
|
declare function middleware<TEnv extends MiddlewareEnv = MiddlewareEnv>(handler: MiddlewareFn<TEnv>): Middleware<TEnv>;
|
|
115
119
|
//#endregion
|
|
116
|
-
export { type Command, type Context, type MiddlewareEnv, autoload, cli, command, compose, decorateContext, defineConfig, middleware };
|
|
120
|
+
export { type CliHelpOptions, type Command, type CommandsConfig, type Context, type MiddlewareEnv, autoload, cli, command, compose, decorateContext, defineConfig, middleware };
|
|
117
121
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/cli.ts","../src/command.ts","../src/compose.ts","../src/autoloader.ts","../src/context/decorate.ts","../src/middleware.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/cli.ts","../src/command.ts","../src/compose.ts","../src/autoloader.ts","../src/context/decorate.ts","../src/middleware.ts"],"mappings":";;;;;;;;AA4BA;;;;;iBAAsB,GAAA,iBAAoB,CAAA,CAAE,OAAA,GAAU,CAAA,CAAE,OAAA,CAAA,CACtD,OAAA,EAAS,UAAA,CAAW,OAAA,IACnB,OAAA;;;;;;;;;;;;;;;;;iBCgBa,OAAA,kBACG,OAAA,GAAU,OAAA,kBACX,MAAA,oBAA0B,MAAA,sDACP,UAAA,CAAW,aAAA,eACnC,UAAA,CAAW,aAAA,IAAA,CACtB,GAAA,EAAK,UAAA,CAAW,QAAA,EAAU,OAAA,EAAS,WAAA,IAAe,OAAA;;;;;;;ADvBpD;UEdU,WAAA,8BAAyC,UAAA,CAAW,aAAA;EAAA,SACnD,SAAA,EAAW,cAAA,CAAe,WAAA,oCACf,CAAA,GACd,MAAA,oBACA,CAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAsBQ,OAAA,oCAA2C,UAAA,CAAW,aAAA,IAAA,CACpE,WAAA,EAAa,WAAA,GACZ,UAAA,CAAW,WAAA,CAAY,WAAA;;;;;;;AFd1B;;iBGVsB,QAAA,CAAS,OAAA,GAAU,eAAA,GAAkB,OAAA,CAAQ,UAAA;;;;;;;AHUnE;;;;;;;;;;;;;;;;;;;;;;iBIAgB,eAAA,6BAAA,CACd,GAAA,EAAK,OAAA,EACL,GAAA,EAAK,IAAA,EACL,KAAA,EAAO,MAAA,GACN,OAAA;;;;;;;AJJH;;;;;;;;;;;;;iBKPgB,UAAA,cAAwB,aAAA,GAAgB,aAAA,CAAA,CACtD,OAAA,EAAS,YAAA,CAAa,IAAA,IACrB,UAAA,CAAW,IAAA"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { basename, extname, join, resolve } from "node:path";
|
|
|
6
6
|
import { loadConfig } from "@kidd-cli/config/loader";
|
|
7
7
|
import { P, attemptAsync, err, isPlainObject, isString, match, ok } from "@kidd-cli/utils/fp";
|
|
8
8
|
import yargs from "yargs";
|
|
9
|
+
import { z } from "zod";
|
|
9
10
|
import * as clack from "@clack/prompts";
|
|
10
11
|
import { TAG, hasTag, withTag } from "@kidd-cli/utils/tag";
|
|
11
12
|
import { jsonStringify } from "@kidd-cli/utils/json";
|
|
@@ -460,6 +461,46 @@ function isCommandDir(entry) {
|
|
|
460
461
|
return !entry.name.startsWith("_") && !entry.name.startsWith(".");
|
|
461
462
|
}
|
|
462
463
|
//#endregion
|
|
464
|
+
//#region src/command.ts
|
|
465
|
+
/**
|
|
466
|
+
* Check whether a value is a structured {@link CommandsConfig} object.
|
|
467
|
+
*
|
|
468
|
+
* Discriminates from a plain `CommandMap` by checking for the `order` (array)
|
|
469
|
+
* or `path` (string) keys — neither can appear on a valid `CommandMap` whose
|
|
470
|
+
* values are tagged `Command` objects.
|
|
471
|
+
*
|
|
472
|
+
* @param value - The value to test.
|
|
473
|
+
* @returns `true` when `value` is a `CommandsConfig`.
|
|
474
|
+
*/
|
|
475
|
+
function isCommandsConfig(value) {
|
|
476
|
+
if (typeof value !== "object" || value === null || value instanceof Promise) return false;
|
|
477
|
+
return "order" in value && Array.isArray(value.order) || "path" in value && typeof value.path === "string";
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Define a CLI command with typed args, config, and handler.
|
|
481
|
+
*
|
|
482
|
+
* The `const TMiddleware` generic preserves the middleware tuple as a literal type,
|
|
483
|
+
* enabling TypeScript to extract and intersect `Variables` from each middleware
|
|
484
|
+
* element onto the handler's `ctx` type.
|
|
485
|
+
*
|
|
486
|
+
* When `def.commands` is a structured {@link CommandsConfig}, the factory
|
|
487
|
+
* normalizes it into flat `commands` and `order` fields on the output
|
|
488
|
+
* `Command` object so downstream consumers never need to handle the grouped form.
|
|
489
|
+
*
|
|
490
|
+
* @param def - Command definition including description, args schema, middleware, and handler.
|
|
491
|
+
* @returns A resolved Command object for registration in the command map.
|
|
492
|
+
*/
|
|
493
|
+
function command(def) {
|
|
494
|
+
return match(def.commands).when(isCommandsConfig, (cfg) => {
|
|
495
|
+
const { order, commands: innerCommands } = cfg;
|
|
496
|
+
return withTag({
|
|
497
|
+
...def,
|
|
498
|
+
commands: innerCommands,
|
|
499
|
+
order
|
|
500
|
+
}, "Command");
|
|
501
|
+
}).otherwise(() => withTag({ ...def }, "Command"));
|
|
502
|
+
}
|
|
503
|
+
//#endregion
|
|
463
504
|
//#region src/runtime/args/zod.ts
|
|
464
505
|
/**
|
|
465
506
|
* Type guard that checks whether a value is a zod object schema.
|
|
@@ -700,6 +741,44 @@ function yargsArgDefToOption(def) {
|
|
|
700
741
|
};
|
|
701
742
|
}
|
|
702
743
|
//#endregion
|
|
744
|
+
//#region src/runtime/sort-commands.ts
|
|
745
|
+
/**
|
|
746
|
+
* Validate that every name in the order array exists in the provided command names.
|
|
747
|
+
*
|
|
748
|
+
* @param params - The order array and available command names to validate against.
|
|
749
|
+
* @returns A Result tuple — `[null, void]` on success or `[Error, null]` on failure.
|
|
750
|
+
*/
|
|
751
|
+
function validateCommandOrder(params) {
|
|
752
|
+
const { order, commandNames } = params;
|
|
753
|
+
const seen = /* @__PURE__ */ new Set();
|
|
754
|
+
const duplicates = order.filter((name) => {
|
|
755
|
+
if (seen.has(name)) return true;
|
|
756
|
+
seen.add(name);
|
|
757
|
+
return false;
|
|
758
|
+
});
|
|
759
|
+
if (duplicates.length > 0) return err(`Invalid command order: duplicate command(s) ${[...new Set(duplicates)].map((n) => `"${n}"`).join(", ")}`);
|
|
760
|
+
const nameSet = new Set(commandNames);
|
|
761
|
+
const invalid = order.filter((name) => !nameSet.has(name));
|
|
762
|
+
if (invalid.length > 0) return err(`Invalid command order: unknown command(s) ${invalid.map((n) => `"${n}"`).join(", ")}`);
|
|
763
|
+
return ok();
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Sort command entries with ordered names first (in specified order),
|
|
767
|
+
* remaining names alphabetically.
|
|
768
|
+
*
|
|
769
|
+
* @param params - The command entries and optional order array.
|
|
770
|
+
* @returns Sorted array of `[name, Command]` entries.
|
|
771
|
+
*/
|
|
772
|
+
function sortCommandEntries(params) {
|
|
773
|
+
const { entries, order } = params;
|
|
774
|
+
if (!order || order.length === 0) return [...entries].toSorted(([a], [b]) => a.localeCompare(b));
|
|
775
|
+
const entryMap = new Map(entries);
|
|
776
|
+
const ordered = order.filter((name) => entryMap.has(name)).map((name) => [name, entryMap.get(name)]);
|
|
777
|
+
const orderedSet = new Set(order);
|
|
778
|
+
const remaining = entries.filter(([name]) => !orderedSet.has(name)).toSorted(([a], [b]) => a.localeCompare(b));
|
|
779
|
+
return [...ordered, ...remaining];
|
|
780
|
+
}
|
|
781
|
+
//#endregion
|
|
703
782
|
//#region src/runtime/register.ts
|
|
704
783
|
/**
|
|
705
784
|
* Type guard that checks whether a value is a Command object.
|
|
@@ -714,22 +793,36 @@ function isCommand(value) {
|
|
|
714
793
|
* Register all commands from a CommandMap on a yargs instance.
|
|
715
794
|
*
|
|
716
795
|
* Iterates over the command map, filters for valid Command objects,
|
|
717
|
-
*
|
|
718
|
-
* the provided yargs Argv instance.
|
|
796
|
+
* validates the order array, sorts entries, and recursively registers
|
|
797
|
+
* each command (including subcommands) on the provided yargs Argv instance.
|
|
719
798
|
*
|
|
720
799
|
* @param options - Registration options including the command map, yargs instance, and resolution ref.
|
|
721
800
|
*/
|
|
722
801
|
function registerCommands(options) {
|
|
723
|
-
const { instance, commands, resolved, parentPath } = options;
|
|
802
|
+
const { instance, commands, resolved, parentPath, order, errorRef } = options;
|
|
724
803
|
const commandEntries = Object.entries(commands).filter((pair) => isCommand(pair[1]));
|
|
725
|
-
|
|
804
|
+
if (order && order.length > 0) {
|
|
805
|
+
const [validationError] = validateCommandOrder({
|
|
806
|
+
commandNames: commandEntries.map(([name]) => name),
|
|
807
|
+
order
|
|
808
|
+
});
|
|
809
|
+
if (validationError && errorRef) {
|
|
810
|
+
errorRef.error = validationError;
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
sortCommandEntries({
|
|
815
|
+
entries: commandEntries,
|
|
816
|
+
order
|
|
817
|
+
}).map(([name, entry]) => registerResolvedCommand({
|
|
726
818
|
builder: instance,
|
|
727
819
|
cmd: entry,
|
|
820
|
+
errorRef,
|
|
728
821
|
instance,
|
|
729
822
|
name,
|
|
730
823
|
parentPath,
|
|
731
824
|
resolved
|
|
732
|
-
});
|
|
825
|
+
}));
|
|
733
826
|
}
|
|
734
827
|
/**
|
|
735
828
|
* Register a single resolved command (and its subcommands) with yargs.
|
|
@@ -742,20 +835,34 @@ function registerCommands(options) {
|
|
|
742
835
|
* @param options - Command registration context.
|
|
743
836
|
*/
|
|
744
837
|
function registerResolvedCommand(options) {
|
|
745
|
-
const { instance, name, cmd, resolved, parentPath } = options;
|
|
838
|
+
const { instance, name, cmd, resolved, parentPath, errorRef } = options;
|
|
746
839
|
const description = cmd.description ?? "";
|
|
747
840
|
instance.command(name, description, (builder) => {
|
|
748
841
|
registerCommandArgs(builder, cmd.args);
|
|
749
842
|
if (cmd.commands) {
|
|
750
843
|
const subCommands = Object.entries(cmd.commands).filter((pair) => isCommand(pair[1]));
|
|
751
|
-
|
|
844
|
+
if (cmd.order && cmd.order.length > 0) {
|
|
845
|
+
const [validationError] = validateCommandOrder({
|
|
846
|
+
commandNames: subCommands.map(([n]) => n),
|
|
847
|
+
order: cmd.order
|
|
848
|
+
});
|
|
849
|
+
if (validationError && errorRef) {
|
|
850
|
+
errorRef.error = validationError;
|
|
851
|
+
return builder;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
sortCommandEntries({
|
|
855
|
+
entries: subCommands,
|
|
856
|
+
order: cmd.order
|
|
857
|
+
}).map(([subName, subEntry]) => registerResolvedCommand({
|
|
752
858
|
builder,
|
|
753
859
|
cmd: subEntry,
|
|
860
|
+
errorRef,
|
|
754
861
|
instance: builder,
|
|
755
862
|
name: subName,
|
|
756
863
|
parentPath: [...parentPath, name],
|
|
757
864
|
resolved
|
|
758
|
-
});
|
|
865
|
+
}));
|
|
759
866
|
if (cmd.handler) builder.demandCommand(0);
|
|
760
867
|
else builder.demandCommand(1, "You must specify a subcommand.");
|
|
761
868
|
}
|
|
@@ -890,31 +997,46 @@ const ARGV_SLICE_START = 2;
|
|
|
890
997
|
async function cli(options) {
|
|
891
998
|
const logger = createCliLogger();
|
|
892
999
|
const [uncaughtError, result] = await attemptAsync(async () => {
|
|
893
|
-
const
|
|
1000
|
+
const [versionError, version] = resolveVersion(options.version);
|
|
1001
|
+
if (versionError) return versionError;
|
|
1002
|
+
const program = yargs(process.argv.slice(ARGV_SLICE_START)).scriptName(options.name).version(version).strict().help().option("cwd", {
|
|
894
1003
|
describe: "Set the working directory",
|
|
895
1004
|
global: true,
|
|
896
1005
|
type: "string"
|
|
897
1006
|
});
|
|
898
1007
|
if (options.description) program.usage(options.description);
|
|
1008
|
+
const footer = extractFooter(options.help);
|
|
1009
|
+
if (footer) program.epilogue(footer);
|
|
899
1010
|
const resolved = { ref: void 0 };
|
|
900
|
-
const
|
|
901
|
-
|
|
1011
|
+
const errorRef = { error: void 0 };
|
|
1012
|
+
const resolvedCmds = await resolveCommands(options.commands);
|
|
1013
|
+
if (resolvedCmds) {
|
|
902
1014
|
registerCommands({
|
|
903
|
-
commands,
|
|
1015
|
+
commands: resolvedCmds.commands,
|
|
1016
|
+
errorRef,
|
|
904
1017
|
instance: program,
|
|
1018
|
+
order: resolvedCmds.order,
|
|
905
1019
|
parentPath: [],
|
|
906
1020
|
resolved
|
|
907
1021
|
});
|
|
908
|
-
|
|
1022
|
+
if (errorRef.error) return errorRef.error;
|
|
909
1023
|
}
|
|
910
1024
|
const argv = await program.parseAsync();
|
|
911
1025
|
applyCwd(argv);
|
|
912
|
-
if (!resolved.ref)
|
|
1026
|
+
if (!resolved.ref) {
|
|
1027
|
+
showNoCommandHelp({
|
|
1028
|
+
argv,
|
|
1029
|
+
commands: resolvedCmds,
|
|
1030
|
+
help: options.help,
|
|
1031
|
+
program
|
|
1032
|
+
});
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
913
1035
|
const [runtimeError, runtime] = await createRuntime({
|
|
914
1036
|
config: options.config,
|
|
915
1037
|
middleware: options.middleware,
|
|
916
1038
|
name: options.name,
|
|
917
|
-
version
|
|
1039
|
+
version
|
|
918
1040
|
});
|
|
919
1041
|
if (runtimeError) return runtimeError;
|
|
920
1042
|
const [executeError] = await runtime.execute({
|
|
@@ -932,23 +1054,64 @@ async function cli(options) {
|
|
|
932
1054
|
}
|
|
933
1055
|
if (result) exitOnError(result, logger);
|
|
934
1056
|
}
|
|
1057
|
+
const VERSION_ERROR = /* @__PURE__ */ new Error("No CLI version available. Either pass `version` to cli() or build with the kidd bundler.");
|
|
1058
|
+
const VersionSchema = z.string().trim().min(1);
|
|
1059
|
+
/**
|
|
1060
|
+
* Resolve the CLI version from an explicit value or the compile-time constant.
|
|
1061
|
+
*
|
|
1062
|
+
* Resolution order:
|
|
1063
|
+
* 1. Explicit version string passed to `cli()`
|
|
1064
|
+
* 2. `__KIDD_VERSION__` injected by the kidd bundler at build time
|
|
1065
|
+
*
|
|
1066
|
+
* Returns an error when neither source provides a non-empty version.
|
|
1067
|
+
*
|
|
1068
|
+
* @private
|
|
1069
|
+
* @param explicit - The version string from `CliOptions.version`, if provided.
|
|
1070
|
+
* @returns A Result tuple with the resolved version string or an Error.
|
|
1071
|
+
*/
|
|
1072
|
+
function resolveVersion(explicit) {
|
|
1073
|
+
if (explicit !== void 0) {
|
|
1074
|
+
const parsed = VersionSchema.safeParse(explicit);
|
|
1075
|
+
if (parsed.success) return ok(parsed.data);
|
|
1076
|
+
return err(VERSION_ERROR);
|
|
1077
|
+
}
|
|
1078
|
+
if (typeof __KIDD_VERSION__ === "string") {
|
|
1079
|
+
const parsed = VersionSchema.safeParse(__KIDD_VERSION__);
|
|
1080
|
+
if (parsed.success) return ok(parsed.data);
|
|
1081
|
+
}
|
|
1082
|
+
return err(VERSION_ERROR);
|
|
1083
|
+
}
|
|
935
1084
|
/**
|
|
936
|
-
* Resolve the commands option to a
|
|
1085
|
+
* Resolve the commands option to a {@link ResolvedCommands}.
|
|
937
1086
|
*
|
|
938
1087
|
* Accepts a directory string (triggers autoload), a static CommandMap,
|
|
939
|
-
* a Promise<CommandMap
|
|
1088
|
+
* a Promise<CommandMap>, a structured {@link CommandsConfig},
|
|
940
1089
|
* or undefined (loads `kidd.config.ts` and autoloads from its `commands` field,
|
|
941
1090
|
* falling back to `'./commands'`).
|
|
942
1091
|
*
|
|
943
1092
|
* @private
|
|
944
1093
|
* @param commands - The commands option from CliOptions.
|
|
945
|
-
* @returns
|
|
1094
|
+
* @returns Resolved commands with optional order, or undefined.
|
|
946
1095
|
*/
|
|
947
1096
|
async function resolveCommands(commands) {
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1097
|
+
return match(commands).when(isString, async (dir) => ({ commands: await autoload({ dir }) })).with(P.instanceOf(Promise), async (p) => ({ commands: await p })).when(isCommandsConfig, (cfg) => resolveCommandsConfig(cfg)).when(isPlainObject, (cmds) => ({ commands: cmds })).otherwise(() => resolveCommandsFromConfig());
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Resolve a structured {@link CommandsConfig} into flat commands and order.
|
|
1101
|
+
*
|
|
1102
|
+
* When `path` is provided, autoloads from that directory. Otherwise uses the
|
|
1103
|
+
* inline `commands` map (resolved if it is a promise).
|
|
1104
|
+
*
|
|
1105
|
+
* @private
|
|
1106
|
+
* @param config - The structured commands configuration.
|
|
1107
|
+
* @returns Resolved commands with optional order.
|
|
1108
|
+
*/
|
|
1109
|
+
async function resolveCommandsConfig(config) {
|
|
1110
|
+
const { order, path, commands: innerCommands } = config;
|
|
1111
|
+
return {
|
|
1112
|
+
commands: await match(innerCommands).when(() => isString(path), async () => autoload({ dir: path })).with(P.instanceOf(Promise), async (p) => p).when(isPlainObject, (cmds) => cmds).otherwise(() => ({})),
|
|
1113
|
+
order
|
|
1114
|
+
};
|
|
952
1115
|
}
|
|
953
1116
|
/**
|
|
954
1117
|
* Load `kidd.config.ts` and autoload commands from its `commands` field.
|
|
@@ -962,8 +1125,8 @@ async function resolveCommands(commands) {
|
|
|
962
1125
|
async function resolveCommandsFromConfig() {
|
|
963
1126
|
const DEFAULT_COMMANDS_DIR = "./commands";
|
|
964
1127
|
const [configError, configResult] = await loadConfig();
|
|
965
|
-
if (configError || !configResult) return autoload({ dir: DEFAULT_COMMANDS_DIR });
|
|
966
|
-
return autoload({ dir: configResult.config.commands ?? DEFAULT_COMMANDS_DIR });
|
|
1128
|
+
if (configError || !configResult) return { commands: await autoload({ dir: DEFAULT_COMMANDS_DIR }) };
|
|
1129
|
+
return { commands: await autoload({ dir: configResult.config.commands ?? DEFAULT_COMMANDS_DIR }) };
|
|
967
1130
|
}
|
|
968
1131
|
/**
|
|
969
1132
|
* Change the process working directory when `--cwd` is provided.
|
|
@@ -978,6 +1141,47 @@ function applyCwd(argv) {
|
|
|
978
1141
|
if (isString(argv.cwd)) process.chdir(resolve(argv.cwd));
|
|
979
1142
|
}
|
|
980
1143
|
/**
|
|
1144
|
+
* Show help output when no command was matched.
|
|
1145
|
+
*
|
|
1146
|
+
* Prints the header (if configured) above the yargs help text. Skipped when
|
|
1147
|
+
* `--help` was explicitly passed, since yargs already handles that case.
|
|
1148
|
+
*
|
|
1149
|
+
* @private
|
|
1150
|
+
* @param params - The argv, commands, help options, and yargs program instance.
|
|
1151
|
+
*/
|
|
1152
|
+
function showNoCommandHelp({ argv, commands, help, program }) {
|
|
1153
|
+
if (!commands) return;
|
|
1154
|
+
if (argv.help) return;
|
|
1155
|
+
const header = extractHeader(help);
|
|
1156
|
+
if (header) {
|
|
1157
|
+
console.log(header);
|
|
1158
|
+
console.log();
|
|
1159
|
+
}
|
|
1160
|
+
program.showHelp("log");
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Extract the header string from help options.
|
|
1164
|
+
*
|
|
1165
|
+
* @private
|
|
1166
|
+
* @param help - The help options, possibly undefined.
|
|
1167
|
+
* @returns The header string or undefined.
|
|
1168
|
+
*/
|
|
1169
|
+
function extractHeader(help) {
|
|
1170
|
+
if (!help) return;
|
|
1171
|
+
return help.header;
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Extract the footer string from help options.
|
|
1175
|
+
*
|
|
1176
|
+
* @private
|
|
1177
|
+
* @param help - The help options, possibly undefined.
|
|
1178
|
+
* @returns The footer string or undefined.
|
|
1179
|
+
*/
|
|
1180
|
+
function extractFooter(help) {
|
|
1181
|
+
if (!help) return;
|
|
1182
|
+
return help.footer;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
981
1185
|
* Handle a CLI error by logging the message and exiting with the appropriate code.
|
|
982
1186
|
*
|
|
983
1187
|
* ContextErrors carry a custom exit code; all other errors exit with code 1.
|
|
@@ -1001,21 +1205,6 @@ function exitOnError(error, logger) {
|
|
|
1001
1205
|
process.exit(info.exitCode);
|
|
1002
1206
|
}
|
|
1003
1207
|
//#endregion
|
|
1004
|
-
//#region src/command.ts
|
|
1005
|
-
/**
|
|
1006
|
-
* Define a CLI command with typed args, config, and handler.
|
|
1007
|
-
*
|
|
1008
|
-
* The `const TMiddleware` generic preserves the middleware tuple as a literal type,
|
|
1009
|
-
* enabling TypeScript to extract and intersect `Variables` from each middleware
|
|
1010
|
-
* element onto the handler's `ctx` type.
|
|
1011
|
-
*
|
|
1012
|
-
* @param def - Command definition including description, args schema, middleware, and handler.
|
|
1013
|
-
* @returns A resolved Command object for registration in the command map.
|
|
1014
|
-
*/
|
|
1015
|
-
function command(def) {
|
|
1016
|
-
return withTag({ ...def }, "Command");
|
|
1017
|
-
}
|
|
1018
|
-
//#endregion
|
|
1019
1208
|
//#region src/compose.ts
|
|
1020
1209
|
/**
|
|
1021
1210
|
* Middleware combinator that merges multiple middleware into one.
|