@expressots/cli 3.0.0 → 4.0.0-preview.3

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 (194) hide show
  1. package/README.md +41 -95
  2. package/bin/cicd/cli.d.ts +6 -0
  3. package/bin/cicd/cli.js +128 -0
  4. package/bin/cicd/form.d.ts +29 -0
  5. package/bin/cicd/form.js +346 -0
  6. package/bin/cicd/generators/azure-devops.d.ts +2 -0
  7. package/bin/cicd/generators/azure-devops.js +370 -0
  8. package/bin/cicd/generators/bitbucket.d.ts +2 -0
  9. package/bin/cicd/generators/bitbucket.js +217 -0
  10. package/bin/cicd/generators/circleci.d.ts +2 -0
  11. package/bin/cicd/generators/circleci.js +274 -0
  12. package/bin/cicd/generators/github-actions.d.ts +14 -0
  13. package/bin/cicd/generators/github-actions.js +426 -0
  14. package/bin/cicd/generators/gitlab-ci.d.ts +2 -0
  15. package/bin/cicd/generators/gitlab-ci.js +237 -0
  16. package/bin/cicd/generators/index.d.ts +6 -0
  17. package/bin/cicd/generators/index.js +15 -0
  18. package/bin/cicd/generators/jenkins.d.ts +2 -0
  19. package/bin/cicd/generators/jenkins.js +248 -0
  20. package/bin/cicd/generators/template-loader.d.ts +17 -0
  21. package/bin/cicd/generators/template-loader.js +128 -0
  22. package/bin/cicd/index.d.ts +1 -0
  23. package/bin/cicd/index.js +5 -0
  24. package/bin/cli.d.ts +1 -5
  25. package/bin/cli.js +72 -7
  26. package/bin/commands/project.commands.d.ts +19 -6
  27. package/bin/commands/project.commands.js +602 -66
  28. package/bin/config/index.d.ts +5 -0
  29. package/bin/config/index.js +10 -0
  30. package/bin/config/manager.d.ts +98 -0
  31. package/bin/config/manager.js +222 -0
  32. package/bin/containerize/analyzers/bootstrap-analyzer.d.ts +46 -0
  33. package/bin/containerize/analyzers/bootstrap-analyzer.js +187 -0
  34. package/bin/containerize/analyzers/project-analyzer.d.ts +20 -0
  35. package/bin/containerize/analyzers/project-analyzer.js +150 -0
  36. package/bin/containerize/cli.d.ts +4 -0
  37. package/bin/containerize/cli.js +113 -0
  38. package/bin/containerize/form.d.ts +15 -0
  39. package/bin/containerize/form.js +152 -0
  40. package/bin/containerize/generators/ci-generator.d.ts +31 -0
  41. package/bin/containerize/generators/ci-generator.js +940 -0
  42. package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
  43. package/bin/containerize/generators/docker-compose-generator.js +187 -0
  44. package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
  45. package/bin/containerize/generators/dockerfile-generator.js +657 -0
  46. package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
  47. package/bin/containerize/generators/kubernetes-generator.js +134 -0
  48. package/bin/containerize/generators/template-loader.d.ts +36 -0
  49. package/bin/containerize/generators/template-loader.js +129 -0
  50. package/bin/containerize/index.d.ts +4 -0
  51. package/bin/containerize/index.js +13 -0
  52. package/bin/containerize/presets/preset-registry.d.ts +20 -0
  53. package/bin/containerize/presets/preset-registry.js +102 -0
  54. package/bin/costs/cli.d.ts +5 -0
  55. package/bin/costs/cli.js +185 -0
  56. package/bin/costs/form.d.ts +44 -0
  57. package/bin/costs/form.js +412 -0
  58. package/bin/costs/index.d.ts +4 -0
  59. package/bin/costs/index.js +25 -0
  60. package/bin/costs/pricing-manager.d.ts +84 -0
  61. package/bin/costs/pricing-manager.js +342 -0
  62. package/bin/costs/providers/index.d.ts +32 -0
  63. package/bin/costs/providers/index.js +153 -0
  64. package/bin/costs/sources/api-source.d.ts +10 -0
  65. package/bin/costs/sources/api-source.js +32 -0
  66. package/bin/costs/sources/index.d.ts +6 -0
  67. package/bin/costs/sources/index.js +15 -0
  68. package/bin/costs/sources/local-json-source.d.ts +23 -0
  69. package/bin/costs/sources/local-json-source.js +59 -0
  70. package/bin/costs/sources/remote-json-source.d.ts +11 -0
  71. package/bin/costs/sources/remote-json-source.js +53 -0
  72. package/bin/costs/types.d.ts +53 -0
  73. package/bin/costs/types.js +5 -0
  74. package/bin/dev/cli.d.ts +4 -0
  75. package/bin/dev/cli.js +136 -0
  76. package/bin/dev/form.d.ts +36 -0
  77. package/bin/dev/form.js +254 -0
  78. package/bin/dev/index.d.ts +1 -0
  79. package/bin/dev/index.js +5 -0
  80. package/bin/generate/cli.d.ts +1 -1
  81. package/bin/generate/cli.js +29 -2
  82. package/bin/generate/form.d.ts +5 -1
  83. package/bin/generate/form.js +3 -3
  84. package/bin/generate/templates/nonopinionated/config.tpl +12 -0
  85. package/bin/generate/templates/nonopinionated/event.tpl +10 -0
  86. package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
  87. package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
  88. package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
  89. package/bin/generate/templates/opinionated/config.tpl +47 -0
  90. package/bin/generate/templates/opinionated/entity.tpl +1 -8
  91. package/bin/generate/templates/opinionated/event.tpl +15 -0
  92. package/bin/generate/templates/opinionated/guard.tpl +41 -0
  93. package/bin/generate/templates/opinionated/handler.tpl +23 -0
  94. package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
  95. package/bin/generate/utils/command-utils.d.ts +20 -5
  96. package/bin/generate/utils/command-utils.js +145 -48
  97. package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
  98. package/bin/generate/utils/nonopininated-cmd.js +100 -1
  99. package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
  100. package/bin/generate/utils/opinionated-cmd.js +128 -16
  101. package/bin/generate/utils/string-utils.d.ts +6 -0
  102. package/bin/generate/utils/string-utils.js +13 -1
  103. package/bin/help/cli.d.ts +1 -1
  104. package/bin/help/command-help-registry.d.ts +23 -0
  105. package/bin/help/command-help-registry.js +303 -0
  106. package/bin/help/command-help.d.ts +36 -0
  107. package/bin/help/command-help.js +56 -0
  108. package/bin/help/form.js +127 -22
  109. package/bin/help/main-help.d.ts +8 -0
  110. package/bin/help/main-help.js +126 -0
  111. package/bin/help/render.d.ts +32 -0
  112. package/bin/help/render.js +46 -0
  113. package/bin/info/cli.d.ts +1 -1
  114. package/bin/info/form.d.ts +1 -1
  115. package/bin/info/form.js +11 -11
  116. package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
  117. package/bin/migrate/analyzers/platform-detector.js +116 -0
  118. package/bin/migrate/cli.d.ts +6 -0
  119. package/bin/migrate/cli.js +98 -0
  120. package/bin/migrate/form.d.ts +25 -0
  121. package/bin/migrate/form.js +348 -0
  122. package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
  123. package/bin/migrate/generators/compose-to-k8s.js +324 -0
  124. package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
  125. package/bin/migrate/generators/compose-to-railway.js +138 -0
  126. package/bin/migrate/generators/compose-to-render.d.ts +2 -0
  127. package/bin/migrate/generators/compose-to-render.js +148 -0
  128. package/bin/migrate/generators/generic-migration.d.ts +9 -0
  129. package/bin/migrate/generators/generic-migration.js +221 -0
  130. package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
  131. package/bin/migrate/generators/heroku-to-fly.js +291 -0
  132. package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
  133. package/bin/migrate/generators/heroku-to-railway.js +283 -0
  134. package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
  135. package/bin/migrate/generators/heroku-to-render.js +148 -0
  136. package/bin/migrate/generators/index.d.ts +7 -0
  137. package/bin/migrate/generators/index.js +17 -0
  138. package/bin/migrate/generators/template-loader.d.ts +21 -0
  139. package/bin/migrate/generators/template-loader.js +59 -0
  140. package/bin/migrate/index.d.ts +1 -0
  141. package/bin/migrate/index.js +5 -0
  142. package/bin/new/cli.d.ts +5 -1
  143. package/bin/new/cli.js +77 -14
  144. package/bin/new/form.d.ts +27 -4
  145. package/bin/new/form.js +605 -75
  146. package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
  147. package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
  148. package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
  149. package/bin/profile/analyzers/image-analyzer.js +85 -0
  150. package/bin/profile/cli.d.ts +4 -0
  151. package/bin/profile/cli.js +94 -0
  152. package/bin/profile/form.d.ts +56 -0
  153. package/bin/profile/form.js +401 -0
  154. package/bin/profile/index.d.ts +1 -0
  155. package/bin/profile/index.js +5 -0
  156. package/bin/profile/optimizers/index.d.ts +19 -0
  157. package/bin/profile/optimizers/index.js +137 -0
  158. package/bin/providers/add/form.d.ts +1 -1
  159. package/bin/providers/add/form.js +27 -6
  160. package/bin/providers/create/form.js +53 -3
  161. package/bin/scripts/form.js +27 -5
  162. package/bin/studio/cli.d.ts +15 -0
  163. package/bin/studio/cli.js +172 -0
  164. package/bin/studio/index.d.ts +5 -0
  165. package/bin/studio/index.js +9 -0
  166. package/bin/templates/cache.d.ts +54 -0
  167. package/bin/templates/cache.js +180 -0
  168. package/bin/templates/cli.d.ts +8 -0
  169. package/bin/templates/cli.js +294 -0
  170. package/bin/templates/fetcher.d.ts +49 -0
  171. package/bin/templates/fetcher.js +208 -0
  172. package/bin/templates/index.d.ts +11 -0
  173. package/bin/templates/index.js +37 -0
  174. package/bin/templates/manager.d.ts +116 -0
  175. package/bin/templates/manager.js +323 -0
  176. package/bin/templates/renderer.d.ts +49 -0
  177. package/bin/templates/renderer.js +204 -0
  178. package/bin/templates/types.d.ts +51 -0
  179. package/bin/templates/types.js +5 -0
  180. package/bin/utils/add-module-to-container.d.ts +14 -3
  181. package/bin/utils/add-module-to-container.js +327 -98
  182. package/bin/utils/cli-ui.d.ts +49 -3
  183. package/bin/utils/cli-ui.js +133 -13
  184. package/bin/utils/index.d.ts +4 -0
  185. package/bin/utils/index.js +4 -0
  186. package/bin/utils/input-validation.d.ts +50 -0
  187. package/bin/utils/input-validation.js +143 -0
  188. package/bin/utils/package-manager-commands.d.ts +24 -0
  189. package/bin/utils/package-manager-commands.js +50 -0
  190. package/bin/utils/safe-spawn.d.ts +35 -0
  191. package/bin/utils/safe-spawn.js +51 -0
  192. package/bin/utils/update-tsconfig-paths.d.ts +35 -0
  193. package/bin/utils/update-tsconfig-paths.js +326 -0
  194. package/package.json +165 -156
@@ -3,30 +3,150 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.printGenerateSuccess = exports.printGenerateError = exports.printWarning = exports.printSuccess = exports.printError = void 0;
6
+ exports.printHeader = exports.printKeyValue = exports.printDivider = exports.printBullet = exports.printSection = exports.printGenerateSuccess = exports.printGenerateError = exports.printDebug = exports.printInfo = exports.printWarning = exports.printSuccess = exports.printError = void 0;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
8
  const process_1 = require("process");
9
- function printError(message, component) {
10
- console.error(chalk_1.default.red(`${message}:`, chalk_1.default.bold(chalk_1.default.white(`[${component}] ❌`))));
9
+ /**
10
+ * Format timestamp for display (matches core logger format)
11
+ */
12
+ function formatTimestamp() {
13
+ const date = new Date();
14
+ const options = {
15
+ year: "numeric",
16
+ month: "2-digit",
17
+ day: "2-digit",
18
+ hour: "2-digit",
19
+ minute: "2-digit",
20
+ second: "2-digit",
21
+ };
22
+ return date.toLocaleString(undefined, options).replace(",", "");
23
+ }
24
+ /**
25
+ * Color a string based on log level
26
+ */
27
+ function colorByLevel(level, text) {
28
+ switch (level) {
29
+ case "INFO":
30
+ return chalk_1.default.green(text);
31
+ case "WARN":
32
+ return chalk_1.default.yellow(text);
33
+ case "ERROR":
34
+ return chalk_1.default.red(text);
35
+ case "DEBUG":
36
+ return chalk_1.default.blue(text);
37
+ default:
38
+ return chalk_1.default.white(text);
39
+ }
40
+ }
41
+ /**
42
+ * Core log function matching ExpressoTS core logger format
43
+ * Format: [ExpressoTS] timestamp LEVEL [context] message
44
+ */
45
+ function log(level, context, message, icon) {
46
+ const timestamp = formatTimestamp();
47
+ const levelStr = colorByLevel(level, level.padEnd(5, " "));
48
+ const contextStr = chalk_1.default.green(`[${context}]`);
49
+ const messageStr = colorByLevel(level, message);
50
+ const iconStr = icon ? ` ${icon}` : "";
51
+ const output = `${chalk_1.default.green("[ExpressoTS]")} ${timestamp} ${levelStr} ${contextStr} ${messageStr}${iconStr}\n`;
52
+ if (level === "ERROR") {
53
+ process.stderr.write(output);
54
+ }
55
+ else {
56
+ process_1.stdout.write(output);
57
+ }
58
+ }
59
+ /**
60
+ * Print error message (matches core logger ERROR format)
61
+ */
62
+ function printError(message, context) {
63
+ log("ERROR", context, message, "❌");
11
64
  }
12
65
  exports.printError = printError;
13
- function printSuccess(message, component) {
14
- process_1.stdout.write(chalk_1.default.green(`${message}:`, chalk_1.default.bold(chalk_1.default.white(`[${component}] ✔️\n`))));
66
+ /**
67
+ * Print success message (matches core logger INFO format)
68
+ */
69
+ function printSuccess(message, context) {
70
+ log("INFO", context, message, "✔️");
15
71
  }
16
72
  exports.printSuccess = printSuccess;
17
- function printWarning(message, component) {
18
- if (component === undefined) {
19
- process_1.stdout.write(chalk_1.default.yellow(`${message} ⚠️\n`));
20
- return;
21
- }
22
- process_1.stdout.write(chalk_1.default.yellow(`${message}:`, chalk_1.default.bold(chalk_1.default.white(`[${component}] ⚠️\n`))));
73
+ /**
74
+ * Print warning message (matches core logger WARN format)
75
+ */
76
+ function printWarning(message, context) {
77
+ log("WARN", context || "cli", message, "⚠️");
23
78
  }
24
79
  exports.printWarning = printWarning;
80
+ /**
81
+ * Print info message (matches core logger INFO format)
82
+ */
83
+ function printInfo(message, context) {
84
+ log("INFO", context, message);
85
+ }
86
+ exports.printInfo = printInfo;
87
+ /**
88
+ * Print debug message (matches core logger DEBUG format)
89
+ */
90
+ function printDebug(message, context) {
91
+ log("DEBUG", context, message);
92
+ }
93
+ exports.printDebug = printDebug;
94
+ /**
95
+ * Print generate error (simplified format for scaffolding)
96
+ */
25
97
  async function printGenerateError(schematic, file) {
26
- console.error(" ", chalk_1.default.redBright(`[${schematic}]`.padEnd(14)), chalk_1.default.bold.white(`${file.split(".")[0]} not created! ❌`));
98
+ log("ERROR", schematic, `${file.split(".")[0]} not created!`, "❌");
27
99
  }
28
100
  exports.printGenerateError = printGenerateError;
101
+ /**
102
+ * Print generate success (simplified format for scaffolding)
103
+ */
29
104
  async function printGenerateSuccess(schematic, file) {
30
- console.log(" ", chalk_1.default.greenBright(`[${schematic}]`.padEnd(14)), chalk_1.default.bold.white(`${file.split(".")[0]} created! ✔️`));
105
+ log("INFO", schematic, `${file.split(".")[0]} created!`, "✔️");
31
106
  }
32
107
  exports.printGenerateSuccess = printGenerateSuccess;
108
+ /**
109
+ * Print a section title. Intended for interactive/listing output (e.g.
110
+ * `templates list`, `costs compare`) where the structured logger format
111
+ * (`[ExpressoTS] timestamp LEVEL`) would be noisy. Leading newline keeps
112
+ * sections visually separated.
113
+ */
114
+ function printSection(title) {
115
+ process_1.stdout.write(`\n${chalk_1.default.bold.cyan(title)}\n`);
116
+ }
117
+ exports.printSection = printSection;
118
+ /**
119
+ * Print an indented bullet point under a section.
120
+ */
121
+ function printBullet(text) {
122
+ process_1.stdout.write(` ${chalk_1.default.gray("-")} ${text}\n`);
123
+ }
124
+ exports.printBullet = printBullet;
125
+ /**
126
+ * Print a dim horizontal divider sized to the terminal width (capped).
127
+ */
128
+ function printDivider() {
129
+ const cols = typeof process.stdout.columns === "number" && process.stdout.columns > 0
130
+ ? process.stdout.columns
131
+ : 80;
132
+ const width = Math.min(Math.max(cols, 20), 80);
133
+ process_1.stdout.write(`${chalk_1.default.dim("\u2500".repeat(width))}\n`);
134
+ }
135
+ exports.printDivider = printDivider;
136
+ /**
137
+ * Print an aligned key/value pair (e.g. `Source: remote`).
138
+ */
139
+ function printKeyValue(key, value, padding = 12) {
140
+ process_1.stdout.write(` ${chalk_1.default.bold(`${key}:`.padEnd(padding))} ${value}\n`);
141
+ }
142
+ exports.printKeyValue = printKeyValue;
143
+ /**
144
+ * Print the ExpressoTS CLI header
145
+ */
146
+ function printHeader(version) {
147
+ const title = version
148
+ ? `🐎 ExpressoTS CLI v${version}`
149
+ : "🐎 ExpressoTS CLI";
150
+ process_1.stdout.write(`\n${chalk_1.default.bold.green(title)}\n\n`);
151
+ }
152
+ exports.printHeader = printHeader;
@@ -1 +1,5 @@
1
1
  export * from "./compiler";
2
+ export * from "./input-validation";
3
+ export * from "./package-manager-commands";
4
+ export * from "./safe-spawn";
5
+ export * from "./update-tsconfig-paths";
@@ -15,3 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./compiler"), exports);
18
+ __exportStar(require("./input-validation"), exports);
19
+ __exportStar(require("./package-manager-commands"), exports);
20
+ __exportStar(require("./safe-spawn"), exports);
21
+ __exportStar(require("./update-tsconfig-paths"), exports);
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Input validation utilities used across the CLI to defend against
3
+ * command injection and path traversal when user-supplied values flow
4
+ * into child_process spawn/exec calls or filesystem writes.
5
+ */
6
+ /**
7
+ * Guard against shell metacharacters in any value that will be
8
+ * interpolated into a shell-evaluated command line.
9
+ */
10
+ export declare function containsShellMetachars(value: string): boolean;
11
+ /**
12
+ * Validate an npm package name (with optional scope).
13
+ */
14
+ export declare function isValidPackageName(name: unknown): name is string;
15
+ /**
16
+ * Validate a version specifier passed to a package manager. Accepts
17
+ * `latest`, `next`, exact versions and common range syntaxes
18
+ * (`>=1.2.3 <2.0.0`, `*`, `1.x`). Returns false for the boolean
19
+ * fallback yargs sometimes assigns when the flag is absent.
20
+ *
21
+ * Versions are forwarded via argv (`shell: false`), so we whitelist
22
+ * the characters npm itself accepts in semver ranges and reject the
23
+ * rest. We do NOT layer the broader `containsShellMetachars` check
24
+ * here because legitimate ranges include `<`, `>`, `|`, and `*`.
25
+ */
26
+ export declare function isValidVersion(version: unknown): version is string;
27
+ /**
28
+ * Validate an npm/yarn/pnpm script name.
29
+ */
30
+ export declare function isValidScriptName(name: unknown): name is string;
31
+ export declare function isValidPackageManager(pm: unknown): pm is "npm" | "yarn" | "pnpm" | "bun";
32
+ /**
33
+ * Resolve `target` against `base` and verify the result is contained
34
+ * within `base`. Returns the resolved absolute path on success, or
35
+ * `null` when the resolved path escapes the base directory (path
36
+ * traversal attempt).
37
+ */
38
+ export declare function safeResolveWithin(base: string, target: string): string | null;
39
+ /**
40
+ * Throws a generic `Error` if the value is not a safe package name.
41
+ */
42
+ export declare function assertValidPackageName(name: unknown): asserts name is string;
43
+ /**
44
+ * Throws a generic `Error` if the value is not a safe version range.
45
+ */
46
+ export declare function assertValidVersion(version: unknown): asserts version is string;
47
+ /**
48
+ * Throws a generic `Error` if the value is not a safe script name.
49
+ */
50
+ export declare function assertValidScriptName(name: unknown): asserts name is string;
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ /**
3
+ * Input validation utilities used across the CLI to defend against
4
+ * command injection and path traversal when user-supplied values flow
5
+ * into child_process spawn/exec calls or filesystem writes.
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.assertValidScriptName = exports.assertValidVersion = exports.assertValidPackageName = exports.safeResolveWithin = exports.isValidPackageManager = exports.isValidScriptName = exports.isValidVersion = exports.isValidPackageName = exports.containsShellMetachars = void 0;
12
+ const node_path_1 = __importDefault(require("node:path"));
13
+ /**
14
+ * Characters that have shell-special meaning across POSIX shells and
15
+ * Windows cmd. If any appear in a value that will be interpolated into
16
+ * a shell-evaluated command (`shell: true` or `execSync(string)`), the
17
+ * value must be rejected.
18
+ */
19
+ const SHELL_METACHARACTERS = /[;&|`$()<>\n\r\\"'*?{}[\]!#~]/;
20
+ /**
21
+ * Conservative regex for npm package names. Allows scoped packages,
22
+ * dotted segments and dashes, mirroring https://docs.npmjs.com/cli/v10/configuring-npm/package-json#name
23
+ * but stricter than npm itself to remove ambiguity (no leading dots,
24
+ * no uppercase to keep it portable across registries).
25
+ */
26
+ const PACKAGE_NAME_RE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
27
+ /**
28
+ * Semver-ish range validator. Accepts the common syntactic shapes
29
+ * (e.g. 1.2.3, ^1.2, ~1, 1.x, latest, next, >=1.2.3 <2.0.0) without
30
+ * pulling in the full semver parser for this guard.
31
+ */
32
+ const VERSION_RE = /^[A-Za-z0-9.\-+~^>=<* |]+$/;
33
+ /**
34
+ * Script name validator for npm/yarn/pnpm `run` targets. Matches what
35
+ * those package managers actually accept (alphanumerics plus
36
+ * `:_-./`), explicitly rejecting whitespace and shell metacharacters.
37
+ */
38
+ const SCRIPT_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9:_./-]*$/;
39
+ /**
40
+ * Guard against shell metacharacters in any value that will be
41
+ * interpolated into a shell-evaluated command line.
42
+ */
43
+ function containsShellMetachars(value) {
44
+ return SHELL_METACHARACTERS.test(value);
45
+ }
46
+ exports.containsShellMetachars = containsShellMetachars;
47
+ /**
48
+ * Validate an npm package name (with optional scope).
49
+ */
50
+ function isValidPackageName(name) {
51
+ if (typeof name !== "string" || name.length === 0 || name.length > 214) {
52
+ return false;
53
+ }
54
+ if (containsShellMetachars(name))
55
+ return false;
56
+ return PACKAGE_NAME_RE.test(name);
57
+ }
58
+ exports.isValidPackageName = isValidPackageName;
59
+ /**
60
+ * Validate a version specifier passed to a package manager. Accepts
61
+ * `latest`, `next`, exact versions and common range syntaxes
62
+ * (`>=1.2.3 <2.0.0`, `*`, `1.x`). Returns false for the boolean
63
+ * fallback yargs sometimes assigns when the flag is absent.
64
+ *
65
+ * Versions are forwarded via argv (`shell: false`), so we whitelist
66
+ * the characters npm itself accepts in semver ranges and reject the
67
+ * rest. We do NOT layer the broader `containsShellMetachars` check
68
+ * here because legitimate ranges include `<`, `>`, `|`, and `*`.
69
+ */
70
+ function isValidVersion(version) {
71
+ if (typeof version !== "string" || version.length === 0)
72
+ return false;
73
+ if (version.length > 64)
74
+ return false;
75
+ return VERSION_RE.test(version);
76
+ }
77
+ exports.isValidVersion = isValidVersion;
78
+ /**
79
+ * Validate an npm/yarn/pnpm script name.
80
+ */
81
+ function isValidScriptName(name) {
82
+ if (typeof name !== "string" || name.length === 0 || name.length > 214) {
83
+ return false;
84
+ }
85
+ if (containsShellMetachars(name))
86
+ return false;
87
+ return SCRIPT_NAME_RE.test(name);
88
+ }
89
+ exports.isValidScriptName = isValidScriptName;
90
+ /**
91
+ * Validate a package manager identifier.
92
+ */
93
+ const ALLOWED_PACKAGE_MANAGERS = new Set(["npm", "yarn", "pnpm", "bun"]);
94
+ function isValidPackageManager(pm) {
95
+ return typeof pm === "string" && ALLOWED_PACKAGE_MANAGERS.has(pm);
96
+ }
97
+ exports.isValidPackageManager = isValidPackageManager;
98
+ /**
99
+ * Resolve `target` against `base` and verify the result is contained
100
+ * within `base`. Returns the resolved absolute path on success, or
101
+ * `null` when the resolved path escapes the base directory (path
102
+ * traversal attempt).
103
+ */
104
+ function safeResolveWithin(base, target) {
105
+ const absoluteBase = node_path_1.default.resolve(base);
106
+ const absoluteTarget = node_path_1.default.resolve(absoluteBase, target);
107
+ const baseWithSep = absoluteBase.endsWith(node_path_1.default.sep)
108
+ ? absoluteBase
109
+ : absoluteBase + node_path_1.default.sep;
110
+ if (absoluteTarget !== absoluteBase &&
111
+ !absoluteTarget.startsWith(baseWithSep)) {
112
+ return null;
113
+ }
114
+ return absoluteTarget;
115
+ }
116
+ exports.safeResolveWithin = safeResolveWithin;
117
+ /**
118
+ * Throws a generic `Error` if the value is not a safe package name.
119
+ */
120
+ function assertValidPackageName(name) {
121
+ if (!isValidPackageName(name)) {
122
+ throw new Error(`Invalid package name: ${JSON.stringify(name)}. Names must match npm package name rules and contain no shell metacharacters.`);
123
+ }
124
+ }
125
+ exports.assertValidPackageName = assertValidPackageName;
126
+ /**
127
+ * Throws a generic `Error` if the value is not a safe version range.
128
+ */
129
+ function assertValidVersion(version) {
130
+ if (!isValidVersion(version)) {
131
+ throw new Error(`Invalid version specifier: ${JSON.stringify(version)}.`);
132
+ }
133
+ }
134
+ exports.assertValidVersion = assertValidVersion;
135
+ /**
136
+ * Throws a generic `Error` if the value is not a safe script name.
137
+ */
138
+ function assertValidScriptName(name) {
139
+ if (!isValidScriptName(name)) {
140
+ throw new Error(`Invalid script name: ${JSON.stringify(name)}. Script names must match ^[a-zA-Z0-9][a-zA-Z0-9:_./-]*$.`);
141
+ }
142
+ }
143
+ exports.assertValidScriptName = assertValidScriptName;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Shared package-manager command helpers for code generators
3
+ * (Dockerfiles, CI/CD pipelines). These centralize the mapping
4
+ * between an analyzer-detected package manager and the literal
5
+ * shell strings emitted into generated files.
6
+ *
7
+ * Two flavors exist:
8
+ * - `RUN`/`CMD`-style strings used INSIDE Dockerfiles.
9
+ * - Plain shell invocations used in CI scripts and informational
10
+ * comments (no `RUN ` prefix).
11
+ */
12
+ export type SupportedPackageManager = "npm" | "yarn" | "pnpm" | "bun";
13
+ /**
14
+ * Shell invocation that installs project dependencies, suitable for
15
+ * a CI step (no `RUN ` prefix). Uses the strict, lockfile-respecting
16
+ * variant for each package manager because CI runs should be
17
+ * reproducible.
18
+ */
19
+ export declare function getCiInstallCommand(packageManager: string): string;
20
+ /**
21
+ * Shell invocation that runs an npm-style script (e.g. `lint`,
22
+ * `test`, `build`). Used in CI scripts and informational comments.
23
+ */
24
+ export declare function getRunScriptCommand(packageManager: string, scriptName: string): string;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ /**
3
+ * Shared package-manager command helpers for code generators
4
+ * (Dockerfiles, CI/CD pipelines). These centralize the mapping
5
+ * between an analyzer-detected package manager and the literal
6
+ * shell strings emitted into generated files.
7
+ *
8
+ * Two flavors exist:
9
+ * - `RUN`/`CMD`-style strings used INSIDE Dockerfiles.
10
+ * - Plain shell invocations used in CI scripts and informational
11
+ * comments (no `RUN ` prefix).
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.getRunScriptCommand = exports.getCiInstallCommand = void 0;
15
+ /**
16
+ * Shell invocation that installs project dependencies, suitable for
17
+ * a CI step (no `RUN ` prefix). Uses the strict, lockfile-respecting
18
+ * variant for each package manager because CI runs should be
19
+ * reproducible.
20
+ */
21
+ function getCiInstallCommand(packageManager) {
22
+ switch (packageManager) {
23
+ case "pnpm":
24
+ return "pnpm install --frozen-lockfile";
25
+ case "yarn":
26
+ return "yarn install --frozen-lockfile";
27
+ case "bun":
28
+ return "bun install --frozen-lockfile";
29
+ default:
30
+ return "npm ci";
31
+ }
32
+ }
33
+ exports.getCiInstallCommand = getCiInstallCommand;
34
+ /**
35
+ * Shell invocation that runs an npm-style script (e.g. `lint`,
36
+ * `test`, `build`). Used in CI scripts and informational comments.
37
+ */
38
+ function getRunScriptCommand(packageManager, scriptName) {
39
+ switch (packageManager) {
40
+ case "pnpm":
41
+ return `pnpm run ${scriptName}`;
42
+ case "yarn":
43
+ return `yarn ${scriptName}`;
44
+ case "bun":
45
+ return `bun run ${scriptName}`;
46
+ default:
47
+ return `npm run ${scriptName}`;
48
+ }
49
+ }
50
+ exports.getRunScriptCommand = getRunScriptCommand;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Cross-platform wrappers around `child_process.spawn` / `spawnSync` for
3
+ * launching package-manager binaries (npm, yarn, pnpm, npx, tsx, tsc,
4
+ * docker, etc.) reliably on every supported platform.
5
+ *
6
+ * Why this exists
7
+ * ---------------
8
+ * Starting with Node.js 18.20.2 / 20.12.2 / 21.7.3 (and every v22+), the
9
+ * runtime refuses to spawn `.bat` / `.cmd` files unless `shell: true` is
10
+ * passed (see CVE-2024-27980). On Windows, `npm`, `yarn`, `pnpm`, `npx`,
11
+ * `tsx`, `tsc`, and the `node_modules/.bin/*` shims are all `.cmd` files,
12
+ * so a direct `spawn("npm", [...], { shell: false })` call now fails with
13
+ * `EINVAL` ("Package manager not found"). At the same time, just flipping
14
+ * `shell: true` reintroduces the original CVE: arguments containing shell
15
+ * metacharacters (`|`, `>`, `<`, `^`, `&`, `(`, `)`, ...) get interpreted
16
+ * by `cmd.exe` instead of being passed verbatim, which is a real concern
17
+ * for inputs like a semver range (`>=1.0.0 <2.0.0`) or a user-supplied
18
+ * `--src` flag.
19
+ *
20
+ * `cross-spawn` solves both problems:
21
+ * - On Windows it parses the command, resolves `.cmd` shims via PATHEXT,
22
+ * and invokes `cmd.exe /d /s /c "command args"` with `shell: false` and
23
+ * `windowsVerbatimArguments: true`. Each argv entry is passed through a
24
+ * cmd.exe-aware escaper, so metacharacters stay literal.
25
+ * - On Unix it falls through to plain `spawn` with `shell: false`.
26
+ *
27
+ * The helpers here are thin wrappers that default `windowsHide: true` so
28
+ * the Windows console doesn't flash, and re-export the same options shape
29
+ * as `child_process` for drop-in usage.
30
+ */
31
+ /// <reference types="node" />
32
+ /// <reference types="node" />
33
+ import type { ChildProcess, SpawnOptions, SpawnSyncOptions, SpawnSyncReturns } from "node:child_process";
34
+ export declare function safeSpawn(command: string, args?: ReadonlyArray<string>, options?: SpawnOptions): ChildProcess;
35
+ export declare function safeSpawnSync(command: string, args?: ReadonlyArray<string>, options?: SpawnSyncOptions): SpawnSyncReturns<Buffer>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * Cross-platform wrappers around `child_process.spawn` / `spawnSync` for
4
+ * launching package-manager binaries (npm, yarn, pnpm, npx, tsx, tsc,
5
+ * docker, etc.) reliably on every supported platform.
6
+ *
7
+ * Why this exists
8
+ * ---------------
9
+ * Starting with Node.js 18.20.2 / 20.12.2 / 21.7.3 (and every v22+), the
10
+ * runtime refuses to spawn `.bat` / `.cmd` files unless `shell: true` is
11
+ * passed (see CVE-2024-27980). On Windows, `npm`, `yarn`, `pnpm`, `npx`,
12
+ * `tsx`, `tsc`, and the `node_modules/.bin/*` shims are all `.cmd` files,
13
+ * so a direct `spawn("npm", [...], { shell: false })` call now fails with
14
+ * `EINVAL` ("Package manager not found"). At the same time, just flipping
15
+ * `shell: true` reintroduces the original CVE: arguments containing shell
16
+ * metacharacters (`|`, `>`, `<`, `^`, `&`, `(`, `)`, ...) get interpreted
17
+ * by `cmd.exe` instead of being passed verbatim, which is a real concern
18
+ * for inputs like a semver range (`>=1.0.0 <2.0.0`) or a user-supplied
19
+ * `--src` flag.
20
+ *
21
+ * `cross-spawn` solves both problems:
22
+ * - On Windows it parses the command, resolves `.cmd` shims via PATHEXT,
23
+ * and invokes `cmd.exe /d /s /c "command args"` with `shell: false` and
24
+ * `windowsVerbatimArguments: true`. Each argv entry is passed through a
25
+ * cmd.exe-aware escaper, so metacharacters stay literal.
26
+ * - On Unix it falls through to plain `spawn` with `shell: false`.
27
+ *
28
+ * The helpers here are thin wrappers that default `windowsHide: true` so
29
+ * the Windows console doesn't flash, and re-export the same options shape
30
+ * as `child_process` for drop-in usage.
31
+ */
32
+ var __importDefault = (this && this.__importDefault) || function (mod) {
33
+ return (mod && mod.__esModule) ? mod : { "default": mod };
34
+ };
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.safeSpawnSync = exports.safeSpawn = void 0;
37
+ const cross_spawn_1 = __importDefault(require("cross-spawn"));
38
+ function safeSpawn(command, args = [], options = {}) {
39
+ return (0, cross_spawn_1.default)(command, args, {
40
+ windowsHide: true,
41
+ ...options,
42
+ });
43
+ }
44
+ exports.safeSpawn = safeSpawn;
45
+ function safeSpawnSync(command, args = [], options = {}) {
46
+ return cross_spawn_1.default.sync(command, args, {
47
+ windowsHide: true,
48
+ ...options,
49
+ });
50
+ }
51
+ exports.safeSpawnSync = safeSpawnSync;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Generate path alias from folder name
3
+ * Handles both default mappings and custom folder names
4
+ *
5
+ * @param folderName - The folder name (e.g., "useCases", "my-custom-folder")
6
+ * @returns The path alias (e.g., "@useCases", "@myCustomFolder")
7
+ */
8
+ export declare function generatePathAlias(folderName: string): string;
9
+ /**
10
+ * Update tsconfig.json paths to include missing aliases for opinionated scaffolding
11
+ * Handles both default folders and custom scaffoldSchematics overrides
12
+ *
13
+ * @param folderName - The folder name where the schematic is being created
14
+ * @param sourceRoot - The source root directory (default: "src")
15
+ */
16
+ export declare function updateTsconfigPaths(folderName: string, sourceRoot?: string): Promise<void>;
17
+ /**
18
+ * Get the path alias for a given folder name
19
+ * Used by other utilities to determine the correct import path
20
+ *
21
+ * @param folderName - The folder name
22
+ * @returns The path alias (e.g., "@useCases")
23
+ */
24
+ export declare function getPathAliasForFolder(folderName: string): string;
25
+ /**
26
+ * Check if tsconfig already has all required path aliases for opinionated mode
27
+ * This can be used to validate project setup
28
+ *
29
+ * @param requiredFolders - List of folder names that need path aliases
30
+ * @returns Object with missing aliases and whether all are present
31
+ */
32
+ export declare function validateTsconfigPaths(requiredFolders: string[]): {
33
+ valid: boolean;
34
+ missingAliases: string[];
35
+ };