express-genix 1.1.4 → 2.0.0

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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +204 -259
  3. package/index.js +229 -113
  4. package/lib/cleanup.js +41 -129
  5. package/lib/features.js +239 -0
  6. package/lib/generator.js +286 -204
  7. package/lib/utils.js +43 -91
  8. package/package.json +81 -63
  9. package/templates/cicd/github-actions.yml.ejs +70 -0
  10. package/templates/config/database.mongo.js.ejs +29 -33
  11. package/templates/config/database.postgres.js.ejs +41 -40
  12. package/templates/config/database.prisma.js.ejs +26 -0
  13. package/templates/config/redis.js.ejs +28 -0
  14. package/templates/config/schema.prisma.ejs +20 -0
  15. package/templates/config/swagger.js.ejs +30 -0
  16. package/templates/config/websocket.js.ejs +62 -0
  17. package/templates/controllers/authController.js.ejs +152 -129
  18. package/templates/controllers/exampleController.js.ejs +92 -152
  19. package/templates/controllers/userController.js.ejs +52 -60
  20. package/templates/core/Dockerfile.ejs +41 -31
  21. package/templates/core/README.md.ejs +191 -179
  22. package/templates/core/app.js.ejs +114 -64
  23. package/templates/core/docker-compose.yml.ejs +59 -47
  24. package/templates/core/dockerignore.ejs +7 -0
  25. package/templates/core/env.ejs +25 -19
  26. package/templates/core/env.example.ejs +26 -0
  27. package/templates/core/eslintrc.json.ejs +50 -20
  28. package/templates/core/gitignore.ejs +51 -51
  29. package/templates/core/healthcheck.js.ejs +24 -24
  30. package/templates/core/jest.config.js.ejs +19 -22
  31. package/templates/core/package.json.ejs +70 -33
  32. package/templates/core/prettierrc.json.ejs +11 -11
  33. package/templates/core/server.js.ejs +64 -48
  34. package/templates/core/tsconfig.json.ejs +19 -0
  35. package/templates/middleware/auth.js.ejs +80 -66
  36. package/templates/middleware/cache.js.ejs +67 -0
  37. package/templates/middleware/errorHandler.js.ejs +50 -46
  38. package/templates/middleware/requestId.js.ejs +9 -0
  39. package/templates/middleware/validation.js.ejs +109 -47
  40. package/templates/migrations/create-users.js.ejs +50 -0
  41. package/templates/migrations/seed-users.js.ejs +34 -0
  42. package/templates/migrations/sequelizerc.ejs +8 -0
  43. package/templates/models/User.mongo.js.ejs +29 -29
  44. package/templates/models/User.postgres.js.ejs +40 -40
  45. package/templates/models/index.mongo.js.ejs +7 -7
  46. package/templates/models/index.postgres.js.ejs +11 -11
  47. package/templates/routes/authRoutes.js.ejs +222 -13
  48. package/templates/routes/exampleRoutes.js.ejs +100 -12
  49. package/templates/routes/index.js.ejs +34 -24
  50. package/templates/routes/userRoutes.js.ejs +78 -15
  51. package/templates/services/authService.js.ejs +111 -35
  52. package/templates/services/exampleService.js.ejs +112 -112
  53. package/templates/services/userService.mongodb.js.ejs +33 -33
  54. package/templates/services/userService.postgres.js.ejs +30 -30
  55. package/templates/services/userService.prisma.js.ejs +36 -0
  56. package/templates/tests/auth.test.js.ejs +83 -66
  57. package/templates/tests/example.test.js.ejs +109 -112
  58. package/templates/tests/setup.js.ejs +11 -11
  59. package/templates/tests/users.test.js.ejs +42 -42
  60. package/templates/utils/envValidator.js.ejs +23 -0
  61. package/templates/utils/errors.js.ejs +12 -12
  62. package/templates/utils/logger.js.ejs +37 -28
  63. package/templates/utils/response.js.ejs +28 -0
  64. package/templates/utils/validators.js.ejs +34 -34
  65. package/templates/config/swagger.json.ejs +0 -194
  66. package/templates/core/index.js.ejs +0 -24
package/lib/generator.js CHANGED
@@ -1,205 +1,287 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const ejs = require('ejs');
4
- const { execSync } = require('child_process');
5
-
6
- /**
7
- * Generate project files from templates
8
- */
9
- const generateProject = async (config, projectDir) => {
10
- // Create directory structure
11
- createDirectoryStructure(projectDir, config);
12
-
13
- // Generate files from templates
14
- await generateFiles(config, projectDir);
15
-
16
- // Install dependencies
17
- installDependencies(projectDir);
18
- };
19
-
20
- const createDirectoryStructure = (projectDir, config) => {
21
- const dirs = [
22
- 'src',
23
- 'src/config',
24
- 'src/controllers',
25
- 'src/middleware',
26
- 'src/routes',
27
- 'src/services',
28
- 'src/utils',
29
- 'tests',
30
- ];
31
-
32
- // Only create models directory if using database
33
- if (config.hasDatabase) {
34
- dirs.push('src/models');
35
- }
36
-
37
- fs.mkdirSync(projectDir);
38
- dirs.forEach(dir => {
39
- fs.mkdirSync(path.join(projectDir, dir), { recursive: true });
40
- });
41
- };
42
-
43
- const generateFiles = async (config, projectDir) => {
44
- const templatesDir = path.join(__dirname, '../templates');
45
-
46
- // Core files (always generated)
47
- const coreFiles = [
48
- { template: 'core/package.json.ejs', output: 'package.json' },
49
- { template: 'core/app.js.ejs', output: 'src/app.js' },
50
- { template: 'core/server.js.ejs', output: 'src/server.js' },
51
- { template: 'core/env.ejs', output: '.env' },
52
- { template: 'core/gitignore.ejs', output: '.gitignore' },
53
- { template: 'core/eslintrc.json.ejs', output: '.eslintrc.json' },
54
- { template: 'core/Dockerfile.ejs', output: 'Dockerfile' },
55
- { template: 'core/docker-compose.yml.ejs', output: 'docker-compose.yml' },
56
- { template: 'core/healthcheck.js.ejs', output: 'healthcheck.js' },
57
- { template: 'core/jest.config.js.ejs', output: 'jest.config.js' },
58
- { template: 'core/README.md.ejs', output: 'README.md' },
59
- ];
60
-
61
- // Config files
62
- const configFiles = [
63
- { template: 'config/swagger.json.ejs', output: 'src/config/swagger.json' },
64
- ];
65
-
66
- // Add database config if needed
67
- if (config.hasDatabase) {
68
- if (config.db === 'mongodb') {
69
- configFiles.push({ template: 'config/database.mongo.js.ejs', output: 'src/config/database.js' });
70
- } else if (config.db === 'postgresql') {
71
- configFiles.push({ template: 'config/database.postgres.js.ejs', output: 'src/config/database.js' });
72
- }
73
- }
74
-
75
- // Controller files
76
- const controllerFiles = [
77
- { template: 'routes/index.js.ejs', output: 'src/routes/index.js' },
78
- ];
79
-
80
- // Add auth/user controllers and routes if database is used
81
- if (config.hasDatabase) {
82
- controllerFiles.push(
83
- { template: 'controllers/authController.js.ejs', output: 'src/controllers/authController.js' },
84
- { template: 'controllers/userController.js.ejs', output: 'src/controllers/userController.js' },
85
- { template: 'routes/authRoutes.js.ejs', output: 'src/routes/authRoutes.js' },
86
- { template: 'routes/userRoutes.js.ejs', output: 'src/routes/userRoutes.js' },
87
- );
88
- } else {
89
- // For no-database setup, add example controller/routes
90
- controllerFiles.push(
91
- { template: 'controllers/exampleController.js.ejs', output: 'src/controllers/exampleController.js' },
92
- { template: 'routes/exampleRoutes.js.ejs', output: 'src/routes/exampleRoutes.js' },
93
- );
94
- }
95
-
96
- // Middleware files
97
- const middlewareFiles = [
98
- { template: 'middleware/errorHandler.js.ejs', output: 'src/middleware/errorHandler.js' },
99
- ];
100
-
101
- if (config.hasDatabase) {
102
- middlewareFiles.push(
103
- { template: 'middleware/auth.js.ejs', output: 'src/middleware/auth.js' },
104
- { template: 'middleware/validation.js.ejs', output: 'src/middleware/validation.js' },
105
- );
106
- }
107
-
108
- // Model files (only if using database)
109
- const modelFiles = [];
110
- if (config.hasDatabase) {
111
- if (config.db === 'mongodb') {
112
- modelFiles.push(
113
- { template: 'models/User.mongo.js.ejs', output: 'src/models/User.js' },
114
- { template: 'models/index.mongo.js.ejs', output: 'src/models/index.js' },
115
- );
116
- } else if (config.db === 'postgresql') {
117
- modelFiles.push(
118
- { template: 'models/User.postgres.js.ejs', output: 'src/models/User.js' },
119
- { template: 'models/index.postgres.js.ejs', output: 'src/models/index.js' },
120
- );
121
- }
122
- }
123
-
124
- // Service files
125
- const serviceFiles = [];
126
- if (config.hasDatabase) {
127
- serviceFiles.push(
128
- { template: 'services/authService.js.ejs', output: 'src/services/authService.js' },
129
- { template: `services/userService.${config.db === 'mongodb' ? 'mongodb' : 'postgresql'}.js.ejs`, output: 'src/services/userService.js' },
130
- );
131
- } else {
132
- serviceFiles.push(
133
- { template: 'services/exampleService.js.ejs', output: 'src/services/exampleService.js' },
134
- );
135
- }
136
-
137
- // Utility files
138
- const utilFiles = [
139
- { template: 'utils/errors.js.ejs', output: 'src/utils/errors.js' },
140
- { template: 'utils/logger.js.ejs', output: 'src/utils/logger.js' },
141
- ];
142
-
143
- if (config.hasDatabase) {
144
- utilFiles.push({ template: 'utils/validators.js.ejs', output: 'src/utils/validators.js' });
145
- }
146
-
147
- // Test files
148
- const testFiles = [
149
- { template: 'tests/setup.js.ejs', output: 'tests/setup.js' },
150
- ];
151
-
152
- if (config.hasDatabase) {
153
- testFiles.push(
154
- { template: 'tests/auth.test.js.ejs', output: 'tests/auth.test.js' },
155
- { template: 'tests/users.test.js.ejs', output: 'tests/users.test.js' },
156
- );
157
- } else {
158
- testFiles.push(
159
- { template: 'tests/example.test.js.ejs', output: 'tests/example.test.js' },
160
- );
161
- }
162
-
163
- // Combine all files
164
- const allFiles = [
165
- ...coreFiles,
166
- ...configFiles,
167
- ...controllerFiles,
168
- ...middlewareFiles,
169
- ...modelFiles,
170
- ...serviceFiles,
171
- ...utilFiles,
172
- ...testFiles,
173
- ];
174
-
175
- // Generate each file
176
- for (const file of allFiles) {
177
- const templatePath = path.join(templatesDir, file.template);
178
- const outputPath = path.join(projectDir, file.output);
179
-
180
- try {
181
- const template = fs.readFileSync(templatePath, 'utf8');
182
- const content = ejs.render(template, config);
183
-
184
- // Ensure directory exists
185
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
186
- fs.writeFileSync(outputPath, content);
187
- } catch (error) {
188
- console.warn(`Warning: Could not generate ${file.output}:`, error.message);
189
- }
190
- }
191
- };
192
-
193
- const installDependencies = (projectDir) => {
194
- try {
195
- execSync(`cd "${projectDir}" && npm install`, { stdio: 'inherit' });
196
- } catch (error) {
197
- console.error('Failed to install dependencies:', error.message);
198
- console.log('Try running "npm install" manually in the project directory');
199
- throw error;
200
- }
201
- };
202
-
203
- module.exports = {
204
- generateProject,
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const ejs = require('ejs');
4
+ const { execSync } = require('child_process');
5
+
6
+ const generateProject = async (config, projectDir, options = {}) => {
7
+ createDirectoryStructure(projectDir, config);
8
+ await generateFiles(config, projectDir);
9
+
10
+ if (!options.skipInstall) {
11
+ installDependencies(projectDir);
12
+ }
13
+
14
+ // Run Prisma generate if selected
15
+ if (config.isPrisma && !options.skipInstall) {
16
+ try {
17
+ execSync('npx prisma generate', { cwd: projectDir, stdio: 'pipe' });
18
+ } catch {
19
+ console.warn('âš ī¸ Prisma generate skipped — run "npx prisma generate" manually');
20
+ }
21
+ }
22
+ };
23
+
24
+ const createDirectoryStructure = (projectDir, config) => {
25
+ const dirs = [
26
+ 'src',
27
+ 'src/config',
28
+ 'src/controllers',
29
+ 'src/middleware',
30
+ 'src/routes',
31
+ 'src/services',
32
+ 'src/utils',
33
+ 'tests',
34
+ ];
35
+
36
+ if (config.hasDatabase && !config.isPrisma) {
37
+ dirs.push('src/models');
38
+ }
39
+
40
+ if (config.isPrisma) {
41
+ dirs.push('prisma');
42
+ }
43
+
44
+ if (config.db === 'postgresql') {
45
+ dirs.push('migrations', 'seeders');
46
+ }
47
+
48
+ if (config.hasCicd) {
49
+ dirs.push('.github', '.github/workflows');
50
+ }
51
+
52
+ fs.mkdirSync(projectDir);
53
+ dirs.forEach((dir) => {
54
+ fs.mkdirSync(path.join(projectDir, dir), { recursive: true });
55
+ });
56
+ };
57
+
58
+ const generateFiles = async (config, projectDir) => {
59
+ const templatesDir = path.join(__dirname, '../templates');
60
+ const ext = config.isTypescript ? 'ts' : 'js';
61
+
62
+ // Core files (always generated)
63
+ const coreFiles = [
64
+ { template: 'core/package.json.ejs', output: 'package.json' },
65
+ { template: 'core/app.js.ejs', output: `src/app.${ext}` },
66
+ { template: 'core/server.js.ejs', output: `src/server.${ext}` },
67
+ { template: 'core/env.ejs', output: '.env' },
68
+ { template: 'core/env.example.ejs', output: '.env.example' },
69
+ { template: 'core/gitignore.ejs', output: '.gitignore' },
70
+ { template: 'core/eslintrc.json.ejs', output: '.eslintrc.json' },
71
+ { template: 'core/prettierrc.json.ejs', output: '.prettierrc' },
72
+ { template: 'core/healthcheck.js.ejs', output: 'healthcheck.js' },
73
+ { template: 'core/jest.config.js.ejs', output: 'jest.config.js' },
74
+ { template: 'core/README.md.ejs', output: 'README.md' },
75
+ ];
76
+
77
+ if (config.isTypescript) {
78
+ coreFiles.push({ template: 'core/tsconfig.json.ejs', output: 'tsconfig.json' });
79
+ }
80
+
81
+ if (config.hasDocker) {
82
+ coreFiles.push(
83
+ { template: 'core/Dockerfile.ejs', output: 'Dockerfile' },
84
+ { template: 'core/docker-compose.yml.ejs', output: 'docker-compose.yml' },
85
+ { template: 'core/dockerignore.ejs', output: '.dockerignore' }
86
+ );
87
+ }
88
+
89
+ if (config.hasCicd) {
90
+ coreFiles.push({ template: 'cicd/github-actions.yml.ejs', output: '.github/workflows/ci.yml' });
91
+ }
92
+
93
+ if (config.db === 'postgresql') {
94
+ coreFiles.push(
95
+ { template: 'migrations/sequelizerc.ejs', output: '.sequelizerc' },
96
+ { template: 'migrations/create-users.js.ejs', output: 'migrations/20240101000000-create-users.js' },
97
+ { template: 'migrations/seed-users.js.ejs', output: 'seeders/20240101000000-demo-users.js' }
98
+ );
99
+ }
100
+
101
+ // Config files
102
+ const configFiles = [];
103
+
104
+ if (config.hasSwagger) {
105
+ configFiles.push({ template: 'config/swagger.js.ejs', output: `src/config/swagger.${ext}` });
106
+ }
107
+
108
+ if (config.hasDatabase && !config.isPrisma) {
109
+ if (config.db === 'mongodb') {
110
+ configFiles.push({ template: 'config/database.mongo.js.ejs', output: `src/config/database.${ext}` });
111
+ } else if (config.db === 'postgresql') {
112
+ configFiles.push({ template: 'config/database.postgres.js.ejs', output: `src/config/database.${ext}` });
113
+ }
114
+ }
115
+
116
+ if (config.isPrisma) {
117
+ configFiles.push(
118
+ { template: 'config/database.prisma.js.ejs', output: `src/config/database.${ext}` },
119
+ { template: 'config/schema.prisma.ejs', output: 'prisma/schema.prisma' }
120
+ );
121
+ }
122
+
123
+ if (config.hasWebsocket) {
124
+ configFiles.push({ template: 'config/websocket.js.ejs', output: `src/config/websocket.${ext}` });
125
+ }
126
+
127
+ if (config.hasRedis) {
128
+ configFiles.push({ template: 'config/redis.js.ejs', output: `src/config/redis.${ext}` });
129
+ }
130
+
131
+ // Route files
132
+ const routeFiles = [
133
+ { template: 'routes/index.js.ejs', output: `src/routes/index.${ext}` },
134
+ ];
135
+
136
+ // Controller, service, model files
137
+ const controllerFiles = [];
138
+ const serviceFiles = [];
139
+ const modelFiles = [];
140
+
141
+ if (config.hasAuth) {
142
+ controllerFiles.push(
143
+ { template: 'controllers/authController.js.ejs', output: `src/controllers/authController.${ext}` },
144
+ { template: 'controllers/userController.js.ejs', output: `src/controllers/userController.${ext}` }
145
+ );
146
+ routeFiles.push(
147
+ { template: 'routes/authRoutes.js.ejs', output: `src/routes/authRoutes.${ext}` },
148
+ { template: 'routes/userRoutes.js.ejs', output: `src/routes/userRoutes.${ext}` }
149
+ );
150
+ serviceFiles.push(
151
+ { template: 'services/authService.js.ejs', output: `src/services/authService.${ext}` }
152
+ );
153
+
154
+ if (config.isPrisma) {
155
+ serviceFiles.push({ template: 'services/userService.prisma.js.ejs', output: `src/services/userService.${ext}` });
156
+ } else if (config.db === 'mongodb') {
157
+ serviceFiles.push({ template: 'services/userService.mongodb.js.ejs', output: `src/services/userService.${ext}` });
158
+ modelFiles.push(
159
+ { template: 'models/User.mongo.js.ejs', output: `src/models/User.${ext}` },
160
+ { template: 'models/index.mongo.js.ejs', output: `src/models/index.${ext}` }
161
+ );
162
+ } else if (config.db === 'postgresql') {
163
+ serviceFiles.push({ template: 'services/userService.postgres.js.ejs', output: `src/services/userService.${ext}` });
164
+ modelFiles.push(
165
+ { template: 'models/User.postgres.js.ejs', output: `src/models/User.${ext}` },
166
+ { template: 'models/index.postgres.js.ejs', output: `src/models/index.${ext}` }
167
+ );
168
+ }
169
+ } else {
170
+ controllerFiles.push(
171
+ { template: 'controllers/exampleController.js.ejs', output: `src/controllers/exampleController.${ext}` }
172
+ );
173
+ routeFiles.push(
174
+ { template: 'routes/exampleRoutes.js.ejs', output: `src/routes/exampleRoutes.${ext}` }
175
+ );
176
+ serviceFiles.push(
177
+ { template: 'services/exampleService.js.ejs', output: `src/services/exampleService.${ext}` }
178
+ );
179
+ }
180
+
181
+ // Middleware files
182
+ const middlewareFiles = [
183
+ { template: 'middleware/errorHandler.js.ejs', output: `src/middleware/errorHandler.${ext}` },
184
+ ];
185
+
186
+ if (config.hasAuth) {
187
+ middlewareFiles.push(
188
+ { template: 'middleware/auth.js.ejs', output: `src/middleware/auth.${ext}` },
189
+ { template: 'middleware/validation.js.ejs', output: `src/middleware/validation.${ext}` }
190
+ );
191
+ }
192
+
193
+ if (config.hasRequestId) {
194
+ middlewareFiles.push(
195
+ { template: 'middleware/requestId.js.ejs', output: `src/middleware/requestId.${ext}` }
196
+ );
197
+ }
198
+
199
+ if (config.hasRedis) {
200
+ middlewareFiles.push(
201
+ { template: 'middleware/cache.js.ejs', output: `src/middleware/cache.${ext}` }
202
+ );
203
+ }
204
+
205
+ // Utility files
206
+ const utilFiles = [
207
+ { template: 'utils/errors.js.ejs', output: `src/utils/errors.${ext}` },
208
+ { template: 'utils/logger.js.ejs', output: `src/utils/logger.${ext}` },
209
+ { template: 'utils/response.js.ejs', output: `src/utils/response.${ext}` },
210
+ ];
211
+
212
+ if (config.hasAuth) {
213
+ utilFiles.push({ template: 'utils/validators.js.ejs', output: `src/utils/validators.${ext}` });
214
+ }
215
+
216
+ if (config.hasDatabase || config.hasAuth) {
217
+ utilFiles.push({ template: 'utils/envValidator.js.ejs', output: `src/utils/envValidator.${ext}` });
218
+ }
219
+
220
+ // Test files
221
+ const testFiles = [
222
+ { template: 'tests/setup.js.ejs', output: 'tests/setup.js' },
223
+ ];
224
+
225
+ if (config.hasAuth) {
226
+ testFiles.push(
227
+ { template: 'tests/auth.test.js.ejs', output: 'tests/auth.test.js' },
228
+ { template: 'tests/users.test.js.ejs', output: 'tests/users.test.js' }
229
+ );
230
+ } else {
231
+ testFiles.push(
232
+ { template: 'tests/example.test.js.ejs', output: 'tests/example.test.js' }
233
+ );
234
+ }
235
+
236
+ const allFiles = [
237
+ ...coreFiles,
238
+ ...configFiles,
239
+ ...routeFiles,
240
+ ...controllerFiles,
241
+ ...middlewareFiles,
242
+ ...modelFiles,
243
+ ...serviceFiles,
244
+ ...utilFiles,
245
+ ...testFiles,
246
+ ];
247
+
248
+ const errors = [];
249
+
250
+ for (const file of allFiles) {
251
+ const templatePath = path.join(templatesDir, file.template);
252
+ const outputPath = path.join(projectDir, file.output);
253
+
254
+ if (!fs.existsSync(templatePath)) {
255
+ errors.push(`Template not found: ${file.template}`);
256
+ continue;
257
+ }
258
+
259
+ try {
260
+ const template = fs.readFileSync(templatePath, 'utf8');
261
+ const content = ejs.render(template, config);
262
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
263
+ fs.writeFileSync(outputPath, content);
264
+ } catch (error) {
265
+ errors.push(`${file.output}: ${error.message}`);
266
+ }
267
+ }
268
+
269
+ if (errors.length > 0) {
270
+ throw new Error(`Failed to generate files:\n ${errors.join('\n ')}`);
271
+ }
272
+ };
273
+
274
+ const installDependencies = (projectDir) => {
275
+ try {
276
+ console.log('đŸ“Ļ Installing dependencies...');
277
+ execSync(`cd "${projectDir}" && npm install`, { stdio: 'inherit' });
278
+ } catch (error) {
279
+ console.error('Failed to install dependencies:', error.message);
280
+ console.log('Try running "npm install" manually in the project directory');
281
+ throw error;
282
+ }
283
+ };
284
+
285
+ module.exports = {
286
+ generateProject,
205
287
  };
package/lib/utils.js CHANGED
@@ -1,92 +1,44 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- /**
5
- * Ensure directory exists, create if it doesn't
6
- */
7
- const ensureDirectoryExists = (dirPath) => {
8
- if (!fs.existsSync(dirPath)) {
9
- fs.mkdirSync(dirPath, { recursive: true });
10
- }
11
- };
12
-
13
- /**
14
- * Check if file exists
15
- */
16
- const fileExists = (filePath) => {
17
- return fs.existsSync(filePath);
18
- };
19
-
20
- /**
21
- * Read file safely with error handling
22
- */
23
- const readFileSafe = (filePath, encoding = 'utf8') => {
24
- try {
25
- return fs.readFileSync(filePath, encoding);
26
- } catch (error) {
27
- console.warn(`Warning: Could not read file ${filePath}:`, error.message);
28
- return null;
29
- }
30
- };
31
-
32
- /**
33
- * Write file safely with error handling
34
- */
35
- const writeFileSafe = (filePath, content) => {
36
- try {
37
- // Ensure directory exists
38
- ensureDirectoryExists(path.dirname(filePath));
39
- fs.writeFileSync(filePath, content);
40
- return true;
41
- } catch (error) {
42
- console.error(`Error writing file ${filePath}:`, error.message);
43
- return false;
44
- }
45
- };
46
-
47
- /**
48
- * Get template file path
49
- */
50
- const getTemplatePath = (templateName) => {
51
- return path.join(__dirname, '../templates', templateName);
52
- };
53
-
54
- /**
55
- * Validate project name
56
- */
57
- const validateProjectName = (name) => {
58
- if (!name || name.trim().length === 0) {
59
- return 'Project name cannot be empty';
60
- }
61
-
62
- if (!/^[a-zA-Z0-9-_]+$/.test(name)) {
63
- return 'Project name can only contain letters, numbers, hyphens, and underscores';
64
- }
65
-
66
- if (name.length > 100) {
67
- return 'Project name must be less than 100 characters';
68
- }
69
-
70
- return null; // Valid
71
- };
72
-
73
- /**
74
- * Format console output with colors (if supported)
75
- */
76
- const formatOutput = {
77
- success: (text) => `✅ ${text}`,
78
- error: (text) => `❌ ${text}`,
79
- warning: (text) => `âš ī¸ ${text}`,
80
- info: (text) => `â„šī¸ ${text}`,
81
- progress: (text) => `🔄 ${text}`,
82
- };
83
-
84
- module.exports = {
85
- ensureDirectoryExists,
86
- fileExists,
87
- readFileSafe,
88
- writeFileSafe,
89
- getTemplatePath,
90
- validateProjectName,
91
- formatOutput,
1
+ const path = require('path');
2
+
3
+ /**
4
+ * Validate project name
5
+ */
6
+ const validateProjectName = (name) => {
7
+ if (!name || name.trim().length === 0) {
8
+ return 'Project name cannot be empty';
9
+ }
10
+
11
+ if (!/^[a-zA-Z0-9-_]+$/.test(name)) {
12
+ return 'Project name can only contain letters, numbers, hyphens, and underscores';
13
+ }
14
+
15
+ if (name.length > 100) {
16
+ return 'Project name must be less than 100 characters';
17
+ }
18
+
19
+ return null; // Valid
20
+ };
21
+
22
+ /**
23
+ * Get template file path
24
+ */
25
+ const getTemplatePath = (templateName) => {
26
+ return path.join(__dirname, '../templates', templateName);
27
+ };
28
+
29
+ /**
30
+ * Format console output with colors (if supported)
31
+ */
32
+ const formatOutput = {
33
+ success: (text) => `✅ ${text}`,
34
+ error: (text) => `❌ ${text}`,
35
+ warning: (text) => `âš ī¸ ${text}`,
36
+ info: (text) => `â„šī¸ ${text}`,
37
+ progress: (text) => `🔄 ${text}`,
38
+ };
39
+
40
+ module.exports = {
41
+ validateProjectName,
42
+ getTemplatePath,
43
+ formatOutput,
92
44
  };