@shell-shock/core 0.17.7 → 0.17.8

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.
Files changed (145) hide show
  1. package/dist/_virtual/_rolldown/runtime.cjs +1 -29
  2. package/dist/api.cjs +1 -95
  3. package/dist/api.d.cts +52 -4
  4. package/dist/api.d.cts.map +1 -1
  5. package/dist/api.d.mts +52 -4
  6. package/dist/api.d.mts.map +1 -1
  7. package/dist/api.mjs +1 -92
  8. package/dist/api.mjs.map +1 -1
  9. package/dist/components/command-validation-logic.cjs +1 -292
  10. package/dist/components/command-validation-logic.mjs +1 -289
  11. package/dist/components/command-validation-logic.mjs.map +1 -1
  12. package/dist/components/docs.cjs +1 -265
  13. package/dist/components/docs.d.cts.map +1 -1
  14. package/dist/components/docs.d.mts.map +1 -1
  15. package/dist/components/docs.mjs +1 -256
  16. package/dist/components/docs.mjs.map +1 -1
  17. package/dist/components/exec-builtin.cjs +13 -429
  18. package/dist/components/exec-builtin.mjs +13 -425
  19. package/dist/components/exec-builtin.mjs.map +1 -1
  20. package/dist/components/helpers.cjs +1 -120
  21. package/dist/components/helpers.mjs +1 -112
  22. package/dist/components/helpers.mjs.map +1 -1
  23. package/dist/components/index.cjs +1 -58
  24. package/dist/components/index.mjs +1 -10
  25. package/dist/components/options-parser-logic.cjs +5 -960
  26. package/dist/components/options-parser-logic.d.cts +1 -1
  27. package/dist/components/options-parser-logic.mjs +5 -945
  28. package/dist/components/options-parser-logic.mjs.map +1 -1
  29. package/dist/components/state-builtin.cjs +8 -629
  30. package/dist/components/state-builtin.d.cts.map +1 -1
  31. package/dist/components/state-builtin.d.mts.map +1 -1
  32. package/dist/components/state-builtin.mjs +8 -622
  33. package/dist/components/state-builtin.mjs.map +1 -1
  34. package/dist/components/usage.cjs +1 -117
  35. package/dist/components/usage.mjs +1 -114
  36. package/dist/components/usage.mjs.map +1 -1
  37. package/dist/components/utils-builtin.cjs +33 -838
  38. package/dist/components/utils-builtin.d.cts.map +1 -1
  39. package/dist/components/utils-builtin.d.mts.map +1 -1
  40. package/dist/components/utils-builtin.mjs +33 -828
  41. package/dist/components/utils-builtin.mjs.map +1 -1
  42. package/dist/config.cjs +1 -31
  43. package/dist/config.mjs +1 -29
  44. package/dist/config.mjs.map +1 -1
  45. package/dist/contexts/command.cjs +1 -26
  46. package/dist/contexts/command.mjs +1 -23
  47. package/dist/contexts/command.mjs.map +1 -1
  48. package/dist/contexts/index.cjs +1 -9
  49. package/dist/contexts/index.mjs +1 -4
  50. package/dist/contexts/options.cjs +1 -63
  51. package/dist/contexts/options.mjs +1 -58
  52. package/dist/contexts/options.mjs.map +1 -1
  53. package/dist/helpers/automd.cjs +1 -71
  54. package/dist/helpers/automd.mjs +1 -70
  55. package/dist/helpers/automd.mjs.map +1 -1
  56. package/dist/helpers/docs-helpers.cjs +1 -23
  57. package/dist/helpers/docs-helpers.mjs +1 -22
  58. package/dist/helpers/docs-helpers.mjs.map +1 -1
  59. package/dist/helpers/paths.cjs +1 -137
  60. package/dist/helpers/paths.mjs +1 -133
  61. package/dist/helpers/paths.mjs.map +1 -1
  62. package/dist/helpers/persistence.cjs +1 -113
  63. package/dist/helpers/persistence.mjs +1 -110
  64. package/dist/helpers/persistence.mjs.map +1 -1
  65. package/dist/helpers/update-package-json.cjs +1 -59
  66. package/dist/helpers/update-package-json.mjs +1 -57
  67. package/dist/helpers/update-package-json.mjs.map +1 -1
  68. package/dist/helpers/utilities.cjs +1 -95
  69. package/dist/helpers/utilities.mjs +1 -93
  70. package/dist/helpers/utilities.mjs.map +1 -1
  71. package/dist/helpers/validations.cjs +1 -71
  72. package/dist/helpers/validations.mjs +1 -71
  73. package/dist/helpers/validations.mjs.map +1 -1
  74. package/dist/index.cjs +1 -52
  75. package/dist/index.d.cts +1 -1
  76. package/dist/index.d.mts +1 -1
  77. package/dist/index.mjs +1 -7
  78. package/dist/plugin-utils/compute-bin.cjs +1 -50
  79. package/dist/plugin-utils/compute-bin.mjs +1 -49
  80. package/dist/plugin-utils/compute-bin.mjs.map +1 -1
  81. package/dist/plugin-utils/context-helpers.cjs +1 -231
  82. package/dist/plugin-utils/context-helpers.mjs +1 -221
  83. package/dist/plugin-utils/context-helpers.mjs.map +1 -1
  84. package/dist/plugin-utils/deepkit.cjs +1 -71
  85. package/dist/plugin-utils/deepkit.mjs +1 -69
  86. package/dist/plugin-utils/deepkit.mjs.map +1 -1
  87. package/dist/plugin-utils/description-helpers.cjs +2 -111
  88. package/dist/plugin-utils/description-helpers.mjs +2 -107
  89. package/dist/plugin-utils/description-helpers.mjs.map +1 -1
  90. package/dist/plugin-utils/get-command-tree.cjs +1 -117
  91. package/dist/plugin-utils/get-command-tree.mjs +1 -114
  92. package/dist/plugin-utils/get-command-tree.mjs.map +1 -1
  93. package/dist/plugin-utils/index.cjs +1 -39
  94. package/dist/plugin-utils/index.mjs +1 -10
  95. package/dist/plugin-utils/reflect.cjs +1 -52
  96. package/dist/plugin-utils/reflect.mjs +1 -52
  97. package/dist/plugin-utils/reflect.mjs.map +1 -1
  98. package/dist/plugin-utils/traverse-command-tree.cjs +1 -64
  99. package/dist/plugin-utils/traverse-command-tree.mjs +1 -62
  100. package/dist/plugin-utils/traverse-command-tree.mjs.map +1 -1
  101. package/dist/plugin-utils/type-checks.cjs +1 -93
  102. package/dist/plugin-utils/type-checks.mjs +1 -88
  103. package/dist/plugin-utils/type-checks.mjs.map +1 -1
  104. package/dist/plugin.cjs +4 -429
  105. package/dist/plugin.d.cts.map +1 -1
  106. package/dist/plugin.d.mts.map +1 -1
  107. package/dist/plugin.mjs +4 -423
  108. package/dist/plugin.mjs.map +1 -1
  109. package/dist/resolver/deepkit.cjs +1 -135
  110. package/dist/resolver/deepkit.mjs +1 -134
  111. package/dist/resolver/deepkit.mjs.map +1 -1
  112. package/dist/resolver/helpers.cjs +1 -173
  113. package/dist/resolver/helpers.mjs +1 -168
  114. package/dist/resolver/helpers.mjs.map +1 -1
  115. package/dist/resolver/module.cjs +1 -145
  116. package/dist/resolver/module.mjs +1 -144
  117. package/dist/resolver/module.mjs.map +1 -1
  118. package/dist/resolver/resolve.cjs +1 -222
  119. package/dist/resolver/resolve.mjs +1 -221
  120. package/dist/resolver/resolve.mjs.map +1 -1
  121. package/dist/types/command.cjs +1 -441
  122. package/dist/types/command.mjs +1 -405
  123. package/dist/types/command.mjs.map +1 -1
  124. package/dist/types/config.cjs +1 -144
  125. package/dist/types/config.d.cts +3 -2
  126. package/dist/types/config.d.cts.map +1 -1
  127. package/dist/types/config.d.mts +3 -2
  128. package/dist/types/config.d.mts.map +1 -1
  129. package/dist/types/config.mjs +1 -138
  130. package/dist/types/config.mjs.map +1 -1
  131. package/dist/types/context.cjs +1 -37
  132. package/dist/types/context.d.cts +3 -2
  133. package/dist/types/context.d.cts.map +1 -1
  134. package/dist/types/context.d.mts +3 -2
  135. package/dist/types/context.d.mts.map +1 -1
  136. package/dist/types/context.mjs +1 -34
  137. package/dist/types/context.mjs.map +1 -1
  138. package/dist/types/env.cjs +1 -52
  139. package/dist/types/env.mjs +1 -50
  140. package/dist/types/env.mjs.map +1 -1
  141. package/dist/types/index.cjs +1 -49
  142. package/dist/types/index.mjs +1 -6
  143. package/dist/types/options.cjs +1 -12
  144. package/dist/types/options.mjs +1 -10
  145. package/package.json +23 -23
package/dist/plugin.mjs CHANGED
@@ -1,424 +1,5 @@
1
- import { getAppDescription, getAppName, getAppTitle, getDynamicPathSegmentName, isDynamicPathSegment, isPathSegmentGroup } from "./plugin-utils/context-helpers.mjs";
2
- import { CommandDocsFile } from "./components/docs.mjs";
3
- import { ExecBuiltin } from "./components/exec-builtin.mjs";
4
- import { traverseCommands } from "./plugin-utils/traverse-command-tree.mjs";
5
- import { getCommandTree } from "./plugin-utils/get-command-tree.mjs";
6
- import { StateBuiltin } from "./components/state-builtin.mjs";
7
- import { UtilsBuiltin } from "./components/utils-builtin.mjs";
8
- import { commands } from "./helpers/automd.mjs";
9
- import { findCommandsRoot, resolveCommandId, resolveCommandName, resolveCommandPath } from "./helpers/paths.mjs";
10
- import { getCommandsPersistencePath, readCommandsPersistence, writeCommandsPersistence } from "./helpers/persistence.mjs";
11
- import { formatBinaryPath, updatePackageJsonBinary } from "./helpers/update-package-json.mjs";
12
- import { formatCommandTree, getGlobalOptions } from "./helpers/utilities.mjs";
13
- import { validateCommand } from "./helpers/validations.mjs";
14
- import { resolve } from "./resolver/resolve.mjs";
15
- import { createComponent } from "@alloy-js/core/jsx-runtime";
16
- import { For, Show } from "@alloy-js/core/components";
17
- import { render } from "@powerlines/plugin-alloy/render";
18
- import automd from "@powerlines/plugin-automd";
19
- import nodejs from "@powerlines/plugin-nodejs";
20
- import tsdown from "@powerlines/plugin-tsdown";
21
- import { toArray } from "@stryke/convert/to-array";
22
- import { chmodX } from "@stryke/fs/chmod-x";
23
- import { appendPath } from "@stryke/path/append";
24
- import { findFilePath } from "@stryke/path/file-path-fns";
25
- import { isParentPath } from "@stryke/path/is-parent-path";
26
- import { joinPaths } from "@stryke/path/join-paths";
27
- import { replacePath } from "@stryke/path/replace";
28
- import { resolveParentPath } from "@stryke/path/resolve-parent-path";
29
- import { camelCase } from "@stryke/string-format/camel-case";
30
- import { constantCase } from "@stryke/string-format/constant-case";
31
- import { kebabCase } from "@stryke/string-format/kebab-case";
32
- import { isObject } from "@stryke/type-checks/is-object";
33
- import { isSetString } from "@stryke/type-checks/is-set-string";
34
- import { defu } from "defu";
35
- import { resolveInputs } from "powerlines/utils";
36
-
37
- //#region src/plugin.tsx
38
- function __assignType(fn, args) {
39
- fn.__type = args;
40
- return fn;
41
- }
42
- const MAX_DEPTH = 50;
43
- /**
44
- * The core Powerlines plugin to build Shell Shock projects.
45
- */
46
- const plugin = __assignType((options = {}) => {
47
- return [
48
- (tsdown.Ω = [["Context", "\"w!"]], tsdown()),
49
- (automd.Ω = [["Context", "\"w!"]], automd()),
50
- {
51
- name: "shell-shock:config",
52
- config: __assignType(async function config() {
53
- this.debug("Resolving the Shell Shock configuration.");
54
- await updatePackageJsonBinary(this);
55
- return defu({ output: { path: joinPaths(this.config.root, "dist") } }, options, {
56
- name: getAppName(this),
57
- title: getAppTitle(this),
58
- description: getAppDescription(this),
59
- platform: "node",
60
- projectType: "application",
61
- framework: "shell-shock",
62
- isCaseSensitive: false,
63
- output: {
64
- format: "esm",
65
- dts: false
66
- },
67
- input: !this.config.input || Array.isArray(this.config.input) && this.config.input.length === 0 || isObject(this.config.input) && Object.keys(this.config.input).length === 0 ? [joinPaths(this.config.root, "src/**/command.ts"), joinPaths(this.config.root, "src/**/command.tsx")] : void 0,
68
- resolve: {
69
- external: ["@powerlines/deepkit"],
70
- skipNodeModulesBundle: true
71
- },
72
- tsdown: {
73
- dts: false,
74
- nodeProtocol: true,
75
- unbundle: false
76
- }
77
- });
78
- }, ["config", "P\"/!"]),
79
- configResolved: {
80
- order: "pre",
81
- async handler() {
82
- this.debug("Shell Shock configuration has been resolved.");
83
- this.config.appSpecificEnvPrefix = isSetString(this.config.autoAssignEnv) ? this.config.autoAssignEnv : constantCase(getAppName(this));
84
- if (!this.config.env.prefix || !Array.isArray(this.config.env.prefix)) this.config.env.prefix = toArray(this.config.env.prefix);
85
- if (!this.config.env.prefix.includes(this.config.appSpecificEnvPrefix)) this.config.env.prefix.push(this.config.appSpecificEnvPrefix);
86
- this.config.bin = (isSetString(this.packageJson.bin) ? { [kebabCase(this.config.name)]: this.packageJson.bin } : this.packageJson.bin) ?? { [kebabCase(this.config.name)]: formatBinaryPath(this.config.output.format) };
87
- if (isSetString(this.config.reference)) if (this.config.reference.includes("{command}")) this.config.reference = {
88
- app: this.config.reference.substring(0, this.config.reference.indexOf("{command}")).replace(/\/?$/, "/"),
89
- commands: this.config.reference
90
- };
91
- else if (this.config.reference.includes("{commands}")) this.config.reference = {
92
- app: this.config.reference.substring(0, this.config.reference.indexOf("{commands}")).replace(/\/?$/, "/"),
93
- commands: this.config.reference
94
- };
95
- else this.config.reference = { app: this.config.reference };
96
- this.inputs ??= [];
97
- this.options = Object.values(getGlobalOptions(this, {
98
- id: null,
99
- name: this.config.name,
100
- path: null,
101
- segments: [],
102
- title: this.config.title,
103
- description: this.config.description,
104
- alias: [],
105
- isVirtual: false
106
- }));
107
- this.options = this.options.map(__assignType((option) => ({
108
- ...option,
109
- name: camelCase(option.name),
110
- alias: option.alias ?? [],
111
- optional: option.optional ?? false
112
- }), [
113
- "option",
114
- "",
115
- "P\"2!\"/\""
116
- ]));
117
- }
118
- }
119
- },
120
- ...(nodejs.Ω = [["Context", "\"w!"]], nodejs(defu(options ?? {}, { env: {
121
- types: "@shell-shock/core/types/env#ShellShockEnv",
122
- validate: false
123
- } }))),
124
- {
125
- name: "shell-shock:inputs",
126
- async configResolved() {
127
- this.debug("Finding command entry point files.");
128
- this.debug(`Checking for commands using input: ${JSON.stringify(this.config.input)}`);
129
- this.commandsPath = await findCommandsRoot(this);
130
- this.debug(`Resolved commands root path: ${this.commandsPath}`);
131
- const inputs = await resolveInputs(this, this.config.input);
132
- this.debug(`Found ${inputs.length} entry points specified in the configuration options.`);
133
- this.inputs = inputs.reduce(__assignType((ret, entry) => {
134
- if (entry.file !== this.commandsPath && !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.`);
135
- const id = resolveCommandId(this, entry.file);
136
- if (!ret.some(__assignType((existing) => existing.id === id, [
137
- "existing",
138
- "",
139
- "P\"2!\"/\""
140
- ]))) {
141
- const name = resolveCommandName(entry.file);
142
- let segments = resolveCommandPath(this, entry.file).split("/").filter(Boolean);
143
- segments = segments.map(__assignType((segment, index) => {
144
- const found = segments.findIndex(__assignType((existing) => existing === segment, [
145
- "existing",
146
- "",
147
- "P\"2!\"/\""
148
- ]));
149
- if (found !== -1 && found !== index) segment += `_${segments.filter(__assignType((segment) => isDynamicPathSegment(segment) && getDynamicPathSegmentName(segment).replace(/_\d+$/, "") === segment, [
150
- "segment",
151
- "",
152
- "P\"2!\"/\""
153
- ])).length}`;
154
- return segment;
155
- }, [
156
- "segment",
157
- "index",
158
- "",
159
- "P\"2!\"2\"\"/#"
160
- ]));
161
- ret.push({
162
- id,
163
- path: segments.join("/"),
164
- segments,
165
- name,
166
- alias: [],
167
- tags: [],
168
- isVirtual: false,
169
- source: "file",
170
- entry: {
171
- ...entry,
172
- file: entry.file,
173
- input: {
174
- file: entry.file,
175
- name: entry.name
176
- },
177
- output: name
178
- }
179
- });
180
- }
181
- return ret;
182
- }, [
183
- "ret",
184
- "entry",
185
- "",
186
- "P\"2!\"2\"\"/#"
187
- ]), this.inputs);
188
- this.debug(`Shell Shock will process ${this.inputs.length} command entry files: \n${this.inputs.map(__assignType((command) => ` - ${command.id}: ${replacePath(command.entry.file, this.commandsPath)}`, [
189
- "command",
190
- "",
191
- "P\"2!\"/\""
192
- ])).join("\n")}`);
193
- },
194
- prepare: __assignType(async function prepare() {
195
- this.debug("Rendering base built-in modules for the Shell Shock application.");
196
- return render(this, [
197
- createComponent(StateBuiltin, {}),
198
- createComponent(UtilsBuiltin, {}),
199
- createComponent(ExecBuiltin, {})
200
- ]);
201
- }, ["prepare", "P\"/!"])
202
- },
203
- {
204
- name: "shell-shock:virtual-inputs",
205
- configResolved: {
206
- order: "post",
207
- async handler() {
208
- if (this.inputs.length === 0) this.warn("No commands were found in the project. Please ensure at least one command exists.");
209
- else {
210
- this.debug("Finding and adding virtual command inputs for each command previously found.");
211
- this.inputs = this.inputs.reduce(__assignType((ret, command) => {
212
- let depth = 0;
213
- let parentPath = resolveParentPath(findFilePath(command.entry.file));
214
- if (isParentPath(parentPath, this.commandsPath)) while (parentPath !== this.commandsPath) {
215
- 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.`);
216
- if (!ret.some(__assignType((existing) => findFilePath(existing.entry.file) === parentPath, [
217
- "existing",
218
- "",
219
- "P\"2!\"/\""
220
- ]))) {
221
- const file = joinPaths(parentPath, "command.ts");
222
- const id = resolveCommandId(this, file);
223
- if (!ret.some(__assignType((existing) => existing.id === id, [
224
- "existing",
225
- "",
226
- "P\"2!\"/\""
227
- ]))) {
228
- const name = resolveCommandName(file);
229
- let segments = resolveCommandPath(this, file).split("/").filter(Boolean);
230
- segments = segments.map(__assignType((segment, index) => {
231
- const found = segments.findIndex(__assignType((existing) => existing === segment, [
232
- "existing",
233
- "",
234
- "P\"2!\"/\""
235
- ]));
236
- if (found !== -1 && found !== index) segment += `_${segments.filter(__assignType((segment) => isDynamicPathSegment(segment) && getDynamicPathSegmentName(segment).replace(/_\d+$/, "") === segment, [
237
- "segment",
238
- "",
239
- "P\"2!\"/\""
240
- ])).length}`;
241
- return segment;
242
- }, [
243
- "segment",
244
- "index",
245
- "",
246
- "P\"2!\"2\"\"/#"
247
- ]));
248
- ret.push({
249
- id,
250
- path: segments.join("/"),
251
- segments,
252
- name,
253
- alias: [],
254
- tags: [],
255
- isVirtual: true,
256
- entry: { file },
257
- source: "file"
258
- });
259
- }
260
- }
261
- parentPath = resolveParentPath(parentPath);
262
- }
263
- return ret;
264
- }, [
265
- "ret",
266
- "command",
267
- "",
268
- "P\"2!\"2\"\"/#"
269
- ]), this.inputs).sort(__assignType((a, b) => a.segments.length - b.segments.length, [
270
- "a",
271
- "b",
272
- "",
273
- "P\"2!\"2\"\"/#"
274
- ]));
275
- this.debug(`Final command input list: \n${this.inputs.map(__assignType((command) => ` - ${command.id}${command.isVirtual ? " (virtual)" : ""}: ${command.source === "file" ? replacePath(command.entry.file, this.commandsPath) : `added by ${command.source}`}`, [
276
- "command",
277
- "",
278
- "P\"2!\"/\""
279
- ])).join("\n")}`);
280
- }
281
- }
282
- }
283
- },
284
- {
285
- name: "shell-shock:resolve-commands",
286
- prepare: {
287
- order: "post",
288
- async handler() {
289
- this.debug("Initializing the CLI application's command tree.");
290
- this.commands = {};
291
- if (this.config.command !== "prepare" && this.config.skipCache !== true && this.persistedMeta?.checksum === this.meta.checksum && this.fs.existsSync(getCommandsPersistencePath(this))) {
292
- this.debug(`Skipping command resolution as the meta checksum has not changed.`);
293
- await readCommandsPersistence(this);
294
- } else {
295
- for (const input of this.inputs.filter(__assignType((input) => input.segments.filter(__assignType((segment) => !isDynamicPathSegment(segment) && !isPathSegmentGroup(segment), [
296
- "segment",
297
- "",
298
- "P\"2!\"/\""
299
- ])).length === 1, [
300
- "input",
301
- "",
302
- "P\"2!\"/\""
303
- ]))) this.commands[input.name] = await resolve({
304
- context: this,
305
- command: input
306
- });
307
- this.debug("Post-processing commands to ensure proper reflection.");
308
- await traverseCommands(this, __assignType((command) => {
309
- command.options = Object.fromEntries(Object.entries(command.options).map(__assignType(([name, option]) => [camelCase(name), {
310
- ...option,
311
- name: camelCase(name),
312
- alias: option.alias ?? [],
313
- optional: option.optional ?? false
314
- }], [
315
- "param0",
316
- "",
317
- "P\"2!\"/\""
318
- ])));
319
- }, [
320
- "command",
321
- "",
322
- "P\"2!\"/\""
323
- ]));
324
- await writeCommandsPersistence(this);
325
- }
326
- this.debug("Validating the CLI applications command tree.");
327
- let isValid = true;
328
- await traverseCommands(this, __assignType((command) => {
329
- const failures = validateCommand(command);
330
- if (failures.length > 0) {
331
- this.error(`Found ${failures.length} issue${failures.length > 1 ? "s" : ""} with the ${command.title} command: \n${failures.map(__assignType((failure) => ` - ${failure.code}: ${failure.details}`, [
332
- "failure",
333
- "",
334
- "P\"2!\"/\""
335
- ])).join("\n")}\n`);
336
- isValid = false;
337
- }
338
- }, [
339
- "command",
340
- "",
341
- "P\"2!\"/\""
342
- ]));
343
- 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.`);
344
- this.info(`\nCreating an application with the following command tree: \n${formatCommandTree(this)}\n`);
345
- }
346
- }
347
- },
348
- {
349
- name: "shell-shock:chmod+x",
350
- configResolved() {
351
- this.config.tsdown.hooks ??= {};
352
- this.config.tsdown.hooks["build:done"] = __assignType(async (_) => {
353
- await Promise.all(Object.values(this.config.bin).map(__assignType(async (bin) => {
354
- const path = appendPath(bin, joinPaths(this.workspaceConfig.workspaceRoot, this.config.root));
355
- if (this.fs.existsSync(path)) {
356
- this.debug(`Adding hashbang to binary executable output file: ${path}`);
357
- const content = await this.fs.read(path);
358
- 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}`);
359
- this.debug(`Adding executable permissions (chmod+x) to binary executable output file: ${path}`);
360
- await chmodX(path);
361
- } else this.warn(`Expected binary output file not found at path: ${path}. Skipping adding hashbang and executable permissions (chmod+x).`);
362
- }, [
363
- "bin",
364
- "",
365
- "P\"2!\"/\""
366
- ])));
367
- }, [
368
- "chunks",
369
- "_",
370
- "",
371
- "PP!P!F4!MK2\"\"/#"
372
- ]);
373
- }
374
- },
375
- {
376
- name: "shell-shock:docs",
377
- configResolved: __assignType(function configResolved() {
378
- this.config.automd ??= {};
379
- this.config.automd.generators = {
380
- ...this.config.automd.generators ?? {},
381
- commands: commands(this)
382
- };
383
- }, ["configResolved", "P\"/!"]),
384
- async docs() {
385
- this.debug("Rendering entrypoint modules for the Shell Shock `script` preset.");
386
- const commands = this.inputs.map(__assignType((input) => getCommandTree(this, input.segments), [
387
- "input",
388
- "",
389
- "P\"2!\"/\""
390
- ])).filter(Boolean);
391
- return render(this, createComponent(For, {
392
- get each() {
393
- return Object.values(commands);
394
- },
395
- doubleHardline: true,
396
- get children() {
397
- return __assignType((child) => createComponent(Show, {
398
- get when() {
399
- return !child.isVirtual;
400
- },
401
- get children() {
402
- return createComponent(CommandDocsFile, { command: child });
403
- }
404
- }), [
405
- "child",
406
- "",
407
- "P\"2!\"/\""
408
- ]);
409
- }
410
- }));
411
- }
412
- }
413
- ];
414
- }, [
415
- "Options",
416
- "options",
417
- () => ({}),
418
- "",
419
- "P\"w!2\">#!F/$"
420
- ]);
421
-
422
- //#endregion
423
- export { plugin as default, plugin };
1
+ import{getAppDescription as e,getAppName as t,getAppTitle as n,getDynamicPathSegmentName as r,isDynamicPathSegment as i,isPathSegmentGroup as a}from"./plugin-utils/context-helpers.mjs";import{CommandDocsFile as o}from"./components/docs.mjs";import{ExecBuiltin as s}from"./components/exec-builtin.mjs";import{extractType as c}from"./plugin-utils/deepkit.mjs";import{traverseCommands as l}from"./plugin-utils/traverse-command-tree.mjs";import{getCommandTree as u}from"./plugin-utils/get-command-tree.mjs";import"./plugin-utils/index.mjs";import{StateBuiltin as d}from"./components/state-builtin.mjs";import{UtilsBuiltin as f}from"./components/utils-builtin.mjs";import{commands as p}from"./helpers/automd.mjs";import{findCommandsRoot as m,resolveCommandId as h,resolveCommandName as g,resolveCommandPath as _}from"./helpers/paths.mjs";import{getCommandsPersistencePath as v,readCommandsPersistence as y,writeCommandsPersistence as b}from"./helpers/persistence.mjs";import{formatBinaryPath as x,updatePackageJsonBinary as S}from"./helpers/update-package-json.mjs";import{formatCommandTree as C,getGlobalOptions as w}from"./helpers/utilities.mjs";import{validateCommand as T}from"./helpers/validations.mjs";import{resolve as E}from"./resolver/resolve.mjs";import{createComponent as D}from"@alloy-js/core/jsx-runtime";import{For as O,Show as k}from"@alloy-js/core/components";import{ReflectionVisibility as A}from"@powerlines/deepkit/vendor/type";import j from"@powerlines/plugin-alloy";import{render as M}from"@powerlines/plugin-alloy/render";import N from"@powerlines/plugin-automd";import{writeEnvTypeReflection as P}from"@powerlines/plugin-env/helpers";import F from"@powerlines/plugin-nodejs";import I from"@powerlines/plugin-tsdown";import{toArray as L}from"@stryke/convert/to-array";import{chmodX as R}from"@stryke/fs/chmod-x";import{appendPath as z}from"@stryke/path/append";import{findFilePath as B}from"@stryke/path/file-path-fns";import{isParentPath as V}from"@stryke/path/is-parent-path";import{joinPaths as H}from"@stryke/path/join-paths";import{replacePath as U}from"@stryke/path/replace";import{resolveParentPath as W}from"@stryke/path/resolve-parent-path";import{camelCase as G}from"@stryke/string-format/camel-case";import{constantCase as K}from"@stryke/string-format/constant-case";import{kebabCase as q}from"@stryke/string-format/kebab-case";import{isObject as J}from"@stryke/type-checks/is-object";import{isSetString as Y}from"@stryke/type-checks/is-set-string";import{defu as X}from"defu";import{resolveInputs as Z}from"powerlines/utils";function Q(e,t){return e.__type=t,e}const $=Q(($={})=>[...(j.Ω=[[`Context`,`"w!`]],j()),(I.Ω=[[`Context`,`"w!`]],I()),(N.Ω=[[`Context`,`"w!`]],N()),{name:`shell-shock:config`,config:Q(async function(){return this.debug(`Resolving the Shell Shock configuration.`),X($,{name:t(this),title:n(this),description:e(this),platform:`node`,projectType:`application`,framework:`shell-shock`,isCaseSensitive:!1,output:{format:`esm`,dts:!1},input:!this.config.input||Array.isArray(this.config.input)&&this.config.input.length===0||J(this.config.input)&&Object.keys(this.config.input).length===0?[`src/**/command.ts`,`src/**/command.tsx`]:void 0,resolve:{external:[`@powerlines/deepkit`],skipNodeModulesBundle:!0},tsdown:{dts:!1,nodeProtocol:!0,unbundle:!1}})},[`config`,`P"/!`]),configResolved:{order:`pre`,async handler(){this.debug(`Shell Shock configuration has been resolved.`),await S(this),this.config.appSpecificEnvPrefix=Y(this.config.autoAssignEnv)?this.config.autoAssignEnv:K(t(this)),(!this.config.env.prefix||!Array.isArray(this.config.env.prefix))&&(this.config.env.prefix=L(this.config.env.prefix)),this.config.env.prefix.includes(this.config.appSpecificEnvPrefix)||this.config.env.prefix.push(this.config.appSpecificEnvPrefix),this.config.bin=(Y(this.packageJson.bin)?{[q(this.config.name)]:this.packageJson.bin}:this.packageJson.bin)??{[q(this.config.name)]:x(this.config.output.format)},Y(this.config.reference)&&(this.config.reference.includes(`{command}`)?this.config.reference={app:this.config.reference.substring(0,this.config.reference.indexOf(`{command}`)).replace(/\/?$/,`/`),commands:this.config.reference}:this.config.reference.includes(`{commands}`)?this.config.reference={app:this.config.reference.substring(0,this.config.reference.indexOf(`{commands}`)).replace(/\/?$/,`/`),commands:this.config.reference}:this.config.reference={app:this.config.reference}),this.inputs??=[],this.globalOptions=Object.values(w(this,{id:null,name:this.config.name,path:null,segments:[],title:this.config.title,description:this.config.description,alias:[],isVirtual:!1})),this.globalOptions=this.globalOptions.map(Q(e=>({...e,name:G(e.name),alias:e.alias??[],optional:e.optional??!1}),[`option`,``,`P"2!"/"`]))}}},...(F.Ω=[[`Context`,`"w!`]],F(X($??{},{env:{types:`@shell-shock/core/types/env#ShellShockEnv`,validate:!1}}))),{name:`shell-shock:inputs`,async configResolved(){this.debug(`Checking for commands using input: ${JSON.stringify(this.config.input)}`),this.commandsPath=await m(this),this.debug(`Resolved commands root path: ${this.commandsPath}`);let e=await Z(this,this.config.input);this.debug(`Found ${e.length} entry points specified in the configuration options.`),this.inputs=e.reduce(Q((e,t)=>{if(t.file!==this.commandsPath&&!V(t.file,this.commandsPath))throw Error(`Command entry point "${t.file}" is not located within the commands root "${this.commandsPath}". Please ensure that all command entry points are located within the current project.`);let n=h(this,t.file);if(!e.some(Q(e=>e.id===n,[`existing`,``,`P"2!"/"`]))){let a=g(t.file),o=_(this,t.file).split(`/`).filter(Boolean);o=o.map(Q((e,t)=>{let n=o.findIndex(Q(t=>t===e,[`existing`,``,`P"2!"/"`]));return n!==-1&&n!==t&&(e+=`_${o.filter(Q(e=>i(e)&&r(e).replace(/_\d+$/,``)===e,[`segment`,``,`P"2!"/"`])).length}`),e},[`segment`,`index`,``,`P"2!"2""/#`])),e.push({id:n,path:o.join(`/`),segments:o,name:a,alias:[],tags:[],isVirtual:!1,source:`file`,entry:{...t,file:t.file,input:{file:t.file,name:t.name},output:a}})}return e},[`ret`,`entry`,``,`P"2!"2""/#`]),this.inputs),this.debug(`Shell Shock will process ${this.inputs.length} command entry files: \n${this.inputs.map(Q(e=>` - ${e.id}: ${U(e.entry.file,this.commandsPath)}`,[`command`,``,`P"2!"/"`])).join(`
2
+ `)}`)},prepare:Q(async function(){return this.debug(`Rendering base built-in modules for the Shell Shock application.`),M(this,[D(d,{}),D(f,{}),D(s,{})])},[`prepare`,`P"/!`])},{name:`shell-shock:virtual-inputs`,configResolved:{order:`post`,async handler(){this.inputs.length===0?this.warn(`No commands were found in the project. Please ensure at least one command exists.`):(this.debug(`Finding and adding virtual command inputs for each command previously found.`),this.inputs=this.inputs.reduce(Q((e,t)=>{let n=0,a=W(B(t.entry.file));if(V(a,this.commandsPath))for(;a!==this.commandsPath;){if(n++>50)throw Error(`Unable to process virtual commands for ${t.name} \n\nPlease ensure ${t.entry.file} is a valid command entry file and does not have an invalid path.`);if(!e.some(Q(e=>B(e.entry.file)===a,[`existing`,``,`P"2!"/"`]))){let t=H(a,`command.ts`),n=h(this,t);if(!e.some(Q(e=>e.id===n,[`existing`,``,`P"2!"/"`]))){let a=g(t),o=_(this,t).split(`/`).filter(Boolean);o=o.map(Q((e,t)=>{let n=o.findIndex(Q(t=>t===e,[`existing`,``,`P"2!"/"`]));return n!==-1&&n!==t&&(e+=`_${o.filter(Q(e=>i(e)&&r(e).replace(/_\d+$/,``)===e,[`segment`,``,`P"2!"/"`])).length}`),e},[`segment`,`index`,``,`P"2!"2""/#`])),e.push({id:n,path:o.join(`/`),segments:o,name:a,alias:[],tags:[],isVirtual:!0,entry:{file:t},source:`file`})}}a=W(a)}return e},[`ret`,`command`,``,`P"2!"2""/#`]),this.inputs).sort(Q((e,t)=>e.segments.length-t.segments.length,[`a`,`b`,``,`P"2!"2""/#`])),this.debug(`Final command input list: \n${this.inputs.map(Q(e=>` - ${e.id}${e.isVirtual?` (virtual)`:``}: ${e.source===`file`?U(e.entry.file,this.commandsPath):`added by ${e.source}`}`,[`command`,``,`P"2!"/"`])).join(`
3
+ `)}`))}}},{name:`shell-shock:update-env`,configResolved:{order:`post`,async handler(){this.debug(`Adding global options to the CLI application's environment variables.`);for(let e of Object.values(this.globalOptions).filter(Q(e=>!!e.env,[`option`,``,`P"2!"/"`])).filter(Q(e=>!this.env.types.env.getPropertyOrUndefined(e.env),[`option`,``,`P"2!"/"`])))this.env.types.env.addProperty({name:e.env,optional:e.optional?!0:void 0,description:e.description,visibility:A.public,type:c(e),default:e.default,tags:{title:e.title,alias:e.alias.filter(Q(e=>e.length>1,[`alias`,``,`P"2!"/"`])).map(Q(e=>K(e),[`alias`,``,`P"2!"/"`])),domain:`cli`}});await P(this,this.env.types.env,`env`)}}},{name:`shell-shock:resolve-commands`,prepare:{order:`post`,async handler(){if(this.debug(`Initializing the CLI application's command tree.`),this.commands={},this.config.command!==`prepare`&&this.config.skipCache!==!0&&this.persistedMeta?.checksum===this.meta.checksum&&this.fs.existsSync(v(this)))this.debug(`Skipping command resolution as the meta checksum has not changed.`),await y(this);else{for(let e of this.inputs.filter(Q(e=>e.segments.filter(Q(e=>!i(e)&&!a(e),[`segment`,``,`P"2!"/"`])).length===1,[`input`,``,`P"2!"/"`])))this.commands[e.name]=await E({context:this,command:e});this.debug(`Post-processing commands to ensure proper reflection.`),await l(this,Q(e=>{e.options=Object.fromEntries(Object.entries(e.options).map(Q(([e,t])=>[G(e),{...t,name:G(e),alias:t.alias??[],optional:t.optional??!1}],[`param0`,``,`P"2!"/"`])))},[`command`,``,`P"2!"/"`])),await b(this)}this.debug(`Validating the CLI applications command tree.`);let e=!0;if(await l(this,Q(t=>{let n=T(t);n.length>0&&(this.error(`Found ${n.length} issue${n.length>1?`s`:``} with the ${t.title} command: \n${n.map(Q(e=>` - ${e.code}: ${e.details}`,[`failure`,``,`P"2!"/"`])).join(`
4
+ `)}\n`),e=!1)},[`command`,``,`P"2!"/"`])),!e)throw Error(`One or more commands in the command tree are invalid. Please review the errors above and correct them before proceeding.`);this.info(`\nCreating an application with the following command tree: \n${C(this)}\n`)}}},{name:`shell-shock:chmod+x`,configResolved(){this.config.tsdown.hooks??={},this.config.tsdown.hooks[`build:done`]=Q(async e=>{await Promise.all(Object.values(this.config.bin).map(Q(async e=>{let t=z(e,H(this.config.cwd,this.config.root));if(this.fs.existsSync(t)){this.debug(`Adding hashbang to binary executable output file: ${t}`);let e=await this.fs.read(t);e&&!e.startsWith(`#!`)&&await this.fs.write(t,`#!/usr/bin/env ${this.config.mode===`development`?`-S NODE_OPTIONS=--enable-source-maps`:``} node\n\n${e}`),this.debug(`Adding executable permissions (chmod+x) to binary executable output file: ${t}`),await R(t)}else this.warn(`Expected binary output file not found at path: ${t}. Skipping adding hashbang and executable permissions (chmod+x).`)},[`bin`,``,`P"2!"/"`])))},[`chunks`,`_`,``,`PP!P!F4!MK2""/#`])}},{name:`shell-shock:docs`,configResolved:Q(function(){this.config.automd??={},this.config.automd.generators={...this.config.automd.generators??{},commands:p(this)}},[`configResolved`,`P"/!`]),async docs(){this.debug("Rendering entrypoint modules for the Shell Shock `script` preset.");let e=this.inputs.map(Q(e=>u(this,e.segments),[`input`,``,`P"2!"/"`])).filter(Boolean);return M(this,D(O,{get each(){return Object.values(e)},doubleHardline:!0,get children(){return Q(e=>D(k,{get when(){return!e.isVirtual},get children(){return D(o,{command:e})}}),[`child`,``,`P"2!"/"`])}}))}}],[`Options`,`options`,()=>({}),``,`P"w!2">#!F/$`]);export{$ as default,$ as plugin};
424
5
  //# sourceMappingURL=plugin.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/plugin.tsx"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Shell Shock\n\n This code was released as part of the Shell Shock project. Shell Shock\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/shell-shock.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/shell-shock\n Documentation: https://docs.stormsoftware.com/projects/shell-shock\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { For, Show } from \"@alloy-js/core/components\";\nimport { render } from \"@powerlines/plugin-alloy/render\";\nimport automd from \"@powerlines/plugin-automd\";\nimport nodejs from \"@powerlines/plugin-nodejs\";\nimport tsdown from \"@powerlines/plugin-tsdown\";\nimport { toArray } from \"@stryke/convert/to-array\";\nimport { chmodX } from \"@stryke/fs/chmod-x\";\nimport { appendPath } from \"@stryke/path/append\";\nimport { findFilePath } from \"@stryke/path/file-path-fns\";\nimport { isParentPath } from \"@stryke/path/is-parent-path\";\nimport { joinPaths } from \"@stryke/path/join-paths\";\nimport { replacePath } from \"@stryke/path/replace\";\nimport { resolveParentPath } from \"@stryke/path/resolve-parent-path\";\nimport { camelCase } from \"@stryke/string-format/camel-case\";\nimport { constantCase } from \"@stryke/string-format/constant-case\";\nimport { kebabCase } from \"@stryke/string-format/kebab-case\";\nimport { isObject } from \"@stryke/type-checks/is-object\";\nimport { isSetString } from \"@stryke/type-checks/is-set-string\";\nimport { defu } from \"defu\";\nimport type { Plugin } from \"powerlines\";\nimport { resolveInputs } from \"powerlines/utils\";\nimport type { BuildContext, RolldownChunk, TsdownHooks } from \"tsdown\";\nimport { CommandDocsFile } from \"./components/docs\";\nimport { ExecBuiltin } from \"./components/exec-builtin\";\nimport { StateBuiltin } from \"./components/state-builtin\";\nimport { UtilsBuiltin } from \"./components/utils-builtin\";\nimport { commands } from \"./helpers/automd\";\nimport {\n findCommandsRoot,\n resolveCommandId,\n resolveCommandName,\n resolveCommandPath\n} from \"./helpers/paths\";\nimport {\n getCommandsPersistencePath,\n readCommandsPersistence,\n writeCommandsPersistence\n} from \"./helpers/persistence\";\nimport {\n formatBinaryPath,\n updatePackageJsonBinary\n} from \"./helpers/update-package-json\";\nimport { formatCommandTree, getGlobalOptions } from \"./helpers/utilities\";\nimport { validateCommand } from \"./helpers/validations\";\nimport {\n getAppDescription,\n getAppName,\n getAppTitle,\n getDynamicPathSegmentName,\n isDynamicPathSegment,\n isPathSegmentGroup\n} from \"./plugin-utils/context-helpers\";\nimport { getCommandTree } from \"./plugin-utils/get-command-tree\";\nimport { traverseCommands } from \"./plugin-utils/traverse-command-tree\";\nimport { resolve } from \"./resolver/resolve\";\nimport type { CommandOption, CommandTree } from \"./types/command\";\nimport type { Options } from \"./types/config\";\nimport type { Context } from \"./types/context\";\n\nconst MAX_DEPTH = 50;\n\n/**\n * The core Powerlines plugin to build Shell Shock projects.\n */\nexport const plugin = <TContext extends Context = Context>(\n options: Options = {}\n): Plugin<TContext>[] => {\n return [\n tsdown<TContext>(),\n automd<TContext>(),\n {\n name: \"shell-shock:config\",\n async config() {\n this.debug(\"Resolving the Shell Shock configuration.\");\n\n await updatePackageJsonBinary(this);\n\n const result = defu(\n {\n output: {\n path: joinPaths(this.config.root, \"dist\")\n }\n },\n options,\n {\n name: getAppName(this),\n title: getAppTitle(this),\n description: getAppDescription(this),\n platform: \"node\",\n projectType: \"application\",\n framework: \"shell-shock\",\n isCaseSensitive: false,\n output: {\n format: \"esm\",\n dts: false\n },\n input:\n !this.config.input ||\n (Array.isArray(this.config.input) &&\n this.config.input.length === 0) ||\n (isObject(this.config.input) &&\n Object.keys(this.config.input).length === 0)\n ? [\n joinPaths(this.config.root, \"src/**/command.ts\"),\n joinPaths(this.config.root, \"src/**/command.tsx\")\n ]\n : undefined,\n resolve: {\n external: [\"@powerlines/deepkit\"],\n skipNodeModulesBundle: true\n },\n tsdown: {\n dts: false,\n nodeProtocol: true,\n unbundle: false\n }\n }\n );\n\n return result;\n },\n configResolved: {\n order: \"pre\",\n async handler() {\n this.debug(\"Shell Shock configuration has been resolved.\");\n\n this.config.appSpecificEnvPrefix = isSetString(\n this.config.autoAssignEnv\n )\n ? this.config.autoAssignEnv\n : constantCase(getAppName(this));\n if (\n !this.config.env.prefix ||\n !Array.isArray(this.config.env.prefix)\n ) {\n this.config.env.prefix = toArray(this.config.env.prefix);\n }\n\n if (\n !this.config.env.prefix.includes(this.config.appSpecificEnvPrefix)\n ) {\n this.config.env.prefix.push(this.config.appSpecificEnvPrefix);\n }\n\n this.config.bin = (isSetString(this.packageJson.bin)\n ? { [kebabCase(this.config.name)]: this.packageJson.bin }\n : this.packageJson.bin) ?? {\n [kebabCase(this.config.name)]: formatBinaryPath(\n this.config.output.format\n )\n };\n\n if (isSetString(this.config.reference)) {\n if (this.config.reference.includes(\"{command}\")) {\n this.config.reference = {\n app: this.config.reference\n .substring(0, this.config.reference.indexOf(\"{command}\"))\n .replace(/\\/?$/, \"/\"),\n commands: this.config.reference\n };\n } else if (this.config.reference.includes(\"{commands}\")) {\n this.config.reference = {\n app: this.config.reference\n .substring(0, this.config.reference.indexOf(\"{commands}\"))\n .replace(/\\/?$/, \"/\"),\n commands: this.config.reference\n };\n } else {\n this.config.reference = {\n app: this.config.reference\n };\n }\n }\n\n this.inputs ??= [];\n this.options = Object.values(\n getGlobalOptions(this, {\n id: null,\n name: this.config.name,\n path: null,\n segments: [],\n title: this.config.title,\n description: this.config.description,\n alias: [],\n isVirtual: false\n })\n );\n\n this.options = this.options.map(\n option =>\n ({\n ...option,\n name: camelCase(option.name),\n alias: option.alias ?? [],\n optional: option.optional ?? false\n }) as CommandOption\n );\n }\n }\n },\n ...nodejs<TContext>(\n defu(options ?? {}, {\n env: {\n types: \"@shell-shock/core/types/env#ShellShockEnv\",\n validate: false\n }\n })\n ),\n {\n name: \"shell-shock:inputs\",\n async configResolved() {\n this.debug(\"Finding command entry point files.\");\n\n this.debug(\n `Checking for commands using input: ${JSON.stringify(this.config.input)}`\n );\n\n this.commandsPath = await findCommandsRoot(this);\n this.debug(`Resolved commands root path: ${this.commandsPath}`);\n\n const inputs = await resolveInputs(this, this.config.input);\n\n this.debug(\n `Found ${\n inputs.length\n } entry points specified in the configuration options.`\n );\n\n this.inputs = inputs.reduce((ret, entry) => {\n if (\n entry.file !== this.commandsPath &&\n !isParentPath(entry.file, this.commandsPath)\n ) {\n throw new Error(\n `Command entry point \"${\n entry.file\n }\" is not located within the commands root \"${\n this.commandsPath\n }\". Please ensure that all command entry points are located within the current project.`\n );\n }\n\n const id = resolveCommandId(this, entry.file);\n if (!ret.some(existing => existing.id === id)) {\n const name = resolveCommandName(entry.file);\n let segments = resolveCommandPath(this, entry.file)\n .split(\"/\")\n .filter(Boolean);\n\n // Ensure unique segment names by appending an index suffix to duplicates\n segments = segments.map((segment, index) => {\n const found = segments.findIndex(\n existing => existing === segment\n );\n if (found !== -1 && found !== index) {\n segment += `_${\n segments.filter(\n segment =>\n isDynamicPathSegment(segment) &&\n getDynamicPathSegmentName(segment).replace(\n /_\\d+$/,\n \"\"\n ) === segment\n ).length\n }`;\n }\n\n return segment;\n });\n\n ret.push({\n id,\n path: segments.join(\"/\"),\n segments,\n name,\n alias: [],\n tags: [],\n isVirtual: false,\n source: \"file\",\n entry: {\n ...entry,\n file: entry.file,\n input: {\n file: entry.file,\n name: entry.name\n },\n output: name\n }\n });\n }\n\n return ret;\n }, this.inputs);\n\n this.debug(\n `Shell Shock will process ${\n this.inputs.length\n } command entry files: \\n${this.inputs\n .map(\n command =>\n ` - ${command.id}: ${replacePath(\n command.entry.file,\n this.commandsPath\n )}`\n )\n .join(\"\\n\")}`\n );\n },\n async prepare() {\n this.debug(\n \"Rendering base built-in modules for the Shell Shock application.\"\n );\n\n return render(\n this,\n <>\n <StateBuiltin />\n <UtilsBuiltin />\n <ExecBuiltin />\n </>\n );\n }\n },\n {\n name: \"shell-shock:virtual-inputs\",\n configResolved: {\n order: \"post\",\n async handler() {\n if (this.inputs.length === 0) {\n this.warn(\n \"No commands were found in the project. Please ensure at least one command exists.\"\n );\n } else {\n this.debug(\n \"Finding and adding virtual command inputs for each command previously found.\"\n );\n\n this.inputs = this.inputs\n .reduce((ret, command) => {\n let depth = 0;\n\n let parentPath = resolveParentPath(\n findFilePath(command.entry.file)\n );\n if (isParentPath(parentPath, this.commandsPath)) {\n while (parentPath !== this.commandsPath) {\n if (depth++ > MAX_DEPTH) {\n throw new Error(\n `Unable to process virtual commands for ${\n command.name\n } \\n\\nPlease ensure ${\n command.entry.file\n } is a valid command entry file and does not have an invalid path.`\n );\n }\n\n if (\n !ret.some(\n existing =>\n findFilePath(existing.entry.file) === parentPath\n )\n ) {\n const file = joinPaths(parentPath, \"command.ts\");\n const id = resolveCommandId(this, file);\n if (!ret.some(existing => existing.id === id)) {\n const name = resolveCommandName(file);\n\n let segments = resolveCommandPath(this, file)\n .split(\"/\")\n .filter(Boolean);\n\n // Ensure unique segment names by appending an index suffix to duplicates\n segments = segments.map((segment, index) => {\n const found = segments.findIndex(\n existing => existing === segment\n );\n if (found !== -1 && found !== index) {\n segment += `_${\n segments.filter(\n segment =>\n isDynamicPathSegment(segment) &&\n getDynamicPathSegmentName(segment).replace(\n /_\\d+$/,\n \"\"\n ) === segment\n ).length\n }`;\n }\n\n return segment;\n });\n\n ret.push({\n id,\n path: segments.join(\"/\"),\n segments,\n name,\n alias: [],\n tags: [],\n isVirtual: true,\n entry: {\n file\n },\n source: \"file\"\n });\n }\n }\n\n parentPath = resolveParentPath(parentPath);\n }\n }\n\n return ret;\n }, this.inputs)\n .sort((a, b) => a.segments.length - b.segments.length);\n\n this.debug(\n `Final command input list: \\n${this.inputs\n .map(\n command =>\n ` - ${command.id}${command.isVirtual ? \" (virtual)\" : \"\"}: ${\n command.source === \"file\"\n ? replacePath(command.entry.file, this.commandsPath)\n : `added by ${command.source}`\n }`\n )\n .join(\"\\n\")}`\n );\n }\n }\n }\n },\n {\n name: \"shell-shock:resolve-commands\",\n prepare: {\n order: \"post\",\n async handler() {\n this.debug(\"Initializing the CLI application's command tree.\");\n\n this.commands = {};\n if (\n this.config.command !== \"prepare\" &&\n this.config.skipCache !== true &&\n this.persistedMeta?.checksum === this.meta.checksum &&\n this.fs.existsSync(getCommandsPersistencePath(this))\n ) {\n this.debug(\n `Skipping command resolution as the meta checksum has not changed.`\n );\n\n await readCommandsPersistence(this);\n } else {\n for (const input of this.inputs.filter(\n input =>\n input.segments.filter(\n segment =>\n !isDynamicPathSegment(segment) &&\n !isPathSegmentGroup(segment)\n ).length === 1\n )) {\n this.commands[input.name] = await resolve({\n context: this,\n command: input\n });\n }\n\n this.debug(\"Post-processing commands to ensure proper reflection.\");\n\n await traverseCommands(this, command => {\n command.options = Object.fromEntries(\n Object.entries(command.options).map(([name, option]) => [\n camelCase(name),\n {\n ...option,\n name: camelCase(name),\n alias: option.alias ?? [],\n optional: option.optional ?? false\n } as CommandOption\n ])\n );\n });\n\n await writeCommandsPersistence(this);\n }\n\n this.debug(\"Validating the CLI applications command tree.\");\n\n let isValid = true;\n await traverseCommands(this, command => {\n const failures = validateCommand(command);\n if (failures.length > 0) {\n this.error(\n `Found ${failures.length} issue${failures.length > 1 ? \"s\" : \"\"} with the ${\n command.title\n } command: \\n${failures\n .map(failure => ` - ${failure.code}: ${failure.details}`)\n .join(\"\\n\")}\\n`\n );\n isValid = false;\n }\n });\n if (!isValid) {\n throw new Error(\n `One or more commands in the command tree are invalid. Please review the errors above and correct them before proceeding.`\n );\n }\n\n this.info(\n `\\nCreating an application with the following command tree: \\n${formatCommandTree(\n this\n )}\\n`\n );\n }\n }\n },\n {\n name: \"shell-shock:chmod+x\",\n configResolved() {\n this.config.tsdown.hooks ??= {} as TsdownHooks;\n (this.config.tsdown.hooks as TsdownHooks)[\"build:done\"] = async (\n _: BuildContext & {\n chunks: RolldownChunk[];\n }\n ) => {\n await Promise.all(\n Object.values(this.config.bin).map(async bin => {\n const path = appendPath(\n bin,\n joinPaths(this.workspaceConfig.workspaceRoot, this.config.root)\n );\n if (this.fs.existsSync(path)) {\n this.debug(\n `Adding hashbang to binary executable output file: ${path}`\n );\n\n const content = await this.fs.read(path);\n if (content && !content.startsWith(\"#!\")) {\n await this.fs.write(\n path,\n `#!/usr/bin/env ${\n this.config.mode === \"development\"\n ? \"-S NODE_OPTIONS=--enable-source-maps\"\n : \"\"\n } node\\n\\n${content}`\n );\n }\n\n this.debug(\n `Adding executable permissions (chmod+x) to binary executable output file: ${\n path\n }`\n );\n\n await chmodX(path);\n } else {\n this.warn(\n `Expected binary output file not found at path: ${\n path\n }. Skipping adding hashbang and executable permissions (chmod+x).`\n );\n }\n })\n );\n };\n }\n },\n {\n name: \"shell-shock:docs\",\n configResolved() {\n this.config.automd ??= {};\n this.config.automd.generators = {\n ...(this.config.automd.generators ?? {}),\n commands: commands(this)\n };\n },\n async docs() {\n this.debug(\n \"Rendering entrypoint modules for the Shell Shock `script` preset.\"\n );\n\n const commands = this.inputs\n .map(input => getCommandTree(this, input.segments))\n .filter(Boolean) as CommandTree[];\n\n return render(\n this,\n <For each={Object.values(commands)} doubleHardline>\n {child => (\n <Show when={!child.isVirtual}>\n <CommandDocsFile command={child} />\n </Show>\n )}\n </For>\n );\n }\n }\n ];\n};\n\nexport default plugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEE,IAAG,SAAS;;;AAsDd,MAAM,YAAC;;;;AAIP,MAAS,SAAA,cAAmB,UAAkB,EAAC,KAAM;AACrD,QAAS;GAAA,OAAA,IAAA,CAAA,CAAe,WAAW,OAAA,CAAO,EAAC,QAAA;GAAY,OAAA,IAAA,CAAA,CAAA,WAAA,OAAA,CAAA,EAAA,QAAA;EAAA;GACvD,MAAO;GACL,QAAA,aAAiB,eAAA,SAAA;AACjB,SAAA,MAAU,2CAAA;AACV,UAAA,wBAAW,KAAA;AA4BP,WA3BJ,KAAA,EACA,QAAA,EACA,MAAA,UAAA,KAAA,OAAA,MAAA,OAAA,EACO,EACF,EAAE,SAAA;KACD,MAAC,WAAgB,KAAG;KACpB,OAAC,YAAkB,KAAA;KACpB,aAAO,kBAAe,KAAc;KACpC,UAAO;KACP,aAAc;;KAEf,iBAAc;;MAElB,QAAA;MACK,KAAK;MACV;KACK,OAAM,CAAA,KAAQ,OAAE,SAAS,MAAQ,QAAU,KAAA,OAAQ,MAAA,IAAA,KAAA,OAAA,MAAA,WAAA,KAAA,SAAA,KAAA,OAAA,MAAA,IAAA,OAAA,KAAA,KAAA,OAAA,MAAA,CAAA,WAAA,IAAA,CAAA,UAAA,KAAA,OAAA,MAAA,oBAAA,EAAA,UAAA,KAAA,OAAA,MAAA,qBAAA,CAAA,GAAA;KACxD,SAAS;MACD,UAAU,CAAC,sBAAI;MAChB,uBAAA;MACL;KACA,QAAO;MACP,KAAA;MACM,cAAc;MAClB,UAAc;MACZ;;;GAIJ,gBAAgB;IACd,OAAI;IACJ,MAAM,UAAQ;AACZ,UAAK,MAAM,+CAAmC;AAC9C,UAAI,OAAA,uBAAA,YAAA,KAAA,OAAA,cAAA,GAAA,KAAA,OAAA,gBAAA,aAAA,WAAA,KAAA,CAAA;AACJ,SAAG,CAAA,KAAA,OAAA,IAAA,UAAA,CAAA,MAAA,QAAA,KAAA,OAAA,IAAA,OAAA,CACD,MAAA,OAAO,IAAA,SAAA,QAAA,KAAA,OAAA,IAAA,OAAA;AAET,SAAI,CAAA,KAAM,OAAA,IAAW,OAAK,SAAA,KAAA,OAAA,qBAAA,CACxB,MAAE,OAAO,IAAA,OAAY,KAAK,KAAA,OAAA,qBAAA;AAE5B,UAAI,OAAQ,OAAO,YAAC,KAAA,YAAA,IAAA,GAAA,GACjB,UAAC,KAAc,OAAA,KAAY,GAAA,KAAA,YAAA,KAC7B,GAAG,KAAA,YAAiB,QAAO,GACzB,UAAC,KAAA,OAAiB,KAAK,GAAA,iBAAA,KAAA,OAAA,OAAA,OAAA,EACzB;AACD,SAAI,YAAW,KAAI,OAAA,UAAA,CACjB,KAAI,KAAK,OAAA,UAAA,SAAA,YAAA,CACP,MAAC,OAAA,YAAA;MACD,KAAK,KAAA,OAAA,UAAA,UAAA,GAAA,KAAA,OAAA,UAAA,QAAA,YAAA,CAAA,CAAA,QAAA,QAAA,IAAA;MACH,UAAM,KAAO,OAAO;MACrB;cACQ,KAAA,OAAY,UAAU,SAAM,aAAA,CACrC,MAAG,OAAS,YAAY;MACtB,KAAE,KAAO,OAAK,UAAY,UAAO,GAAO,KAAK,OAAA,UAAA,QAAA,aAAA,CAAA,CAAA,QAAA,QAAA,IAAA;MAC7C,UAAI,KAAA,OAAA;MACL;SAED,MAAK,OAAC,YAAA,EACJ,KAAI,KAAA,OAAS,WACf;AAGJ,UAAK,WAAA,EAAA;AACL,UAAI,UAAQ,OAAA,OAAA,iBAAA,MAAA;MACV,IAAI;MACJ,MAAI,KAAA,OAAc;MAClB,MAAI;MACJ,UAAE,EAAA;MACF,OAAA,KAAA,OAAA;MACD,aAAA,KAAA,OAAA;;MAED,WAAa;MACd,CAAA,CAAA;AACD,UAAA,UAAgB,KAAA,QAAA,IAAA,cAAA,YAAA;MACd,GAAK;MACL,MAAM,UAAU,OAAA,KAAA;MACd,OAAK,OAAO,SAAW,EAAC;;MAEzB,GAAC;MAAA;MAAY;MAAA;MAAA,CAAA,CAAA;;IAEjB;GACF;EAAE,IAAI,OAAK,IAAK,CAAA,CAAA,WAAO,OAAA,CAAA,EAAA,OAAA,KAAA,WAAA,EAAA,EAAA,EACtB,KAAK;GACH,OAAO;GACP,UAAO;GACR,EACF,CAAC,CAAC;EAAG;GACJ,MAAM;GACN,MAAM,iBAAA;;AAEJ,SAAI,MAAG,sCAAA,KAAA,UAAA,KAAA,OAAA,MAAA,GAAA;AACP,SAAK,eAAc,MAAI,iBAAoB,KAAC;AAC5C,SAAK,MAAC,gCAAA,KAAA,eAAA;IACN,MAAM,SAAK,MAAU,cAAa,MAAK,KAAO,OAAA,MAAA;AAC9C,SAAI,MAAA,SAAA,OAAA,OAAA,uDAAA;;AAEF,SAAE,MAAK,SAAY,KAAE,gBAAiB,CAAA,aAAe,MAAA,MAAA,KAAA,aAAA,CACnD,OAAM,IAAC,MAAS,wBAAqB,MAAK,KAAA,6CAAgB,KAAA,aAAA,wFAAA;KAE5D,MAAK,KAAA,iBAAsB,MAAO,MAAC,KAAA;AACnC,SAAI,CAAC,IAAC,KAAK,cAAc,aAAA,SAAA,OAAA,IAAA;MAAA;MAAA;MAAA;MAAA,CAAA,CAAA,EAAA;MACvB,MAAE,OAAA,mBAAA,MAAA,KAAA;MACF,IAAC,WAAA,mBAAA,MAAA,MAAA,KAAA,CAAA,MAAA,IAAA,CAAA,OAAA,QAAA;AAED,iBAAI,SAAgB,IAAC,cAAiB,SAAE,UAAA;OACtC,MAAI,QAAK,SAAO,UAAU,cAAoB,aAAG,aAAA,SAAA;QAAA;QAAA;QAAA;QAAA,CAAA,CAAA;AACjD,WAAE,UAAY,MAAA,UAAY,MACxB,YAAW,IAAC,SAAO,OAAA,cAAA,YAAA,qBAAA,QAAA,IAAA,0BAAA,QAAA,CAAA,QAAA,SAAA,GAAA,KAAA,SAAA;QAAA;QAAA;QAAA;QAAA,CAAA,CAAA,CAAA;AAErB,cAAO;SACN;OAAC;OAAW;OAAM;OAAO;OAAA,CAAA,CAAA;AAC5B,UAAI,KAAC;OACH;OACA,MAAM,SAAQ,KAAA,IAAU;OACxB;OACA;OACA,OAAO,EAAA;OACP,MAAI,EAAA;OACJ,WAAG;OACH,QAAO;OACP,OAAO;QACL,GAAE;QACF,MAAC,MAAA;QACH,OAAA;SACF,MAAA,MAAA;;SAEK;QACD,QAAQ;QACV;OACD,CAAC;;AAEJ,YAAM;OACL;KAAC;KAAI;KAAY;KAAA;KAAA,CAAA,EAAA,KAAA,OAAA;AACpB,SAAK,MAAG,4BAAwB,KAAA,OAAA,OAAA,0BAAA,KAAA,OAAA,IAAA,cAAA,YAAA,MAAA,QAAA,GAAA,IAAA,YAAA,QAAA,MAAA,MAAA,KAAA,aAAA,IAAA;KAAA;KAAA;KAAA;KAAA,CAAA,CAAA,CAAA,KAAA,KAAA,GAAA;;GAElC,SAAS,aAAU,eAAA,UAAA;AACjB,SAAK,MAAG,mEAAW;AACnB,WAAO,OAAA,MAAA;KAAA,gBAAA,cAAA,EAAA,CAAA;KAAA,gBAAA,cAAA,EAAA,CAAA;KAAA,gBAAA,aAAA,EAAA,CAAA;KAAA,CAAA;MACN,CAAC,WAAG,QAAA,CAAA;;;GAEP,MAAM;GACN,gBAAgB;IACd,OAAO;IACP,MAAM,UAAO;AACX,SAAI,KAAI,OAAM,WAAU,EACtB,MAAK,KAAC,oFAAyB;UAC1B;AACL,WAAK,MAAK,+EAAA;AACV,WAAC,SAAA,KAAA,OAAA,OAAA,cAAA,KAAA,YAAA;OACH,IAAA,QAAA;OACF,IAAA,aAAA,kBAAA,aAAA,QAAA,MAAA,KAAA,CAAA;AACD,WAAA,aAAA,YAAA,KAAA,aAAA,CACS,QAAA,eAAS,KAAA,cAAA;AACZ,YAAS,UAAM,UACb,OAAA,IAAA,MAAA,0CAAA,QAAA,KAAA,qBAAA,QAAA,MAAA,KAAA,mEAAA;AAEH,YAAU,CAAA,IAAA,KAAA,cAAA,aAAA,aAAA,SAAA,MAAA,KAAA,KAAA,YAAA;SAAA;SAAA;SAAA;SAAA,CAAA,CAAA,EAAA;SACZ,MAAA,OAAA,UAAA,YAAA,aAAA;SACD,MAAA,KAAA,iBAAA,MAAA,KAAA;AACF,aAAA,CAAA,IAAA,KAAA,cAAA,aAAA,SAAA,OAAA,IAAA;UAAA;UAAA;UAAA;UAAA,CAAA,CAAA,EAAA;UACD,MAAA,OAAA,mBAAA,KAAA;UACe,IAAK,WAAQ,mBAAA,MAAA,KAAA,CAAA,MAAA,IAAA,CAAA,OAAA,QAAA;AAEZ,qBAAQ,SAAQ,IAAM,cAAc,SAAA,UAAA;;;;;;AAEtC,eAAA,UAAA,MAAA,UAAA,MACM,YAAS,IAAM,SAAS,OAAK,cAAe,YAAO,qBAAO,QAAA,IAAA,0BAAA,QAAA,CAAA,QAAA,SAAA,GAAA,KAAA,SAAA;YAAA;YAAA;YAAA;YAAA,CAAA,CAAA,CAAA;;aAGrE;WAAA;WAAqB;WAAA;WAAA;WAAsB,CAAA,CAAA;AACpC,cAAA,KAAS;;WAEP,MAAM,SAAC,KAAa,IAAC;;WAEzB;WACA,OAAA,EAAA;WACC,MAAA,EAAA;WACD,WAAO;WAChB,OAAA,QAEa;WACT,QAAA;WACK,CAAI;;;AAGV,qBAAe,kBAAA,WAAA;;AAGf,cAAO;SACN;OAAC;OAAO;OAAA;OAAA;OAAA,CAAA,EAAA,KAAA,OAAA,CAAA,KAAA,cAAA,GAAA,MAAA,EAAA,SAAA,SAAA,EAAA,SAAA,QAAA;OAAA;OAAA;OAAA;OAAA;OAAA,CAAA,CAAA;AACX,WAAK,MAAG,+BAA+B,KAAM,OAAO,IAAI,cAAe,YAAW,MAAC,QAAQ,KAAA,QAAA,YAAA,eAAA,GAAA,IAAA,QAAA,WAAA,SAAA,YAAA,QAAA,MAAA,MAAA,KAAA,aAAA,GAAA,YAAA,QAAA,YAAA;OAAA;OAAA;OAAA;OAAA,CAAA,CAAA,CAAA,KAAA,KAAA,GAAA;;;;GAIlG;EAAE;GACD,MAAM;GACN,SAAQ;IACN,OAAM;IACN,MAAM,UAAU;AACd,UAAK,MAAE,mDAAe;;AAEtB,SAAI,KAAG,OAAO,YAAc,aAAU,KAAA,OAAa,cAAgB,QAAA,KAAA,eAAA,aAAA,KAAA,KAAA,YAAA,KAAA,GAAA,WAAA,2BAAA,KAAA,CAAA,EAAA;AACjE,WAAE,MAAS,oEAAmC;AAC9C,YAAI,wBAAuB,KAAA;YACtB;AACL,WAAK,MAAA,SAAA,KAAA,OAAA,OAAA,cAAA,UAAA,MAAA,SAAA,OAAA,cAAA,YAAA,CAAA,qBAAA,QAAA,IAAA,CAAA,mBAAA,QAAA,EAAA;OAAA;OAAA;OAAA;OAAA,CAAA,CAAA,CAAA,WAAA,GAAA;OAAA;OAAA;OAAA;OAAA,CAAA,CAAA,CACH,MAAK,SAAS,MAAM,QAAQ,MAAI,QAAO;OACrC,SAAS;OACT,SAAI;OACL,CAAC;AAEJ,WAAK,MAAM,wDAA2C;AACtD,YAAM,iBAAe,MAAA,cAAA,YAAA;AACnB,eAAQ,UAAK,OAAA,YAAA,OAAA,QAAA,QAAA,QAAA,CAAA,IAAA,cAAA,CAAA,MAAA,YAAA,CAAA,UAAA,KAAA,EAAA;QACX,GAAG;QACH,MAAM,UAAA,KAAA;QACN,OAAI,OAAA,SAAA,EAAA;QACJ,UAAA,OAAA,YAAA;;;;;;SAED;OAAC;OAAO;OAAO;OAAA,CAAA,CAAA;AAClB,YAAI,yBAAA,KAAA;;AAEN,UAAI,MAAI,gDAAK;KACb,IAAI,UAAI;AACR,WAAM,iBAAe,MAAQ,cAAC,YAAA;MAC5B,MAAI,WAAQ,gBAAA,QAAA;AACZ,UAAI,SAAI,SAAA,GAAA;AACN,YAAE,MAAS,SAAA,SAAA,OAAA,QAAA,SAAA,SAAA,IAAA,MAAA,GAAA,YAAA,QAAA,MAAA,cAAA,SAAA,IAAA,cAAA,YAAA,MAAA,QAAA,KAAA,IAAA,QAAA,WAAA;QAAA;QAAA;QAAA;QAAA,CAAA,CAAA,CAAA,KAAA,KAAA,CAAA,IAAA;AACX,iBAAU;;QAEX;MAAC;MAAW;MAAI;MAAC,CAAA,CAAA;AACpB,SAAI,CAAC,QACH,OAAM,IAAG,MAAK,2HAAA;AAEhB,UAAK,KAAG,gEAAO,kBAAA,KAAA,CAAA,IAAA;;IAElB;GACF;EAAE;GACD,MAAM;GACN,iBAAU;AACR,SAAK,OAAG,OAAA,UAAA,EAAA;AACR,SAAI,OAAA,OAAA,MAAA,gBAAA,aAAA,OAAA,MAAA;;MAEA,MAAM,OAAI,WAAA,KAAA,UAAA,KAAA,gBAAA,eAAA,KAAA,OAAA,KAAA,CAAA;AACV,UAAC,KAAK,GAAM,WAAC,KAAA,EAAA;;OAEX,MAAM,UAAA,MAAA,KAAA,GAAA,KAAA,KAAA;AACP,WAAK,WAAW,CAAC,QAAQ,WAAC,KAAA,CACzB,OAAK,KAAO,GAAA,MAAA,MAAA,kBAAA,KAAA,OAAA,SAAA,gBAAA,yCAAA,GAAA,WAAA,UAAA;AAEZ,YAAI,MAAA,6EAAA,OAAA;AACJ,aAAE,OAAS,KAAA;YAEX,MAAK,KAAC,kDAAkB,KAAA,kEAAA;QAEzB;MAAC;MAAM;MAAA;MAAA,CAAA,CAAA,CAAA;OACT;KAAC;KAAE;KAAA;KAAA;KAAA,CAAA;;GAET;EAAE;GACD,MAAG;GACH,gBAAgB,aAAE,SAAA,iBAAA;AAChB,SAAE,OAAU,WAAA,EAAA;AACZ,SAAK,OAAA,OAAc,aAAU;KAC3B,GAAC,KAAA,OAAA,OAAA,cAAA,EAAA;;KAEF;MACA,CAAC,kBAAM,QAAA,CAAA;GACV,MAAM,OAAC;AACL,SAAK,MAAE,oEAAc;IACrB,MAAM,WAAC,KAAc,OAAA,IAAA,cAAA,UAAA,eAAA,MAAA,MAAA,SAAA,EAAA;KAAA;KAAA;KAAA;KAAA,CAAA,CAAA,CAAA,OAAA,QAAA;AACrB,WAAO,OAAA,MAAa,gBAAA,KAAA;KAClB,IAAI,OAAA;AACH,aAAA,OAAA,OAAA,SAAA;;KAEJ,gBAAA;KACD,IAAA,WAAA;AACM,aAAG,cAAY,UAAc,gBAAC,MAAA;OAClC,IAAA,OAAgB;AACR,eAAO,CAAA,MAAA;;OAET,IAAE,WAAY;AACd,eAAS,gBAAA,iBAAA,EACN,SAAG,OACL,CAAA;;OAEF,CAAC,EAAA;OAAA;OAAU;OAAA;OAAA,CAAA;;KAEf,CAAC,CAAC;;GAEN;EAAC;GACD;CAAC;CAAW;QAAa,EAAO;CAAG;CAAE;CAAA,CAAA"}
1
+ {"version":3,"file":"plugin.mjs","names":[],"sources":["../src/plugin.tsx"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Shell Shock\n\n This code was released as part of the Shell Shock project. Shell Shock\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/shell-shock.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/shell-shock\n Documentation: https://docs.stormsoftware.com/projects/shell-shock\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { For, Show } from \"@alloy-js/core/components\";\nimport { ReflectionVisibility } from \"@powerlines/deepkit/vendor/type\";\nimport alloy from \"@powerlines/plugin-alloy\";\nimport { render } from \"@powerlines/plugin-alloy/render\";\nimport automd from \"@powerlines/plugin-automd\";\nimport { writeEnvTypeReflection } from \"@powerlines/plugin-env/helpers\";\nimport nodejs from \"@powerlines/plugin-nodejs\";\nimport tsdown from \"@powerlines/plugin-tsdown\";\nimport { toArray } from \"@stryke/convert/to-array\";\nimport { chmodX } from \"@stryke/fs/chmod-x\";\nimport { appendPath } from \"@stryke/path/append\";\nimport { findFilePath } from \"@stryke/path/file-path-fns\";\nimport { isParentPath } from \"@stryke/path/is-parent-path\";\nimport { joinPaths } from \"@stryke/path/join-paths\";\nimport { replacePath } from \"@stryke/path/replace\";\nimport { resolveParentPath } from \"@stryke/path/resolve-parent-path\";\nimport { camelCase } from \"@stryke/string-format/camel-case\";\nimport { constantCase } from \"@stryke/string-format/constant-case\";\nimport { kebabCase } from \"@stryke/string-format/kebab-case\";\nimport { isObject } from \"@stryke/type-checks/is-object\";\nimport { isSetString } from \"@stryke/type-checks/is-set-string\";\nimport { defu } from \"defu\";\nimport type { Plugin } from \"powerlines\";\nimport { resolveInputs } from \"powerlines/utils\";\nimport type { BuildContext, RolldownChunk, TsdownHooks } from \"tsdown\";\nimport { CommandDocsFile } from \"./components/docs\";\nimport { ExecBuiltin } from \"./components/exec-builtin\";\nimport { StateBuiltin } from \"./components/state-builtin\";\nimport { UtilsBuiltin } from \"./components/utils-builtin\";\nimport { commands } from \"./helpers/automd\";\nimport {\n findCommandsRoot,\n resolveCommandId,\n resolveCommandName,\n resolveCommandPath\n} from \"./helpers/paths\";\nimport {\n getCommandsPersistencePath,\n readCommandsPersistence,\n writeCommandsPersistence\n} from \"./helpers/persistence\";\nimport {\n formatBinaryPath,\n updatePackageJsonBinary\n} from \"./helpers/update-package-json\";\nimport { formatCommandTree, getGlobalOptions } from \"./helpers/utilities\";\nimport { validateCommand } from \"./helpers/validations\";\nimport { extractType } from \"./plugin-utils\";\nimport {\n getAppDescription,\n getAppName,\n getAppTitle,\n getDynamicPathSegmentName,\n isDynamicPathSegment,\n isPathSegmentGroup\n} from \"./plugin-utils/context-helpers\";\nimport { getCommandTree } from \"./plugin-utils/get-command-tree\";\nimport { traverseCommands } from \"./plugin-utils/traverse-command-tree\";\nimport { resolve } from \"./resolver/resolve\";\nimport type { CommandTree } from \"./types/command\";\nimport type { Options } from \"./types/config\";\nimport type { Context } from \"./types/context\";\n\nconst MAX_DEPTH = 50;\n\n/**\n * The core Powerlines plugin to build Shell Shock projects.\n */\nexport const plugin = <TContext extends Context = Context>(\n options: Options = {}\n): Plugin<TContext>[] => {\n return [\n ...alloy<TContext>(),\n tsdown<TContext>(),\n automd<TContext>(),\n {\n name: \"shell-shock:config\",\n async config() {\n this.debug(\"Resolving the Shell Shock configuration.\");\n\n const result = defu(options, {\n name: getAppName(this),\n title: getAppTitle(this),\n description: getAppDescription(this),\n platform: \"node\",\n projectType: \"application\",\n framework: \"shell-shock\",\n isCaseSensitive: false,\n output: {\n format: \"esm\",\n dts: false\n },\n input:\n !this.config.input ||\n (Array.isArray(this.config.input) &&\n this.config.input.length === 0) ||\n (isObject(this.config.input) &&\n Object.keys(this.config.input).length === 0)\n ? [\"src/**/command.ts\", \"src/**/command.tsx\"]\n : undefined,\n resolve: {\n external: [\"@powerlines/deepkit\"],\n skipNodeModulesBundle: true\n },\n tsdown: {\n dts: false,\n nodeProtocol: true,\n unbundle: false\n }\n });\n\n return result;\n },\n configResolved: {\n order: \"pre\",\n async handler() {\n this.debug(\"Shell Shock configuration has been resolved.\");\n\n await updatePackageJsonBinary(this);\n\n this.config.appSpecificEnvPrefix = isSetString(\n this.config.autoAssignEnv\n )\n ? this.config.autoAssignEnv\n : constantCase(getAppName(this));\n if (\n !this.config.env.prefix ||\n !Array.isArray(this.config.env.prefix)\n ) {\n this.config.env.prefix = toArray(this.config.env.prefix);\n }\n\n if (\n !this.config.env.prefix.includes(this.config.appSpecificEnvPrefix)\n ) {\n this.config.env.prefix.push(this.config.appSpecificEnvPrefix);\n }\n\n this.config.bin = (isSetString(this.packageJson.bin)\n ? { [kebabCase(this.config.name)]: this.packageJson.bin }\n : this.packageJson.bin) ?? {\n [kebabCase(this.config.name)]: formatBinaryPath(\n this.config.output.format\n )\n };\n\n if (isSetString(this.config.reference)) {\n if (this.config.reference.includes(\"{command}\")) {\n this.config.reference = {\n app: this.config.reference\n .substring(0, this.config.reference.indexOf(\"{command}\"))\n .replace(/\\/?$/, \"/\"),\n commands: this.config.reference\n };\n } else if (this.config.reference.includes(\"{commands}\")) {\n this.config.reference = {\n app: this.config.reference\n .substring(0, this.config.reference.indexOf(\"{commands}\"))\n .replace(/\\/?$/, \"/\"),\n commands: this.config.reference\n };\n } else {\n this.config.reference = {\n app: this.config.reference\n };\n }\n }\n\n this.inputs ??= [];\n this.globalOptions = Object.values(\n getGlobalOptions(this, {\n id: null,\n name: this.config.name,\n path: null,\n segments: [],\n title: this.config.title,\n description: this.config.description,\n alias: [],\n isVirtual: false\n })\n );\n\n this.globalOptions = this.globalOptions.map(option => ({\n ...option,\n name: camelCase(option.name),\n alias: option.alias ?? [],\n optional: option.optional ?? false\n }));\n }\n }\n },\n ...nodejs<TContext>(\n defu(options ?? {}, {\n env: {\n types: \"@shell-shock/core/types/env#ShellShockEnv\",\n validate: false\n }\n })\n ),\n {\n name: \"shell-shock:inputs\",\n async configResolved() {\n this.debug(\n `Checking for commands using input: ${JSON.stringify(this.config.input)}`\n );\n\n this.commandsPath = await findCommandsRoot(this);\n this.debug(`Resolved commands root path: ${this.commandsPath}`);\n\n const inputs = await resolveInputs(this, this.config.input);\n\n this.debug(\n `Found ${\n inputs.length\n } entry points specified in the configuration options.`\n );\n\n this.inputs = inputs.reduce((ret, entry) => {\n if (\n entry.file !== this.commandsPath &&\n !isParentPath(entry.file, this.commandsPath)\n ) {\n throw new Error(\n `Command entry point \"${\n entry.file\n }\" is not located within the commands root \"${\n this.commandsPath\n }\". Please ensure that all command entry points are located within the current project.`\n );\n }\n\n const id = resolveCommandId(this, entry.file);\n if (!ret.some(existing => existing.id === id)) {\n const name = resolveCommandName(entry.file);\n let segments = resolveCommandPath(this, entry.file)\n .split(\"/\")\n .filter(Boolean);\n\n // Ensure unique segment names by appending an index suffix to duplicates\n segments = segments.map((segment, index) => {\n const found = segments.findIndex(\n existing => existing === segment\n );\n if (found !== -1 && found !== index) {\n segment += `_${\n segments.filter(\n segment =>\n isDynamicPathSegment(segment) &&\n getDynamicPathSegmentName(segment).replace(\n /_\\d+$/,\n \"\"\n ) === segment\n ).length\n }`;\n }\n\n return segment;\n });\n\n ret.push({\n id,\n path: segments.join(\"/\"),\n segments,\n name,\n alias: [],\n tags: [],\n isVirtual: false,\n source: \"file\",\n entry: {\n ...entry,\n file: entry.file,\n input: {\n file: entry.file,\n name: entry.name\n },\n output: name\n }\n });\n }\n\n return ret;\n }, this.inputs);\n\n this.debug(\n `Shell Shock will process ${\n this.inputs.length\n } command entry files: \\n${this.inputs\n .map(\n command =>\n ` - ${command.id}: ${replacePath(\n command.entry.file,\n this.commandsPath\n )}`\n )\n .join(\"\\n\")}`\n );\n },\n async prepare() {\n this.debug(\n \"Rendering base built-in modules for the Shell Shock application.\"\n );\n\n return render(\n this,\n <>\n <StateBuiltin />\n <UtilsBuiltin />\n <ExecBuiltin />\n </>\n );\n }\n },\n {\n name: \"shell-shock:virtual-inputs\",\n configResolved: {\n order: \"post\",\n async handler() {\n if (this.inputs.length === 0) {\n this.warn(\n \"No commands were found in the project. Please ensure at least one command exists.\"\n );\n } else {\n this.debug(\n \"Finding and adding virtual command inputs for each command previously found.\"\n );\n\n this.inputs = this.inputs\n .reduce((ret, command) => {\n let depth = 0;\n\n let parentPath = resolveParentPath(\n findFilePath(command.entry.file)\n );\n if (isParentPath(parentPath, this.commandsPath)) {\n while (parentPath !== this.commandsPath) {\n if (depth++ > MAX_DEPTH) {\n throw new Error(\n `Unable to process virtual commands for ${\n command.name\n } \\n\\nPlease ensure ${\n command.entry.file\n } is a valid command entry file and does not have an invalid path.`\n );\n }\n\n if (\n !ret.some(\n existing =>\n findFilePath(existing.entry.file) === parentPath\n )\n ) {\n const file = joinPaths(parentPath, \"command.ts\");\n const id = resolveCommandId(this, file);\n if (!ret.some(existing => existing.id === id)) {\n const name = resolveCommandName(file);\n\n let segments = resolveCommandPath(this, file)\n .split(\"/\")\n .filter(Boolean);\n\n // Ensure unique segment names by appending an index suffix to duplicates\n segments = segments.map((segment, index) => {\n const found = segments.findIndex(\n existing => existing === segment\n );\n if (found !== -1 && found !== index) {\n segment += `_${\n segments.filter(\n segment =>\n isDynamicPathSegment(segment) &&\n getDynamicPathSegmentName(segment).replace(\n /_\\d+$/,\n \"\"\n ) === segment\n ).length\n }`;\n }\n\n return segment;\n });\n\n ret.push({\n id,\n path: segments.join(\"/\"),\n segments,\n name,\n alias: [],\n tags: [],\n isVirtual: true,\n entry: {\n file\n },\n source: \"file\"\n });\n }\n }\n\n parentPath = resolveParentPath(parentPath);\n }\n }\n\n return ret;\n }, this.inputs)\n .sort((a, b) => a.segments.length - b.segments.length);\n\n this.debug(\n `Final command input list: \\n${this.inputs\n .map(\n command =>\n ` - ${command.id}${command.isVirtual ? \" (virtual)\" : \"\"}: ${\n command.source === \"file\"\n ? replacePath(command.entry.file, this.commandsPath)\n : `added by ${command.source}`\n }`\n )\n .join(\"\\n\")}`\n );\n }\n }\n }\n },\n {\n name: \"shell-shock:update-env\",\n configResolved: {\n order: \"post\",\n async handler() {\n this.debug(\n \"Adding global options to the CLI application's environment variables.\"\n );\n\n for (const option of Object.values(this.globalOptions)\n .filter(option => Boolean(option.env))\n .filter(\n option =>\n !this.env.types.env.getPropertyOrUndefined(option.env as string)\n )) {\n this.env.types.env.addProperty({\n name: option.env as string,\n optional: option.optional ? true : undefined,\n description: option.description,\n visibility: ReflectionVisibility.public,\n type: extractType(option),\n default: option.default,\n tags: {\n title: option.title,\n alias: option.alias\n .filter(alias => alias.length > 1)\n .map(alias => constantCase(alias)),\n domain: \"cli\"\n }\n });\n }\n\n await writeEnvTypeReflection(this, this.env.types.env, \"env\");\n }\n }\n },\n {\n name: \"shell-shock:resolve-commands\",\n prepare: {\n order: \"post\",\n async handler() {\n this.debug(\"Initializing the CLI application's command tree.\");\n\n this.commands = {};\n if (\n this.config.command !== \"prepare\" &&\n this.config.skipCache !== true &&\n this.persistedMeta?.checksum === this.meta.checksum &&\n this.fs.existsSync(getCommandsPersistencePath(this))\n ) {\n this.debug(\n `Skipping command resolution as the meta checksum has not changed.`\n );\n\n await readCommandsPersistence(this);\n } else {\n for (const input of this.inputs.filter(\n input =>\n input.segments.filter(\n segment =>\n !isDynamicPathSegment(segment) &&\n !isPathSegmentGroup(segment)\n ).length === 1\n )) {\n this.commands[input.name] = await resolve({\n context: this,\n command: input\n });\n }\n\n this.debug(\"Post-processing commands to ensure proper reflection.\");\n\n await traverseCommands(this, command => {\n command.options = Object.fromEntries(\n Object.entries(command.options).map(([name, option]) => [\n camelCase(name),\n {\n ...option,\n name: camelCase(name),\n alias: option.alias ?? [],\n optional: option.optional ?? false\n }\n ])\n );\n });\n\n await writeCommandsPersistence(this);\n }\n\n this.debug(\"Validating the CLI applications command tree.\");\n\n let isValid = true;\n await traverseCommands(this, command => {\n const failures = validateCommand(command);\n if (failures.length > 0) {\n this.error(\n `Found ${failures.length} issue${failures.length > 1 ? \"s\" : \"\"} with the ${\n command.title\n } command: \\n${failures\n .map(failure => ` - ${failure.code}: ${failure.details}`)\n .join(\"\\n\")}\\n`\n );\n isValid = false;\n }\n });\n if (!isValid) {\n throw new Error(\n `One or more commands in the command tree are invalid. Please review the errors above and correct them before proceeding.`\n );\n }\n\n this.info(\n `\\nCreating an application with the following command tree: \\n${formatCommandTree(\n this\n )}\\n`\n );\n }\n }\n },\n {\n name: \"shell-shock:chmod+x\",\n configResolved() {\n this.config.tsdown.hooks ??= {};\n (this.config.tsdown.hooks as TsdownHooks)[\"build:done\"] = async (\n _: BuildContext & {\n chunks: RolldownChunk[];\n }\n ) => {\n await Promise.all(\n Object.values(this.config.bin).map(async bin => {\n const path = appendPath(\n bin,\n joinPaths(this.config.cwd, this.config.root)\n );\n if (this.fs.existsSync(path)) {\n this.debug(\n `Adding hashbang to binary executable output file: ${path}`\n );\n\n const content = await this.fs.read(path);\n if (content && !content.startsWith(\"#!\")) {\n await this.fs.write(\n path,\n `#!/usr/bin/env ${\n this.config.mode === \"development\"\n ? \"-S NODE_OPTIONS=--enable-source-maps\"\n : \"\"\n } node\\n\\n${content}`\n );\n }\n\n this.debug(\n `Adding executable permissions (chmod+x) to binary executable output file: ${\n path\n }`\n );\n\n await chmodX(path);\n } else {\n this.warn(\n `Expected binary output file not found at path: ${\n path\n }. Skipping adding hashbang and executable permissions (chmod+x).`\n );\n }\n })\n );\n };\n }\n },\n {\n name: \"shell-shock:docs\",\n configResolved() {\n this.config.automd ??= {};\n this.config.automd.generators = {\n ...(this.config.automd.generators ?? {}),\n commands: commands(this)\n };\n },\n async docs() {\n this.debug(\n \"Rendering entrypoint modules for the Shell Shock `script` preset.\"\n );\n\n const commands = this.inputs\n .map(input => getCommandTree(this, input.segments))\n .filter(Boolean) as CommandTree[];\n\n return render(\n this,\n <For each={Object.values(commands)} doubleHardline>\n {child => (\n <Show when={!child.isVirtual}>\n <CommandDocsFile command={child} />\n </Show>\n )}\n </For>\n );\n }\n }\n ];\n};\n\nexport default plugin;\n"],"mappings":"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"}