ingeniuscliq-core 0.4.15 → 0.4.16

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 (77) hide show
  1. package/dist/node_modules/@radix-ui/react-accordion/dist/index.js +3 -3
  2. package/dist/node_modules/@radix-ui/{react-select/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow → react-arrow}/dist/index.js +1 -1
  3. package/dist/node_modules/@radix-ui/react-avatar/dist/index.js +1 -1
  4. package/dist/node_modules/@radix-ui/react-checkbox/dist/index.js +2 -2
  5. package/dist/node_modules/@radix-ui/{react-accordion/node_modules/@radix-ui/react-collapsible → react-collapsible}/dist/index.js +7 -7
  6. package/dist/node_modules/@radix-ui/{react-select/node_modules/@radix-ui/react-collection → react-collection}/dist/index.js +3 -3
  7. package/dist/node_modules/@radix-ui/react-dialog/dist/index.js +5 -5
  8. package/dist/node_modules/@radix-ui/{react-select/node_modules/@radix-ui/react-dismissable-layer → react-dismissable-layer}/dist/index.js +4 -4
  9. package/dist/node_modules/@radix-ui/react-dropdown-menu/dist/index.js +2 -2
  10. package/dist/node_modules/@radix-ui/{react-dialog/node_modules/@radix-ui/react-focus-scope → react-focus-scope}/dist/index.js +2 -2
  11. package/dist/node_modules/@radix-ui/react-label/dist/index.js +1 -1
  12. package/dist/node_modules/@radix-ui/{react-dropdown-menu/node_modules/@radix-ui/react-menu → react-menu}/dist/index.js +17 -17
  13. package/dist/node_modules/@radix-ui/react-popover/dist/index.js +6 -6
  14. package/dist/node_modules/@radix-ui/{react-popover/node_modules/@radix-ui/react-popper → react-popper}/dist/index.js +8 -8
  15. package/dist/node_modules/@radix-ui/{react-popover/node_modules/@radix-ui/react-portal → react-portal}/dist/index.js +1 -1
  16. package/dist/node_modules/@radix-ui/{react-popover/node_modules/@radix-ui/react-presence → react-presence}/dist/index.js +2 -2
  17. package/dist/node_modules/@radix-ui/{react-dropdown-menu/node_modules/@radix-ui/react-primitive → react-primitive}/dist/index.js +1 -1
  18. package/dist/node_modules/@radix-ui/react-radio-group/dist/index.js +3 -3
  19. package/dist/node_modules/@radix-ui/{react-radio-group/node_modules/@radix-ui/react-roving-focus → react-roving-focus}/dist/index.js +8 -8
  20. package/dist/node_modules/@radix-ui/react-select/dist/index.js +7 -7
  21. package/dist/node_modules/@radix-ui/react-separator/dist/index.js +1 -1
  22. package/dist/node_modules/@radix-ui/react-slider/dist/index.js +2 -2
  23. package/dist/node_modules/@radix-ui/react-switch/dist/index.js +1 -1
  24. package/dist/node_modules/@radix-ui/react-tabs/dist/index.js +3 -3
  25. package/dist/node_modules/@radix-ui/react-tooltip/dist/index.js +5 -5
  26. package/dist/node_modules/react-i18next/dist/es/defaults.js +2 -1
  27. package/package.json +9 -9
  28. package/src/core/commands/create-core-module.js +288 -0
  29. package/src/core/commands/create-module.js +288 -0
  30. package/src/core/commands/create-template.js +169 -0
  31. package/src/core/commands/rollback-core-module.js +195 -0
  32. package/src/core/commands/rollback-module.js +208 -0
  33. package/dist/node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collapsible/node_modules/@radix-ui/react-presence/dist/index.js +0 -130
  34. package/dist/node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-collection/dist/index.js +0 -70
  35. package/dist/node_modules/@radix-ui/react-accordion/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  36. package/dist/node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  37. package/dist/node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-presence/dist/index.js +0 -130
  38. package/dist/node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  39. package/dist/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer/dist/index.js +0 -211
  40. package/dist/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal/dist/index.js +0 -17
  41. package/dist/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence/dist/index.js +0 -130
  42. package/dist/node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive/dist/index.js +0 -43
  43. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-collection/dist/index.js +0 -70
  44. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer/dist/index.js +0 -211
  45. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope/dist/index.js +0 -207
  46. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/dist/index.js +0 -283
  47. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow/dist/index.js +0 -25
  48. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal/dist/index.js +0 -17
  49. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence/dist/index.js +0 -130
  50. package/dist/node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-roving-focus/dist/index.js +0 -223
  51. package/dist/node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  52. package/dist/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-dismissable-layer/dist/index.js +0 -211
  53. package/dist/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-focus-scope/dist/index.js +0 -207
  54. package/dist/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow/dist/index.js +0 -25
  55. package/dist/node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-primitive/dist/index.js +0 -43
  56. package/dist/node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-presence/dist/index.js +0 -130
  57. package/dist/node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  58. package/dist/node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection/dist/index.js +0 -70
  59. package/dist/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope/dist/index.js +0 -207
  60. package/dist/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper/dist/index.js +0 -283
  61. package/dist/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-portal/dist/index.js +0 -17
  62. package/dist/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive/dist/index.js +0 -43
  63. package/dist/node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-visually-hidden/dist/index.js +0 -34
  64. package/dist/node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  65. package/dist/node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-collection/dist/index.js +0 -70
  66. package/dist/node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  67. package/dist/node_modules/@radix-ui/react-switch/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  68. package/dist/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-presence/dist/index.js +0 -130
  69. package/dist/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive/dist/index.js +0 -40
  70. package/dist/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus/dist/index.js +0 -223
  71. package/dist/node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection/dist/index.js +0 -70
  72. package/dist/node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer/dist/index.js +0 -211
  73. package/dist/node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper/dist/index.js +0 -283
  74. package/dist/node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-arrow/dist/index.js +0 -25
  75. package/dist/node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence/dist/index.js +0 -130
  76. package/dist/node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive/dist/index.js +0 -43
  77. /package/dist/node_modules/@radix-ui/{react-tooltip/node_modules/@radix-ui/react-visually-hidden → react-visually-hidden}/dist/index.js +0 -0
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createBaseDir, joinPaths } from './helpers/index.js';
4
+
5
+ import { SUPPORTED_DIRECTORIES } from './common/constants.js'
6
+ import chalk from 'chalk';
7
+ import enquirer from 'enquirer';
8
+ import fs from 'fs';
9
+ import { serviceTemplate } from './templates/service.js';
10
+ import { localeTemplate } from './templates/locale.js';
11
+ import { typeTemplate } from './templates/type.js';
12
+
13
+ const { prompt } = enquirer;
14
+
15
+ /**
16
+ * Updates or creates the modules index file
17
+ * @param {string} moduleName The name of the module
18
+ */
19
+ function updateModulesIndex(moduleName) {
20
+ const modulesDir = createBaseDir('modules', ['core']);
21
+ const indexPath = joinPaths(modulesDir, 'index.ts');
22
+ const importStatement = `import './${moduleName}'`;
23
+
24
+ try {
25
+ let content = '';
26
+
27
+ // If file exists, read its content
28
+ if (fs.existsSync(indexPath)) {
29
+ content = fs.readFileSync(indexPath, 'utf8');
30
+
31
+ // Check if import already exists
32
+ if (!content.includes(importStatement)) {
33
+ // Find the last import statement
34
+ const lines = content.split('\n');
35
+ let lastImportIndex = -1;
36
+
37
+ for (let i = 0; i < lines.length; i++) {
38
+ if (lines[i].startsWith('import ')) {
39
+ lastImportIndex = i;
40
+ }
41
+ }
42
+
43
+ if (lastImportIndex !== -1) {
44
+ // Insert after the last import
45
+ lines.splice(lastImportIndex + 1, 0, importStatement);
46
+ } else {
47
+ // No imports found, add at the beginning
48
+ lines.unshift(importStatement);
49
+ }
50
+
51
+ content = lines.join('\n');
52
+ }
53
+ } else {
54
+ // Create new file with initial import
55
+ content = `// Import all modules here\n${importStatement}\n\n// You can add more module imports here as needed`;
56
+ }
57
+
58
+ fs.writeFileSync(indexPath, content);
59
+ console.log(chalk.green(`✓ Updated ${chalk.bold('modules/index.ts')} file`));
60
+ } catch (error) {
61
+ console.error(chalk.yellow(`⚠️ Warning: Could not update modules index: ${error.message}`));
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Creates a new module with the selected folder structure
67
+ * @param {string} moduleName The name of the module to create
68
+ * @param {string[]} selectedDirectories Array of directories to create (defaults to all)
69
+ */
70
+ function createModule(moduleName, selectedDirectories = SUPPORTED_DIRECTORIES) {
71
+ if (!moduleName) {
72
+ console.error(chalk.red.bold('❌ Error: Core module name is required'));
73
+ console.log(chalk.yellow('⚠️ Usage: npm run create:core-module <module-name>'));
74
+ process.exit(1);
75
+ }
76
+
77
+ const baseDir = createBaseDir(moduleName, ['core', 'modules']);
78
+
79
+ // Check if module already exists
80
+ if (fs.existsSync(baseDir)) {
81
+ console.error(chalk.red.bold(`❌ Error: Core module '${moduleName}' already exists`));
82
+ process.exit(1);
83
+ }
84
+
85
+ try {
86
+ // Create module base directory
87
+ fs.mkdirSync(baseDir, { recursive: true });
88
+ console.log(chalk.green(`✓ Created core module directory: ${chalk.bold(moduleName)}`));
89
+
90
+ // Create selected subdirectories
91
+ for (const dir of selectedDirectories) {
92
+ const dirPath = joinPaths(baseDir, dir);
93
+ fs.mkdirSync(dirPath, { recursive: true });
94
+ console.log(chalk.green(`✓ Created ${chalk.bold(dir)} directory`));
95
+
96
+ // Create ui and layouts subdirectories inside components
97
+ if (dir === 'components') {
98
+ const componentsSubDirs = ['ui', 'layouts'];
99
+ for (const subDir of componentsSubDirs) {
100
+ const subDirPath = joinPaths(dirPath, subDir);
101
+ fs.mkdirSync(subDirPath, { recursive: true });
102
+ console.log(chalk.green(`✓ Created ${chalk.bold(`components/${subDir}`)} directory`));
103
+ }
104
+ }
105
+
106
+ // Create locale subdirectory inside components
107
+ if (dir === 'locale') {
108
+ const localeSubDirEn = joinPaths(dirPath, 'en.json');
109
+ fs.writeFileSync(localeSubDirEn, '{}');
110
+ console.log(chalk.green(`✓ Created ${chalk.bold('locale/en.json')} file`));
111
+ const localeSubDirEs = joinPaths(dirPath, 'es.json');
112
+ fs.writeFileSync(localeSubDirEs, '{}');
113
+ console.log(chalk.green(`✓ Created ${chalk.bold('locale/es.json')} file`));
114
+ }
115
+
116
+ // Create base.ts file inside services directory
117
+ if (dir === 'services') {
118
+ const baseServicePath = joinPaths(dirPath, 'base.ts');
119
+ const baseServiceContent = serviceTemplate(moduleName);
120
+ fs.writeFileSync(baseServicePath, baseServiceContent);
121
+ console.log(chalk.green(`✓ Created ${chalk.bold('services/base.ts')} file`));
122
+ }
123
+
124
+ // Create base entity file inside types directory
125
+ if(dir === 'types') {
126
+ const typesPath = joinPaths(dirPath, `${moduleName}.ts`);
127
+ const typesContent = typeTemplate(moduleName);
128
+ fs.writeFileSync(typesPath, typesContent);
129
+ console.log(chalk.green(`✓ Created ${chalk.bold(`types/${moduleName}.ts`)} file`));
130
+ }
131
+ }
132
+
133
+ // Create index.ts file
134
+ const indexPath = joinPaths(baseDir, 'index.ts');
135
+ if (selectedDirectories.includes('locale')) {
136
+ fs.writeFileSync(indexPath, localeTemplate(moduleName));
137
+ // Update modules/index.ts only if locale is selected
138
+ updateModulesIndex(moduleName);
139
+ } else {
140
+ fs.writeFileSync(indexPath, `// ${moduleName} module exports\n`);
141
+ }
142
+ console.log(chalk.green(`✓ Created ${chalk.bold('index.ts')} file`));
143
+
144
+ console.log(chalk.green.bold(`\n✨ Module '${moduleName}' successfully created at core/modules/${moduleName}`));
145
+ } catch (error) {
146
+ console.error(chalk.red.bold(`❌ Error creating module: ${error.message}`));
147
+ process.exit(1);
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Prompts the user to select which directories to include
153
+ * @param {string} moduleName The name of the module to create
154
+ */
155
+ async function promptDirectorySelection(moduleName) {
156
+ try {
157
+ console.log(chalk.cyan.bold('\n=== Feature Selection ===\n'));
158
+
159
+ const response = await prompt({
160
+ type: 'multiselect',
161
+ name: 'directories',
162
+ message: 'Select the directories to include (use space to select, enter to confirm):',
163
+ choices: SUPPORTED_DIRECTORIES.map(dir => ({
164
+ name: dir,
165
+ value: dir,
166
+ message: dir
167
+ })),
168
+ min: 1,
169
+ instructions: false,
170
+ symbols: {
171
+ indicator: {
172
+ on: '◉',
173
+ off: '◯'
174
+ }
175
+ },
176
+ styles: {
177
+ primary: chalk.cyan,
178
+ highlight: chalk.cyan.bold,
179
+ selected: chalk.green.bold
180
+ }
181
+ });
182
+
183
+ if (response.directories && response.directories.length > 0) {
184
+ console.log(chalk.cyan(`\nCreating core module with ${chalk.bold(response.directories.length)} selected features...\n`));
185
+ createModule(moduleName, response.directories);
186
+ } else {
187
+ console.log(chalk.yellow('⚠️ You must select at least one feature. Operation cancelled.'));
188
+ }
189
+ } catch (error) {
190
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
191
+ throw error;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Displays options and gets user choice using radio buttons
197
+ * @param {string} moduleName The name of the module to create
198
+ */
199
+ async function promptOptions(moduleName) {
200
+ console.log(chalk.cyan.bold('\n==================================='));
201
+ console.log(chalk.cyan.bold(` Create Core Module: ${chalk.white(moduleName)}`));
202
+ console.log(chalk.cyan.bold('===================================\n'));
203
+
204
+ try {
205
+ const response = await prompt({
206
+ type: 'select',
207
+ name: 'action',
208
+ message: 'Select an option:',
209
+ choices: [
210
+ { name: 'create_all', message: 'Create core module with all features', value: 'create_all' },
211
+ { name: 'create_custom', message: 'Select features', value: 'create_custom' },
212
+ { name: 'exit', message: 'Exit', value: 'exit' }
213
+ ],
214
+ styles: {
215
+ primary: chalk.cyan,
216
+ highlight: chalk.cyan.bold,
217
+ selected: chalk.green.bold
218
+ }
219
+ });
220
+
221
+ switch (response.action) {
222
+ case 'create_all':
223
+ console.log(chalk.cyan(`\nCreating core module with all features: ${chalk.bold(moduleName)}...\n`));
224
+ createModule(moduleName);
225
+ break;
226
+ case 'create_custom':
227
+ await promptDirectorySelection(moduleName);
228
+ break;
229
+ default:
230
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
231
+ break;
232
+ }
233
+ } catch (error) {
234
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
235
+ throw error;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Prompts the user to enter a module name
241
+ * @returns {Promise<string>} The entered module name
242
+ */
243
+ async function promptModuleName() {
244
+ console.log(chalk.cyan.bold('\n==================================='));
245
+ console.log(chalk.cyan.bold(' Create Core Module'));
246
+ console.log(chalk.cyan.bold('===================================\n'));
247
+
248
+ try {
249
+ const response = await prompt({
250
+ type: 'input',
251
+ name: 'moduleName',
252
+ message: 'Please enter the name of the core module to create:',
253
+ validate: (input) => {
254
+ if (!input.trim()) {
255
+ return 'Core module name is required';
256
+ }
257
+ const baseDir = createBaseDir(input, ['src', 'core', 'modules']);
258
+ if (fs.existsSync(baseDir)) {
259
+ return `Core module '${input}' already exists`;
260
+ }
261
+ return true;
262
+ }
263
+ });
264
+
265
+ return response.moduleName.trim();
266
+ } catch (error) {
267
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
268
+ throw error;
269
+ }
270
+ }
271
+
272
+ // Get module name from command line arguments or prompt
273
+ const moduleNameArg = process.argv[2];
274
+
275
+ async function main() {
276
+ let moduleName = moduleNameArg;
277
+
278
+ if (!moduleName) {
279
+ moduleName = await promptModuleName();
280
+ }
281
+
282
+ promptOptions(moduleName);
283
+ }
284
+
285
+ main().catch(error => {
286
+ console.error(chalk.red.bold(`❌ Unexpected error: ${error.message}`));
287
+ process.exit(1);
288
+ });
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createBaseDir, joinPaths } from './helpers/index.js';
4
+
5
+ import { SUPPORTED_DIRECTORIES } from './common/constants.js';
6
+ import chalk from 'chalk';
7
+ import enquirer from 'enquirer';
8
+ import fs from 'fs';
9
+ import { serviceTemplate } from './templates/service.js';
10
+ import { localeTemplate } from './templates/locale.js';
11
+ import { typeTemplate } from './templates/type.js';
12
+
13
+ const { prompt } = enquirer;
14
+
15
+ /**
16
+ * Updates or creates the modules index file
17
+ * @param {string} moduleName The name of the module
18
+ */
19
+ function updateModulesIndex(moduleName) {
20
+ const modulesDir = createBaseDir('modules', ['src']);
21
+ const indexPath = joinPaths(modulesDir, 'index.ts');
22
+ const importStatement = `import './${moduleName}'`;
23
+
24
+ try {
25
+ let content = '';
26
+
27
+ // If file exists, read its content
28
+ if (fs.existsSync(indexPath)) {
29
+ content = fs.readFileSync(indexPath, 'utf8');
30
+
31
+ // Check if import already exists
32
+ if (!content.includes(importStatement)) {
33
+ // Find the last import statement
34
+ const lines = content.split('\n');
35
+ let lastImportIndex = -1;
36
+
37
+ for (let i = 0; i < lines.length; i++) {
38
+ if (lines[i].startsWith('import ')) {
39
+ lastImportIndex = i;
40
+ }
41
+ }
42
+
43
+ if (lastImportIndex !== -1) {
44
+ // Insert after the last import
45
+ lines.splice(lastImportIndex + 1, 0, importStatement);
46
+ } else {
47
+ // No imports found, add at the beginning
48
+ lines.unshift(importStatement);
49
+ }
50
+
51
+ content = lines.join('\n');
52
+ }
53
+ } else {
54
+ // Create new file with initial import
55
+ content = `// Import all modules here\n${importStatement}\n\n// You can add more module imports here as needed`;
56
+ }
57
+
58
+ fs.writeFileSync(indexPath, content);
59
+ console.log(chalk.green(`✓ Updated ${chalk.bold('modules/index.ts')} file`));
60
+ } catch (error) {
61
+ console.error(chalk.yellow(`⚠️ Warning: Could not update modules index: ${error.message}`));
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Creates a new module with the selected folder structure
67
+ * @param {string} moduleName The name of the module to create
68
+ * @param {string[]} selectedDirectories Array of directories to create (defaults to all)
69
+ */
70
+ function createModule(moduleName, selectedDirectories = SUPPORTED_DIRECTORIES) {
71
+ if (!moduleName) {
72
+ console.error(chalk.red.bold('❌ Error: Module name is required'));
73
+ console.log(chalk.yellow('⚠️ Usage: npm run create:module <module-name>'));
74
+ process.exit(1);
75
+ }
76
+
77
+ const baseDir = createBaseDir(moduleName, ['src', 'modules'])
78
+
79
+ // Check if module already exists
80
+ if (fs.existsSync(baseDir)) {
81
+ console.error(chalk.red.bold(`❌ Error: Module '${moduleName}' already exists`));
82
+ process.exit(1);
83
+ }
84
+
85
+ try {
86
+ // Create module base directory
87
+ fs.mkdirSync(baseDir, { recursive: true });
88
+ console.log(chalk.green(`✓ Created module directory: ${chalk.bold(moduleName)}`));
89
+
90
+ // Create selected subdirectories
91
+ for (const dir of selectedDirectories) {
92
+ const dirPath = joinPaths(baseDir, dir);
93
+ fs.mkdirSync(dirPath, { recursive: true });
94
+ console.log(chalk.green(`✓ Created ${chalk.bold(dir)} directory`));
95
+
96
+ // Create ui and layouts subdirectories inside components
97
+ if (dir === 'components') {
98
+ const componentsSubDirs = ['ui', 'layouts'];
99
+ for (const subDir of componentsSubDirs) {
100
+ const subDirPath = joinPaths(dirPath, subDir);
101
+ fs.mkdirSync(subDirPath, { recursive: true });
102
+ console.log(chalk.green(`✓ Created ${chalk.bold(`components/${subDir}`)} directory`));
103
+ }
104
+ }
105
+
106
+ // Create locale subdirectory inside components
107
+ if (dir === 'locale') {
108
+ const localeSubDirEn = joinPaths(dirPath, 'en.json');
109
+ fs.writeFileSync(localeSubDirEn, '{}');
110
+ console.log(chalk.green(`✓ Created ${chalk.bold('locale/en.json')} file`));
111
+ const localeSubDirEs = joinPaths(dirPath, 'es.json');
112
+ fs.writeFileSync(localeSubDirEs, '{}');
113
+ console.log(chalk.green(`✓ Created ${chalk.bold('locale/es.json')} file`));
114
+ }
115
+
116
+ // Create base.ts file inside services directory
117
+ if (dir === 'services') {
118
+ const baseServicePath = joinPaths(dirPath, 'base.ts');
119
+ const baseServiceContent = serviceTemplate(moduleName);
120
+ fs.writeFileSync(baseServicePath, baseServiceContent);
121
+ console.log(chalk.green(`✓ Created ${chalk.bold('services/base.ts')} file`));
122
+ }
123
+
124
+ // Create base entity file inside types directory
125
+ if(dir === 'types') {
126
+ const typesPath = joinPaths(dirPath, `${moduleName}.ts`);
127
+ const typesContent = typeTemplate(moduleName);
128
+ fs.writeFileSync(typesPath, typesContent);
129
+ console.log(chalk.green(`✓ Created ${chalk.bold(`types/${moduleName}.ts`)} file`));
130
+ }
131
+ }
132
+
133
+ // Create index.ts file
134
+ const indexPath = joinPaths(baseDir, 'index.ts');
135
+ if(selectedDirectories.includes('locale')){
136
+ fs.writeFileSync(indexPath, localeTemplate(moduleName));
137
+ // Update modules/index.ts only if locale is selected
138
+ updateModulesIndex(moduleName);
139
+ }else {
140
+ fs.writeFileSync(indexPath, `// ${moduleName} module exports\n`);
141
+ }
142
+ console.log(chalk.green(`✓ Created ${chalk.bold('index.ts')} file`));
143
+
144
+ console.log(chalk.green.bold(`\n✨ Module '${moduleName}' successfully created at src/modules/${moduleName}`));
145
+ } catch (error) {
146
+ console.error(chalk.red.bold(`❌ Error creating module: ${error.message}`));
147
+ process.exit(1);
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Prompts the user to select which directories to include
153
+ * @param {string} moduleName The name of the module to create
154
+ */
155
+ async function promptDirectorySelection(moduleName) {
156
+ try {
157
+ console.log(chalk.cyan.bold('\n=== Feature Selection ===\n'));
158
+
159
+ const response = await prompt({
160
+ type: 'multiselect',
161
+ name: 'directories',
162
+ message: 'Select the directories to include (use space to select, enter to confirm):',
163
+ choices: SUPPORTED_DIRECTORIES.map(dir => ({
164
+ name: dir,
165
+ value: dir,
166
+ message: dir
167
+ })),
168
+ min: 1,
169
+ instructions: false,
170
+ symbols: {
171
+ indicator: {
172
+ on: '◉',
173
+ off: '◯'
174
+ }
175
+ },
176
+ styles: {
177
+ primary: chalk.cyan,
178
+ highlight: chalk.cyan.bold,
179
+ selected: chalk.green.bold
180
+ }
181
+ });
182
+
183
+ if (response.directories && response.directories.length > 0) {
184
+ console.log(chalk.cyan(`\nCreating module with ${chalk.bold(response.directories.length)} selected features...\n`));
185
+ createModule(moduleName, response.directories);
186
+ } else {
187
+ console.log(chalk.yellow('⚠️ You must select at least one feature. Operation cancelled.'));
188
+ }
189
+ } catch (error) {
190
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
191
+ throw error;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Displays options and gets user choice using radio buttons
197
+ * @param {string} moduleName The name of the module to create
198
+ */
199
+ async function promptOptions(moduleName) {
200
+ console.log(chalk.cyan.bold('\n==================================='));
201
+ console.log(chalk.cyan.bold(` Create Module: ${chalk.white(moduleName)}`));
202
+ console.log(chalk.cyan.bold('===================================\n'));
203
+
204
+ try {
205
+ const response = await prompt({
206
+ type: 'select',
207
+ name: 'action',
208
+ message: 'Select an option:',
209
+ choices: [
210
+ { name: 'create_all', message: 'Create module with all features', value: 'create_all' },
211
+ { name: 'create_custom', message: 'Select features', value: 'create_custom' },
212
+ { name: 'exit', message: 'Exit', value: 'exit' }
213
+ ],
214
+ styles: {
215
+ primary: chalk.cyan,
216
+ highlight: chalk.cyan.bold,
217
+ selected: chalk.green.bold
218
+ }
219
+ });
220
+
221
+ switch (response.action) {
222
+ case 'create_all':
223
+ console.log(chalk.cyan(`\nCreating module with all features: ${chalk.bold(moduleName)}...\n`));
224
+ createModule(moduleName);
225
+ break;
226
+ case 'create_custom':
227
+ await promptDirectorySelection(moduleName);
228
+ break;
229
+ default:
230
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
231
+ break;
232
+ }
233
+ } catch (error) {
234
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
235
+ throw error;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Prompts the user to enter a module name
241
+ * @returns {Promise<string>} The entered module name
242
+ */
243
+ async function promptModuleName() {
244
+ console.log(chalk.cyan.bold('\n==================================='));
245
+ console.log(chalk.cyan.bold(' Create Module'));
246
+ console.log(chalk.cyan.bold('===================================\n'));
247
+
248
+ try {
249
+ const response = await prompt({
250
+ type: 'input',
251
+ name: 'moduleName',
252
+ message: 'Please enter the name of the module to create:',
253
+ validate: (input) => {
254
+ if (!input.trim()) {
255
+ return 'Module name is required';
256
+ }
257
+ const baseDir = createBaseDir(input, ['src', 'modules'])
258
+ if (fs.existsSync(baseDir)) {
259
+ return `Module '${input}' already exists`;
260
+ }
261
+ return true;
262
+ }
263
+ });
264
+
265
+ return response.moduleName.trim();
266
+ } catch (error) {
267
+ console.log(chalk.yellow('⚠️ Operation cancelled.'));
268
+ throw error;
269
+ }
270
+ }
271
+
272
+ // Get module name from command line arguments or prompt
273
+ const moduleNameArg = process.argv[2];
274
+
275
+ async function main() {
276
+ let moduleName = moduleNameArg;
277
+
278
+ if (!moduleName) {
279
+ moduleName = await promptModuleName();
280
+ }
281
+
282
+ promptOptions(moduleName);
283
+ }
284
+
285
+ main().catch(error => {
286
+ console.error(chalk.red.bold(`❌ Unexpected error: ${error.message}`));
287
+ process.exit(1);
288
+ });