@expressots/cli 3.0.0-beta.4 → 4.0.0-preview.2

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 (180) hide show
  1. package/README.md +41 -95
  2. package/bin/cicd/cli.d.ts +6 -0
  3. package/bin/cicd/cli.js +126 -0
  4. package/bin/cicd/form.d.ts +29 -0
  5. package/bin/cicd/form.js +345 -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 -1
  25. package/bin/cli.js +18 -3
  26. package/bin/commands/project.commands.d.ts +19 -6
  27. package/bin/commands/project.commands.js +390 -61
  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 +154 -0
  40. package/bin/containerize/generators/ci-generator.d.ts +31 -0
  41. package/bin/containerize/generators/ci-generator.js +936 -0
  42. package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
  43. package/bin/containerize/generators/docker-compose-generator.js +186 -0
  44. package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
  45. package/bin/containerize/generators/dockerfile-generator.js +635 -0
  46. package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
  47. package/bin/containerize/generators/kubernetes-generator.js +133 -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 +183 -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 +134 -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.js +29 -2
  81. package/bin/generate/form.d.ts +5 -1
  82. package/bin/generate/form.js +3 -3
  83. package/bin/generate/templates/nonopinionated/config.tpl +12 -0
  84. package/bin/generate/templates/nonopinionated/event.tpl +10 -0
  85. package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
  86. package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
  87. package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
  88. package/bin/generate/templates/opinionated/config.tpl +47 -0
  89. package/bin/generate/templates/opinionated/entity.tpl +1 -8
  90. package/bin/generate/templates/opinionated/event.tpl +15 -0
  91. package/bin/generate/templates/opinionated/guard.tpl +41 -0
  92. package/bin/generate/templates/opinionated/handler.tpl +23 -0
  93. package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
  94. package/bin/generate/utils/command-utils.d.ts +7 -3
  95. package/bin/generate/utils/command-utils.js +95 -31
  96. package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
  97. package/bin/generate/utils/nonopininated-cmd.js +100 -1
  98. package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
  99. package/bin/generate/utils/opinionated-cmd.js +112 -7
  100. package/bin/generate/utils/string-utils.d.ts +6 -0
  101. package/bin/generate/utils/string-utils.js +13 -1
  102. package/bin/help/form.js +11 -3
  103. package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
  104. package/bin/migrate/analyzers/platform-detector.js +116 -0
  105. package/bin/migrate/cli.d.ts +6 -0
  106. package/bin/migrate/cli.js +96 -0
  107. package/bin/migrate/form.d.ts +25 -0
  108. package/bin/migrate/form.js +347 -0
  109. package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
  110. package/bin/migrate/generators/compose-to-k8s.js +324 -0
  111. package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
  112. package/bin/migrate/generators/compose-to-railway.js +138 -0
  113. package/bin/migrate/generators/compose-to-render.d.ts +2 -0
  114. package/bin/migrate/generators/compose-to-render.js +148 -0
  115. package/bin/migrate/generators/generic-migration.d.ts +9 -0
  116. package/bin/migrate/generators/generic-migration.js +221 -0
  117. package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
  118. package/bin/migrate/generators/heroku-to-fly.js +291 -0
  119. package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
  120. package/bin/migrate/generators/heroku-to-railway.js +283 -0
  121. package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
  122. package/bin/migrate/generators/heroku-to-render.js +148 -0
  123. package/bin/migrate/generators/index.d.ts +7 -0
  124. package/bin/migrate/generators/index.js +17 -0
  125. package/bin/migrate/generators/template-loader.d.ts +21 -0
  126. package/bin/migrate/generators/template-loader.js +59 -0
  127. package/bin/migrate/index.d.ts +1 -0
  128. package/bin/migrate/index.js +5 -0
  129. package/bin/new/cli.js +21 -6
  130. package/bin/new/form.d.ts +25 -4
  131. package/bin/new/form.js +285 -70
  132. package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
  133. package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
  134. package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
  135. package/bin/profile/analyzers/image-analyzer.js +85 -0
  136. package/bin/profile/cli.d.ts +4 -0
  137. package/bin/profile/cli.js +92 -0
  138. package/bin/profile/form.d.ts +56 -0
  139. package/bin/profile/form.js +400 -0
  140. package/bin/profile/index.d.ts +1 -0
  141. package/bin/profile/index.js +5 -0
  142. package/bin/profile/optimizers/index.d.ts +19 -0
  143. package/bin/profile/optimizers/index.js +137 -0
  144. package/bin/providers/add/form.d.ts +1 -1
  145. package/bin/providers/add/form.js +27 -6
  146. package/bin/providers/create/form.js +2 -1
  147. package/bin/scripts/form.js +27 -5
  148. package/bin/studio/cli.d.ts +15 -0
  149. package/bin/studio/cli.js +166 -0
  150. package/bin/studio/index.d.ts +5 -0
  151. package/bin/studio/index.js +9 -0
  152. package/bin/templates/cache.d.ts +54 -0
  153. package/bin/templates/cache.js +180 -0
  154. package/bin/templates/cli.d.ts +8 -0
  155. package/bin/templates/cli.js +292 -0
  156. package/bin/templates/fetcher.d.ts +49 -0
  157. package/bin/templates/fetcher.js +208 -0
  158. package/bin/templates/index.d.ts +11 -0
  159. package/bin/templates/index.js +37 -0
  160. package/bin/templates/manager.d.ts +116 -0
  161. package/bin/templates/manager.js +323 -0
  162. package/bin/templates/renderer.d.ts +49 -0
  163. package/bin/templates/renderer.js +204 -0
  164. package/bin/templates/types.d.ts +51 -0
  165. package/bin/templates/types.js +5 -0
  166. package/bin/utils/add-module-to-container.d.ts +2 -2
  167. package/bin/utils/add-module-to-container.js +15 -5
  168. package/bin/utils/cli-ui.d.ts +30 -3
  169. package/bin/utils/cli-ui.js +95 -13
  170. package/bin/utils/index.d.ts +4 -0
  171. package/bin/utils/index.js +4 -0
  172. package/bin/utils/input-validation.d.ts +50 -0
  173. package/bin/utils/input-validation.js +143 -0
  174. package/bin/utils/package-manager-commands.d.ts +24 -0
  175. package/bin/utils/package-manager-commands.js +50 -0
  176. package/bin/utils/safe-spawn.d.ts +35 -0
  177. package/bin/utils/safe-spawn.js +51 -0
  178. package/bin/utils/update-tsconfig-paths.d.ts +35 -0
  179. package/bin/utils/update-tsconfig-paths.js +286 -0
  180. package/package.json +154 -154
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Template renderer - processes templates with variable substitution
3
+ * Uses Mustache-like syntax: {{variable}}, {{#condition}}...{{/condition}}
4
+ */
5
+ import type { RenderOptions } from "./types";
6
+ export declare class TemplateRenderer {
7
+ /**
8
+ * Render template with variable substitution
9
+ */
10
+ render(template: string, options: RenderOptions): string;
11
+ /**
12
+ * Process conditional blocks {{#condition}}...{{/condition}}
13
+ */
14
+ private processConditionals;
15
+ /**
16
+ * Process negative conditional blocks {{^condition}}...{{/condition}}
17
+ */
18
+ private processNegativeConditionals;
19
+ /**
20
+ * Process loop blocks for arrays
21
+ */
22
+ private processLoops;
23
+ /**
24
+ * Process simple variable substitution {{variable}}
25
+ */
26
+ private processVariables;
27
+ /**
28
+ * Get nested value from object using dot notation. Falls back to a
29
+ * flat-key lookup so callers can provide either
30
+ * `{ app: { version: "1.0.0" } }` or `{ "app.version": "1.0.0" }`.
31
+ */
32
+ private getNestedValue;
33
+ /**
34
+ * Check if value is truthy for conditional evaluation
35
+ */
36
+ private isTruthy;
37
+ /**
38
+ * Validate template syntax
39
+ */
40
+ validateTemplate(template: string): {
41
+ valid: boolean;
42
+ errors: string[];
43
+ };
44
+ /**
45
+ * Extract variable names from template
46
+ */
47
+ extractVariables(template: string): string[];
48
+ }
49
+ export declare function getTemplateRenderer(): TemplateRenderer;
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ /**
3
+ * Template renderer - processes templates with variable substitution
4
+ * Uses Mustache-like syntax: {{variable}}, {{#condition}}...{{/condition}}
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.getTemplateRenderer = exports.TemplateRenderer = void 0;
8
+ class TemplateRenderer {
9
+ /**
10
+ * Render template with variable substitution
11
+ */
12
+ render(template, options) {
13
+ let result = template;
14
+ // Process conditionals first: {{#condition}}content{{/condition}}
15
+ result = this.processConditionals(result, options);
16
+ // Process negative conditionals: {{^condition}}content{{/condition}}
17
+ result = this.processNegativeConditionals(result, options);
18
+ // Process loops: {{#items}}{{.}}{{/items}}
19
+ result = this.processLoops(result, options);
20
+ // Process simple variable substitution: {{variable}}
21
+ result = this.processVariables(result, options);
22
+ return result;
23
+ }
24
+ /**
25
+ * Process conditional blocks {{#condition}}...{{/condition}}
26
+ */
27
+ processConditionals(template, options) {
28
+ const pattern = /\{\{#(\w+)\}\}([\s\S]*?)\{\{\/\1\}\}/g;
29
+ return template.replace(pattern, (match, condition, content) => {
30
+ const value = options.conditionals?.[condition] ??
31
+ options.variables[condition];
32
+ // Check if value is truthy
33
+ if (this.isTruthy(value)) {
34
+ // Recursively process the content
35
+ return this.render(content, options);
36
+ }
37
+ return "";
38
+ });
39
+ }
40
+ /**
41
+ * Process negative conditional blocks {{^condition}}...{{/condition}}
42
+ */
43
+ processNegativeConditionals(template, options) {
44
+ const pattern = /\{\{\^(\w+)\}\}([\s\S]*?)\{\{\/\1\}\}/g;
45
+ return template.replace(pattern, (match, condition, content) => {
46
+ const value = options.conditionals?.[condition] ??
47
+ options.variables[condition];
48
+ // Check if value is falsy
49
+ if (!this.isTruthy(value)) {
50
+ return this.render(content, options);
51
+ }
52
+ return "";
53
+ });
54
+ }
55
+ /**
56
+ * Process loop blocks for arrays
57
+ */
58
+ processLoops(template, options) {
59
+ const pattern = /\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g;
60
+ return template.replace(pattern, (match, arrayName, content) => {
61
+ const array = options.variables[arrayName];
62
+ if (!Array.isArray(array)) {
63
+ return "";
64
+ }
65
+ return array
66
+ .map((item, index) => {
67
+ // Create new options with item context
68
+ const itemOptions = {
69
+ ...options,
70
+ variables: {
71
+ ...options.variables,
72
+ ".": String(item),
73
+ "@index": index,
74
+ "@first": index === 0,
75
+ "@last": index === array.length - 1,
76
+ ...(typeof item === "object" ? item : {}),
77
+ },
78
+ };
79
+ return this.render(content, itemOptions);
80
+ })
81
+ .join("");
82
+ });
83
+ }
84
+ /**
85
+ * Process simple variable substitution {{variable}}
86
+ */
87
+ processVariables(template, options) {
88
+ // Match {{variable}} but not {{#variable}} or {{/variable}} or {{^variable}}
89
+ const pattern = /\{\{([^#/^}][^}]*?)\}\}/g;
90
+ return template.replace(pattern, (match, variable) => {
91
+ const trimmedVar = variable.trim();
92
+ // Handle dot notation for nested variables
93
+ const value = this.getNestedValue(options.variables, trimmedVar);
94
+ if (value === undefined || value === null) {
95
+ // Keep the placeholder if variable not found (for debugging)
96
+ return "";
97
+ }
98
+ return String(value);
99
+ });
100
+ }
101
+ /**
102
+ * Get nested value from object using dot notation. Falls back to a
103
+ * flat-key lookup so callers can provide either
104
+ * `{ app: { version: "1.0.0" } }` or `{ "app.version": "1.0.0" }`.
105
+ */
106
+ getNestedValue(obj, path) {
107
+ if (Object.prototype.hasOwnProperty.call(obj, path)) {
108
+ return obj[path];
109
+ }
110
+ const parts = path.split(".");
111
+ let current = obj;
112
+ for (const part of parts) {
113
+ if (current === null || current === undefined) {
114
+ return undefined;
115
+ }
116
+ if (typeof current !== "object") {
117
+ return undefined;
118
+ }
119
+ current = current[part];
120
+ }
121
+ return current;
122
+ }
123
+ /**
124
+ * Check if value is truthy for conditional evaluation
125
+ */
126
+ isTruthy(value) {
127
+ if (value === undefined || value === null)
128
+ return false;
129
+ if (typeof value === "boolean")
130
+ return value;
131
+ if (typeof value === "number")
132
+ return value !== 0;
133
+ if (typeof value === "string")
134
+ return value.length > 0;
135
+ if (Array.isArray(value))
136
+ return value.length > 0;
137
+ if (typeof value === "object")
138
+ return Object.keys(value).length > 0;
139
+ return Boolean(value);
140
+ }
141
+ /**
142
+ * Validate template syntax
143
+ */
144
+ validateTemplate(template) {
145
+ const errors = [];
146
+ // Check for unclosed conditionals
147
+ const openConditionals = template.match(/\{\{#(\w+)\}\}/g) || [];
148
+ const closeConditionals = template.match(/\{\{\/(\w+)\}\}/g) || [];
149
+ for (const open of openConditionals) {
150
+ const name = open.match(/\{\{#(\w+)\}\}/)?.[1];
151
+ if (name) {
152
+ const closePattern = new RegExp(`\\{\\{\\/${name}\\}\\}`);
153
+ if (!closePattern.test(template)) {
154
+ errors.push(`Unclosed conditional block: {{#${name}}}`);
155
+ }
156
+ }
157
+ }
158
+ // Check for orphaned closing tags
159
+ for (const close of closeConditionals) {
160
+ const name = close.match(/\{\{\/(\w+)\}\}/)?.[1];
161
+ if (name) {
162
+ const openPattern = new RegExp(`\\{\\{[#\\^]${name}\\}\\}`);
163
+ if (!openPattern.test(template)) {
164
+ errors.push(`Orphaned closing tag: {{/${name}}}`);
165
+ }
166
+ }
167
+ }
168
+ return {
169
+ valid: errors.length === 0,
170
+ errors,
171
+ };
172
+ }
173
+ /**
174
+ * Extract variable names from template
175
+ */
176
+ extractVariables(template) {
177
+ const variables = new Set();
178
+ // Match simple variables
179
+ const simplePattern = /\{\{([^#/^}][^}]*?)\}\}/g;
180
+ let match;
181
+ while ((match = simplePattern.exec(template)) !== null) {
182
+ const variable = match[1].trim();
183
+ if (!variable.startsWith(".") && !variable.startsWith("@")) {
184
+ variables.add(variable.split(".")[0]); // Get root variable
185
+ }
186
+ }
187
+ // Match conditional variables
188
+ const conditionalPattern = /\{\{[#^](\w+)\}\}/g;
189
+ while ((match = conditionalPattern.exec(template)) !== null) {
190
+ variables.add(match[1]);
191
+ }
192
+ return Array.from(variables);
193
+ }
194
+ }
195
+ exports.TemplateRenderer = TemplateRenderer;
196
+ // Singleton instance
197
+ let rendererInstance = null;
198
+ function getTemplateRenderer() {
199
+ if (!rendererInstance) {
200
+ rendererInstance = new TemplateRenderer();
201
+ }
202
+ return rendererInstance;
203
+ }
204
+ exports.getTemplateRenderer = getTemplateRenderer;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Template types and interfaces
3
+ */
4
+ export type TemplateCategory = "cicd" | "docker" | "kubernetes" | "migrations";
5
+ export type CICDPlatform = "github" | "gitlab" | "circleci" | "jenkins" | "bitbucket" | "azure";
6
+ export type CIStrategy = "basic" | "comprehensive" | "security-focused";
7
+ export type DockerTemplate = "production" | "development" | "compose" | "compose-development";
8
+ export type KubernetesTemplate = "deployment" | "service" | "configmap" | "ingress" | "secrets" | "kustomization";
9
+ export interface TemplateInfo {
10
+ path: string;
11
+ version: string;
12
+ description?: string;
13
+ variables?: string[];
14
+ }
15
+ export interface TemplateManifest {
16
+ version: string;
17
+ updated: string;
18
+ templates: {
19
+ cicd?: Record<CICDPlatform, Record<CIStrategy, TemplateInfo>>;
20
+ docker?: Record<DockerTemplate, TemplateInfo>;
21
+ kubernetes?: Record<KubernetesTemplate, TemplateInfo>;
22
+ migrations?: Record<string, Record<string, TemplateInfo>>;
23
+ };
24
+ }
25
+ export interface TemplateVariable {
26
+ name: string;
27
+ value: string | number | boolean;
28
+ }
29
+ export interface RenderOptions {
30
+ variables: Record<string, string | number | boolean | undefined>;
31
+ conditionals?: Record<string, boolean>;
32
+ }
33
+ export interface CacheEntry<T> {
34
+ data: T;
35
+ timestamp: number;
36
+ ttl: number;
37
+ }
38
+ export interface CacheConfig {
39
+ directory: string;
40
+ ttl: number;
41
+ }
42
+ export interface TemplateConfig {
43
+ repository: string;
44
+ branch: string;
45
+ cacheTTL: number;
46
+ }
47
+ export interface FetchResult<T> {
48
+ data: T | null;
49
+ source: "cache" | "remote" | "fallback";
50
+ error?: string;
51
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * Template types and interfaces
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,3 @@
1
- declare function addModuleToContainer(name: string, modulePath?: string, path?: string): Promise<void>;
2
- declare function addModuleToContainerNestedPath(name: string, path?: string): Promise<void>;
1
+ declare function addModuleToContainer(name: string, modulePath?: string, path?: string, folderName?: string): Promise<void>;
2
+ declare function addModuleToContainerNestedPath(name: string, path?: string, folderName?: string): Promise<void>;
3
3
  export { addModuleToContainer, addModuleToContainerNestedPath };
@@ -9,6 +9,7 @@ const glob_1 = require("glob");
9
9
  const node_fs_1 = __importDefault(require("node:fs"));
10
10
  const cli_ui_1 = require("./cli-ui");
11
11
  const compiler_1 = __importDefault(require("./compiler"));
12
+ const update_tsconfig_paths_1 = require("./update-tsconfig-paths");
12
13
  const APP_CONTAINER = "app.ts";
13
14
  async function validateAppContainer() {
14
15
  const { sourceRoot } = await compiler_1.default.loadConfig();
@@ -56,14 +57,18 @@ async function validateAppContainer() {
56
57
  notImports,
57
58
  };
58
59
  }
59
- async function addModuleToContainer(name, modulePath, path) {
60
- console.log("To chamando esse cara");
60
+ async function addModuleToContainer(name, modulePath, path, folderName) {
61
61
  const containerData = await validateAppContainer();
62
62
  const moduleName = (name[0].toUpperCase() + name.slice(1)).trimStart();
63
63
  const { opinionated } = await compiler_1.default.loadConfig();
64
64
  let usecaseDir;
65
65
  if (opinionated) {
66
- usecaseDir = `@useCases/`;
66
+ // Use dynamic path alias based on the actual folder
67
+ // Default to @useCases for backward compatibility
68
+ const pathAlias = folderName
69
+ ? (0, update_tsconfig_paths_1.getPathAliasForFolder)(folderName)
70
+ : "@useCases";
71
+ usecaseDir = `${pathAlias}/`;
67
72
  }
68
73
  else {
69
74
  usecaseDir = `./`;
@@ -99,13 +104,18 @@ async function addModuleToContainer(name, modulePath, path) {
99
104
  await node_fs_1.default.promises.writeFile(containerData.path, newFileContent, "utf8");
100
105
  }
101
106
  exports.addModuleToContainer = addModuleToContainer;
102
- async function addModuleToContainerNestedPath(name, path) {
107
+ async function addModuleToContainerNestedPath(name, path, folderName) {
103
108
  const containerData = await validateAppContainer();
104
109
  const moduleName = (name[0].toUpperCase() + name.slice(1)).trimStart();
105
110
  const { opinionated } = await compiler_1.default.loadConfig();
106
111
  let usecaseDir;
107
112
  if (opinionated) {
108
- usecaseDir = `@useCases/`;
113
+ // Use dynamic path alias based on the actual folder
114
+ // Default to @useCases for backward compatibility
115
+ const pathAlias = folderName
116
+ ? (0, update_tsconfig_paths_1.getPathAliasForFolder)(folderName)
117
+ : "@useCases";
118
+ usecaseDir = `${pathAlias}/`;
109
119
  }
110
120
  else {
111
121
  usecaseDir = `./`;
@@ -1,5 +1,32 @@
1
- export declare function printError(message: string, component: string): void;
2
- export declare function printSuccess(message: string, component: string): void;
3
- export declare function printWarning(message: string, component?: string): void;
1
+ /**
2
+ * Print error message (matches core logger ERROR format)
3
+ */
4
+ export declare function printError(message: string, context: string): void;
5
+ /**
6
+ * Print success message (matches core logger INFO format)
7
+ */
8
+ export declare function printSuccess(message: string, context: string): void;
9
+ /**
10
+ * Print warning message (matches core logger WARN format)
11
+ */
12
+ export declare function printWarning(message: string, context?: string): void;
13
+ /**
14
+ * Print info message (matches core logger INFO format)
15
+ */
16
+ export declare function printInfo(message: string, context: string): void;
17
+ /**
18
+ * Print debug message (matches core logger DEBUG format)
19
+ */
20
+ export declare function printDebug(message: string, context: string): void;
21
+ /**
22
+ * Print generate error (simplified format for scaffolding)
23
+ */
4
24
  export declare function printGenerateError(schematic: string, file: string): Promise<void>;
25
+ /**
26
+ * Print generate success (simplified format for scaffolding)
27
+ */
5
28
  export declare function printGenerateSuccess(schematic: string, file: string): Promise<void>;
29
+ /**
30
+ * Print the ExpressoTS CLI header
31
+ */
32
+ export declare function printHeader(): void;
@@ -3,30 +3,112 @@ 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.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 the ExpressoTS CLI header
110
+ */
111
+ function printHeader() {
112
+ process_1.stdout.write(`\n${chalk_1.default.bold.green("🐎 ExpressoTS CLI")}\n\n`);
113
+ }
114
+ 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;