@shell-shock/core 0.17.21 → 0.17.23
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 +16 -7
- package/dist/api.cjs +4 -5
- package/dist/api.d.cts +1 -1
- package/dist/api.d.mts +1 -1
- package/dist/api.mjs +2 -2
- package/dist/command-B6KYexlV.d.mts +308 -0
- package/dist/command-B6KYexlV.d.mts.map +1 -0
- package/dist/command-CtfR7hKM.d.cts +308 -0
- package/dist/command-CtfR7hKM.d.cts.map +1 -0
- package/dist/components/command-validation-logic.cjs +153 -216
- package/dist/components/command-validation-logic.d.cts +2 -1
- package/dist/components/command-validation-logic.d.cts.map +1 -1
- package/dist/components/command-validation-logic.d.mts +2 -1
- package/dist/components/command-validation-logic.mjs +153 -214
- package/dist/components/docs.cjs +6 -364
- package/dist/components/docs.d.cts +2 -3
- package/dist/components/docs.d.cts.map +1 -1
- package/dist/components/docs.d.mts +2 -3
- package/dist/components/docs.mjs +2 -356
- package/dist/components/exec-builtin.cjs +63 -100
- package/dist/components/exec-builtin.d.cts +1 -2
- package/dist/components/exec-builtin.d.cts.map +1 -1
- package/dist/components/exec-builtin.d.mts +1 -2
- package/dist/components/exec-builtin.mjs +7 -41
- package/dist/components/helpers.cjs +2 -52
- package/dist/components/helpers.d.cts +2 -1
- package/dist/components/helpers.d.cts.map +1 -1
- package/dist/components/helpers.d.mts +2 -1
- package/dist/components/helpers.mjs +2 -50
- package/dist/components/index.cjs +7 -23
- package/dist/components/index.mjs +9 -9
- package/dist/components/options-parser-logic.cjs +198 -420
- package/dist/components/options-parser-logic.d.cts +2 -5
- package/dist/components/options-parser-logic.d.cts.map +1 -1
- package/dist/components/options-parser-logic.d.mts +2 -5
- package/dist/components/options-parser-logic.mjs +192 -407
- package/dist/components/state-builtin.cjs +106 -164
- package/dist/components/state-builtin.d.cts +1 -2
- package/dist/components/state-builtin.d.cts.map +1 -1
- package/dist/components/state-builtin.d.mts +1 -2
- package/dist/components/state-builtin.mjs +12 -68
- package/dist/components/usage.cjs +4 -48
- package/dist/components/usage.d.cts +1 -2
- package/dist/components/usage.d.cts.map +1 -1
- package/dist/components/usage.d.mts +1 -2
- package/dist/components/usage.mjs +4 -46
- package/dist/components/utils-builtin.cjs +77 -144
- package/dist/components/utils-builtin.d.cts +1 -2
- package/dist/components/utils-builtin.d.cts.map +1 -1
- package/dist/components/utils-builtin.d.mts +1 -2
- package/dist/components/utils-builtin.mjs +9 -74
- package/dist/config-BIF9mEz0.d.cts +157 -0
- package/dist/config-BIF9mEz0.d.cts.map +1 -0
- package/dist/config-CnNYdfsL.d.mts +157 -0
- package/dist/config-CnNYdfsL.d.mts.map +1 -0
- package/dist/config.cjs +24 -58
- package/dist/config.d.cts +1 -2
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +1 -2
- package/dist/config.mjs +23 -55
- package/dist/{plugin-utils/context-helpers.mjs → context-helpers-D3EJxwbq.mjs} +5 -83
- package/dist/context-helpers-D3EJxwbq.mjs.map +1 -0
- package/dist/{plugin-utils/context-helpers.cjs → context-helpers-_wUuFRB8.cjs} +63 -92
- package/dist/contexts/command.cjs +3 -9
- package/dist/contexts/command.d.cts +1 -2
- package/dist/contexts/command.d.cts.map +1 -1
- package/dist/contexts/command.d.mts +1 -2
- package/dist/contexts/command.mjs +2 -7
- package/dist/contexts/index.cjs +19 -1
- package/dist/contexts/index.d.cts +2 -1
- package/dist/contexts/index.d.mts +2 -1
- package/dist/contexts/index.mjs +2 -1
- package/dist/contexts/options.cjs +7 -30
- package/dist/contexts/options.d.cts +1 -2
- package/dist/contexts/options.d.cts.map +1 -1
- package/dist/contexts/options.d.mts +1 -2
- package/dist/contexts/options.mjs +7 -27
- package/dist/contexts/power-plant.cjs +19 -0
- package/dist/contexts/power-plant.d.cts +2 -0
- package/dist/contexts/power-plant.d.mts +2 -0
- package/dist/contexts/power-plant.mjs +5 -0
- package/dist/docs-C6ZvsVMu.cjs +278 -0
- package/dist/docs-CGQ2HtEY.mjs +249 -0
- package/dist/docs-CGQ2HtEY.mjs.map +1 -0
- package/dist/engine.cjs +5 -39
- package/dist/engine.d.cts +1 -2
- package/dist/engine.d.cts.map +1 -1
- package/dist/engine.d.mts +1 -2
- package/dist/engine.mjs +4 -37
- package/dist/generator.cjs +68 -0
- package/dist/generator.d.cts +15 -0
- package/dist/generator.d.cts.map +1 -0
- package/dist/generator.d.mts +15 -0
- package/dist/generator.d.mts.map +1 -0
- package/dist/generator.mjs +66 -0
- package/dist/generator.mjs.map +1 -0
- package/dist/{helpers/get-framework.cjs → get-framework-CxZc2krd.cjs} +7 -8
- package/dist/{helpers/get-framework.mjs → get-framework-Dlqz2hVZ.mjs} +3 -8
- package/dist/get-framework-Dlqz2hVZ.mjs.map +1 -0
- package/dist/helpers/power-plant.cjs +102 -0
- package/dist/helpers/power-plant.d.cts +61 -0
- package/dist/helpers/power-plant.d.cts.map +1 -0
- package/dist/helpers/power-plant.d.mts +61 -0
- package/dist/helpers/power-plant.d.mts.map +1 -0
- package/dist/helpers/power-plant.mjs +99 -0
- package/dist/helpers/power-plant.mjs.map +1 -0
- package/dist/index-D4klH_pj.d.mts +2 -0
- package/dist/index-DYOBadKY.d.cts +2 -0
- package/dist/index.cjs +1 -37
- package/dist/index.d.cts +4 -6
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +4 -6
- package/dist/index.mjs +0 -35
- package/dist/package-B7Vu265G.mjs +6 -0
- package/dist/package-B7Vu265G.mjs.map +1 -0
- package/dist/{package.cjs → package-BLC4qc8t.cjs} +2 -4
- package/dist/plugin-B-hM2twc.mjs +1458 -0
- package/dist/plugin-B-hM2twc.mjs.map +1 -0
- package/dist/plugin-Bhfq0DMC.cjs +1490 -0
- package/dist/plugin-utils/index.cjs +359 -26
- package/dist/plugin-utils/index.d.cts +273 -9
- package/dist/plugin-utils/index.d.cts.map +1 -0
- package/dist/plugin-utils/index.d.mts +273 -9
- package/dist/plugin-utils/index.d.mts.map +1 -0
- package/dist/plugin-utils/index.mjs +346 -10
- package/dist/plugin-utils/index.mjs.map +1 -0
- package/dist/plugin.cjs +3 -496
- package/dist/plugin.d.cts +1 -3
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.mts +1 -3
- package/dist/plugin.mjs +2 -491
- package/dist/power-plant-LgxcvlMN.d.cts +4 -0
- package/dist/power-plant-LgxcvlMN.d.mts +4 -0
- package/dist/reflect-CSiffeL9.cjs +27 -0
- package/dist/reflect-DXKSFgvS.mjs +23 -0
- package/dist/reflect-DXKSFgvS.mjs.map +1 -0
- package/dist/schemas/env.cjs +91 -0
- package/dist/schemas/env.d.cts +145 -0
- package/dist/schemas/env.d.cts.map +1 -0
- package/dist/schemas/env.d.mts +145 -0
- package/dist/{types → schemas}/env.d.mts.map +1 -1
- package/dist/schemas/env.mjs +91 -0
- package/dist/schemas/index.cjs +4 -0
- package/dist/schemas/index.d.cts +2 -0
- package/dist/schemas/index.d.mts +2 -0
- package/dist/schemas/index.mjs +3 -0
- package/dist/types/command.cjs +0 -402
- package/dist/types/command.d.cts +2 -309
- package/dist/types/command.d.mts +2 -309
- package/dist/types/command.mjs +1 -368
- package/dist/types/config.cjs +0 -175
- package/dist/types/config.d.cts +2 -126
- package/dist/types/config.d.mts +2 -126
- package/dist/types/config.mjs +1 -164
- package/dist/types/context.cjs +0 -45
- package/dist/types/context.d.cts +2 -31
- package/dist/types/context.d.mts +2 -31
- package/dist/types/context.mjs +1 -41
- package/dist/types/index.cjs +3 -53
- package/dist/types/index.d.cts +4 -5
- package/dist/types/index.d.mts +4 -5
- package/dist/types/index.mjs +4 -5
- package/package.json +106 -42
- package/dist/_virtual/_rolldown/runtime.cjs +0 -29
- package/dist/api.cjs.map +0 -1
- package/dist/components/command-validation-logic.cjs.map +0 -1
- package/dist/components/docs.cjs.map +0 -1
- package/dist/components/docs.mjs.map +0 -1
- package/dist/components/exec-builtin.cjs.map +0 -1
- package/dist/components/helpers.cjs.map +0 -1
- package/dist/components/options-parser-logic.cjs.map +0 -1
- package/dist/components/state-builtin.cjs.map +0 -1
- package/dist/components/usage.cjs.map +0 -1
- package/dist/components/utils-builtin.cjs.map +0 -1
- package/dist/config.cjs.map +0 -1
- package/dist/contexts/command.cjs.map +0 -1
- package/dist/contexts/options.cjs.map +0 -1
- package/dist/engine.cjs.map +0 -1
- package/dist/helpers/automd.cjs +0 -193
- package/dist/helpers/automd.cjs.map +0 -1
- package/dist/helpers/automd.mjs +0 -190
- package/dist/helpers/automd.mjs.map +0 -1
- package/dist/helpers/docs-helpers.cjs +0 -24
- package/dist/helpers/docs-helpers.cjs.map +0 -1
- package/dist/helpers/docs-helpers.mjs +0 -24
- package/dist/helpers/docs-helpers.mjs.map +0 -1
- package/dist/helpers/get-framework.cjs.map +0 -1
- package/dist/helpers/get-framework.mjs.map +0 -1
- package/dist/helpers/paths.cjs +0 -137
- package/dist/helpers/paths.cjs.map +0 -1
- package/dist/helpers/paths.mjs +0 -134
- package/dist/helpers/paths.mjs.map +0 -1
- package/dist/helpers/persistence.cjs +0 -114
- package/dist/helpers/persistence.cjs.map +0 -1
- package/dist/helpers/persistence.mjs +0 -113
- package/dist/helpers/persistence.mjs.map +0 -1
- package/dist/helpers/update-package-json.cjs +0 -65
- package/dist/helpers/update-package-json.cjs.map +0 -1
- package/dist/helpers/update-package-json.mjs +0 -64
- package/dist/helpers/update-package-json.mjs.map +0 -1
- package/dist/helpers/utilities.cjs +0 -95
- package/dist/helpers/utilities.cjs.map +0 -1
- package/dist/helpers/utilities.mjs +0 -94
- package/dist/helpers/utilities.mjs.map +0 -1
- package/dist/helpers/validations.cjs +0 -71
- package/dist/helpers/validations.cjs.map +0 -1
- package/dist/helpers/validations.mjs +0 -70
- package/dist/helpers/validations.mjs.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/package.cjs.map +0 -1
- package/dist/package.mjs +0 -6
- package/dist/package.mjs.map +0 -1
- package/dist/plugin-utils/compute-bin.cjs +0 -49
- package/dist/plugin-utils/compute-bin.cjs.map +0 -1
- package/dist/plugin-utils/compute-bin.d.cts +0 -13
- package/dist/plugin-utils/compute-bin.d.cts.map +0 -1
- package/dist/plugin-utils/compute-bin.d.mts +0 -13
- package/dist/plugin-utils/compute-bin.d.mts.map +0 -1
- package/dist/plugin-utils/compute-bin.mjs +0 -49
- package/dist/plugin-utils/compute-bin.mjs.map +0 -1
- package/dist/plugin-utils/context-helpers.cjs.map +0 -1
- package/dist/plugin-utils/context-helpers.d.cts +0 -106
- package/dist/plugin-utils/context-helpers.d.cts.map +0 -1
- package/dist/plugin-utils/context-helpers.d.mts +0 -106
- package/dist/plugin-utils/context-helpers.d.mts.map +0 -1
- package/dist/plugin-utils/context-helpers.mjs.map +0 -1
- package/dist/plugin-utils/deepkit.cjs +0 -70
- package/dist/plugin-utils/deepkit.cjs.map +0 -1
- package/dist/plugin-utils/deepkit.d.cts +0 -23
- package/dist/plugin-utils/deepkit.d.cts.map +0 -1
- package/dist/plugin-utils/deepkit.d.mts +0 -23
- package/dist/plugin-utils/deepkit.d.mts.map +0 -1
- package/dist/plugin-utils/deepkit.mjs +0 -69
- package/dist/plugin-utils/deepkit.mjs.map +0 -1
- package/dist/plugin-utils/description-helpers.cjs +0 -112
- package/dist/plugin-utils/description-helpers.cjs.map +0 -1
- package/dist/plugin-utils/description-helpers.d.cts +0 -44
- package/dist/plugin-utils/description-helpers.d.cts.map +0 -1
- package/dist/plugin-utils/description-helpers.d.mts +0 -44
- package/dist/plugin-utils/description-helpers.d.mts.map +0 -1
- package/dist/plugin-utils/description-helpers.mjs +0 -108
- package/dist/plugin-utils/description-helpers.mjs.map +0 -1
- package/dist/plugin-utils/get-command-tree.cjs +0 -118
- package/dist/plugin-utils/get-command-tree.cjs.map +0 -1
- package/dist/plugin-utils/get-command-tree.d.cts +0 -36
- package/dist/plugin-utils/get-command-tree.d.cts.map +0 -1
- package/dist/plugin-utils/get-command-tree.d.mts +0 -36
- package/dist/plugin-utils/get-command-tree.d.mts.map +0 -1
- package/dist/plugin-utils/get-command-tree.mjs +0 -115
- package/dist/plugin-utils/get-command-tree.mjs.map +0 -1
- package/dist/plugin-utils/reflect.cjs +0 -54
- package/dist/plugin-utils/reflect.cjs.map +0 -1
- package/dist/plugin-utils/reflect.d.cts +0 -14
- package/dist/plugin-utils/reflect.d.cts.map +0 -1
- package/dist/plugin-utils/reflect.d.mts +0 -14
- package/dist/plugin-utils/reflect.d.mts.map +0 -1
- package/dist/plugin-utils/reflect.mjs +0 -53
- package/dist/plugin-utils/reflect.mjs.map +0 -1
- package/dist/plugin-utils/traverse-command-tree.cjs +0 -65
- package/dist/plugin-utils/traverse-command-tree.cjs.map +0 -1
- package/dist/plugin-utils/traverse-command-tree.d.cts +0 -22
- package/dist/plugin-utils/traverse-command-tree.d.cts.map +0 -1
- package/dist/plugin-utils/traverse-command-tree.d.mts +0 -22
- package/dist/plugin-utils/traverse-command-tree.d.mts.map +0 -1
- package/dist/plugin-utils/traverse-command-tree.mjs +0 -63
- package/dist/plugin-utils/traverse-command-tree.mjs.map +0 -1
- package/dist/plugin-utils/type-checks.cjs +0 -222
- package/dist/plugin-utils/type-checks.cjs.map +0 -1
- package/dist/plugin-utils/type-checks.d.cts +0 -41
- package/dist/plugin-utils/type-checks.d.cts.map +0 -1
- package/dist/plugin-utils/type-checks.d.mts +0 -41
- package/dist/plugin-utils/type-checks.d.mts.map +0 -1
- package/dist/plugin-utils/type-checks.mjs +0 -218
- package/dist/plugin-utils/type-checks.mjs.map +0 -1
- package/dist/plugin.cjs.map +0 -1
- package/dist/plugin.mjs.map +0 -1
- package/dist/resolver/deepkit.cjs +0 -110
- package/dist/resolver/deepkit.cjs.map +0 -1
- package/dist/resolver/deepkit.mjs +0 -109
- package/dist/resolver/deepkit.mjs.map +0 -1
- package/dist/resolver/helpers.cjs +0 -184
- package/dist/resolver/helpers.cjs.map +0 -1
- package/dist/resolver/helpers.mjs +0 -180
- package/dist/resolver/helpers.mjs.map +0 -1
- package/dist/resolver/resolve.cjs +0 -473
- package/dist/resolver/resolve.cjs.map +0 -1
- package/dist/resolver/resolve.mjs +0 -473
- package/dist/resolver/resolve.mjs.map +0 -1
- package/dist/types/command.cjs.map +0 -1
- package/dist/types/command.d.cts.map +0 -1
- package/dist/types/command.d.mts.map +0 -1
- package/dist/types/command.mjs.map +0 -1
- package/dist/types/config.cjs.map +0 -1
- package/dist/types/config.d.cts.map +0 -1
- package/dist/types/config.d.mts.map +0 -1
- package/dist/types/config.mjs.map +0 -1
- package/dist/types/context.cjs.map +0 -1
- package/dist/types/context.d.cts.map +0 -1
- package/dist/types/context.d.mts.map +0 -1
- package/dist/types/context.mjs.map +0 -1
- package/dist/types/env.cjs +0 -53
- package/dist/types/env.cjs.map +0 -1
- package/dist/types/env.d.cts +0 -71
- package/dist/types/env.d.cts.map +0 -1
- package/dist/types/env.d.mts +0 -71
- package/dist/types/env.mjs +0 -51
- /package/dist/{types → schemas}/env.mjs.map +0 -0
|
@@ -0,0 +1,1490 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
const require_docs = require('./docs-C6ZvsVMu.cjs');
|
|
29
|
+
const require_context_helpers = require('./context-helpers-_wUuFRB8.cjs');
|
|
30
|
+
const require_plugin_utils_index = require('./plugin-utils/index.cjs');
|
|
31
|
+
const require_helpers_power_plant = require('./helpers/power-plant.cjs');
|
|
32
|
+
const require_generator = require('./generator.cjs');
|
|
33
|
+
const require_get_framework = require('./get-framework-CxZc2krd.cjs');
|
|
34
|
+
let _alloy_js_core_jsx_runtime = require("@alloy-js/core/jsx-runtime");
|
|
35
|
+
let _alloy_js_core = require("@alloy-js/core");
|
|
36
|
+
let _power_plant_schema = require("@power-plant/schema");
|
|
37
|
+
let _powerlines_plugin_automd = require("@powerlines/plugin-automd");
|
|
38
|
+
let _powerlines_plugin_env_helpers_schema = require("@powerlines/plugin-env/helpers/schema");
|
|
39
|
+
let _powerlines_plugin_nodejs = require("@powerlines/plugin-nodejs");
|
|
40
|
+
let _powerlines_plugin_tsdown = require("@powerlines/plugin-tsdown");
|
|
41
|
+
let _stryke_convert_extract_file_reference = require("@stryke/convert/extract-file-reference");
|
|
42
|
+
let _stryke_convert_to_array = require("@stryke/convert/to-array");
|
|
43
|
+
let _stryke_fs_chmod_x = require("@stryke/fs/chmod-x");
|
|
44
|
+
let _stryke_path_append = require("@stryke/path/append");
|
|
45
|
+
let _stryke_path_find = require("@stryke/path/find");
|
|
46
|
+
let _stryke_path_is_parent_path = require("@stryke/path/is-parent-path");
|
|
47
|
+
let _stryke_path_join_paths = require("@stryke/path/join-paths");
|
|
48
|
+
let _stryke_path_replace = require("@stryke/path/replace");
|
|
49
|
+
let _stryke_path_resolve_parent_path = require("@stryke/path/resolve-parent-path");
|
|
50
|
+
let _stryke_string_format_camel_case = require("@stryke/string-format/camel-case");
|
|
51
|
+
let _stryke_string_format_constant_case = require("@stryke/string-format/constant-case");
|
|
52
|
+
let _stryke_string_format_kebab_case = require("@stryke/string-format/kebab-case");
|
|
53
|
+
let _stryke_type_checks_is_object = require("@stryke/type-checks/is-object");
|
|
54
|
+
let _stryke_type_checks_is_set_object = require("@stryke/type-checks/is-set-object");
|
|
55
|
+
let _stryke_type_checks_is_set_string = require("@stryke/type-checks/is-set-string");
|
|
56
|
+
let defu = require("defu");
|
|
57
|
+
let powerlines = require("powerlines");
|
|
58
|
+
let powerlines_utils = require("powerlines/utils");
|
|
59
|
+
let _alloy_js_markdown = require("@alloy-js/markdown");
|
|
60
|
+
let _power_plant_alloy_js_core_components_spacing = require("@power-plant/alloy-js/core/components/spacing");
|
|
61
|
+
let _stryke_string_format_title_case = require("@stryke/string-format/title-case");
|
|
62
|
+
let _powerlines_plugin_alloy_render = require("@powerlines/plugin-alloy/render");
|
|
63
|
+
let zod = require("zod");
|
|
64
|
+
let automd = require("automd");
|
|
65
|
+
let _stryke_fs_list_files = require("@stryke/fs/list-files");
|
|
66
|
+
let _stryke_path_common = require("@stryke/path/common");
|
|
67
|
+
let _stryke_path_file_path_fns = require("@stryke/path/file-path-fns");
|
|
68
|
+
let node_fs = require("node:fs");
|
|
69
|
+
let _powerlines_plugin_env_helpers = require("@powerlines/plugin-env/helpers");
|
|
70
|
+
let _stryke_helpers_get_unique = require("@stryke/helpers/get-unique");
|
|
71
|
+
let _stryke_json_storm_json = require("@stryke/json/storm-json");
|
|
72
|
+
let _stryke_cli_utils_tree = require("@stryke/cli/utils/tree");
|
|
73
|
+
let _stryke_type_checks_is_function = require("@stryke/type-checks/is-function");
|
|
74
|
+
let _stryke_json = require("@stryke/json");
|
|
75
|
+
let jiti = require("jiti");
|
|
76
|
+
let node_path = require("node:path");
|
|
77
|
+
let _stryke_type_checks_is_string = require("@stryke/type-checks/is-string");
|
|
78
|
+
let typescript = require("typescript");
|
|
79
|
+
typescript = __toESM(typescript, 1);
|
|
80
|
+
let node_fs_promises = require("node:fs/promises");
|
|
81
|
+
|
|
82
|
+
//#region src/helpers/automd.tsx
|
|
83
|
+
/**
|
|
84
|
+
* AutoMD generator to generate CLI command documentation
|
|
85
|
+
*
|
|
86
|
+
* @see https://automd.unjs.io/
|
|
87
|
+
*
|
|
88
|
+
* @param context - The generator context.
|
|
89
|
+
* @returns The generated documentation content.
|
|
90
|
+
*/
|
|
91
|
+
const commands = (context) => (0, automd.defineGenerator)({
|
|
92
|
+
name: "commands",
|
|
93
|
+
async generate(ctx) {
|
|
94
|
+
let commands = Object.values(context.commands).filter((cmd) => !cmd.virtual);
|
|
95
|
+
if (ctx.args.command) {
|
|
96
|
+
if (!context.commands[ctx.args.command]) throw new Error(`The command "${ctx.args.command}" does not exist in the application.`);
|
|
97
|
+
commands = [context.commands[ctx.args.command]];
|
|
98
|
+
}
|
|
99
|
+
return { contents: (0, _powerlines_plugin_alloy_render.renderString)(context, [
|
|
100
|
+
(0, _alloy_js_core_jsx_runtime.createComponent)(_alloy_js_core.Show, {
|
|
101
|
+
get when() {
|
|
102
|
+
return !ctx.args.command;
|
|
103
|
+
},
|
|
104
|
+
get children() {
|
|
105
|
+
return [
|
|
106
|
+
(0, _alloy_js_core_jsx_runtime.createComponent)(_alloy_js_markdown.Heading, {
|
|
107
|
+
level: 2,
|
|
108
|
+
children: "Commands"
|
|
109
|
+
}),
|
|
110
|
+
(0, _alloy_js_core_jsx_runtime.createComponent)(_power_plant_alloy_js_core_components_spacing.Spacing, {}),
|
|
111
|
+
(0, _alloy_js_core_jsx_runtime.memo)(() => _alloy_js_core.code`The following commands are available in the ${require_context_helpers.getAppTitle(context, true)} command-line interface application:`),
|
|
112
|
+
(0, _alloy_js_core_jsx_runtime.createComponent)(_power_plant_alloy_js_core_components_spacing.Spacing, {})
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
}),
|
|
116
|
+
(0, _alloy_js_core_jsx_runtime.createComponent)(_alloy_js_core.For, {
|
|
117
|
+
each: commands,
|
|
118
|
+
doubleHardline: true,
|
|
119
|
+
children: (child) => (0, _alloy_js_core_jsx_runtime.createComponent)(_alloy_js_core.Show, {
|
|
120
|
+
get when() {
|
|
121
|
+
return !child.virtual;
|
|
122
|
+
},
|
|
123
|
+
get children() {
|
|
124
|
+
return (0, _alloy_js_core_jsx_runtime.createComponent)(require_docs.CommandDocs, {
|
|
125
|
+
command: child,
|
|
126
|
+
levelOffset: 2
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
}),
|
|
131
|
+
(0, _alloy_js_core_jsx_runtime.createComponent)(_power_plant_alloy_js_core_components_spacing.Spacing, {})
|
|
132
|
+
]) };
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
/**
|
|
136
|
+
* AutoMD generator to generate usage examples for a specific command.
|
|
137
|
+
*
|
|
138
|
+
* @param context - The generator context.
|
|
139
|
+
* @returns The generated usage content.
|
|
140
|
+
*/
|
|
141
|
+
const usage = (context) => (0, automd.defineGenerator)({
|
|
142
|
+
name: "usage",
|
|
143
|
+
async generate(ctx) {
|
|
144
|
+
if (!ctx.args.command) throw new Error("The 'usage' generator requires the \"command\" argument.");
|
|
145
|
+
if (!context.commands[ctx.args.command]) throw new Error(`The command "${ctx.args.command}" does not exist in the application.`);
|
|
146
|
+
let packageManagers = [
|
|
147
|
+
"npm",
|
|
148
|
+
"yarn",
|
|
149
|
+
"pnpm",
|
|
150
|
+
"bun"
|
|
151
|
+
];
|
|
152
|
+
if (ctx.args.packageManager) packageManagers = [String(ctx.args.packageManager)];
|
|
153
|
+
if (packageManagers.some((pm) => ![
|
|
154
|
+
"npm",
|
|
155
|
+
"yarn",
|
|
156
|
+
"pnpm",
|
|
157
|
+
"bun"
|
|
158
|
+
].includes(pm))) throw new Error(`Invalid package manager specified. Supported package managers are: npm, yarn, pnpm, and bun.`);
|
|
159
|
+
return { contents: (0, _powerlines_plugin_alloy_render.renderString)(context, [(0, _alloy_js_core_jsx_runtime.createComponent)(_alloy_js_core.For, {
|
|
160
|
+
each: packageManagers,
|
|
161
|
+
doubleHardline: true,
|
|
162
|
+
children: (packageManager) => [(0, _alloy_js_core_jsx_runtime.createComponent)(require_docs.CommandDocsUsageExample, {
|
|
163
|
+
packageManager,
|
|
164
|
+
get command() {
|
|
165
|
+
return context.commands[ctx.args.command];
|
|
166
|
+
},
|
|
167
|
+
get expand() {
|
|
168
|
+
return packageManagers && packageManagers.length > 1;
|
|
169
|
+
}
|
|
170
|
+
})]
|
|
171
|
+
})]) };
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
/**
|
|
175
|
+
* AutoMD generator to generate options for a specific command.
|
|
176
|
+
*
|
|
177
|
+
* @param context - The generator context.
|
|
178
|
+
* @returns The generated options content.
|
|
179
|
+
*/
|
|
180
|
+
const options = (context) => (0, automd.defineGenerator)({
|
|
181
|
+
name: "options",
|
|
182
|
+
async generate(ctx) {
|
|
183
|
+
if (!ctx.args.command) throw new Error("The 'options' generator requires the \"command\" argument.");
|
|
184
|
+
if (!context.commands[ctx.args.command]) throw new Error(`The command "${ctx.args.command}" does not exist in the application.`);
|
|
185
|
+
return { contents: (0, _powerlines_plugin_alloy_render.renderString)(context, (0, _alloy_js_core_jsx_runtime.createComponent)(require_docs.CommandOptionsDocs, { get command() {
|
|
186
|
+
return context.commands[ctx.args.command];
|
|
187
|
+
} })) };
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
/**
|
|
191
|
+
* AutoMD generator to generate arguments for a specific command.
|
|
192
|
+
*
|
|
193
|
+
* @param context - The generator context.
|
|
194
|
+
* @returns The generated arguments content.
|
|
195
|
+
*/
|
|
196
|
+
const args = (context) => (0, automd.defineGenerator)({
|
|
197
|
+
name: "args",
|
|
198
|
+
async generate(ctx) {
|
|
199
|
+
if (!ctx.args.command) throw new Error("The 'args' generator requires the \"command\" argument.");
|
|
200
|
+
if (!context.commands[ctx.args.command]) throw new Error(`The command "${ctx.args.command}" does not exist in the application.`);
|
|
201
|
+
return { contents: (0, _powerlines_plugin_alloy_render.renderString)(context, (0, _alloy_js_core_jsx_runtime.createComponent)(require_docs.CommandArgumentDocs, { get command() {
|
|
202
|
+
return context.commands[ctx.args.command];
|
|
203
|
+
} })) };
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/helpers/paths.ts
|
|
209
|
+
function resolveCommandId(context, file) {
|
|
210
|
+
return (0, _stryke_path_replace.replacePath)((0, _stryke_path_file_path_fns.findFilePath)(file), context.commandsPath).split("/").filter((p) => Boolean(p) && !require_context_helpers.isDynamicPathSegment(p)).join("/").replaceAll(/^\/+/g, "").replaceAll(/\/+$/g, "").replaceAll("/", "-");
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Finds the command name from the given file path.
|
|
214
|
+
*
|
|
215
|
+
* @param file - The file path to extract the command name from.
|
|
216
|
+
* @returns The command name.
|
|
217
|
+
*/
|
|
218
|
+
function resolveCommandName(file) {
|
|
219
|
+
let path = (0, _stryke_path_file_path_fns.findFilePath)(file);
|
|
220
|
+
let name = (0, _stryke_path_file_path_fns.findFolderName)(file, { requireExtension: true });
|
|
221
|
+
while (require_context_helpers.isDynamicPathSegment(name)) {
|
|
222
|
+
path = (0, _stryke_path_resolve_parent_path.resolveParentPath)(path);
|
|
223
|
+
name = (0, _stryke_path_file_path_fns.findFolderName)(path, { requireExtension: true });
|
|
224
|
+
}
|
|
225
|
+
return name;
|
|
226
|
+
}
|
|
227
|
+
function resolveCommandPath(context, file) {
|
|
228
|
+
return (0, _stryke_path_replace.replacePath)((0, _stryke_path_file_path_fns.findFilePath)(file), context.commandsPath).replaceAll(/^\/+/g, "").replaceAll(/\/+$/g, "").split("/").filter((path) => path && !require_context_helpers.isPathSegmentGroup(path)).join("/");
|
|
229
|
+
}
|
|
230
|
+
async function findCommandsRoot(context) {
|
|
231
|
+
let paths = [];
|
|
232
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(context.config.input)) paths = await (0, _stryke_fs_list_files.listFiles)((0, _stryke_path_append.appendPath)((0, _stryke_path_append.appendPath)(context.config.input, context.config.root), context.config.cwd));
|
|
233
|
+
else if ((0, powerlines_utils.isFileReference)(context.config.input)) paths = await (0, _stryke_fs_list_files.listFiles)((0, _stryke_path_append.appendPath)((0, _stryke_path_append.appendPath)(context.config.input.file, context.config.root), context.config.cwd));
|
|
234
|
+
else if (Array.isArray(context.config.input) && context.config.input.length > 0) paths = (await Promise.all(context.config.input.map(async (input) => (0, _stryke_fs_list_files.listFiles)((0, _stryke_path_append.appendPath)((0, _stryke_path_append.appendPath)((0, _stryke_type_checks_is_set_string.isSetString)(input) ? input : input.file, context.config.root), context.config.cwd))))).flat();
|
|
235
|
+
else if ((0, _stryke_type_checks_is_set_object.isSetObject)(context.config.input)) paths = (await Promise.all(Object.values(context.config.input).map(async (input) => Array.isArray(input) ? (await Promise.all(input.map(async (i) => (0, _stryke_fs_list_files.listFiles)((0, _stryke_path_append.appendPath)((0, _stryke_path_append.appendPath)((0, _stryke_type_checks_is_set_string.isSetString)(i) ? i : i.file, context.config.root), context.config.cwd))))).flat() : (0, _stryke_fs_list_files.listFiles)((0, _stryke_path_append.appendPath)((0, _stryke_path_append.appendPath)((0, _stryke_type_checks_is_set_string.isSetString)(input) ? input : input.file, context.config.root), context.config.cwd))))).flat();
|
|
236
|
+
if (paths.length > 0) return (0, _stryke_path_common.commonPath)(paths.map((p) => (0, _stryke_path_file_path_fns.findFilePath)(p)));
|
|
237
|
+
let commandsPath = (0, _stryke_path_join_paths.joinPaths)(context.config.root, "src/commands");
|
|
238
|
+
if (!(0, node_fs.existsSync)(commandsPath)) {
|
|
239
|
+
commandsPath = (0, _stryke_path_join_paths.joinPaths)(context.config.root, "commands");
|
|
240
|
+
if (!(0, node_fs.existsSync)(commandsPath)) {
|
|
241
|
+
commandsPath = (0, _stryke_path_join_paths.joinPaths)(context.config.root, "src");
|
|
242
|
+
if (!(0, node_fs.existsSync)(commandsPath)) commandsPath = context.config.root;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
paths = (await Promise.all([(0, _stryke_fs_list_files.listFiles)((0, _stryke_path_join_paths.joinPaths)((0, _stryke_path_append.appendPath)(commandsPath, context.config.cwd), "**/command.ts")), (0, _stryke_fs_list_files.listFiles)((0, _stryke_path_join_paths.joinPaths)((0, _stryke_path_append.appendPath)(commandsPath, context.config.cwd), "**/command.tsx"))])).flat();
|
|
246
|
+
if (paths.length > 0) return (0, _stryke_path_common.commonPath)(paths.map((p) => (0, _stryke_path_file_path_fns.findFilePath)(p)));
|
|
247
|
+
return (0, _stryke_path_append.appendPath)(commandsPath, context.config.cwd);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/helpers/persistence.ts
|
|
252
|
+
function serialize(command) {
|
|
253
|
+
return {
|
|
254
|
+
...command,
|
|
255
|
+
parent: command.parent?.name ? command.parent.name : null,
|
|
256
|
+
children: Object.fromEntries(Object.entries(command.children || {}).map(([name, child]) => [name, serialize(child)]))
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function deserialize(command, parent = null) {
|
|
260
|
+
const result = {
|
|
261
|
+
...command,
|
|
262
|
+
parent: parent ?? null,
|
|
263
|
+
children: {}
|
|
264
|
+
};
|
|
265
|
+
result.children = Object.fromEntries(Object.entries(command.children || {}).map(([name, child]) => [name, deserialize(child, result)]));
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Gets the file path for persisting CLI command reflections.
|
|
270
|
+
*
|
|
271
|
+
* @param context - The Shell Shock context.
|
|
272
|
+
* @returns The file path for persisting CLI command reflections.
|
|
273
|
+
*/
|
|
274
|
+
function getCommandsPersistencePath(context) {
|
|
275
|
+
return (0, _stryke_path_join_paths.joinPaths)(context.dataPath, "reflections", "commands.json");
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Reads the persisted CLI command reflections from the file system and populates the context's commands.
|
|
279
|
+
*
|
|
280
|
+
* @param context - The Shell Shock context.
|
|
281
|
+
* @throws Will throw an error if the reflections file is empty or cannot be read.
|
|
282
|
+
*/
|
|
283
|
+
async function readCommandsPersistence(context) {
|
|
284
|
+
const reflections = await context.fs.read(getCommandsPersistencePath(context));
|
|
285
|
+
if (!reflections || !reflections.length) throw new Error(`CLI Command reflection file ${getCommandsPersistencePath(context)} is empty`);
|
|
286
|
+
context.commands = Object.fromEntries(Object.entries(JSON.parse(reflections) ?? {}).map(([name, command]) => [name, deserialize(command)]));
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Writes the current CLI command reflections from the context to the file system for persistence.
|
|
290
|
+
*
|
|
291
|
+
* @param context - The Shell Shock context.
|
|
292
|
+
* @returns A promise that resolves when the reflections have been successfully written to the file system.
|
|
293
|
+
* @throws Will throw an error if there is an issue writing the reflections to the file system.
|
|
294
|
+
*/
|
|
295
|
+
async function writeCommandsPersistence(context) {
|
|
296
|
+
const filePath = getCommandsPersistencePath(context);
|
|
297
|
+
await (0, _powerlines_plugin_env_helpers.writeEnv)(context);
|
|
298
|
+
await context.fs.write(filePath, JSON.stringify(Object.fromEntries(Object.entries(context.commands).map(([name, command]) => [name, serialize(command)])), null, context.config.mode === "production" ? 0 : 2));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region src/helpers/update-package-json.ts
|
|
303
|
+
function formatBinaryPath(format) {
|
|
304
|
+
return `./dist/bin.${format === "cjs" || Array.isArray(format) && format.includes("cjs") ? "cjs" : "mjs"}`;
|
|
305
|
+
}
|
|
306
|
+
async function updatePackageJsonBinary(context) {
|
|
307
|
+
const packageJsonPath = (0, _stryke_path_join_paths.joinPaths)(context.config.cwd, context.config.root, "package.json");
|
|
308
|
+
if (!context.packageJson) {
|
|
309
|
+
const packageJson = await context.fs.read(packageJsonPath);
|
|
310
|
+
if (packageJson) context.packageJson ??= JSON.parse(packageJson);
|
|
311
|
+
}
|
|
312
|
+
if (context.packageJson) {
|
|
313
|
+
if (context.config.bin && Array.isArray(context.config.bin) && context.config.bin.length > 0) {
|
|
314
|
+
context.packageJson.bin = Object.fromEntries((0, _stryke_helpers_get_unique.getUnique)((0, _stryke_convert_to_array.toArray)(context.config.bin)).map((bin) => [bin, formatBinaryPath(context.config.output.format)]));
|
|
315
|
+
await context.fs.write(packageJsonPath, _stryke_json_storm_json.StormJSON.stringify(context.packageJson));
|
|
316
|
+
} else {
|
|
317
|
+
if (Array.isArray(context.config.output.format) && context.config.output.format.length > 1) {
|
|
318
|
+
context.packageJson.bin = { [(0, _stryke_string_format_kebab_case.kebabCase)(require_context_helpers.getAppName(context))]: formatBinaryPath((0, _stryke_convert_to_array.toArray)(context.config.output.format)[0]) };
|
|
319
|
+
context.packageJson.bin = (0, _stryke_convert_to_array.toArray)(context.config.output.format).reduce((ret, format) => {
|
|
320
|
+
ret[`${(0, _stryke_string_format_kebab_case.kebabCase)(require_context_helpers.getAppName(context))}-${format}`] = formatBinaryPath(format);
|
|
321
|
+
return ret;
|
|
322
|
+
}, context.packageJson.bin);
|
|
323
|
+
} else context.packageJson.bin = { [(0, _stryke_string_format_kebab_case.kebabCase)(require_context_helpers.getAppName(context))]: formatBinaryPath(context.config.output.format) };
|
|
324
|
+
await context.fs.write(packageJsonPath, _stryke_json_storm_json.StormJSON.stringify(context.packageJson));
|
|
325
|
+
}
|
|
326
|
+
if (!(0, _stryke_type_checks_is_set_object.isSetObject)(context.packageJson.bin)) throw new Error("Unable to determine the CLI binary name. Please specify the `bin` option in your Shell Shock configuration or ensure that the `name` field is set in your package.json.");
|
|
327
|
+
context.config.bin = context.packageJson.bin;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/helpers/utilities.ts
|
|
333
|
+
function innerFormatCommandTree(command) {
|
|
334
|
+
return {
|
|
335
|
+
name: `${command.name}${command.virtual ? " (virtual)" : ""}`,
|
|
336
|
+
children: Object.values(command.children ?? {}).map(innerFormatCommandTree)
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function formatCommandTree(context) {
|
|
340
|
+
return (0, _stryke_cli_utils_tree.formatTree)({
|
|
341
|
+
name: context.config.name,
|
|
342
|
+
children: Object.values(context.commands ?? {}).map(innerFormatCommandTree)
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Retrieves the global command options based on the context configuration.
|
|
347
|
+
*
|
|
348
|
+
* @param context - The build context.
|
|
349
|
+
* @param command - The command for which to retrieve global options.
|
|
350
|
+
* @returns A record of global command options.
|
|
351
|
+
*/
|
|
352
|
+
function getGlobalOptions(context, command) {
|
|
353
|
+
let options;
|
|
354
|
+
if (Array.isArray(context.config.globalOptions)) options = Object.fromEntries((0, _stryke_helpers_get_unique.getUniqueBy)(context.config.globalOptions, (item) => item.name).map((option) => [option.name, option]));
|
|
355
|
+
else if ((0, _stryke_type_checks_is_function.isFunction)(context.config.globalOptions)) options = Object.fromEntries((0, _stryke_helpers_get_unique.getUniqueBy)(context.config.globalOptions(context, command), (item) => item.name).map((option) => [option.name, option]));
|
|
356
|
+
else options = {};
|
|
357
|
+
return Object.fromEntries(Object.entries(options).map(([key, value]) => [key, {
|
|
358
|
+
...value,
|
|
359
|
+
env: value.env ?? (0, _stryke_string_format_constant_case.constantCase)(key)
|
|
360
|
+
}]));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region src/helpers/validations.ts
|
|
365
|
+
function validateArguments(command) {
|
|
366
|
+
const failures = [];
|
|
367
|
+
let sequential = false;
|
|
368
|
+
for (const argument of command.args ?? []) if ((argument.type === "string" || argument.type === "number") && argument.variadic) {
|
|
369
|
+
if (!sequential) sequential = true;
|
|
370
|
+
else failures.push({
|
|
371
|
+
code: "SEQUENTIAL_VARIADIC_ARGUMENTS",
|
|
372
|
+
details: `Sequential variadic arguments are not allowed - since the argument preceding ${argument.name} is variadic, it must not also be variadic.`
|
|
373
|
+
});
|
|
374
|
+
} else sequential = false;
|
|
375
|
+
return failures;
|
|
376
|
+
}
|
|
377
|
+
function validateOptions(command) {
|
|
378
|
+
const failures = [];
|
|
379
|
+
const optionNames = /* @__PURE__ */ new Set();
|
|
380
|
+
for (const option of Object.values(command.options ?? {})) {
|
|
381
|
+
if (optionNames.has(option.name)) failures.push({
|
|
382
|
+
code: "DUPLICATE_OPTION_NAME",
|
|
383
|
+
details: `Duplicate option name "${option.name}" found in command.`
|
|
384
|
+
});
|
|
385
|
+
optionNames.add(option.name);
|
|
386
|
+
for (const alias of option.alias) {
|
|
387
|
+
if (optionNames.has(alias)) failures.push({
|
|
388
|
+
code: "DUPLICATE_OPTION_ALIAS",
|
|
389
|
+
details: `Duplicate option name "${alias}" (an alias of "${option.name}") found in command.`
|
|
390
|
+
});
|
|
391
|
+
optionNames.add(alias);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return failures;
|
|
395
|
+
}
|
|
396
|
+
function validateCommand(command) {
|
|
397
|
+
const results = [];
|
|
398
|
+
let failures = validateOptions(command);
|
|
399
|
+
if (failures.length > 0) results.push(...failures);
|
|
400
|
+
failures = validateArguments(command);
|
|
401
|
+
if (failures.length > 0) results.push(...failures);
|
|
402
|
+
return results;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region src/resolver/helpers.ts
|
|
407
|
+
/**
|
|
408
|
+
* Resolves the description for a command option based on its reflection.
|
|
409
|
+
*
|
|
410
|
+
* @param name - The name of the command option.
|
|
411
|
+
* @param type - The reflection kind of the command option.
|
|
412
|
+
* @param required - Whether the command option is required.
|
|
413
|
+
* @param variadic - Whether the command option is variadic (i.e., an array).
|
|
414
|
+
* @param title - The title of the command option, if any.
|
|
415
|
+
* @param defaultValue - The default value of the command option, if any.
|
|
416
|
+
* @returns The resolved description for the command option.
|
|
417
|
+
*/
|
|
418
|
+
function resolveCommandOptionDescription(name, type, required = true, variadic = false, title, defaultValue) {
|
|
419
|
+
return `A${!required && !defaultValue ? "n optional" : ""} command-line ${type === "boolean" ? "flag" : "option"} that allows the user to ${type === "boolean" ? "set the" : variadic ? "specify custom" : "specify a custom"} ${title?.trim() || (0, _stryke_string_format_title_case.titleCase)(name)} ${type === "boolean" ? "indicator" : `${type === "number" ? "numeric" : "string"} value${variadic ? "s" : ""}`}.`;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Resolves the description for a command argument based on its reflection.
|
|
423
|
+
*
|
|
424
|
+
* @param name - The name of the command argument.
|
|
425
|
+
* @param type - The reflection kind of the command argument.
|
|
426
|
+
* @param required - Whether the command argument is required.
|
|
427
|
+
* @param variadic - Whether the command argument is variadic (i.e., an array).
|
|
428
|
+
* @param title - The title of the command argument, if any.
|
|
429
|
+
* @param defaultValue - The default value of the command argument, if any.
|
|
430
|
+
* @returns The resolved description for the command argument.
|
|
431
|
+
*/
|
|
432
|
+
function resolveCommandArgumentDescription(name, type, required = true, variadic = false, title, defaultValue) {
|
|
433
|
+
return `An${!required && !defaultValue ? " optional" : ""} argument that allows the user to ${type === "boolean" ? "set the" : variadic ? "specify custom" : "specify a custom"} ${title?.trim() || (0, _stryke_string_format_title_case.titleCase)(name)} ${type === "boolean" ? "indicator" : `${type === "number" ? "numeric" : "string"} value${variadic ? "s" : ""}`}.`;
|
|
434
|
+
}
|
|
435
|
+
function applyOptionsDefaults(ctx) {
|
|
436
|
+
return Object.fromEntries(Object.entries(ctx.output.options).map(([key, option]) => {
|
|
437
|
+
const name = option.name || key;
|
|
438
|
+
const title = option.title || (0, _stryke_string_format_title_case.titleCase)(name);
|
|
439
|
+
return [key, {
|
|
440
|
+
...option,
|
|
441
|
+
name,
|
|
442
|
+
title,
|
|
443
|
+
description: option.description || resolveCommandOptionDescription(name, option.type, option.required, option.type !== "boolean" && option.variadic, title, option.default),
|
|
444
|
+
env: option.env || option.env === false ? option.env : ctx.input.context.config.autoAssignEnv ? (0, _stryke_string_format_constant_case.constantCase)(name) : false
|
|
445
|
+
}];
|
|
446
|
+
}));
|
|
447
|
+
}
|
|
448
|
+
function applyArgsDefaults(ctx) {
|
|
449
|
+
return ctx.output.args.map((arg, i) => {
|
|
450
|
+
const name = arg.name || `arg${i + 1}`;
|
|
451
|
+
const title = arg.title || (0, _stryke_string_format_title_case.titleCase)(name);
|
|
452
|
+
return {
|
|
453
|
+
...arg,
|
|
454
|
+
name,
|
|
455
|
+
title,
|
|
456
|
+
description: arg.description || resolveCommandArgumentDescription(name, arg.type, arg.required, arg.type !== "boolean" && arg.variadic, title, arg.default),
|
|
457
|
+
env: arg.name ? arg.env || arg.env === false ? arg.env : ctx.input.context.config.autoAssignEnv ? (0, _stryke_string_format_constant_case.constantCase)(name) : false : false
|
|
458
|
+
};
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
function applyDefaults(ctx) {
|
|
462
|
+
ctx.output.description ??= `The ${ctx.output.title.replace(/(?:c|C)ommands?$/, "").trim()} executable command-line interface.`;
|
|
463
|
+
if (ctx.input.command.segments.length && (0, _stryke_type_checks_is_set_string.isSetString)(ctx.input.context.config.docs?.commands) && /\{(?:(?:C|c)ommands?|(?:C|c)mds?)\}/.test(ctx.input.context.config.docs.commands)) ctx.output.docs ??= ctx.input.context.config.docs.commands ? ctx.input.context.config.docs.commands.replace(/\{(?:(?:C|c)ommands?|(?:C|c)mds?)\}/, ctx.input.command.segments.filter((segment) => !require_context_helpers.isDynamicPathSegment(segment)).join("/")) : void 0;
|
|
464
|
+
else if (!ctx.input.command.segments.length && (0, _stryke_type_checks_is_set_string.isSetString)(ctx.input.context.config.docs?.app)) ctx.output.docs ??= ctx.input.context.config.docs.app;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Resolves a virtual command by applying default values to its title and description based on the command name and application title.
|
|
468
|
+
*
|
|
469
|
+
* @template TContext - The type of the context object.
|
|
470
|
+
* @param ctx - The resolver context containing the input and output for the command resolution process.
|
|
471
|
+
*/
|
|
472
|
+
function resolveVirtualCommand(ctx) {
|
|
473
|
+
ctx.output.title ??= (0, _stryke_string_format_title_case.titleCase)(ctx.input.command.name);
|
|
474
|
+
ctx.output.description ??= `A collection of available ${ctx.output.title.replace(/(?:c|C)ommands?$/, "").trim() || (0, _stryke_string_format_title_case.titleCase)(ctx.input.command.name)} commands that are included in the ${require_context_helpers.getAppTitle(ctx.input.context, true)} command-line application.`;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Merges two command parameters, giving precedence to string values in the second configuration.
|
|
478
|
+
*
|
|
479
|
+
* @param objA - The first command parameter object.
|
|
480
|
+
* @param objB - The second command parameter object.
|
|
481
|
+
* @returns The merged command parameter object.
|
|
482
|
+
*/
|
|
483
|
+
const mergeCommandParameter = (0, defu.createDefu)((obj, key, value) => {
|
|
484
|
+
if ((0, _stryke_type_checks_is_string.isString)(obj[key]) && (0, _stryke_type_checks_is_string.isString)(value)) {
|
|
485
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(value)) obj[key] = value;
|
|
486
|
+
return true;
|
|
487
|
+
} else if (Array.isArray(obj[key]) && Array.isArray(value)) {
|
|
488
|
+
if (value.length > 0) obj[key] = (0, _stryke_helpers_get_unique.getUniqueBy)(obj[key].concat(value), (item) => (0, _stryke_type_checks_is_string.isString)(item) ? item : JSON.stringify(item));
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
return false;
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
//#endregion
|
|
495
|
+
//#region src/resolver/schema.ts
|
|
496
|
+
function getTypeNodeDescription(node) {
|
|
497
|
+
const docs = typescript.getJSDocCommentsAndTags(node).filter(typescript.isJSDoc);
|
|
498
|
+
for (const doc of docs) {
|
|
499
|
+
const comment = doc.comment;
|
|
500
|
+
if (!comment) continue;
|
|
501
|
+
const text = typeof comment === "string" ? comment.trim() : comment.map((part) => "text" in part ? part.text : "").join("").trim();
|
|
502
|
+
if (text) return text;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function findTypeDeclaration(sourceFile, typeName) {
|
|
506
|
+
for (const statement of sourceFile.statements) if ((typescript.isInterfaceDeclaration(statement) || typescript.isTypeAliasDeclaration(statement)) && statement.name.text === typeName) return statement;
|
|
507
|
+
}
|
|
508
|
+
function parseTypeNodeFromText(typeText) {
|
|
509
|
+
const statement = typescript.createSourceFile("__shell-shock-type.ts", `type __ShellShockType = ${typeText};`, typescript.ScriptTarget.Latest, true, typescript.ScriptKind.TS).statements[0];
|
|
510
|
+
if (statement && typescript.isTypeAliasDeclaration(statement)) return statement.type;
|
|
511
|
+
}
|
|
512
|
+
function membersToObjectSchema(members, lookupFile) {
|
|
513
|
+
const properties = {};
|
|
514
|
+
const required = [];
|
|
515
|
+
for (const member of members) {
|
|
516
|
+
if (!typescript.isPropertySignature(member) || !member.name || !member.type) continue;
|
|
517
|
+
const name = member.name.getText();
|
|
518
|
+
const schema = typeNodeToJsonSchema(member.type, lookupFile);
|
|
519
|
+
const description = getTypeNodeDescription(member);
|
|
520
|
+
properties[name] = description ? {
|
|
521
|
+
...schema,
|
|
522
|
+
description
|
|
523
|
+
} : schema;
|
|
524
|
+
if (!member.questionToken) required.push(name);
|
|
525
|
+
}
|
|
526
|
+
return {
|
|
527
|
+
type: "object",
|
|
528
|
+
properties,
|
|
529
|
+
...required.length > 0 ? { required } : {}
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
function typeNodeToJsonSchema(typeNode, lookupFile) {
|
|
533
|
+
if (typescript.isParenthesizedTypeNode(typeNode)) return typeNodeToJsonSchema(typeNode.type, lookupFile);
|
|
534
|
+
if (typeNode.kind === typescript.SyntaxKind.StringKeyword) return { type: "string" };
|
|
535
|
+
if (typeNode.kind === typescript.SyntaxKind.NumberKeyword || typeNode.kind === typescript.SyntaxKind.BigIntKeyword) return { type: "number" };
|
|
536
|
+
if (typeNode.kind === typescript.SyntaxKind.BooleanKeyword) return { type: "boolean" };
|
|
537
|
+
if (typescript.isLiteralTypeNode(typeNode)) {
|
|
538
|
+
const literal = typeNode.literal;
|
|
539
|
+
if (typescript.isStringLiteral(literal)) return {
|
|
540
|
+
type: "string",
|
|
541
|
+
enum: [literal.text]
|
|
542
|
+
};
|
|
543
|
+
if (typescript.isNumericLiteral(literal)) return {
|
|
544
|
+
type: "number",
|
|
545
|
+
enum: [Number(literal.text)]
|
|
546
|
+
};
|
|
547
|
+
if (literal.kind === typescript.SyntaxKind.TrueKeyword) return {
|
|
548
|
+
type: "boolean",
|
|
549
|
+
enum: [true]
|
|
550
|
+
};
|
|
551
|
+
if (literal.kind === typescript.SyntaxKind.FalseKeyword) return {
|
|
552
|
+
type: "boolean",
|
|
553
|
+
enum: [false]
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (typescript.isArrayTypeNode(typeNode)) return {
|
|
557
|
+
type: "array",
|
|
558
|
+
items: typeNodeToJsonSchema(typeNode.elementType, lookupFile)
|
|
559
|
+
};
|
|
560
|
+
if (typescript.isTypeOperatorNode(typeNode) && typeNode.operator === typescript.SyntaxKind.ReadonlyKeyword) return typeNodeToJsonSchema(typeNode.type, lookupFile);
|
|
561
|
+
if (typescript.isUnionTypeNode(typeNode)) {
|
|
562
|
+
const members = typeNode.types.filter((member) => member.kind !== typescript.SyntaxKind.UndefinedKeyword && member.kind !== typescript.SyntaxKind.NullKeyword);
|
|
563
|
+
if (members.length === 1 && members[0]) return typeNodeToJsonSchema(members[0], lookupFile);
|
|
564
|
+
const stringLiterals = members.map((member) => typescript.isLiteralTypeNode(member) && typescript.isStringLiteral(member.literal) ? member.literal.text : void 0);
|
|
565
|
+
if (stringLiterals.every(_stryke_type_checks_is_set_string.isSetString)) return {
|
|
566
|
+
type: "string",
|
|
567
|
+
enum: stringLiterals
|
|
568
|
+
};
|
|
569
|
+
const numberLiterals = members.map((member) => typescript.isLiteralTypeNode(member) && typescript.isNumericLiteral(member.literal) ? Number(member.literal.text) : void 0);
|
|
570
|
+
if (numberLiterals.every(isFiniteNumber)) return {
|
|
571
|
+
type: "number",
|
|
572
|
+
enum: numberLiterals
|
|
573
|
+
};
|
|
574
|
+
return { anyOf: members.map((member) => typeNodeToJsonSchema(member, lookupFile)) };
|
|
575
|
+
}
|
|
576
|
+
if (typescript.isTypeLiteralNode(typeNode)) return membersToObjectSchema(typeNode.members, lookupFile);
|
|
577
|
+
if (typescript.isTypeReferenceNode(typeNode)) {
|
|
578
|
+
const name = typeNode.typeName.getText();
|
|
579
|
+
if ((name === "Array" || name === "ReadonlyArray") && typeNode.typeArguments?.[0]) return {
|
|
580
|
+
type: "array",
|
|
581
|
+
items: typeNodeToJsonSchema(typeNode.typeArguments[0], lookupFile)
|
|
582
|
+
};
|
|
583
|
+
const declaration = findTypeDeclaration(lookupFile, name);
|
|
584
|
+
if (declaration) {
|
|
585
|
+
if (typescript.isInterfaceDeclaration(declaration)) return membersToObjectSchema(declaration.members, lookupFile);
|
|
586
|
+
return typeNodeToJsonSchema(declaration.type, lookupFile);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
throw new Error(`Unsupported TypeScript type "${typeNode.getText()}" for command schema extraction.`);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Generates a JSON Schema for a TypeScript type from the command source AST.
|
|
593
|
+
*
|
|
594
|
+
* @param filePath - Path to the TypeScript file containing the type.
|
|
595
|
+
* @param typeName - Named type to extract when available.
|
|
596
|
+
* @param typeText - Inline type text used when no named type exists.
|
|
597
|
+
*/
|
|
598
|
+
async function extractTypeSchema(filePath, typeName, typeText, sourceText) {
|
|
599
|
+
const sourceFile = typescript.createSourceFile(filePath, sourceText ?? (0, node_fs.readFileSync)(filePath, "utf8"), typescript.ScriptTarget.Latest, true, typescript.ScriptKind.TS);
|
|
600
|
+
if (typeName && /^[A-Z_][\w.]*$/i.test(typeName) && !typeName.includes(".")) {
|
|
601
|
+
const declaration = findTypeDeclaration(sourceFile, typeName);
|
|
602
|
+
if (declaration) {
|
|
603
|
+
if (typescript.isInterfaceDeclaration(declaration)) return membersToObjectSchema(declaration.members, sourceFile);
|
|
604
|
+
return typeNodeToJsonSchema(declaration.type, sourceFile);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
const typeNode = parseTypeNodeFromText(typeText);
|
|
608
|
+
if (!typeNode) throw new Error(`Unable to parse TypeScript type "${typeText}".`);
|
|
609
|
+
return typeNodeToJsonSchema(typeNode, sourceFile);
|
|
610
|
+
}
|
|
611
|
+
function asRecord(value) {
|
|
612
|
+
return (0, _stryke_type_checks_is_set_object.isSetObject)(value) ? value : {};
|
|
613
|
+
}
|
|
614
|
+
function isFiniteNumber(value) {
|
|
615
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
616
|
+
}
|
|
617
|
+
function toAliasList(value) {
|
|
618
|
+
if (Array.isArray(value)) return value.filter(_stryke_type_checks_is_set_string.isSetString);
|
|
619
|
+
if (!(0, _stryke_type_checks_is_set_string.isSetString)(value)) return [];
|
|
620
|
+
return value.split(/[,\s]+/).map((part) => part.trim()).filter(Boolean);
|
|
621
|
+
}
|
|
622
|
+
function parseTagDefault(value) {
|
|
623
|
+
if (!(0, _stryke_type_checks_is_set_string.isSetString)(value)) return;
|
|
624
|
+
const trimmed = value.trim();
|
|
625
|
+
if (!trimmed) return;
|
|
626
|
+
if (trimmed === "true") return true;
|
|
627
|
+
if (trimmed === "false") return false;
|
|
628
|
+
if (/^-?\d+(?:\.\d+)?$/.test(trimmed)) return Number(trimmed);
|
|
629
|
+
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
|
|
630
|
+
try {
|
|
631
|
+
return JSON.parse(trimmed);
|
|
632
|
+
} catch {
|
|
633
|
+
return trimmed;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Resolves the root schema definition when a generator returns a `$ref`.
|
|
638
|
+
*/
|
|
639
|
+
function dereferenceSchema(schema) {
|
|
640
|
+
const record = asRecord(schema);
|
|
641
|
+
const ref = record.$ref;
|
|
642
|
+
const definitions = asRecord(record.definitions);
|
|
643
|
+
const defs = asRecord(record.$defs);
|
|
644
|
+
if (!(0, _stryke_type_checks_is_set_string.isSetString)(ref)) return schema;
|
|
645
|
+
const key = decodeURIComponent(ref.replace(/^#\/(?:definitions|\$defs)\//, ""));
|
|
646
|
+
const resolved = definitions[key] ?? defs[key];
|
|
647
|
+
if (!(0, _stryke_type_checks_is_set_object.isSetObject)(resolved)) return schema;
|
|
648
|
+
return {
|
|
649
|
+
...resolved,
|
|
650
|
+
...Object.keys(definitions).length > 0 ? { definitions: record.definitions } : {},
|
|
651
|
+
...Object.keys(defs).length > 0 ? { $defs: record.$defs } : {}
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
function isObjectLikeSchema(schema) {
|
|
655
|
+
const resolved = dereferenceSchema(schema);
|
|
656
|
+
if (!(0, _power_plant_schema.isJsonSchemaObject)(resolved)) return false;
|
|
657
|
+
const record = asRecord(resolved);
|
|
658
|
+
return record.type === "object" || (0, _stryke_type_checks_is_set_object.isSetObject)(record.properties) || Array.isArray(record.allOf) || Array.isArray(record.anyOf) || Array.isArray(record.oneOf);
|
|
659
|
+
}
|
|
660
|
+
function inferParameterType(input) {
|
|
661
|
+
const schemaType = input.type;
|
|
662
|
+
if (Array.isArray(schemaType)) {
|
|
663
|
+
const first = schemaType.find((type) => type !== "null");
|
|
664
|
+
if (first === "integer" || first === "number") return "number";
|
|
665
|
+
if (first === "boolean") return "boolean";
|
|
666
|
+
if (first === "array") {
|
|
667
|
+
const nestedType = asRecord(input.items).type;
|
|
668
|
+
if (nestedType === "integer" || nestedType === "number") return "number";
|
|
669
|
+
if (nestedType === "boolean") return "boolean";
|
|
670
|
+
return "string";
|
|
671
|
+
}
|
|
672
|
+
return "string";
|
|
673
|
+
}
|
|
674
|
+
if (schemaType === "integer" || schemaType === "number") return "number";
|
|
675
|
+
if (schemaType === "boolean") return "boolean";
|
|
676
|
+
if (schemaType === "array") {
|
|
677
|
+
const nestedType = asRecord(input.items).type;
|
|
678
|
+
if (nestedType === "integer" || nestedType === "number") return "number";
|
|
679
|
+
if (nestedType === "boolean") return "boolean";
|
|
680
|
+
return "string";
|
|
681
|
+
}
|
|
682
|
+
if (Array.isArray(input.enum) && input.enum.length > 0) {
|
|
683
|
+
const first = input.enum.find((value) => value !== null);
|
|
684
|
+
if (isFiniteNumber(first)) return "number";
|
|
685
|
+
if (typeof first === "boolean") return "boolean";
|
|
686
|
+
}
|
|
687
|
+
if (isFiniteNumber(input.default)) return "number";
|
|
688
|
+
if (typeof input.default === "boolean") return "boolean";
|
|
689
|
+
return "string";
|
|
690
|
+
}
|
|
691
|
+
function inferVariadic(input) {
|
|
692
|
+
if (typeof input.variadic === "boolean") return input.variadic;
|
|
693
|
+
return input.type === "array";
|
|
694
|
+
}
|
|
695
|
+
function normalizeDefault(input, type, variadic) {
|
|
696
|
+
const defaultValue = input.default;
|
|
697
|
+
if (defaultValue === void 0) return;
|
|
698
|
+
if (type === "boolean") {
|
|
699
|
+
if (variadic) {
|
|
700
|
+
if (Array.isArray(defaultValue)) return defaultValue.filter((value) => typeof value === "boolean");
|
|
701
|
+
return typeof defaultValue === "boolean" ? [defaultValue] : void 0;
|
|
702
|
+
}
|
|
703
|
+
if (Array.isArray(defaultValue)) return defaultValue.find((value) => typeof value === "boolean");
|
|
704
|
+
return typeof defaultValue === "boolean" ? defaultValue : void 0;
|
|
705
|
+
}
|
|
706
|
+
if (type === "number") {
|
|
707
|
+
if (variadic) {
|
|
708
|
+
if (Array.isArray(defaultValue)) return defaultValue.map((item) => typeof item === "bigint" ? Number(item) : item).filter(isFiniteNumber);
|
|
709
|
+
const normalized = typeof defaultValue === "bigint" ? Number(defaultValue) : defaultValue;
|
|
710
|
+
return isFiniteNumber(normalized) ? [normalized] : void 0;
|
|
711
|
+
}
|
|
712
|
+
if (Array.isArray(defaultValue)) return defaultValue.map((item) => typeof item === "bigint" ? Number(item) : item).find(isFiniteNumber);
|
|
713
|
+
const normalized = typeof defaultValue === "bigint" ? Number(defaultValue) : defaultValue;
|
|
714
|
+
return isFiniteNumber(normalized) ? normalized : void 0;
|
|
715
|
+
}
|
|
716
|
+
if (variadic) {
|
|
717
|
+
if (Array.isArray(defaultValue)) return defaultValue.filter(_stryke_type_checks_is_set_string.isSetString);
|
|
718
|
+
return (0, _stryke_type_checks_is_set_string.isSetString)(defaultValue) ? [defaultValue] : void 0;
|
|
719
|
+
}
|
|
720
|
+
if (Array.isArray(defaultValue)) return defaultValue.find(_stryke_type_checks_is_set_string.isSetString);
|
|
721
|
+
return (0, _stryke_type_checks_is_set_string.isSetString)(defaultValue) ? defaultValue : void 0;
|
|
722
|
+
}
|
|
723
|
+
function normalizeStringChoices(input) {
|
|
724
|
+
const source = Array.isArray(input.choices) ? input.choices : input.enum;
|
|
725
|
+
if (!Array.isArray(source)) return;
|
|
726
|
+
return source.filter(_stryke_type_checks_is_set_string.isSetString);
|
|
727
|
+
}
|
|
728
|
+
function normalizeNumberChoices(input) {
|
|
729
|
+
const source = Array.isArray(input.choices) ? input.choices : input.enum;
|
|
730
|
+
if (!Array.isArray(source)) return;
|
|
731
|
+
return source.map((item) => typeof item === "bigint" ? Number(item) : item).filter(isFiniteNumber);
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Maps a JSON Schema fragment to a command option or argument.
|
|
735
|
+
*/
|
|
736
|
+
function resolveCommandParameter(schema, defaults) {
|
|
737
|
+
const input = asRecord(schema);
|
|
738
|
+
const type = inferParameterType(input);
|
|
739
|
+
const variadic = inferVariadic(input);
|
|
740
|
+
const defaultValue = normalizeDefault(input, type, variadic);
|
|
741
|
+
const required = typeof input.required === "boolean" ? input.required : defaultValue === void 0 ? defaults.fallbackRequired : false;
|
|
742
|
+
const env = (0, _stryke_type_checks_is_set_string.isSetString)(input.env) ? input.env : false;
|
|
743
|
+
const result = {
|
|
744
|
+
name: (0, _stryke_type_checks_is_set_string.isSetString)(input.name) ? input.name : "",
|
|
745
|
+
type,
|
|
746
|
+
title: (0, _stryke_type_checks_is_set_string.isSetString)(input.title) ? input.title : "",
|
|
747
|
+
description: (0, _stryke_type_checks_is_set_string.isSetString)(input.description) ? input.description : "",
|
|
748
|
+
alias: toAliasList(input.alias),
|
|
749
|
+
default: defaultValue,
|
|
750
|
+
env,
|
|
751
|
+
required,
|
|
752
|
+
variadic
|
|
753
|
+
};
|
|
754
|
+
if (type === "string") {
|
|
755
|
+
const stringChoices = normalizeStringChoices(input);
|
|
756
|
+
if (Array.isArray(stringChoices)) result.choices = stringChoices;
|
|
757
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(input.format)) result.format = input.format;
|
|
758
|
+
}
|
|
759
|
+
if (type === "number") {
|
|
760
|
+
const numberChoices = normalizeNumberChoices(input);
|
|
761
|
+
if (Array.isArray(numberChoices)) result.choices = numberChoices;
|
|
762
|
+
}
|
|
763
|
+
if (defaults.includeBooleanOptionFields && type === "boolean" && !variadic) {
|
|
764
|
+
const optionResult = result;
|
|
765
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(input.isNegativeOf)) optionResult.isNegativeOf = input.isNegativeOf;
|
|
766
|
+
if (typeof input.skipAddingNegative === "boolean") optionResult.skipAddingNegative = input.skipAddingNegative;
|
|
767
|
+
}
|
|
768
|
+
return result;
|
|
769
|
+
}
|
|
770
|
+
function applyMemberTags(property, tags) {
|
|
771
|
+
if (!tags) return property;
|
|
772
|
+
const next = { ...property };
|
|
773
|
+
if (tags.alias !== void 0) next.alias = toAliasList(tags.alias);
|
|
774
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(tags.title)) next.title = tags.title.trim();
|
|
775
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(tags.env)) next.env = tags.env;
|
|
776
|
+
if (next.default === void 0) {
|
|
777
|
+
const tagDefault = parseTagDefault(tags.default ?? tags.defaultValue);
|
|
778
|
+
if (tagDefault !== void 0) next.default = tagDefault;
|
|
779
|
+
}
|
|
780
|
+
return next;
|
|
781
|
+
}
|
|
782
|
+
function resolveArgumentFromSchema(ctx, index, parameter, schema) {
|
|
783
|
+
const existing = ctx.output.args.length > index ? ctx.output.args[index] : {};
|
|
784
|
+
const argument = resolveCommandParameter(applyMemberTags({
|
|
785
|
+
...asRecord(schema),
|
|
786
|
+
name: parameter.name,
|
|
787
|
+
description: parameter.description ?? asRecord(schema).description,
|
|
788
|
+
required: !parameter.optional,
|
|
789
|
+
variadic: parameter.rest || asRecord(schema).type === "array",
|
|
790
|
+
...parameter.defaultValue !== void 0 ? { default: parameter.defaultValue } : {},
|
|
791
|
+
...parameter.tags.alias !== void 0 ? { alias: toAliasList(parameter.tags.alias) } : {},
|
|
792
|
+
...(0, _stryke_type_checks_is_set_string.isSetString)(parameter.tags.title) ? { title: parameter.tags.title.trim() } : {},
|
|
793
|
+
...(0, _stryke_type_checks_is_set_string.isSetString)(parameter.tags.env) ? { env: parameter.tags.env } : {}
|
|
794
|
+
}, parameter.tags), {
|
|
795
|
+
fallbackRequired: !parameter.optional,
|
|
796
|
+
includeBooleanOptionFields: false
|
|
797
|
+
});
|
|
798
|
+
return mergeCommandParameter(existing, argument, { name: `arg${index}` });
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Resolves command options and arguments from a parsed TypeScript handler signature
|
|
802
|
+
* using {@link extractTypeSchema}.
|
|
803
|
+
*/
|
|
804
|
+
async function applySignatureParameters(ctx, filePath, signature) {
|
|
805
|
+
const parameters = signature?.parameters ?? [];
|
|
806
|
+
if (parameters.length === 0) return;
|
|
807
|
+
const first = parameters[0];
|
|
808
|
+
let hasOptions = false;
|
|
809
|
+
let optionsSchema;
|
|
810
|
+
if (first && !first.rest) {
|
|
811
|
+
optionsSchema = await extractTypeSchema(filePath, first.typeName, first.typeText, ctx.sourceText);
|
|
812
|
+
hasOptions = isObjectLikeSchema(optionsSchema);
|
|
813
|
+
}
|
|
814
|
+
if (hasOptions && !ctx.module?.options && optionsSchema && first) {
|
|
815
|
+
if (!(0, _power_plant_schema.isJsonSchemaObject)(optionsSchema)) throw new TypeError(`Unsupported options type for command "${ctx.input.command.name}". Expected an object type, received ${JSON.stringify(asRecord(optionsSchema).type ?? optionsSchema)}.`);
|
|
816
|
+
for (const property of (0, _power_plant_schema.getPropertiesList)(optionsSchema)) {
|
|
817
|
+
const tagged = applyMemberTags({
|
|
818
|
+
...asRecord(property),
|
|
819
|
+
name: property.name,
|
|
820
|
+
required: property.required
|
|
821
|
+
}, signature.typeMemberTags[property.name]);
|
|
822
|
+
const existing = ctx.output.options[property.name] ?? {};
|
|
823
|
+
const option = resolveCommandParameter(tagged, {
|
|
824
|
+
fallbackRequired: false,
|
|
825
|
+
includeBooleanOptionFields: true
|
|
826
|
+
});
|
|
827
|
+
ctx.output.options[property.name] = mergeCommandParameter(existing, option);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
if (!ctx.module?.args) {
|
|
831
|
+
const argumentParameters = hasOptions ? parameters.slice(1) : parameters;
|
|
832
|
+
ctx.output.args = await Promise.all(argumentParameters.map(async (parameter, index) => {
|
|
833
|
+
const schema = await extractTypeSchema(filePath, parameter.typeName, parameter.typeText, ctx.sourceText);
|
|
834
|
+
if (isObjectLikeSchema(schema) && asRecord(schema).type === "object" && !parameter.rest) throw new Error(`Unsupported type for positional argument "${parameter.name}" in command "${ctx.input.command.name}". Only string, number, boolean, string[], number[], or literal unions are supported, received object.`);
|
|
835
|
+
return resolveArgumentFromSchema(ctx, index, parameter, schema);
|
|
836
|
+
}));
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
//#endregion
|
|
841
|
+
//#region src/resolver/signature.ts
|
|
842
|
+
function getJSDocCommentText(comment) {
|
|
843
|
+
if (!comment) return;
|
|
844
|
+
if (typeof comment === "string") return comment.trim() || void 0;
|
|
845
|
+
return comment.map((part) => "text" in part ? part.text : "").join("").trim() || void 0;
|
|
846
|
+
}
|
|
847
|
+
function getJSDocTags(node) {
|
|
848
|
+
const tags = {};
|
|
849
|
+
for (const tag of typescript.getJSDocTags(node)) {
|
|
850
|
+
const name = tag.tagName.text;
|
|
851
|
+
const value = getJSDocCommentText(tag.comment) ?? "";
|
|
852
|
+
const existing = tags[name];
|
|
853
|
+
if (existing === void 0) tags[name] = value;
|
|
854
|
+
else if (Array.isArray(existing)) existing.push(value);
|
|
855
|
+
else tags[name] = [existing, value];
|
|
856
|
+
}
|
|
857
|
+
return tags;
|
|
858
|
+
}
|
|
859
|
+
function getNodeDescription(node) {
|
|
860
|
+
const docs = typescript.getJSDocCommentsAndTags(node).filter(typescript.isJSDoc);
|
|
861
|
+
for (const doc of docs) {
|
|
862
|
+
const text = getJSDocCommentText(doc.comment);
|
|
863
|
+
if (text) return text;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
function parseDefaultExpression(node) {
|
|
867
|
+
if (!node) return;
|
|
868
|
+
if (typescript.isStringLiteral(node) || typescript.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
869
|
+
if (node.kind === typescript.SyntaxKind.TrueKeyword) return true;
|
|
870
|
+
if (node.kind === typescript.SyntaxKind.FalseKeyword) return false;
|
|
871
|
+
if (typescript.isNumericLiteral(node)) return Number(node.text);
|
|
872
|
+
if (typescript.isPrefixUnaryExpression(node) && node.operator === typescript.SyntaxKind.MinusToken && typescript.isNumericLiteral(node.operand)) return -Number(node.operand.text);
|
|
873
|
+
if (typescript.isArrayLiteralExpression(node)) return node.elements.map((element) => typescript.isSpreadElement(element) ? void 0 : parseDefaultExpression(element)).filter((value) => value !== void 0);
|
|
874
|
+
if (typescript.isAsExpression(node) || typescript.isSatisfiesExpression(node)) return parseDefaultExpression(node.expression);
|
|
875
|
+
if (typescript.isParenthesizedExpression(node)) return parseDefaultExpression(node.expression);
|
|
876
|
+
}
|
|
877
|
+
function findFunctionByName(sourceFile, name) {
|
|
878
|
+
for (const statement of sourceFile.statements) {
|
|
879
|
+
if (typescript.isFunctionDeclaration(statement) && statement.name?.text === name) return statement;
|
|
880
|
+
if (typescript.isVariableStatement(statement)) {
|
|
881
|
+
for (const declaration of statement.declarationList.declarations) if (typescript.isIdentifier(declaration.name) && declaration.name.text === name && declaration.initializer && (typescript.isArrowFunction(declaration.initializer) || typescript.isFunctionExpression(declaration.initializer))) return declaration.initializer;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
function getDefaultExportFunction(sourceFile) {
|
|
886
|
+
for (const statement of sourceFile.statements) {
|
|
887
|
+
if (typescript.isFunctionDeclaration(statement) && statement.modifiers?.some((modifier) => modifier.kind === typescript.SyntaxKind.DefaultKeyword)) return statement;
|
|
888
|
+
if (typescript.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
889
|
+
if (typescript.isIdentifier(statement.expression)) return findFunctionByName(sourceFile, statement.expression.text);
|
|
890
|
+
if (typescript.isFunctionExpression(statement.expression) || typescript.isArrowFunction(statement.expression)) return statement.expression;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
function getParamName(parameter) {
|
|
895
|
+
if (typescript.isIdentifier(parameter.name)) return parameter.name.text;
|
|
896
|
+
return parameter.name.getText();
|
|
897
|
+
}
|
|
898
|
+
function collectTypeMemberTags(sourceFile, typeName) {
|
|
899
|
+
const result = {};
|
|
900
|
+
for (const statement of sourceFile.statements) {
|
|
901
|
+
if (typescript.isInterfaceDeclaration(statement) && statement.name.text === typeName) {
|
|
902
|
+
for (const member of statement.members) if (typescript.isPropertySignature(member) && member.name && typescript.isIdentifier(member.name)) result[member.name.text] = getJSDocTags(member);
|
|
903
|
+
}
|
|
904
|
+
if (typescript.isTypeAliasDeclaration(statement) && statement.name.text === typeName && typescript.isTypeLiteralNode(statement.type)) {
|
|
905
|
+
for (const member of statement.type.members) if (typescript.isPropertySignature(member) && member.name && typescript.isIdentifier(member.name)) result[member.name.text] = getJSDocTags(member);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return result;
|
|
909
|
+
}
|
|
910
|
+
function getParamDescriptions(functionNode) {
|
|
911
|
+
const descriptions = {};
|
|
912
|
+
for (const tag of typescript.getJSDocTags(functionNode)) if (tag.tagName.text === "param" && typescript.isJSDocParameterTag(tag) && tag.name && typescript.isIdentifier(tag.name)) {
|
|
913
|
+
const text = getJSDocCommentText(tag.comment);
|
|
914
|
+
if (text) descriptions[tag.name.text] = text;
|
|
915
|
+
}
|
|
916
|
+
return descriptions;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Parses the default-export command handler signature from a TypeScript source file.
|
|
920
|
+
*
|
|
921
|
+
* @param filePath - Absolute or relative path to the command entry file.
|
|
922
|
+
* @returns The parsed command signature, or `undefined` when no default export function is found.
|
|
923
|
+
*/
|
|
924
|
+
async function parseCommandSignature(filePath, sourceText) {
|
|
925
|
+
const sourceFile = typescript.createSourceFile(filePath, sourceText ?? await (0, node_fs_promises.readFile)(filePath, "utf8"), typescript.ScriptTarget.Latest, true, typescript.ScriptKind.TS);
|
|
926
|
+
const functionNode = getDefaultExportFunction(sourceFile);
|
|
927
|
+
if (!functionNode) return;
|
|
928
|
+
const paramDescriptions = getParamDescriptions(functionNode);
|
|
929
|
+
const parameters = functionNode.parameters.map((parameter) => {
|
|
930
|
+
const name = getParamName(parameter);
|
|
931
|
+
const typeNode = parameter.type;
|
|
932
|
+
const typeName = typeNode && typescript.isTypeReferenceNode(typeNode) ? typeNode.typeName.getText(sourceFile) : void 0;
|
|
933
|
+
const tags = getJSDocTags(parameter);
|
|
934
|
+
const description = getNodeDescription(parameter) || paramDescriptions[name] || ((0, _stryke_type_checks_is_set_string.isSetString)(tags.description) ? tags.description : void 0);
|
|
935
|
+
return {
|
|
936
|
+
name,
|
|
937
|
+
optional: Boolean(parameter.questionToken ?? parameter.initializer),
|
|
938
|
+
rest: Boolean(parameter.dotDotDotToken),
|
|
939
|
+
typeText: typeNode?.getText(sourceFile) ?? "unknown",
|
|
940
|
+
typeName,
|
|
941
|
+
description,
|
|
942
|
+
defaultValue: parseDefaultExpression(parameter.initializer),
|
|
943
|
+
tags
|
|
944
|
+
};
|
|
945
|
+
});
|
|
946
|
+
const firstNamedType = parameters.find((parameter) => parameter.typeName)?.typeName;
|
|
947
|
+
return {
|
|
948
|
+
description: getNodeDescription(functionNode),
|
|
949
|
+
parameters,
|
|
950
|
+
typeMemberTags: firstNamedType ? collectTypeMemberTags(sourceFile, firstNamedType) : {}
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
//#endregion
|
|
955
|
+
//#region src/resolver/resolve.ts
|
|
956
|
+
function toExtractableSchema(input) {
|
|
957
|
+
if ((0, _stryke_type_checks_is_set_object.isSetObject)(input) && "_zod" in input) return zod.z.toJSONSchema(input);
|
|
958
|
+
return input;
|
|
959
|
+
}
|
|
960
|
+
const CONSOLE_STUB_EXPORTS = [
|
|
961
|
+
"banner",
|
|
962
|
+
"blockquote",
|
|
963
|
+
"bold",
|
|
964
|
+
"code",
|
|
965
|
+
"cyan",
|
|
966
|
+
"debug",
|
|
967
|
+
"dim",
|
|
968
|
+
"divider",
|
|
969
|
+
"error",
|
|
970
|
+
"fatal",
|
|
971
|
+
"gray",
|
|
972
|
+
"green",
|
|
973
|
+
"help",
|
|
974
|
+
"info",
|
|
975
|
+
"inlineCode",
|
|
976
|
+
"italic",
|
|
977
|
+
"link",
|
|
978
|
+
"log",
|
|
979
|
+
"red",
|
|
980
|
+
"reset",
|
|
981
|
+
"shine",
|
|
982
|
+
"spinner",
|
|
983
|
+
"stripAnsi",
|
|
984
|
+
"success",
|
|
985
|
+
"table",
|
|
986
|
+
"trace",
|
|
987
|
+
"underline",
|
|
988
|
+
"warn",
|
|
989
|
+
"wrapAnsi",
|
|
990
|
+
"write",
|
|
991
|
+
"writeLine",
|
|
992
|
+
"yellow"
|
|
993
|
+
];
|
|
994
|
+
function stubExport(...args) {
|
|
995
|
+
return args[0] == null ? "" : args[0];
|
|
996
|
+
}
|
|
997
|
+
function createColorGroup() {
|
|
998
|
+
return {
|
|
999
|
+
primary: stubExport,
|
|
1000
|
+
secondary: stubExport,
|
|
1001
|
+
tertiary: stubExport
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
function createVirtualModuleStub(exportNames = CONSOLE_STUB_EXPORTS) {
|
|
1005
|
+
const stub = { textColors: {
|
|
1006
|
+
heading: createColorGroup(),
|
|
1007
|
+
body: createColorGroup(),
|
|
1008
|
+
message: createColorGroup()
|
|
1009
|
+
} };
|
|
1010
|
+
for (const name of exportNames) stub[name] = stubExport;
|
|
1011
|
+
stub.default = stub;
|
|
1012
|
+
return stub;
|
|
1013
|
+
}
|
|
1014
|
+
function resolveBuiltinAliases(context) {
|
|
1015
|
+
const builtinsDir = context.entryPath ? (0, node_path.join)((0, node_path.dirname)(context.entryPath), "builtins") : (0, node_path.join)(context.config.cwd, ".shell-shock", "builtins");
|
|
1016
|
+
if (!(0, node_fs.existsSync)(builtinsDir)) return {};
|
|
1017
|
+
const aliases = {};
|
|
1018
|
+
for (const file of (0, node_fs.readdirSync)(builtinsDir)) {
|
|
1019
|
+
if (!/\.(c|m)?tsx?$/.test(file)) continue;
|
|
1020
|
+
const name = file.replace(/\.(c|m)?tsx?$/, "");
|
|
1021
|
+
const absolutePath = (0, node_path.join)(builtinsDir, file);
|
|
1022
|
+
aliases[name] = absolutePath;
|
|
1023
|
+
aliases[`shell-shock:${name}`] = absolutePath;
|
|
1024
|
+
}
|
|
1025
|
+
return aliases;
|
|
1026
|
+
}
|
|
1027
|
+
function collectVirtualModules(source) {
|
|
1028
|
+
const consoleStub = createVirtualModuleStub();
|
|
1029
|
+
const modules = /* @__PURE__ */ new Map([
|
|
1030
|
+
["console", consoleStub],
|
|
1031
|
+
["shell-shock:console", consoleStub],
|
|
1032
|
+
["shell-shock:utils", createVirtualModuleStub()],
|
|
1033
|
+
["shell-shock:env", createVirtualModuleStub([
|
|
1034
|
+
"env",
|
|
1035
|
+
"isDevelopment",
|
|
1036
|
+
"isDebug"
|
|
1037
|
+
])],
|
|
1038
|
+
["shell-shock:state", createVirtualModuleStub(["hasFlag"])]
|
|
1039
|
+
]);
|
|
1040
|
+
for (const match of source.matchAll(/["'](shell-shock:[^"']+)["']/g)) {
|
|
1041
|
+
const id = match[1];
|
|
1042
|
+
if (id && !modules.has(id)) modules.set(id, createVirtualModuleStub());
|
|
1043
|
+
}
|
|
1044
|
+
for (const match of source.matchAll(/import\s+\{([^}]+)\}\s+from\s+["']((?:shell-shock:)?[^"']+)["']/g)) {
|
|
1045
|
+
const id = match[2];
|
|
1046
|
+
if (!id || !id.startsWith("shell-shock:") && id !== "console") continue;
|
|
1047
|
+
const stub = modules.get(id) ?? createVirtualModuleStub();
|
|
1048
|
+
for (const specifier of match[1]?.split(",") ?? []) {
|
|
1049
|
+
const exportName = specifier.trim().split(/\s+as\s+/)[0]?.trim();
|
|
1050
|
+
if (exportName && !(exportName in stub)) stub[exportName] = stubExport;
|
|
1051
|
+
}
|
|
1052
|
+
modules.set(id, stub);
|
|
1053
|
+
}
|
|
1054
|
+
return Object.fromEntries(modules);
|
|
1055
|
+
}
|
|
1056
|
+
async function preprocess(input) {
|
|
1057
|
+
const { context, command, parent } = input;
|
|
1058
|
+
const title = command.title || `${parent?.title ? `${parent.virtual ? parent.title.replace(/(?:c|C)ommands?$/, "").trim() : parent.title} - ` : ""}${(0, _stryke_string_format_title_case.titleCase)(command.name)}${command.virtual ? " Commands" : ""}`;
|
|
1059
|
+
const result = {
|
|
1060
|
+
input,
|
|
1061
|
+
output: {
|
|
1062
|
+
alias: [],
|
|
1063
|
+
icon: parent?.icon,
|
|
1064
|
+
tags: parent?.tags ?? [],
|
|
1065
|
+
...command,
|
|
1066
|
+
title,
|
|
1067
|
+
options: parent === null ? getGlobalOptions(context, command) : {},
|
|
1068
|
+
args: [],
|
|
1069
|
+
parent: parent ?? null,
|
|
1070
|
+
children: {}
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
if (!command.virtual) {
|
|
1074
|
+
if (!command.entry.input?.file || !context.fs.existsSync(command.entry.input.file)) throw new Error(`${!command.entry.input?.file ? "Missing" : "Non-existent"} command entry file for "${command.name}"`);
|
|
1075
|
+
context.debug(`Resolving CLI command schema: ${command.id} (file: ${(0, _stryke_path_replace.replacePath)(command.entry.input.file, context.config.cwd)})`);
|
|
1076
|
+
const rawSource = await context.fs.read(command.entry.input.file);
|
|
1077
|
+
const sourceText = typeof rawSource === "string" ? rawSource : Buffer.from(rawSource).toString("utf8");
|
|
1078
|
+
result.sourceText = sourceText;
|
|
1079
|
+
let loaded;
|
|
1080
|
+
try {
|
|
1081
|
+
loaded = await (0, jiti.createJiti)(require("url").pathToFileURL(__filename).href, {
|
|
1082
|
+
jsx: true,
|
|
1083
|
+
interopDefault: false,
|
|
1084
|
+
alias: resolveBuiltinAliases(context),
|
|
1085
|
+
virtualModules: collectVirtualModules(sourceText)
|
|
1086
|
+
}).evalModule(sourceText, { filename: command.entry.input.file });
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
context.debug(`Command module evaluation failed for "${command.id}", falling back to signature extraction: ${error instanceof Error ? error.message : String(error)}`);
|
|
1089
|
+
loaded = { default: () => void 0 };
|
|
1090
|
+
}
|
|
1091
|
+
result.module = (0, _stryke_type_checks_is_function.isFunction)(loaded) ? { default: loaded } : loaded;
|
|
1092
|
+
if (!result.module) throw new Error(`Failed to resolve command module at path "${command.entry.input.file}". Please ensure the file exists and is a valid module.`);
|
|
1093
|
+
if ((0, _stryke_type_checks_is_function.isFunction)(result.module)) result.module = { default: result.module };
|
|
1094
|
+
result.signature = await parseCommandSignature(command.entry.input.file, sourceText);
|
|
1095
|
+
}
|
|
1096
|
+
if (!command.virtual) {
|
|
1097
|
+
if (!result.module?.default) throw new Error(`The command entry file "${input.command.entry.input?.file || input.command.path}" does not include a handler function as its default export - this is required for command resolution and execution.`);
|
|
1098
|
+
if (!(0, _stryke_type_checks_is_function.isFunction)(result.module.default)) throw new Error(`The command entry file "${input.command.entry.input?.file || input.command.path}" does not have a valid function as its default export - this is required for command resolution and execution.`);
|
|
1099
|
+
}
|
|
1100
|
+
return result;
|
|
1101
|
+
}
|
|
1102
|
+
async function postprocess(ctx) {
|
|
1103
|
+
ctx.output.options = applyOptionsDefaults(ctx);
|
|
1104
|
+
ctx.output.args = applyArgsDefaults(ctx);
|
|
1105
|
+
ctx.output.args.forEach((arg, index) => {
|
|
1106
|
+
const found = ctx.output.args.findIndex((a) => a.name === arg.name);
|
|
1107
|
+
if (found !== -1 && found !== index || ctx.output.segments.some((segment) => require_context_helpers.isDynamicPathSegment(segment) && require_context_helpers.getDynamicPathSegmentName(segment) === arg.name)) {
|
|
1108
|
+
arg.name += `_${ctx.output.segments.filter((segment) => require_context_helpers.isDynamicPathSegment(segment) && require_context_helpers.getDynamicPathSegmentName(segment).replace(/_\d+$/, "") === arg.name).length + ctx.output.args.filter((a) => a.name.replace(/_\d+$/, "") === arg.name).length}`;
|
|
1109
|
+
arg.env = arg.name ? arg.env || arg.env === false ? arg.env : ctx.input.context.config.autoAssignEnv ? (0, _stryke_string_format_constant_case.constantCase)(arg.name) : false : false;
|
|
1110
|
+
}
|
|
1111
|
+
});
|
|
1112
|
+
applyDefaults(ctx);
|
|
1113
|
+
if (ctx.input.context.env) {
|
|
1114
|
+
if ((0, _stryke_type_checks_is_set_object.isSetObject)(ctx.output.options)) Object.values(ctx.output.options).filter((option) => Boolean(option.env)).forEach((option) => {
|
|
1115
|
+
(0, _power_plant_schema.addProperty)(ctx.input.context.env.config.schema, option.env, {
|
|
1116
|
+
...option,
|
|
1117
|
+
name: option.env,
|
|
1118
|
+
alias: option.alias.filter((alias) => alias.length > 1).map((alias) => (0, _stryke_string_format_constant_case.constantCase)(alias))
|
|
1119
|
+
});
|
|
1120
|
+
});
|
|
1121
|
+
ctx.output.args.filter((arg) => Boolean(arg.env)).forEach((arg) => (0, _power_plant_schema.addProperty)(ctx.input.context.env.config.schema, arg.env, {
|
|
1122
|
+
...arg,
|
|
1123
|
+
name: arg.env,
|
|
1124
|
+
alias: arg.alias.filter((alias) => alias.length > 1).map((alias) => (0, _stryke_string_format_constant_case.constantCase)(alias))
|
|
1125
|
+
}));
|
|
1126
|
+
}
|
|
1127
|
+
await Promise.all(ctx.input.context.inputs.filter((input) => input.segments.filter((segment) => !require_context_helpers.isDynamicPathSegment(segment)).length === ctx.input.command.segments.filter((segment) => !require_context_helpers.isDynamicPathSegment(segment)).length + 1 && input.segments.slice(0, ctx.input.command.segments.length).every((value, index) => value === ctx.input.command.segments[index])).map(async (input) => {
|
|
1128
|
+
ctx.output.children[input.name] = await resolve({
|
|
1129
|
+
context: ctx.input.context,
|
|
1130
|
+
command: input,
|
|
1131
|
+
parent: ctx.output
|
|
1132
|
+
});
|
|
1133
|
+
}));
|
|
1134
|
+
return ctx.output;
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Resolves a command tree from the given resolver input.
|
|
1138
|
+
*
|
|
1139
|
+
* @param input - The resolver input containing the context, command, and optional parent command tree.
|
|
1140
|
+
* @returns A promise that resolves to the resolved command tree.
|
|
1141
|
+
*/
|
|
1142
|
+
async function resolve(input) {
|
|
1143
|
+
const ctx = await preprocess(input);
|
|
1144
|
+
if (!ctx.output.virtual) {
|
|
1145
|
+
if (!ctx.module) throw new Error(`Command module at path "${ctx.input.command.path}" is undefined or null. Please ensure the module exports a valid command.`);
|
|
1146
|
+
else if (!(0, _stryke_type_checks_is_set_object.isSetObject)(ctx.module)) throw new TypeError(`Command module at path "${ctx.input.command.path}" is not an object. Please ensure the module exports a valid command.`);
|
|
1147
|
+
else if (!("default" in ctx.module)) throw new Error(`Command module at path "${ctx.input.command.path}" does not appear to be valid. Please ensure the module's default export is a valid command handler function.`);
|
|
1148
|
+
const metadata = ctx.module.metadata ?? {};
|
|
1149
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(metadata.title)) ctx.output.title = metadata.title;
|
|
1150
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(metadata.description)) ctx.output.description = metadata.description;
|
|
1151
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(metadata.alias) || Array.isArray(metadata.alias) && metadata.alias.length > 0) ctx.output.alias = (0, _stryke_convert_to_array.toArray)(metadata.alias);
|
|
1152
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(metadata.icon)) ctx.output.icon = metadata.icon;
|
|
1153
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(metadata.tags)) ctx.output.tags = (0, _stryke_helpers_get_unique.getUnique)(ctx.output.tags.concat((0, _stryke_convert_to_array.toArray)(metadata.tags)));
|
|
1154
|
+
ctx.output.description ??= ctx.input.command.description || ctx.signature?.description;
|
|
1155
|
+
if (ctx.module.options) {
|
|
1156
|
+
const options = await (0, _power_plant_schema.extract)(toExtractableSchema(ctx.module.options), { cwd: ctx.input.context.config.cwd });
|
|
1157
|
+
if (!(0, _stryke_type_checks_is_set_object.isSetObject)(options) || !(0, _stryke_json.isJsonSchemaObjectType)(options.schema)) throw new TypeError(`Command options for command at path "${ctx.input.command.path}" must resolve to an object.`);
|
|
1158
|
+
ctx.output.options = (0, _power_plant_schema.getPropertiesList)(options).reduce((ret, property) => {
|
|
1159
|
+
ret[property.name] = resolveCommandParameter(property, {
|
|
1160
|
+
fallbackRequired: false,
|
|
1161
|
+
includeBooleanOptionFields: true
|
|
1162
|
+
});
|
|
1163
|
+
return ret;
|
|
1164
|
+
}, {});
|
|
1165
|
+
}
|
|
1166
|
+
if (ctx.module.args) {
|
|
1167
|
+
const args = await (0, _power_plant_schema.extract)(toExtractableSchema(ctx.module.args), { cwd: ctx.input.context.config.cwd });
|
|
1168
|
+
if ((0, _stryke_type_checks_is_set_object.isSetObject)(args)) {
|
|
1169
|
+
if (!(0, _stryke_json.isJsonSchemaTupleType)(args.schema) && !(0, _power_plant_schema.isJsonSchemaArray)(args.schema)) throw new TypeError(`Command arguments for command at path "${ctx.input.command.path}" must resolve to a tuple${args?.schema?.type ? `, instead received ${JSON.stringify(args.schema.type)}` : ""}.`);
|
|
1170
|
+
if (Array.isArray(args.schema.items)) ctx.output.args = args.schema.items.map((item) => resolveCommandParameter(item, {
|
|
1171
|
+
fallbackRequired: true,
|
|
1172
|
+
includeBooleanOptionFields: false
|
|
1173
|
+
}));
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
if (ctx.signature && ctx.input.command.entry.input?.file && (!ctx.module.options || !ctx.module.args)) await applySignatureParameters(ctx, ctx.input.command.entry.input.file, ctx.signature);
|
|
1177
|
+
} else resolveVirtualCommand(ctx);
|
|
1178
|
+
return postprocess(ctx);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
//#endregion
|
|
1182
|
+
//#region src/plugin.tsx
|
|
1183
|
+
const MAX_DEPTH = 50;
|
|
1184
|
+
/**
|
|
1185
|
+
* The core Powerlines plugin to build Shell Shock projects.
|
|
1186
|
+
*/
|
|
1187
|
+
const plugin = (options$1 = {}) => {
|
|
1188
|
+
return [
|
|
1189
|
+
(0, _powerlines_plugin_tsdown.plugin)(),
|
|
1190
|
+
(0, _powerlines_plugin_automd.plugin)(),
|
|
1191
|
+
{
|
|
1192
|
+
name: "shell-shock/core:config",
|
|
1193
|
+
async config() {
|
|
1194
|
+
this.debug("Resolving the Shell Shock configuration.");
|
|
1195
|
+
return (0, defu.defu)(options$1, {
|
|
1196
|
+
name: require_context_helpers.getAppName(this),
|
|
1197
|
+
title: require_context_helpers.getAppTitle(this),
|
|
1198
|
+
description: require_context_helpers.getAppDescription(this),
|
|
1199
|
+
platform: "node",
|
|
1200
|
+
projectType: "application",
|
|
1201
|
+
framework: require_get_framework.getFramework(),
|
|
1202
|
+
isCaseSensitive: false,
|
|
1203
|
+
output: {
|
|
1204
|
+
format: "esm",
|
|
1205
|
+
dts: false
|
|
1206
|
+
},
|
|
1207
|
+
input: !this.config.input || Array.isArray(this.config.input) && this.config.input.length === 0 || (0, _stryke_type_checks_is_object.isObject)(this.config.input) && Object.keys(this.config.input).length === 0 ? ["src/**/command.ts", "src/**/command.tsx"] : void 0,
|
|
1208
|
+
resolve: {
|
|
1209
|
+
external: ["@power-plant/schema"],
|
|
1210
|
+
skipNodeModulesBundle: true
|
|
1211
|
+
},
|
|
1212
|
+
tsdown: {
|
|
1213
|
+
dts: false,
|
|
1214
|
+
nodeProtocol: true,
|
|
1215
|
+
unbundle: false
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
},
|
|
1219
|
+
configResolved: {
|
|
1220
|
+
order: "pre",
|
|
1221
|
+
async handler() {
|
|
1222
|
+
this.debug("Shell Shock configuration has been resolved.");
|
|
1223
|
+
const envConfigReference = (0, _stryke_type_checks_is_set_string.isSetString)(this.config.env.config) ? (0, _stryke_convert_extract_file_reference.extractFileReference)(this.config.env.config) : void 0;
|
|
1224
|
+
if (envConfigReference) {
|
|
1225
|
+
const envConfigFile = await this.fs.resolve(envConfigReference.file);
|
|
1226
|
+
if (envConfigFile) this.config.env.config = {
|
|
1227
|
+
...envConfigReference,
|
|
1228
|
+
file: envConfigFile
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
await updatePackageJsonBinary(this);
|
|
1232
|
+
this.config.appSpecificEnvPrefix = (0, _stryke_type_checks_is_set_string.isSetString)(this.config.autoAssignEnv) ? this.config.autoAssignEnv : (0, _stryke_string_format_constant_case.constantCase)(require_context_helpers.getAppName(this));
|
|
1233
|
+
if (!this.config.env.prefix || !Array.isArray(this.config.env.prefix)) this.config.env.prefix = (0, _stryke_convert_to_array.toArray)(this.config.env.prefix);
|
|
1234
|
+
if (!this.config.env.prefix.includes(this.config.appSpecificEnvPrefix)) this.config.env.prefix.push(this.config.appSpecificEnvPrefix);
|
|
1235
|
+
this.config.bin = ((0, _stryke_type_checks_is_set_string.isSetString)(this.packageJson.bin) ? { [(0, _stryke_string_format_kebab_case.kebabCase)(this.config.name)]: this.packageJson.bin } : this.packageJson.bin) ?? { [(0, _stryke_string_format_kebab_case.kebabCase)(this.config.name)]: formatBinaryPath(this.config.output.format) };
|
|
1236
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(this.config.docs)) {
|
|
1237
|
+
const docsWithoutCommandPath = this.config.docs.replace(/\/?\{(?:command|cmd)\}.*$/, "");
|
|
1238
|
+
this.config.docs = {
|
|
1239
|
+
commands: this.config.docs,
|
|
1240
|
+
app: this.config.docs.endsWith("/") ? docsWithoutCommandPath.endsWith("/") ? docsWithoutCommandPath : `${docsWithoutCommandPath}/` : docsWithoutCommandPath
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
this.inputs ??= [];
|
|
1244
|
+
this.globalOptions = Object.values(getGlobalOptions(this, {
|
|
1245
|
+
id: null,
|
|
1246
|
+
name: this.config.name,
|
|
1247
|
+
path: null,
|
|
1248
|
+
segments: [],
|
|
1249
|
+
title: this.config.title,
|
|
1250
|
+
description: this.config.description,
|
|
1251
|
+
alias: [],
|
|
1252
|
+
virtual: false
|
|
1253
|
+
})).map((option) => ({
|
|
1254
|
+
...option,
|
|
1255
|
+
name: (0, _stryke_string_format_camel_case.camelCase)(option.name),
|
|
1256
|
+
alias: option.alias ?? [],
|
|
1257
|
+
required: option.required ?? true
|
|
1258
|
+
}));
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
...(0, _powerlines_plugin_nodejs.plugin)((0, defu.defu)(options$1 ?? {}, { env: {
|
|
1263
|
+
config: "@shell-shock/core/schemas/env#envSchema",
|
|
1264
|
+
validate: false
|
|
1265
|
+
} })),
|
|
1266
|
+
{
|
|
1267
|
+
name: "shell-shock/core:inputs",
|
|
1268
|
+
async configResolved() {
|
|
1269
|
+
const toInputLocation = (value) => {
|
|
1270
|
+
if ((0, _stryke_type_checks_is_set_string.isSetString)(value)) return value;
|
|
1271
|
+
if ((0, _stryke_type_checks_is_set_object.isSetObject)(value) && (0, powerlines.isFileReference)(value)) return String(value.file);
|
|
1272
|
+
return null;
|
|
1273
|
+
};
|
|
1274
|
+
const configuredInputs = [];
|
|
1275
|
+
if (Array.isArray(this.config.input)) configuredInputs.push(...this.config.input.map(toInputLocation).filter((value) => (0, _stryke_type_checks_is_set_string.isSetString)(value)));
|
|
1276
|
+
else if ((0, _stryke_type_checks_is_set_string.isSetString)(this.config.input)) configuredInputs.push(this.config.input);
|
|
1277
|
+
else if ((0, _stryke_type_checks_is_set_object.isSetObject)(this.config.input) && (0, powerlines.isFileReference)(this.config.input)) configuredInputs.push(String(this.config.input.file));
|
|
1278
|
+
else if ((0, _stryke_type_checks_is_set_object.isSetObject)(this.config.input)) configuredInputs.push(...Object.values(this.config.input).map(toInputLocation).filter((value) => (0, _stryke_type_checks_is_set_string.isSetString)(value)));
|
|
1279
|
+
this.debug(configuredInputs.length <= 1 ? `Checking for command modules in the following location: ${configuredInputs[0] ?? "(none configured)"}.` : `Checking for command modules in the following locations:\n${configuredInputs.map((input) => ` - ${input}`).join("\n")}`);
|
|
1280
|
+
this.commandsPath = await findCommandsRoot(this);
|
|
1281
|
+
this.debug(`Resolved commands root path: ${this.commandsPath}`);
|
|
1282
|
+
const inputs = await (0, powerlines_utils.resolveInputs)(this, this.config.input);
|
|
1283
|
+
this.debug(`Found ${inputs.length} entry points specified in the configuration options.`);
|
|
1284
|
+
this.inputs = inputs.reduce((ret, entry) => {
|
|
1285
|
+
if (entry.file !== this.commandsPath && !(0, _stryke_path_is_parent_path.isParentPath)(entry.file, this.commandsPath)) throw new Error(`Command entry point "${entry.file}" is not located within the commands root "${this.commandsPath}". Please ensure that all command entry points are located within the current project.`);
|
|
1286
|
+
const id = resolveCommandId(this, entry.file);
|
|
1287
|
+
if (!ret.some((existing) => existing.id === id)) {
|
|
1288
|
+
const name = resolveCommandName(entry.file);
|
|
1289
|
+
let segments = resolveCommandPath(this, entry.file).split("/").filter(Boolean);
|
|
1290
|
+
segments = segments.map((segment, index) => {
|
|
1291
|
+
const found = segments.findIndex((existing) => existing === segment);
|
|
1292
|
+
if (found !== -1 && found !== index) segment += `_${segments.filter((segment) => require_context_helpers.isDynamicPathSegment(segment) && require_context_helpers.getDynamicPathSegmentName(segment).replace(/_\d+$/, "") === segment).length}`;
|
|
1293
|
+
return segment;
|
|
1294
|
+
});
|
|
1295
|
+
ret.push({
|
|
1296
|
+
id,
|
|
1297
|
+
path: segments.join("/"),
|
|
1298
|
+
segments,
|
|
1299
|
+
name,
|
|
1300
|
+
alias: [],
|
|
1301
|
+
tags: [],
|
|
1302
|
+
virtual: false,
|
|
1303
|
+
entry: {
|
|
1304
|
+
...entry,
|
|
1305
|
+
input: {
|
|
1306
|
+
file: entry.file,
|
|
1307
|
+
export: entry.export
|
|
1308
|
+
},
|
|
1309
|
+
output: name
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
return ret;
|
|
1314
|
+
}, this.inputs);
|
|
1315
|
+
this.debug(`Shell Shock will process ${this.inputs.length} command entry files: \n${this.inputs.map((command) => ` - ${command.id}: ${(0, _stryke_path_replace.replacePath)(command.entry.file, this.commandsPath)}`).join("\n")}`);
|
|
1316
|
+
},
|
|
1317
|
+
async prepare() {
|
|
1318
|
+
this.debug("Rendering base built-in modules for the Shell Shock application via Power Plant.");
|
|
1319
|
+
return require_helpers_power_plant.executeCommandGenerator(this, require_generator.coreBuiltinsGenerator);
|
|
1320
|
+
}
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
name: "shell-shock/core:virtual-inputs",
|
|
1324
|
+
configResolved: {
|
|
1325
|
+
order: "post",
|
|
1326
|
+
async handler() {
|
|
1327
|
+
if (this.inputs.length === 0) this.warn("No commands were found in the project. Please ensure at least one command exists.");
|
|
1328
|
+
else {
|
|
1329
|
+
this.debug("Finding and adding virtual command inputs for each command previously found.");
|
|
1330
|
+
this.inputs = this.inputs.reduce((ret, command) => {
|
|
1331
|
+
let depth = 0;
|
|
1332
|
+
let parentPath = (0, _stryke_path_resolve_parent_path.resolveParentPath)((0, _stryke_path_find.findFilePath)(command.entry.file));
|
|
1333
|
+
if ((0, _stryke_path_is_parent_path.isParentPath)(parentPath, this.commandsPath)) while (parentPath !== this.commandsPath) {
|
|
1334
|
+
if (depth++ > MAX_DEPTH) throw new Error(`Unable to process virtual commands for ${command.name} \n\nPlease ensure ${command.entry.file} is a valid command entry file and does not have an invalid path.`);
|
|
1335
|
+
if (!ret.some((existing) => (0, _stryke_path_find.findFilePath)(existing.entry.file) === parentPath)) {
|
|
1336
|
+
const file = (0, _stryke_path_join_paths.joinPaths)(parentPath, "command.ts");
|
|
1337
|
+
const id = resolveCommandId(this, file);
|
|
1338
|
+
if (!ret.some((existing) => existing.id === id)) {
|
|
1339
|
+
const name = resolveCommandName(file);
|
|
1340
|
+
let segments = resolveCommandPath(this, file).split("/").filter(Boolean);
|
|
1341
|
+
segments = segments.map((segment, index) => {
|
|
1342
|
+
const found = segments.findIndex((existing) => existing === segment);
|
|
1343
|
+
if (found !== -1 && found !== index) segment += `_${segments.filter((segment) => require_context_helpers.isDynamicPathSegment(segment) && require_context_helpers.getDynamicPathSegmentName(segment).replace(/_\d+$/, "") === segment).length}`;
|
|
1344
|
+
return segment;
|
|
1345
|
+
});
|
|
1346
|
+
ret.push({
|
|
1347
|
+
id,
|
|
1348
|
+
path: segments.join("/"),
|
|
1349
|
+
segments,
|
|
1350
|
+
name,
|
|
1351
|
+
alias: [],
|
|
1352
|
+
tags: [],
|
|
1353
|
+
virtual: true,
|
|
1354
|
+
entry: { file }
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
parentPath = (0, _stryke_path_resolve_parent_path.resolveParentPath)(parentPath);
|
|
1359
|
+
}
|
|
1360
|
+
return ret;
|
|
1361
|
+
}, this.inputs).sort((a, b) => a.segments.length - b.segments.length);
|
|
1362
|
+
this.debug(`Final command input list: \n${this.inputs.map((command) => ` - ${command.id}${command.virtual ? " (virtual)" : ""}`).join("\n")}`);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
name: "shell-shock/core:update-env",
|
|
1369
|
+
configResolved: {
|
|
1370
|
+
order: "post",
|
|
1371
|
+
async handler() {
|
|
1372
|
+
this.debug("Adding global options to the CLI application's environment variables.");
|
|
1373
|
+
if (!this.env.config) {
|
|
1374
|
+
this.debug("Environment variable schema not found in plugin context. Extracting environment variable schema from type definitions provided in plugin options.");
|
|
1375
|
+
await (0, _powerlines_plugin_env_helpers_schema.extractEnv)(this);
|
|
1376
|
+
if (!this.env.config) throw new Error("Failed to extract environment variable schema from type definitions provided in plugin options. Please ensure the `env.types` option is correctly specified and points to a valid TypeScript type definition file.");
|
|
1377
|
+
}
|
|
1378
|
+
if (!(0, _power_plant_schema.isJsonSchemaObject)(this.env.config.schema)) throw new Error("Invalid environment variable schema extracted.");
|
|
1379
|
+
const env = (0, _power_plant_schema.getProperties)(this.env.config);
|
|
1380
|
+
this.globalOptions.filter((option) => (0, _stryke_type_checks_is_set_string.isSetString)(option.env) && !env[option.env]).forEach((option) => {
|
|
1381
|
+
(0, _power_plant_schema.addProperty)(this.env.config, option.env, {
|
|
1382
|
+
...option,
|
|
1383
|
+
name: option.env,
|
|
1384
|
+
alias: option.alias.filter((alias) => alias.length > 1).map((alias) => (0, _stryke_string_format_constant_case.constantCase)(alias))
|
|
1385
|
+
});
|
|
1386
|
+
});
|
|
1387
|
+
await (0, _powerlines_plugin_env_helpers_schema.writeEnv)(this);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
},
|
|
1391
|
+
{
|
|
1392
|
+
name: "shell-shock/core:resolve-commands",
|
|
1393
|
+
prepare: {
|
|
1394
|
+
order: "post",
|
|
1395
|
+
async handler() {
|
|
1396
|
+
this.debug("Initializing the CLI application's command tree.");
|
|
1397
|
+
this.commands = {};
|
|
1398
|
+
if (this.config.command !== "prepare" && this.config.skipCache !== true && this.persistedMeta?.checksum === this.meta.checksum) {
|
|
1399
|
+
this.debug(`Skipping command resolution as the meta checksum has not changed.`);
|
|
1400
|
+
await (0, _powerlines_plugin_env_helpers_schema.extractEnv)(this);
|
|
1401
|
+
await readCommandsPersistence(this);
|
|
1402
|
+
} else {
|
|
1403
|
+
for (const input of this.inputs.filter((input) => input.segments.filter((segment) => !require_context_helpers.isDynamicPathSegment(segment) && !require_context_helpers.isPathSegmentGroup(segment)).length === 1)) this.commands[input.name] = await resolve({
|
|
1404
|
+
context: this,
|
|
1405
|
+
command: input
|
|
1406
|
+
});
|
|
1407
|
+
this.debug("Post-processing commands to ensure proper reflection.");
|
|
1408
|
+
await require_plugin_utils_index.traverseCommands(this, (command) => {
|
|
1409
|
+
command.options = Object.fromEntries(Object.entries(command.options).map(([name, option]) => [(0, _stryke_string_format_camel_case.camelCase)(name), {
|
|
1410
|
+
...option,
|
|
1411
|
+
name: (0, _stryke_string_format_camel_case.camelCase)(name),
|
|
1412
|
+
alias: option.alias ?? [],
|
|
1413
|
+
required: option.required ?? true
|
|
1414
|
+
}]));
|
|
1415
|
+
});
|
|
1416
|
+
await writeCommandsPersistence(this);
|
|
1417
|
+
}
|
|
1418
|
+
this.debug("Validating the CLI applications command tree.");
|
|
1419
|
+
let isValid = true;
|
|
1420
|
+
await require_plugin_utils_index.traverseCommands(this, (command) => {
|
|
1421
|
+
const failures = validateCommand(command);
|
|
1422
|
+
if (failures.length > 0) {
|
|
1423
|
+
this.error(`Found ${failures.length} issue${failures.length > 1 ? "s" : ""} with the ${command.title} command: \n${failures.map((failure) => ` - ${failure.code}: ${failure.details}`).join("\n")}\n`);
|
|
1424
|
+
isValid = false;
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
if (!isValid) throw new Error(`One or more commands in the command tree are invalid. Please review the errors above and correct them before proceeding.`);
|
|
1428
|
+
this.info(`\nCreating an application with the following command tree: \n${formatCommandTree(this)}\n`);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
name: "shell-shock/core:chmod+x",
|
|
1434
|
+
configResolved() {
|
|
1435
|
+
this.config.tsdown.hooks ??= {};
|
|
1436
|
+
this.config.tsdown.hooks["build:done"] = async (_) => {
|
|
1437
|
+
await Promise.all(Object.values(this.config.bin ?? {}).map(async (bin) => {
|
|
1438
|
+
const path = (0, _stryke_path_append.appendPath)(bin ?? "", (0, _stryke_path_join_paths.joinPaths)(this.config.cwd, this.config.root));
|
|
1439
|
+
if (this.fs.existsSync(path)) {
|
|
1440
|
+
this.debug(`Adding hashbang to binary executable output file: ${path}`);
|
|
1441
|
+
const content = await this.fs.read(path);
|
|
1442
|
+
if (content && !content.startsWith("#!")) await this.fs.write(path, `#!/usr/bin/env ${this.config.mode === "development" ? "-S NODE_OPTIONS=--enable-source-maps" : ""} node\n\n${content}`);
|
|
1443
|
+
this.debug(`Adding executable permissions (chmod+x) to binary executable output file: ${path}`);
|
|
1444
|
+
await (0, _stryke_fs_chmod_x.chmodX)(path);
|
|
1445
|
+
} else this.warn(`Expected binary output file not found at path: ${path}. Skipping adding hashbang and executable permissions (chmod+x).`);
|
|
1446
|
+
}));
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
},
|
|
1450
|
+
{
|
|
1451
|
+
name: "shell-shock/core:docs",
|
|
1452
|
+
configResolved() {
|
|
1453
|
+
this.config.automd ??= {};
|
|
1454
|
+
this.config.automd.generators = {
|
|
1455
|
+
...this.config.automd.generators ?? {},
|
|
1456
|
+
commands: commands(this),
|
|
1457
|
+
usage: usage(this),
|
|
1458
|
+
options: options(this),
|
|
1459
|
+
args: args(this)
|
|
1460
|
+
};
|
|
1461
|
+
},
|
|
1462
|
+
async docs() {
|
|
1463
|
+
this.debug("Rendering CLI command reference documentation via Power Plant.");
|
|
1464
|
+
const commands = this.inputs.map((input) => require_plugin_utils_index.getCommandTree(this, input.segments)).filter(Boolean);
|
|
1465
|
+
return require_helpers_power_plant.executeCommandGenerator(this, require_generator.coreDocsGenerator, { template: (0, _alloy_js_core_jsx_runtime.createComponent)(_alloy_js_core.For, {
|
|
1466
|
+
get each() {
|
|
1467
|
+
return Object.values(commands);
|
|
1468
|
+
},
|
|
1469
|
+
doubleHardline: true,
|
|
1470
|
+
children: (child) => (0, _alloy_js_core_jsx_runtime.createComponent)(_alloy_js_core.Show, {
|
|
1471
|
+
get when() {
|
|
1472
|
+
return !child.virtual;
|
|
1473
|
+
},
|
|
1474
|
+
get children() {
|
|
1475
|
+
return (0, _alloy_js_core_jsx_runtime.createComponent)(require_docs.CommandDocsFile, { command: child });
|
|
1476
|
+
}
|
|
1477
|
+
})
|
|
1478
|
+
}) });
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
];
|
|
1482
|
+
};
|
|
1483
|
+
|
|
1484
|
+
//#endregion
|
|
1485
|
+
Object.defineProperty(exports, 'plugin', {
|
|
1486
|
+
enumerable: true,
|
|
1487
|
+
get: function () {
|
|
1488
|
+
return plugin;
|
|
1489
|
+
}
|
|
1490
|
+
});
|