@kidd-cli/core 0.2.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/{config-Db_sjFU-.js → config-D8e5qxLp.js} +5 -17
- package/dist/config-D8e5qxLp.js.map +1 -0
- package/dist/{create-store-D-fQpCql.js → create-store-OHdkm_Yt.js} +3 -4
- package/dist/{create-store-D-fQpCql.js.map → create-store-OHdkm_Yt.js.map} +1 -1
- package/dist/index.d.ts +36 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +297 -73
- package/dist/index.js.map +1 -1
- package/dist/lib/config.js +3 -4
- package/dist/lib/logger.d.ts +1 -1
- package/dist/lib/logger.js +1 -2
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/project.d.ts +1 -1
- package/dist/lib/project.d.ts.map +1 -1
- package/dist/lib/project.js +2 -3
- package/dist/lib/store.d.ts +1 -1
- package/dist/lib/store.js +3 -4
- package/dist/{logger-BkQQej8h.d.ts → logger-9j49T5da.d.ts} +1 -1
- package/dist/{logger-BkQQej8h.d.ts.map → logger-9j49T5da.d.ts.map} +1 -1
- package/dist/middleware/auth.d.ts +81 -41
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +287 -233
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/http.d.ts +1 -1
- package/dist/middleware/http.js +163 -4
- package/dist/middleware/http.js.map +1 -1
- package/dist/{middleware-BFBKNSPQ.js → middleware-BWnPSRWR.js} +2 -4
- package/dist/{middleware-BFBKNSPQ.js.map → middleware-BWnPSRWR.js.map} +1 -1
- package/dist/{project-DuXgjaa_.js → project-D0g84bZY.js} +4 -8
- package/dist/project-D0g84bZY.js.map +1 -0
- package/dist/{types-C0CYivzY.d.ts → types-D-BxshYM.d.ts} +1 -1
- package/dist/{types-C0CYivzY.d.ts.map → types-D-BxshYM.d.ts.map} +1 -1
- package/dist/{types-BaZ5WqVM.d.ts → types-U73X_oQ_.d.ts} +60 -10
- package/dist/types-U73X_oQ_.d.ts.map +1 -0
- package/package.json +7 -7
- package/dist/config-Db_sjFU-.js.map +0 -1
- package/dist/create-http-client-tZJWlWp1.js +0 -165
- package/dist/create-http-client-tZJWlWp1.js.map +0 -1
- package/dist/project-DuXgjaa_.js.map +0 -1
- package/dist/types-BaZ5WqVM.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createCliLogger } from "./lib/logger.js";
|
|
2
|
-
import { n as
|
|
3
|
-
import
|
|
4
|
-
import "./
|
|
2
|
+
import { n as decorateContext, t as middleware } from "./middleware-BWnPSRWR.js";
|
|
3
|
+
import "./project-D0g84bZY.js";
|
|
4
|
+
import { t as createConfigClient } from "./config-D8e5qxLp.js";
|
|
5
5
|
import { basename, extname, join, resolve } from "node:path";
|
|
6
6
|
import { loadConfig } from "@kidd-cli/config/loader";
|
|
7
|
-
import { attemptAsync, err, isPlainObject, isString, ok } from "@kidd-cli/utils/fp";
|
|
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";
|
|
@@ -13,7 +14,6 @@ import { readdir } from "node:fs/promises";
|
|
|
13
14
|
import { formatZodIssues } from "@kidd-cli/utils/validate";
|
|
14
15
|
import { match as match$1 } from "ts-pattern";
|
|
15
16
|
import { defineConfig } from "@kidd-cli/config";
|
|
16
|
-
|
|
17
17
|
//#region src/context/error.ts
|
|
18
18
|
/**
|
|
19
19
|
* Create a ContextError with an exit code and optional error code.
|
|
@@ -63,7 +63,7 @@ function isContextError(error) {
|
|
|
63
63
|
}
|
|
64
64
|
function resolveExitCode(options) {
|
|
65
65
|
if (options && options.exitCode !== void 0) return options.exitCode;
|
|
66
|
-
return
|
|
66
|
+
return 1;
|
|
67
67
|
}
|
|
68
68
|
function resolveCode(options) {
|
|
69
69
|
if (options && options.code !== void 0) return options.code;
|
|
@@ -75,7 +75,6 @@ function createContextErrorData(message, options) {
|
|
|
75
75
|
message
|
|
76
76
|
}, "ContextError");
|
|
77
77
|
}
|
|
78
|
-
|
|
79
78
|
//#endregion
|
|
80
79
|
//#region src/context/output.ts
|
|
81
80
|
/**
|
|
@@ -192,7 +191,6 @@ function writeTableToStream(stream, rows, keys) {
|
|
|
192
191
|
].join("\n");
|
|
193
192
|
stream.write(`${content}\n`);
|
|
194
193
|
}
|
|
195
|
-
|
|
196
194
|
//#endregion
|
|
197
195
|
//#region src/context/prompts.ts
|
|
198
196
|
/**
|
|
@@ -234,12 +232,11 @@ function unwrapCancelSignal(result) {
|
|
|
234
232
|
clack.cancel("Operation cancelled.");
|
|
235
233
|
throw createContextError("Prompt cancelled by user", {
|
|
236
234
|
code: "PROMPT_CANCELLED",
|
|
237
|
-
exitCode:
|
|
235
|
+
exitCode: 1
|
|
238
236
|
});
|
|
239
237
|
}
|
|
240
238
|
return result;
|
|
241
239
|
}
|
|
242
|
-
|
|
243
240
|
//#endregion
|
|
244
241
|
//#region src/context/store.ts
|
|
245
242
|
/**
|
|
@@ -268,7 +265,6 @@ function createMemoryStore() {
|
|
|
268
265
|
}
|
|
269
266
|
};
|
|
270
267
|
}
|
|
271
|
-
|
|
272
268
|
//#endregion
|
|
273
269
|
//#region src/context/create-context.ts
|
|
274
270
|
/**
|
|
@@ -306,7 +302,6 @@ function createContext(options) {
|
|
|
306
302
|
store: ctxStore
|
|
307
303
|
};
|
|
308
304
|
}
|
|
309
|
-
|
|
310
305
|
//#endregion
|
|
311
306
|
//#region src/autoloader.ts
|
|
312
307
|
const VALID_EXTENSIONS = new Set([
|
|
@@ -426,7 +421,8 @@ async function importCommand(filePath) {
|
|
|
426
421
|
*/
|
|
427
422
|
function isCommandExport(mod) {
|
|
428
423
|
if (typeof mod !== "object" || mod === null) return false;
|
|
429
|
-
|
|
424
|
+
if (!("default" in mod)) return false;
|
|
425
|
+
const def = mod.default;
|
|
430
426
|
if (!isPlainObject(def)) return false;
|
|
431
427
|
return hasTag(def, "Command");
|
|
432
428
|
}
|
|
@@ -464,7 +460,46 @@ function isCommandDir(entry) {
|
|
|
464
460
|
if (!entry.isDirectory()) return false;
|
|
465
461
|
return !entry.name.startsWith("_") && !entry.name.startsWith(".");
|
|
466
462
|
}
|
|
467
|
-
|
|
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
|
+
}
|
|
468
503
|
//#endregion
|
|
469
504
|
//#region src/runtime/args/zod.ts
|
|
470
505
|
/**
|
|
@@ -624,7 +659,6 @@ function getZodTypeOption(schema) {
|
|
|
624
659
|
};
|
|
625
660
|
return base;
|
|
626
661
|
}
|
|
627
|
-
|
|
628
662
|
//#endregion
|
|
629
663
|
//#region src/runtime/args/parser.ts
|
|
630
664
|
/**
|
|
@@ -671,7 +705,6 @@ function validateArgs(argsDef, parsedArgs) {
|
|
|
671
705
|
if (!result.success) return err(/* @__PURE__ */ new Error(`Invalid arguments:\n ${formatZodIssues(result.error.issues).message}`));
|
|
672
706
|
return ok(result.data);
|
|
673
707
|
}
|
|
674
|
-
|
|
675
708
|
//#endregion
|
|
676
709
|
//#region src/runtime/args/register.ts
|
|
677
710
|
/**
|
|
@@ -688,10 +721,7 @@ function registerCommandArgs(builder, args) {
|
|
|
688
721
|
if (isZodSchema(args)) {
|
|
689
722
|
const options = zodSchemaToYargsOptions(args);
|
|
690
723
|
for (const [key, opt] of Object.entries(options)) builder.option(key, opt);
|
|
691
|
-
} else
|
|
692
|
-
const argsDef = args;
|
|
693
|
-
for (const [key, def] of Object.entries(argsDef)) builder.option(key, yargsArgDefToOption(def));
|
|
694
|
-
}
|
|
724
|
+
} else for (const [key, def] of Object.entries(args)) builder.option(key, yargsArgDefToOption(def));
|
|
695
725
|
}
|
|
696
726
|
/**
|
|
697
727
|
* Convert a yargs-native arg definition into a yargs option object.
|
|
@@ -710,7 +740,44 @@ function yargsArgDefToOption(def) {
|
|
|
710
740
|
type: def.type
|
|
711
741
|
};
|
|
712
742
|
}
|
|
713
|
-
|
|
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
|
+
}
|
|
714
781
|
//#endregion
|
|
715
782
|
//#region src/runtime/register.ts
|
|
716
783
|
/**
|
|
@@ -726,22 +793,36 @@ function isCommand(value) {
|
|
|
726
793
|
* Register all commands from a CommandMap on a yargs instance.
|
|
727
794
|
*
|
|
728
795
|
* Iterates over the command map, filters for valid Command objects,
|
|
729
|
-
*
|
|
730
|
-
* 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.
|
|
731
798
|
*
|
|
732
799
|
* @param options - Registration options including the command map, yargs instance, and resolution ref.
|
|
733
800
|
*/
|
|
734
801
|
function registerCommands(options) {
|
|
735
|
-
const { instance, commands, resolved, parentPath } = options;
|
|
736
|
-
const commandEntries = Object.entries(commands).filter((
|
|
737
|
-
|
|
802
|
+
const { instance, commands, resolved, parentPath, order, errorRef } = options;
|
|
803
|
+
const commandEntries = Object.entries(commands).filter((pair) => isCommand(pair[1]));
|
|
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({
|
|
738
818
|
builder: instance,
|
|
739
819
|
cmd: entry,
|
|
820
|
+
errorRef,
|
|
740
821
|
instance,
|
|
741
822
|
name,
|
|
742
823
|
parentPath,
|
|
743
824
|
resolved
|
|
744
|
-
});
|
|
825
|
+
}));
|
|
745
826
|
}
|
|
746
827
|
/**
|
|
747
828
|
* Register a single resolved command (and its subcommands) with yargs.
|
|
@@ -754,20 +835,34 @@ function registerCommands(options) {
|
|
|
754
835
|
* @param options - Command registration context.
|
|
755
836
|
*/
|
|
756
837
|
function registerResolvedCommand(options) {
|
|
757
|
-
const { instance, name, cmd, resolved, parentPath } = options;
|
|
838
|
+
const { instance, name, cmd, resolved, parentPath, errorRef } = options;
|
|
758
839
|
const description = cmd.description ?? "";
|
|
759
840
|
instance.command(name, description, (builder) => {
|
|
760
841
|
registerCommandArgs(builder, cmd.args);
|
|
761
842
|
if (cmd.commands) {
|
|
762
|
-
const subCommands = Object.entries(cmd.commands).filter((
|
|
763
|
-
|
|
843
|
+
const subCommands = Object.entries(cmd.commands).filter((pair) => isCommand(pair[1]));
|
|
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({
|
|
764
858
|
builder,
|
|
765
859
|
cmd: subEntry,
|
|
860
|
+
errorRef,
|
|
766
861
|
instance: builder,
|
|
767
862
|
name: subName,
|
|
768
863
|
parentPath: [...parentPath, name],
|
|
769
864
|
resolved
|
|
770
|
-
});
|
|
865
|
+
}));
|
|
771
866
|
if (cmd.handler) builder.demandCommand(0);
|
|
772
867
|
else builder.demandCommand(1, "You must specify a subcommand.");
|
|
773
868
|
}
|
|
@@ -781,7 +876,6 @@ function registerResolvedCommand(options) {
|
|
|
781
876
|
};
|
|
782
877
|
});
|
|
783
878
|
}
|
|
784
|
-
|
|
785
879
|
//#endregion
|
|
786
880
|
//#region src/runtime/runner.ts
|
|
787
881
|
/**
|
|
@@ -832,7 +926,6 @@ async function runMiddlewareChain(middlewares, ctx, finalHandler) {
|
|
|
832
926
|
}
|
|
833
927
|
await executeChain(0);
|
|
834
928
|
}
|
|
835
|
-
|
|
836
929
|
//#endregion
|
|
837
930
|
//#region src/runtime/runtime.ts
|
|
838
931
|
/**
|
|
@@ -855,7 +948,7 @@ async function createRuntime(options) {
|
|
|
855
948
|
args: validatedArgs,
|
|
856
949
|
config,
|
|
857
950
|
meta: {
|
|
858
|
-
command: command.commandPath,
|
|
951
|
+
command: [...command.commandPath],
|
|
859
952
|
name: options.name,
|
|
860
953
|
version: options.version
|
|
861
954
|
}
|
|
@@ -890,7 +983,6 @@ async function resolveConfig(configOptions, defaultName) {
|
|
|
890
983
|
if (configError || !configResult) return {};
|
|
891
984
|
return configResult.config;
|
|
892
985
|
}
|
|
893
|
-
|
|
894
986
|
//#endregion
|
|
895
987
|
//#region src/cli.ts
|
|
896
988
|
const ARGV_SLICE_START = 2;
|
|
@@ -905,31 +997,46 @@ const ARGV_SLICE_START = 2;
|
|
|
905
997
|
async function cli(options) {
|
|
906
998
|
const logger = createCliLogger();
|
|
907
999
|
const [uncaughtError, result] = await attemptAsync(async () => {
|
|
908
|
-
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", {
|
|
909
1003
|
describe: "Set the working directory",
|
|
910
1004
|
global: true,
|
|
911
1005
|
type: "string"
|
|
912
1006
|
});
|
|
913
1007
|
if (options.description) program.usage(options.description);
|
|
1008
|
+
const footer = extractFooter(options.help);
|
|
1009
|
+
if (footer) program.epilogue(footer);
|
|
914
1010
|
const resolved = { ref: void 0 };
|
|
915
|
-
const
|
|
916
|
-
|
|
1011
|
+
const errorRef = { error: void 0 };
|
|
1012
|
+
const resolvedCmds = await resolveCommands(options.commands);
|
|
1013
|
+
if (resolvedCmds) {
|
|
917
1014
|
registerCommands({
|
|
918
|
-
commands,
|
|
1015
|
+
commands: resolvedCmds.commands,
|
|
1016
|
+
errorRef,
|
|
919
1017
|
instance: program,
|
|
1018
|
+
order: resolvedCmds.order,
|
|
920
1019
|
parentPath: [],
|
|
921
1020
|
resolved
|
|
922
1021
|
});
|
|
923
|
-
|
|
1022
|
+
if (errorRef.error) return errorRef.error;
|
|
924
1023
|
}
|
|
925
1024
|
const argv = await program.parseAsync();
|
|
926
1025
|
applyCwd(argv);
|
|
927
|
-
if (!resolved.ref)
|
|
1026
|
+
if (!resolved.ref) {
|
|
1027
|
+
showNoCommandHelp({
|
|
1028
|
+
argv,
|
|
1029
|
+
commands: resolvedCmds,
|
|
1030
|
+
help: options.help,
|
|
1031
|
+
program
|
|
1032
|
+
});
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
928
1035
|
const [runtimeError, runtime] = await createRuntime({
|
|
929
1036
|
config: options.config,
|
|
930
1037
|
middleware: options.middleware,
|
|
931
1038
|
name: options.name,
|
|
932
|
-
version
|
|
1039
|
+
version
|
|
933
1040
|
});
|
|
934
1041
|
if (runtimeError) return runtimeError;
|
|
935
1042
|
const [executeError] = await runtime.execute({
|
|
@@ -947,23 +1054,64 @@ async function cli(options) {
|
|
|
947
1054
|
}
|
|
948
1055
|
if (result) exitOnError(result, logger);
|
|
949
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
|
+
}
|
|
950
1084
|
/**
|
|
951
|
-
* Resolve the commands option to a
|
|
1085
|
+
* Resolve the commands option to a {@link ResolvedCommands}.
|
|
952
1086
|
*
|
|
953
1087
|
* Accepts a directory string (triggers autoload), a static CommandMap,
|
|
954
|
-
* a Promise<CommandMap
|
|
1088
|
+
* a Promise<CommandMap>, a structured {@link CommandsConfig},
|
|
955
1089
|
* or undefined (loads `kidd.config.ts` and autoloads from its `commands` field,
|
|
956
1090
|
* falling back to `'./commands'`).
|
|
957
1091
|
*
|
|
958
1092
|
* @private
|
|
959
1093
|
* @param commands - The commands option from CliOptions.
|
|
960
|
-
* @returns
|
|
1094
|
+
* @returns Resolved commands with optional order, or undefined.
|
|
961
1095
|
*/
|
|
962
1096
|
async function resolveCommands(commands) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
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
|
+
};
|
|
967
1115
|
}
|
|
968
1116
|
/**
|
|
969
1117
|
* Load `kidd.config.ts` and autoload commands from its `commands` field.
|
|
@@ -977,8 +1125,8 @@ async function resolveCommands(commands) {
|
|
|
977
1125
|
async function resolveCommandsFromConfig() {
|
|
978
1126
|
const DEFAULT_COMMANDS_DIR = "./commands";
|
|
979
1127
|
const [configError, configResult] = await loadConfig();
|
|
980
|
-
if (configError || !configResult) return autoload({ dir: DEFAULT_COMMANDS_DIR });
|
|
981
|
-
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 }) };
|
|
982
1130
|
}
|
|
983
1131
|
/**
|
|
984
1132
|
* Change the process working directory when `--cwd` is provided.
|
|
@@ -993,6 +1141,47 @@ function applyCwd(argv) {
|
|
|
993
1141
|
if (isString(argv.cwd)) process.chdir(resolve(argv.cwd));
|
|
994
1142
|
}
|
|
995
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
|
+
/**
|
|
996
1185
|
* Handle a CLI error by logging the message and exiting with the appropriate code.
|
|
997
1186
|
*
|
|
998
1187
|
* ContextErrors carry a custom exit code; all other errors exit with code 1.
|
|
@@ -1002,34 +1191,69 @@ function applyCwd(argv) {
|
|
|
1002
1191
|
* @param logger - Logger with an error method for output.
|
|
1003
1192
|
*/
|
|
1004
1193
|
function exitOnError(error, logger) {
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1194
|
+
const info = match(error).when(isContextError, (e) => ({
|
|
1195
|
+
exitCode: e.exitCode,
|
|
1196
|
+
message: e.message
|
|
1197
|
+
})).with(P.instanceOf(Error), (e) => ({
|
|
1198
|
+
exitCode: 1,
|
|
1199
|
+
message: e.message
|
|
1200
|
+
})).otherwise((e) => ({
|
|
1201
|
+
exitCode: 1,
|
|
1202
|
+
message: String(e)
|
|
1203
|
+
}));
|
|
1204
|
+
logger.error(info.message);
|
|
1205
|
+
process.exit(info.exitCode);
|
|
1015
1206
|
}
|
|
1016
|
-
|
|
1017
1207
|
//#endregion
|
|
1018
|
-
//#region src/
|
|
1208
|
+
//#region src/compose.ts
|
|
1019
1209
|
/**
|
|
1020
|
-
*
|
|
1210
|
+
* Middleware combinator that merges multiple middleware into one.
|
|
1021
1211
|
*
|
|
1022
|
-
*
|
|
1023
|
-
|
|
1024
|
-
|
|
1212
|
+
* @module
|
|
1213
|
+
*/
|
|
1214
|
+
/**
|
|
1215
|
+
* Compose multiple middleware into a single middleware.
|
|
1025
1216
|
*
|
|
1026
|
-
*
|
|
1027
|
-
*
|
|
1217
|
+
* Executes each middleware in order, threading `next()` through the chain.
|
|
1218
|
+
* The final `next()` call from the last composed middleware continues to
|
|
1219
|
+
* the downstream middleware or command handler.
|
|
1220
|
+
*
|
|
1221
|
+
* The returned middleware's type merges all `Variables` from the input tuple,
|
|
1222
|
+
* so downstream handlers see the combined context.
|
|
1223
|
+
*
|
|
1224
|
+
* @param middlewares - An ordered tuple of middleware to compose.
|
|
1225
|
+
* @returns A single Middleware whose Variables is the intersection of all input Variables.
|
|
1226
|
+
*
|
|
1227
|
+
* @example
|
|
1228
|
+
* ```ts
|
|
1229
|
+
* const combined = compose([auth({ strategies: [auth.env()] }), auth.require()])
|
|
1230
|
+
* ```
|
|
1028
1231
|
*/
|
|
1029
|
-
function
|
|
1030
|
-
return
|
|
1232
|
+
function compose(middlewares) {
|
|
1233
|
+
return middleware((ctx, next) => executeChain(middlewares, 0, ctx, next));
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Recursively execute middleware in order, calling next() after the last one.
|
|
1237
|
+
*
|
|
1238
|
+
* @private
|
|
1239
|
+
* @param middlewares - The middleware array.
|
|
1240
|
+
* @param index - Current position in the array.
|
|
1241
|
+
* @param ctx - The context object.
|
|
1242
|
+
* @param next - The downstream next function.
|
|
1243
|
+
*/
|
|
1244
|
+
async function executeChain(middlewares, index, ctx, next) {
|
|
1245
|
+
if (index >= middlewares.length) {
|
|
1246
|
+
await next();
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
const mw = middlewares[index];
|
|
1250
|
+
if (mw === void 0) {
|
|
1251
|
+
await next();
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
await mw.handler(ctx, () => executeChain(middlewares, index + 1, ctx, next));
|
|
1031
1255
|
}
|
|
1032
|
-
|
|
1033
1256
|
//#endregion
|
|
1034
|
-
export { autoload, cli, command, decorateContext, defineConfig, middleware };
|
|
1257
|
+
export { autoload, cli, command, compose, decorateContext, defineConfig, middleware };
|
|
1258
|
+
|
|
1035
1259
|
//# sourceMappingURL=index.js.map
|