create-coreback 1.0.4 → 1.0.5

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 (181) hide show
  1. package/README.md +30 -1
  2. package/dist/generators/docker.d.ts.map +1 -1
  3. package/dist/generators/docker.js +61 -4
  4. package/dist/generators/docker.js.map +1 -1
  5. package/dist/generators/envExample.d.ts.map +1 -1
  6. package/dist/generators/envExample.js +26 -0
  7. package/dist/generators/envExample.js.map +1 -1
  8. package/dist/generators/index.js +1 -1
  9. package/dist/generators/index.js.map +1 -1
  10. package/dist/generators/packageJson.d.ts.map +1 -1
  11. package/dist/generators/packageJson.js +36 -0
  12. package/dist/generators/packageJson.js.map +1 -1
  13. package/dist/generators/sourceFiles/controllers/index.d.ts +3 -0
  14. package/dist/generators/sourceFiles/controllers/index.d.ts.map +1 -0
  15. package/dist/generators/sourceFiles/controllers/index.js +147 -0
  16. package/dist/generators/sourceFiles/controllers/index.js.map +1 -0
  17. package/dist/generators/sourceFiles/core/configFiles.d.ts +3 -0
  18. package/dist/generators/sourceFiles/core/configFiles.d.ts.map +1 -0
  19. package/dist/generators/sourceFiles/core/configFiles.js +148 -0
  20. package/dist/generators/sourceFiles/core/configFiles.js.map +1 -0
  21. package/dist/generators/sourceFiles/core/index.d.ts +3 -0
  22. package/dist/generators/sourceFiles/core/index.d.ts.map +1 -0
  23. package/dist/generators/sourceFiles/core/index.js +17 -0
  24. package/dist/generators/sourceFiles/core/index.js.map +1 -0
  25. package/dist/generators/sourceFiles/core/indexFile.d.ts +3 -0
  26. package/dist/generators/sourceFiles/core/indexFile.d.ts.map +1 -0
  27. package/dist/generators/sourceFiles/core/indexFile.js +47 -0
  28. package/dist/generators/sourceFiles/core/indexFile.js.map +1 -0
  29. package/dist/generators/sourceFiles/core/middlewares.d.ts +3 -0
  30. package/dist/generators/sourceFiles/core/middlewares.d.ts.map +1 -0
  31. package/dist/generators/sourceFiles/core/middlewares.js +123 -0
  32. package/dist/generators/sourceFiles/core/middlewares.js.map +1 -0
  33. package/dist/generators/sourceFiles/core/routes.d.ts +3 -0
  34. package/dist/generators/sourceFiles/core/routes.d.ts.map +1 -0
  35. package/dist/generators/sourceFiles/core/routes.js +281 -0
  36. package/dist/generators/sourceFiles/core/routes.js.map +1 -0
  37. package/dist/generators/sourceFiles/core/tests.d.ts +3 -0
  38. package/dist/generators/sourceFiles/core/tests.d.ts.map +1 -0
  39. package/dist/generators/sourceFiles/core/tests.js +48 -0
  40. package/dist/generators/sourceFiles/core/tests.js.map +1 -0
  41. package/dist/generators/sourceFiles/core/types.d.ts +2 -0
  42. package/dist/generators/sourceFiles/core/types.d.ts.map +1 -0
  43. package/dist/generators/sourceFiles/core/types.js +13 -0
  44. package/dist/generators/sourceFiles/core/types.js.map +1 -0
  45. package/dist/generators/sourceFiles/core/utils.d.ts +2 -0
  46. package/dist/generators/sourceFiles/core/utils.d.ts.map +1 -0
  47. package/dist/generators/sourceFiles/core/utils.js +173 -0
  48. package/dist/generators/sourceFiles/core/utils.js.map +1 -0
  49. package/dist/generators/sourceFiles/core/validators.d.ts +3 -0
  50. package/dist/generators/sourceFiles/core/validators.d.ts.map +1 -0
  51. package/dist/generators/sourceFiles/core/validators.js +37 -0
  52. package/dist/generators/sourceFiles/core/validators.js.map +1 -0
  53. package/dist/generators/sourceFiles/features/fileUpload.d.ts +3 -0
  54. package/dist/generators/sourceFiles/features/fileUpload.d.ts.map +1 -0
  55. package/dist/generators/sourceFiles/features/fileUpload.js +229 -0
  56. package/dist/generators/sourceFiles/features/fileUpload.js.map +1 -0
  57. package/dist/generators/sourceFiles/features/queue.d.ts +3 -0
  58. package/dist/generators/sourceFiles/features/queue.d.ts.map +1 -0
  59. package/dist/generators/sourceFiles/features/queue.js +211 -0
  60. package/dist/generators/sourceFiles/features/queue.js.map +1 -0
  61. package/dist/generators/sourceFiles/features/redis.d.ts +3 -0
  62. package/dist/generators/sourceFiles/features/redis.d.ts.map +1 -0
  63. package/dist/generators/sourceFiles/features/redis.js +68 -0
  64. package/dist/generators/sourceFiles/features/redis.js.map +1 -0
  65. package/dist/generators/sourceFiles/index.d.ts +3 -0
  66. package/dist/generators/sourceFiles/index.d.ts.map +1 -0
  67. package/dist/generators/sourceFiles/index.js +99 -0
  68. package/dist/generators/sourceFiles/index.js.map +1 -0
  69. package/dist/generators/sourceFiles/phase1/cliGenerators.d.ts +2 -0
  70. package/dist/generators/sourceFiles/phase1/cliGenerators.d.ts.map +1 -0
  71. package/dist/generators/sourceFiles/phase1/cliGenerators.js +336 -0
  72. package/dist/generators/sourceFiles/phase1/cliGenerators.js.map +1 -0
  73. package/dist/generators/sourceFiles/phase1/seedersFactories.d.ts +3 -0
  74. package/dist/generators/sourceFiles/phase1/seedersFactories.d.ts.map +1 -0
  75. package/dist/generators/sourceFiles/phase1/seedersFactories.js +89 -0
  76. package/dist/generators/sourceFiles/phase1/seedersFactories.js.map +1 -0
  77. package/dist/generators/sourceFiles/phase2/dtos.d.ts +2 -0
  78. package/dist/generators/sourceFiles/phase2/dtos.d.ts.map +1 -0
  79. package/dist/generators/sourceFiles/phase2/dtos.js +59 -0
  80. package/dist/generators/sourceFiles/phase2/dtos.js.map +1 -0
  81. package/dist/generators/sourceFiles/phase2/events.d.ts +2 -0
  82. package/dist/generators/sourceFiles/phase2/events.d.ts.map +1 -0
  83. package/dist/generators/sourceFiles/phase2/events.js +76 -0
  84. package/dist/generators/sourceFiles/phase2/events.js.map +1 -0
  85. package/dist/generators/sourceFiles/phase2/exceptionHandling.d.ts +2 -0
  86. package/dist/generators/sourceFiles/phase2/exceptionHandling.d.ts.map +1 -0
  87. package/dist/generators/sourceFiles/phase2/exceptionHandling.js +107 -0
  88. package/dist/generators/sourceFiles/phase2/exceptionHandling.js.map +1 -0
  89. package/dist/generators/sourceFiles/phase2/guards.d.ts +2 -0
  90. package/dist/generators/sourceFiles/phase2/guards.d.ts.map +1 -0
  91. package/dist/generators/sourceFiles/phase2/guards.js +98 -0
  92. package/dist/generators/sourceFiles/phase2/guards.js.map +1 -0
  93. package/dist/generators/sourceFiles/phase2/healthChecks.d.ts +3 -0
  94. package/dist/generators/sourceFiles/phase2/healthChecks.d.ts.map +1 -0
  95. package/dist/generators/sourceFiles/phase2/healthChecks.js +73 -0
  96. package/dist/generators/sourceFiles/phase2/healthChecks.js.map +1 -0
  97. package/dist/generators/sourceFiles/phase2/scheduledTasks.d.ts +2 -0
  98. package/dist/generators/sourceFiles/phase2/scheduledTasks.d.ts.map +1 -0
  99. package/dist/generators/sourceFiles/phase2/scheduledTasks.js +56 -0
  100. package/dist/generators/sourceFiles/phase2/scheduledTasks.js.map +1 -0
  101. package/dist/generators/sourceFiles/phase3/apiVersioning.d.ts +3 -0
  102. package/dist/generators/sourceFiles/phase3/apiVersioning.d.ts.map +1 -0
  103. package/dist/generators/sourceFiles/phase3/apiVersioning.js +72 -0
  104. package/dist/generators/sourceFiles/phase3/apiVersioning.js.map +1 -0
  105. package/dist/generators/sourceFiles/phase3/cliCommands.d.ts +2 -0
  106. package/dist/generators/sourceFiles/phase3/cliCommands.d.ts.map +1 -0
  107. package/dist/generators/sourceFiles/phase3/cliCommands.js +102 -0
  108. package/dist/generators/sourceFiles/phase3/cliCommands.js.map +1 -0
  109. package/dist/generators/sourceFiles/phase3/configSystem.d.ts +2 -0
  110. package/dist/generators/sourceFiles/phase3/configSystem.d.ts.map +1 -0
  111. package/dist/generators/sourceFiles/phase3/configSystem.js +57 -0
  112. package/dist/generators/sourceFiles/phase3/configSystem.js.map +1 -0
  113. package/dist/generators/sourceFiles/phase3/dependencyInjection.d.ts +2 -0
  114. package/dist/generators/sourceFiles/phase3/dependencyInjection.d.ts.map +1 -0
  115. package/dist/generators/sourceFiles/phase3/dependencyInjection.js +153 -0
  116. package/dist/generators/sourceFiles/phase3/dependencyInjection.js.map +1 -0
  117. package/dist/generators/sourceFiles/phase3/moduleSystem.d.ts +2 -0
  118. package/dist/generators/sourceFiles/phase3/moduleSystem.d.ts.map +1 -0
  119. package/dist/generators/sourceFiles/phase3/moduleSystem.js +166 -0
  120. package/dist/generators/sourceFiles/phase3/moduleSystem.js.map +1 -0
  121. package/dist/generators/sourceFiles/phase3/structuredLogging.d.ts +3 -0
  122. package/dist/generators/sourceFiles/phase3/structuredLogging.d.ts.map +1 -0
  123. package/dist/generators/sourceFiles/phase3/structuredLogging.js +155 -0
  124. package/dist/generators/sourceFiles/phase3/structuredLogging.js.map +1 -0
  125. package/dist/generators/sourceFiles/repositories/index.d.ts +3 -0
  126. package/dist/generators/sourceFiles/repositories/index.d.ts.map +1 -0
  127. package/dist/generators/sourceFiles/repositories/index.js +109 -0
  128. package/dist/generators/sourceFiles/repositories/index.js.map +1 -0
  129. package/dist/generators/sourceFiles/services/index.d.ts +3 -0
  130. package/dist/generators/sourceFiles/services/index.d.ts.map +1 -0
  131. package/dist/generators/sourceFiles/services/index.js +353 -0
  132. package/dist/generators/sourceFiles/services/index.js.map +1 -0
  133. package/dist/generators/sourceFiles.d.ts +1 -2
  134. package/dist/generators/sourceFiles.d.ts.map +1 -1
  135. package/dist/generators/sourceFiles.js +2 -1238
  136. package/dist/generators/sourceFiles.js.map +1 -1
  137. package/dist/prompts.d.ts.map +1 -1
  138. package/dist/prompts.js +35 -0
  139. package/dist/prompts.js.map +1 -1
  140. package/dist/types.d.ts +5 -0
  141. package/dist/types.d.ts.map +1 -1
  142. package/jest.config.js +21 -0
  143. package/package.json +4 -1
  144. package/src/generators/docker.ts +61 -4
  145. package/src/generators/envExample.ts +28 -0
  146. package/src/generators/index.ts +1 -1
  147. package/src/generators/packageJson.ts +40 -1
  148. package/src/generators/sourceFiles/controllers/index.ts +157 -0
  149. package/src/generators/sourceFiles/core/configFiles.ts +158 -0
  150. package/src/generators/sourceFiles/core/index.ts +28 -0
  151. package/src/generators/sourceFiles/core/indexFile.ts +49 -0
  152. package/src/generators/sourceFiles/core/middlewares.ts +129 -0
  153. package/src/generators/sourceFiles/core/routes.ts +295 -0
  154. package/src/generators/sourceFiles/core/tests.ts +62 -0
  155. package/src/generators/sourceFiles/core/types.ts +14 -0
  156. package/src/generators/sourceFiles/core/utils.ts +178 -0
  157. package/src/generators/sourceFiles/core/validators.ts +39 -0
  158. package/src/generators/sourceFiles/features/fileUpload.ts +241 -0
  159. package/src/generators/sourceFiles/features/queue.ts +226 -0
  160. package/src/generators/sourceFiles/features/redis.ts +73 -0
  161. package/src/generators/sourceFiles/index.ts +125 -0
  162. package/src/generators/sourceFiles/phase1/cliGenerators.ts +338 -0
  163. package/src/generators/sourceFiles/phase1/seedersFactories.ts +97 -0
  164. package/src/generators/sourceFiles/phase2/dtos.ts +60 -0
  165. package/src/generators/sourceFiles/phase2/events.ts +80 -0
  166. package/src/generators/sourceFiles/phase2/exceptionHandling.ts +111 -0
  167. package/src/generators/sourceFiles/phase2/guards.ts +99 -0
  168. package/src/generators/sourceFiles/phase2/healthChecks.ts +81 -0
  169. package/src/generators/sourceFiles/phase2/scheduledTasks.ts +58 -0
  170. package/src/generators/sourceFiles/phase3/apiVersioning.ts +77 -0
  171. package/src/generators/sourceFiles/phase3/cliCommands.ts +110 -0
  172. package/src/generators/sourceFiles/phase3/configSystem.ts +64 -0
  173. package/src/generators/sourceFiles/phase3/dependencyInjection.ts +155 -0
  174. package/src/generators/sourceFiles/phase3/moduleSystem.ts +170 -0
  175. package/src/generators/sourceFiles/phase3/structuredLogging.ts +160 -0
  176. package/src/generators/sourceFiles/repositories/index.ts +114 -0
  177. package/src/generators/sourceFiles/services/index.ts +363 -0
  178. package/src/generators/sourceFiles.ts +2 -1317
  179. package/src/prompts.ts +36 -1
  180. package/src/types.ts +5 -0
  181. package/tests/integration.test.ts +233 -0
@@ -0,0 +1,338 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ export async function generateCLIGenerators(projectPath: string): Promise<void> {
5
+ const scriptsDir = path.join(projectPath, 'scripts');
6
+ await fs.ensureDir(scriptsDir);
7
+
8
+ // make.ts - CLI generator
9
+ const makeContent = `#!/usr/bin/env node
10
+ import fs from 'fs-extra';
11
+ import path from 'path';
12
+ import { fileURLToPath } from 'url';
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ const projectRoot = path.resolve(__dirname, '..');
17
+
18
+ const templates = {
19
+ controller: \`import { Request, Response } from 'express';
20
+ import { AppError } from '../middlewares/errorHandler.js';
21
+
22
+ export const {{name}}Controller = {
23
+ index: async (req: Request, res: Response) => {
24
+ try {
25
+ res.json({
26
+ status: 'success',
27
+ data: [],
28
+ });
29
+ } catch (error) {
30
+ if (error instanceof AppError) {
31
+ throw error;
32
+ }
33
+ throw new AppError(500, 'Failed to fetch {{name}}');
34
+ }
35
+ },
36
+
37
+ show: async (req: Request, res: Response) => {
38
+ try {
39
+ const { id } = req.params;
40
+ res.json({
41
+ status: 'success',
42
+ data: { id },
43
+ });
44
+ } catch (error) {
45
+ if (error instanceof AppError) {
46
+ throw error;
47
+ }
48
+ throw new AppError(500, 'Failed to fetch {{name}}');
49
+ }
50
+ },
51
+
52
+ create: async (req: Request, res: Response) => {
53
+ try {
54
+ res.status(201).json({
55
+ status: 'success',
56
+ data: req.body,
57
+ });
58
+ } catch (error) {
59
+ if (error instanceof AppError) {
60
+ throw error;
61
+ }
62
+ throw new AppError(500, 'Failed to create {{name}}');
63
+ }
64
+ },
65
+
66
+ update: async (req: Request, res: Response) => {
67
+ try {
68
+ const { id } = req.params;
69
+ res.json({
70
+ status: 'success',
71
+ data: { id, ...req.body },
72
+ });
73
+ } catch (error) {
74
+ if (error instanceof AppError) {
75
+ throw error;
76
+ }
77
+ throw new AppError(500, 'Failed to update {{name}}');
78
+ }
79
+ },
80
+
81
+ delete: async (req: Request, res: Response) => {
82
+ try {
83
+ const { id } = req.params;
84
+ res.json({
85
+ status: 'success',
86
+ message: '{{name}} deleted successfully',
87
+ });
88
+ } catch (error) {
89
+ if (error instanceof AppError) {
90
+ throw error;
91
+ }
92
+ throw new AppError(500, 'Failed to delete {{name}}');
93
+ }
94
+ },
95
+ };
96
+ \`,
97
+
98
+ service: \`import { AppError } from '../middlewares/errorHandler.js';
99
+
100
+ export const {{name}}Service = {
101
+ findAll: async () => {
102
+ // Implement your logic here
103
+ return [];
104
+ },
105
+
106
+ findById: async (id: string) => {
107
+ // Implement your logic here
108
+ return { id };
109
+ },
110
+
111
+ create: async (data: unknown) => {
112
+ // Implement your logic here
113
+ return data;
114
+ },
115
+
116
+ update: async (id: string, data: unknown) => {
117
+ // Implement your logic here
118
+ return { id, ...data };
119
+ },
120
+
121
+ delete: async (id: string) => {
122
+ // Implement your logic here
123
+ return true;
124
+ },
125
+ };
126
+ \`,
127
+
128
+ repository: \`import { prisma } from '../config/database.js';
129
+
130
+ export const {{name}}Repository = {
131
+ findAll: async () => {
132
+ return prisma.{{modelName}}.findMany();
133
+ },
134
+
135
+ findById: async (id: string) => {
136
+ return prisma.{{modelName}}.findUnique({
137
+ where: { id },
138
+ });
139
+ },
140
+
141
+ create: async (data: unknown) => {
142
+ return prisma.{{modelName}}.create({
143
+ data: data as any,
144
+ });
145
+ },
146
+
147
+ update: async (id: string, data: unknown) => {
148
+ return prisma.{{modelName}}.update({
149
+ where: { id },
150
+ data: data as any,
151
+ });
152
+ },
153
+
154
+ delete: async (id: string) => {
155
+ return prisma.{{modelName}}.delete({
156
+ where: { id },
157
+ });
158
+ },
159
+ };
160
+ \`,
161
+
162
+ route: \`import { Router } from 'express';
163
+ import { {{name}}Controller } from '../controllers/{{name}}.controller.js';
164
+ // Uncomment if you need authentication:
165
+ // import { authenticate } from '../middlewares/auth.js';
166
+
167
+ const router = Router();
168
+
169
+ /**
170
+ * @swagger
171
+ * tags:
172
+ * name: {{Name}}
173
+ * description: {{Name}} management endpoints
174
+ */
175
+
176
+ // Uncomment if you need authentication:
177
+ // router.use(authenticate);
178
+
179
+ /**
180
+ * @swagger
181
+ * /api/{{name}}:
182
+ * get:
183
+ * summary: Get all {{name}}
184
+ * tags: [{{Name}}]
185
+ * responses:
186
+ * 200:
187
+ * description: List of {{name}}
188
+ */
189
+ router.get('/', {{name}}Controller.index);
190
+
191
+ /**
192
+ * @swagger
193
+ * /api/{{name}}/{id}:
194
+ * get:
195
+ * summary: Get {{name}} by ID
196
+ * tags: [{{Name}}]
197
+ * parameters:
198
+ * - in: path
199
+ * name: id
200
+ * required: true
201
+ * schema:
202
+ * type: string
203
+ * responses:
204
+ * 200:
205
+ * description: {{Name}} details
206
+ */
207
+ router.get('/:id', {{name}}Controller.show);
208
+
209
+ /**
210
+ * @swagger
211
+ * /api/{{name}}:
212
+ * post:
213
+ * summary: Create {{name}}
214
+ * tags: [{{Name}}]
215
+ * requestBody:
216
+ * required: true
217
+ * content:
218
+ * application/json:
219
+ * schema:
220
+ * type: object
221
+ * responses:
222
+ * 201:
223
+ * description: {{Name}} created
224
+ */
225
+ router.post('/', {{name}}Controller.create);
226
+
227
+ /**
228
+ * @swagger
229
+ * /api/{{name}}/{id}:
230
+ * put:
231
+ * summary: Update {{name}}
232
+ * tags: [{{Name}}]
233
+ * parameters:
234
+ * - in: path
235
+ * name: id
236
+ * required: true
237
+ * schema:
238
+ * type: string
239
+ * responses:
240
+ * 200:
241
+ * description: {{Name}} updated
242
+ */
243
+ router.put('/:id', {{name}}Controller.update);
244
+
245
+ /**
246
+ * @swagger
247
+ * /api/{{name}}/{id}:
248
+ * delete:
249
+ * summary: Delete {{name}}
250
+ * tags: [{{Name}}]
251
+ * parameters:
252
+ * - in: path
253
+ * name: id
254
+ * required: true
255
+ * schema:
256
+ * type: string
257
+ * responses:
258
+ * 200:
259
+ * description: {{Name}} deleted
260
+ */
261
+ router.delete('/:id', {{name}}Controller.delete);
262
+
263
+ export { router as {{name}}Routes };
264
+ \`,
265
+ };
266
+
267
+ function toPascalCase(str: string): string {
268
+ return str
269
+ .split(/[-_]/)
270
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
271
+ .join('');
272
+ }
273
+
274
+ function toCamelCase(str: string): string {
275
+ const pascal = toPascalCase(str);
276
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
277
+ }
278
+
279
+ function replacePlaceholders(content: string, name: string, modelName?: string): string {
280
+ const Name = toPascalCase(name);
281
+ const camelName = toCamelCase(name);
282
+ const model = modelName || Name;
283
+
284
+ return content
285
+ .replace(/{{name}}/g, camelName)
286
+ .replace(/{{Name}}/g, Name)
287
+ .replace(/{{modelName}}/g, model.toLowerCase());
288
+ }
289
+
290
+ async function generateFile(type: string, name: string, modelName?: string) {
291
+ const template = templates[type as keyof typeof templates];
292
+ if (!template) {
293
+ console.error(\`Unknown type: \\\${type}\`);
294
+ process.exit(1);
295
+ }
296
+
297
+ const content = replacePlaceholders(template, name, modelName);
298
+ const dirMap: Record<string, string> = {
299
+ controller: 'src/controllers',
300
+ service: 'src/services',
301
+ repository: 'src/repositories',
302
+ route: 'src/routes',
303
+ };
304
+
305
+ const dir = path.join(projectRoot, dirMap[type] || 'src');
306
+ await fs.ensureDir(dir);
307
+
308
+ const fileName = \`\\\${toCamelCase(name)}.\\\${type === 'route' ? 'routes' : type}.ts\`;
309
+ const filePath = path.join(dir, fileName);
310
+
311
+ if (await fs.pathExists(filePath)) {
312
+ console.error(\`File already exists: \\\${filePath}\`);
313
+ process.exit(1);
314
+ }
315
+
316
+ await fs.writeFile(filePath, content);
317
+ console.log(\`✅ Created \\\${filePath}\`);
318
+ }
319
+
320
+ const args = process.argv.slice(2);
321
+ if (args.length < 2) {
322
+ console.error('Usage: npm run make:<type> <name> [modelName]');
323
+ console.error('Example: npm run make:controller user');
324
+ console.error('Example: npm run make:repository user User');
325
+ process.exit(1);
326
+ }
327
+
328
+ const [type, name] = args;
329
+ const modelName = args[2];
330
+
331
+ generateFile(type, name, modelName).catch((error) => {
332
+ console.error('Error:', error);
333
+ process.exit(1);
334
+ });
335
+ `;
336
+
337
+ await fs.writeFile(path.join(scriptsDir, 'make.ts'), makeContent);
338
+ }
@@ -0,0 +1,97 @@
1
+ import { ProjectConfig } from '../../../types.js';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export async function generateSeedersAndFactories(
6
+ projectPath: string,
7
+ config: ProjectConfig
8
+ ): Promise<void> {
9
+ const prismaDir = path.join(projectPath, 'prisma');
10
+ const factoriesDir = path.join(projectPath, 'src', 'factories');
11
+ await fs.ensureDir(factoriesDir);
12
+
13
+ // seed.ts
14
+ const seedContent = `import { PrismaClient } from '@prisma/client';
15
+
16
+ const prisma = new PrismaClient();
17
+
18
+ async function main() {
19
+ console.log('🌱 Seeding database...');
20
+
21
+ // Add your seed data here
22
+ // Example:
23
+ // await prisma.user.create({
24
+ // data: {
25
+ // email: 'admin@example.com',
26
+ // password: '$2b$10$...', // hashed password
27
+ // name: 'Admin User',
28
+ // emailVerified: true,
29
+ // },
30
+ // });
31
+
32
+ console.log('✅ Seeding completed');
33
+ }
34
+
35
+ main()
36
+ .catch((e) => {
37
+ console.error('❌ Seeding failed:', e);
38
+ process.exit(1);
39
+ })
40
+ .finally(async () => {
41
+ await prisma.$disconnect();
42
+ });
43
+ `;
44
+
45
+ await fs.writeFile(path.join(prismaDir, 'seed.ts'), seedContent);
46
+
47
+ // user.factory.ts (if auth is enabled)
48
+ if (config.includeAuth) {
49
+ const userFactoryContent = `import bcrypt from 'bcrypt';
50
+ import { PrismaClient } from '@prisma/client';
51
+
52
+ const prisma = new PrismaClient();
53
+
54
+ export interface UserFactoryData {
55
+ email?: string;
56
+ password?: string;
57
+ name?: string;
58
+ emailVerified?: boolean;
59
+ }
60
+
61
+ export async function createUser(data: UserFactoryData = {}) {
62
+ const defaultPassword = data.password || 'password123';
63
+ const hashedPassword = await bcrypt.hash(defaultPassword, 10);
64
+
65
+ return prisma.user.create({
66
+ data: {
67
+ email: data.email || \`user-\${Date.now()}@example.com\`,
68
+ password: hashedPassword,
69
+ name: data.name || 'Test User',
70
+ emailVerified: data.emailVerified ?? true,
71
+ },
72
+ });
73
+ }
74
+
75
+ export async function createManyUsers(count: number, data: UserFactoryData = {}) {
76
+ const users = [];
77
+ for (let i = 0; i < count; i++) {
78
+ const defaultPassword = data.password || 'password123';
79
+ const hashedPassword = await bcrypt.hash(defaultPassword, 10);
80
+
81
+ users.push({
82
+ email: data.email || \`user-\${Date.now()}-\${i}@example.com\`,
83
+ password: hashedPassword,
84
+ name: data.name || \`Test User \${i + 1}\`,
85
+ emailVerified: data.emailVerified ?? true,
86
+ });
87
+ }
88
+
89
+ return prisma.user.createMany({
90
+ data: users,
91
+ });
92
+ }
93
+ `;
94
+
95
+ await fs.writeFile(path.join(factoriesDir, 'user.factory.ts'), userFactoryContent);
96
+ }
97
+ }
@@ -0,0 +1,60 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ export async function generateDTOs(validatorsDir: string): Promise<void> {
5
+ const dtoContent = `import { z } from 'zod';
6
+
7
+ /**
8
+ * Base DTO class with Zod validation
9
+ */
10
+ export class DTO<T extends z.ZodTypeAny> {
11
+ constructor(private schema: T) {}
12
+
13
+ /**
14
+ * Validate and parse data
15
+ */
16
+ parse(data: unknown): z.infer<T> {
17
+ return this.schema.parse(data);
18
+ }
19
+
20
+ /**
21
+ * Safe parse (returns result object)
22
+ */
23
+ safeParse(data: unknown): z.SafeParseReturnType<unknown, z.infer<T>> {
24
+ return this.schema.safeParse(data);
25
+ }
26
+
27
+ /**
28
+ * Get the schema
29
+ */
30
+ getSchema(): T {
31
+ return this.schema;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Create a DTO from a Zod schema
37
+ */
38
+ export function createDTO<T extends z.ZodTypeAny>(schema: T): DTO<T> {
39
+ return new DTO(schema);
40
+ }
41
+
42
+ /**
43
+ * Common DTOs
44
+ */
45
+ export const PaginationDTO = createDTO(
46
+ z.object({
47
+ page: z.coerce.number().int().min(1).default(1).optional(),
48
+ limit: z.coerce.number().int().min(1).max(100).default(10).optional(),
49
+ })
50
+ );
51
+
52
+ export const IdDTO = createDTO(
53
+ z.object({
54
+ id: z.string().min(1),
55
+ })
56
+ );
57
+ `;
58
+
59
+ await fs.writeFile(path.join(validatorsDir, 'dto.ts'), dtoContent);
60
+ }
@@ -0,0 +1,80 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ export async function generateEventsAndListeners(srcDir: string): Promise<void> {
5
+ const eventsDir = path.join(srcDir, 'events');
6
+ const listenersDir = path.join(eventsDir, 'listeners');
7
+ await fs.ensureDir(eventsDir);
8
+ await fs.ensureDir(listenersDir);
9
+
10
+ // eventEmitter.ts
11
+ const eventEmitterContent = `import { EventEmitter } from 'events';
12
+ import { logger } from '../utils/logger.js';
13
+
14
+ class AppEventEmitter extends EventEmitter {
15
+ emit(event: string | symbol, ...args: any[]): boolean {
16
+ logger.debug(\`Event emitted: \${String(event)}\`);
17
+ return super.emit(event, ...args);
18
+ }
19
+ }
20
+
21
+ export const eventEmitter = new AppEventEmitter();
22
+
23
+ // Event names
24
+ export const Events = {
25
+ USER_REGISTERED: 'user.registered',
26
+ USER_VERIFIED: 'user.verified',
27
+ PASSWORD_RESET_REQUESTED: 'password.reset.requested',
28
+ PASSWORD_RESET: 'password.reset',
29
+ EMAIL_SENT: 'email.sent',
30
+ } as const;
31
+
32
+ export type EventName = typeof Events[keyof typeof Events];
33
+ `;
34
+
35
+ await fs.writeFile(path.join(eventsDir, 'eventEmitter.ts'), eventEmitterContent);
36
+
37
+ // listeners/index.ts
38
+ const listenersContent = `import { eventEmitter, Events } from '../eventEmitter.js';
39
+ import { logger } from '../utils/logger.js';
40
+
41
+ /**
42
+ * Register all event listeners
43
+ */
44
+ export function registerListeners() {
45
+ // User registered listener
46
+ eventEmitter.on(Events.USER_REGISTERED, (data) => {
47
+ logger.info(\`User registered: \${data.email}\`);
48
+ // Add your custom logic here
49
+ });
50
+
51
+ // User verified listener
52
+ eventEmitter.on(Events.USER_VERIFIED, (data) => {
53
+ logger.info(\`User verified: \${data.email}\`);
54
+ // Add your custom logic here
55
+ });
56
+
57
+ // Password reset requested listener
58
+ eventEmitter.on(Events.PASSWORD_RESET_REQUESTED, (data) => {
59
+ logger.info(\`Password reset requested for: \${data.email}\`);
60
+ // Add your custom logic here
61
+ });
62
+
63
+ // Password reset listener
64
+ eventEmitter.on(Events.PASSWORD_RESET, (data) => {
65
+ logger.info(\`Password reset for: \${data.email}\`);
66
+ // Add your custom logic here
67
+ });
68
+
69
+ // Email sent listener
70
+ eventEmitter.on(Events.EMAIL_SENT, (data) => {
71
+ logger.debug(\`Email sent to: \${data.to}\`);
72
+ // Add your custom logic here
73
+ });
74
+
75
+ logger.info('Event listeners registered');
76
+ }
77
+ `;
78
+
79
+ await fs.writeFile(path.join(listenersDir, 'index.ts'), listenersContent);
80
+ }
@@ -0,0 +1,111 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ export async function generateAdvancedExceptionHandling(middlewaresDir: string): Promise<void> {
5
+ const exceptionHandlerContent = `import { Request, Response, NextFunction } from 'express';
6
+ import { ZodError } from 'zod';
7
+ import { logger } from '../utils/logger.js';
8
+
9
+ export class AppError extends Error {
10
+ constructor(
11
+ public statusCode: number,
12
+ message: string,
13
+ public isOperational = true,
14
+ public code?: string
15
+ ) {
16
+ super(message);
17
+ Object.setPrototypeOf(this, AppError.prototype);
18
+ Error.captureStackTrace(this, this.constructor);
19
+ }
20
+ }
21
+
22
+ export class ValidationError extends AppError {
23
+ constructor(message: string, public errors?: unknown[]) {
24
+ super(400, message, true, 'VALIDATION_ERROR');
25
+ this.name = 'ValidationError';
26
+ }
27
+ }
28
+
29
+ export class NotFoundError extends AppError {
30
+ constructor(resource: string = 'Resource') {
31
+ super(404, \`\${resource} not found\`, true, 'NOT_FOUND');
32
+ this.name = 'NotFoundError';
33
+ }
34
+ }
35
+
36
+ export class UnauthorizedError extends AppError {
37
+ constructor(message: string = 'Unauthorized') {
38
+ super(401, message, true, 'UNAUTHORIZED');
39
+ this.name = 'UnauthorizedError';
40
+ }
41
+ }
42
+
43
+ export class ForbiddenError extends AppError {
44
+ constructor(message: string = 'Forbidden') {
45
+ super(403, message, true, 'FORBIDDEN');
46
+ this.name = 'ForbiddenError';
47
+ }
48
+ }
49
+
50
+ export class ConflictError extends AppError {
51
+ constructor(message: string = 'Resource conflict') {
52
+ super(409, message, true, 'CONFLICT');
53
+ this.name = 'ConflictError';
54
+ }
55
+ }
56
+
57
+ export const errorHandler = (
58
+ err: Error,
59
+ req: Request,
60
+ res: Response,
61
+ next: NextFunction
62
+ ) => {
63
+ // Log error
64
+ logger.error('Error:', {
65
+ message: err.message,
66
+ stack: err.stack,
67
+ url: req.url,
68
+ method: req.method,
69
+ ip: req.ip,
70
+ });
71
+
72
+ // Zod validation errors
73
+ if (err instanceof ZodError) {
74
+ return res.status(400).json({
75
+ status: 'error',
76
+ code: 'VALIDATION_ERROR',
77
+ message: 'Validation error',
78
+ errors: err.errors,
79
+ });
80
+ }
81
+
82
+ // App errors (operational)
83
+ if (err instanceof AppError && err.isOperational) {
84
+ return res.status(err.statusCode).json({
85
+ status: 'error',
86
+ code: err.code || 'APP_ERROR',
87
+ message: err.message,
88
+ });
89
+ }
90
+
91
+ // Unknown errors (programming errors, etc.)
92
+ const statusCode = err instanceof AppError ? err.statusCode : 500;
93
+ const message =
94
+ process.env.NODE_ENV === 'production'
95
+ ? 'Internal server error'
96
+ : err.message;
97
+
98
+ return res.status(statusCode).json({
99
+ status: 'error',
100
+ code: 'INTERNAL_ERROR',
101
+ message,
102
+ ...(process.env.NODE_ENV !== 'production' && { stack: err.stack }),
103
+ });
104
+ };
105
+ `;
106
+
107
+ await fs.writeFile(
108
+ path.join(middlewaresDir, 'errorHandler.ts'),
109
+ exceptionHandlerContent
110
+ );
111
+ }