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.
- package/README.md +30 -1
- package/dist/generators/docker.d.ts.map +1 -1
- package/dist/generators/docker.js +61 -4
- package/dist/generators/docker.js.map +1 -1
- package/dist/generators/envExample.d.ts.map +1 -1
- package/dist/generators/envExample.js +26 -0
- package/dist/generators/envExample.js.map +1 -1
- package/dist/generators/index.js +1 -1
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/packageJson.d.ts.map +1 -1
- package/dist/generators/packageJson.js +36 -0
- package/dist/generators/packageJson.js.map +1 -1
- package/dist/generators/sourceFiles/controllers/index.d.ts +3 -0
- package/dist/generators/sourceFiles/controllers/index.d.ts.map +1 -0
- package/dist/generators/sourceFiles/controllers/index.js +147 -0
- package/dist/generators/sourceFiles/controllers/index.js.map +1 -0
- package/dist/generators/sourceFiles/core/configFiles.d.ts +3 -0
- package/dist/generators/sourceFiles/core/configFiles.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/configFiles.js +148 -0
- package/dist/generators/sourceFiles/core/configFiles.js.map +1 -0
- package/dist/generators/sourceFiles/core/index.d.ts +3 -0
- package/dist/generators/sourceFiles/core/index.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/index.js +17 -0
- package/dist/generators/sourceFiles/core/index.js.map +1 -0
- package/dist/generators/sourceFiles/core/indexFile.d.ts +3 -0
- package/dist/generators/sourceFiles/core/indexFile.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/indexFile.js +47 -0
- package/dist/generators/sourceFiles/core/indexFile.js.map +1 -0
- package/dist/generators/sourceFiles/core/middlewares.d.ts +3 -0
- package/dist/generators/sourceFiles/core/middlewares.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/middlewares.js +123 -0
- package/dist/generators/sourceFiles/core/middlewares.js.map +1 -0
- package/dist/generators/sourceFiles/core/routes.d.ts +3 -0
- package/dist/generators/sourceFiles/core/routes.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/routes.js +281 -0
- package/dist/generators/sourceFiles/core/routes.js.map +1 -0
- package/dist/generators/sourceFiles/core/tests.d.ts +3 -0
- package/dist/generators/sourceFiles/core/tests.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/tests.js +48 -0
- package/dist/generators/sourceFiles/core/tests.js.map +1 -0
- package/dist/generators/sourceFiles/core/types.d.ts +2 -0
- package/dist/generators/sourceFiles/core/types.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/types.js +13 -0
- package/dist/generators/sourceFiles/core/types.js.map +1 -0
- package/dist/generators/sourceFiles/core/utils.d.ts +2 -0
- package/dist/generators/sourceFiles/core/utils.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/utils.js +173 -0
- package/dist/generators/sourceFiles/core/utils.js.map +1 -0
- package/dist/generators/sourceFiles/core/validators.d.ts +3 -0
- package/dist/generators/sourceFiles/core/validators.d.ts.map +1 -0
- package/dist/generators/sourceFiles/core/validators.js +37 -0
- package/dist/generators/sourceFiles/core/validators.js.map +1 -0
- package/dist/generators/sourceFiles/features/fileUpload.d.ts +3 -0
- package/dist/generators/sourceFiles/features/fileUpload.d.ts.map +1 -0
- package/dist/generators/sourceFiles/features/fileUpload.js +229 -0
- package/dist/generators/sourceFiles/features/fileUpload.js.map +1 -0
- package/dist/generators/sourceFiles/features/queue.d.ts +3 -0
- package/dist/generators/sourceFiles/features/queue.d.ts.map +1 -0
- package/dist/generators/sourceFiles/features/queue.js +211 -0
- package/dist/generators/sourceFiles/features/queue.js.map +1 -0
- package/dist/generators/sourceFiles/features/redis.d.ts +3 -0
- package/dist/generators/sourceFiles/features/redis.d.ts.map +1 -0
- package/dist/generators/sourceFiles/features/redis.js +68 -0
- package/dist/generators/sourceFiles/features/redis.js.map +1 -0
- package/dist/generators/sourceFiles/index.d.ts +3 -0
- package/dist/generators/sourceFiles/index.d.ts.map +1 -0
- package/dist/generators/sourceFiles/index.js +99 -0
- package/dist/generators/sourceFiles/index.js.map +1 -0
- package/dist/generators/sourceFiles/phase1/cliGenerators.d.ts +2 -0
- package/dist/generators/sourceFiles/phase1/cliGenerators.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase1/cliGenerators.js +336 -0
- package/dist/generators/sourceFiles/phase1/cliGenerators.js.map +1 -0
- package/dist/generators/sourceFiles/phase1/seedersFactories.d.ts +3 -0
- package/dist/generators/sourceFiles/phase1/seedersFactories.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase1/seedersFactories.js +89 -0
- package/dist/generators/sourceFiles/phase1/seedersFactories.js.map +1 -0
- package/dist/generators/sourceFiles/phase2/dtos.d.ts +2 -0
- package/dist/generators/sourceFiles/phase2/dtos.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase2/dtos.js +59 -0
- package/dist/generators/sourceFiles/phase2/dtos.js.map +1 -0
- package/dist/generators/sourceFiles/phase2/events.d.ts +2 -0
- package/dist/generators/sourceFiles/phase2/events.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase2/events.js +76 -0
- package/dist/generators/sourceFiles/phase2/events.js.map +1 -0
- package/dist/generators/sourceFiles/phase2/exceptionHandling.d.ts +2 -0
- package/dist/generators/sourceFiles/phase2/exceptionHandling.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase2/exceptionHandling.js +107 -0
- package/dist/generators/sourceFiles/phase2/exceptionHandling.js.map +1 -0
- package/dist/generators/sourceFiles/phase2/guards.d.ts +2 -0
- package/dist/generators/sourceFiles/phase2/guards.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase2/guards.js +98 -0
- package/dist/generators/sourceFiles/phase2/guards.js.map +1 -0
- package/dist/generators/sourceFiles/phase2/healthChecks.d.ts +3 -0
- package/dist/generators/sourceFiles/phase2/healthChecks.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase2/healthChecks.js +73 -0
- package/dist/generators/sourceFiles/phase2/healthChecks.js.map +1 -0
- package/dist/generators/sourceFiles/phase2/scheduledTasks.d.ts +2 -0
- package/dist/generators/sourceFiles/phase2/scheduledTasks.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase2/scheduledTasks.js +56 -0
- package/dist/generators/sourceFiles/phase2/scheduledTasks.js.map +1 -0
- package/dist/generators/sourceFiles/phase3/apiVersioning.d.ts +3 -0
- package/dist/generators/sourceFiles/phase3/apiVersioning.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase3/apiVersioning.js +72 -0
- package/dist/generators/sourceFiles/phase3/apiVersioning.js.map +1 -0
- package/dist/generators/sourceFiles/phase3/cliCommands.d.ts +2 -0
- package/dist/generators/sourceFiles/phase3/cliCommands.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase3/cliCommands.js +102 -0
- package/dist/generators/sourceFiles/phase3/cliCommands.js.map +1 -0
- package/dist/generators/sourceFiles/phase3/configSystem.d.ts +2 -0
- package/dist/generators/sourceFiles/phase3/configSystem.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase3/configSystem.js +57 -0
- package/dist/generators/sourceFiles/phase3/configSystem.js.map +1 -0
- package/dist/generators/sourceFiles/phase3/dependencyInjection.d.ts +2 -0
- package/dist/generators/sourceFiles/phase3/dependencyInjection.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase3/dependencyInjection.js +153 -0
- package/dist/generators/sourceFiles/phase3/dependencyInjection.js.map +1 -0
- package/dist/generators/sourceFiles/phase3/moduleSystem.d.ts +2 -0
- package/dist/generators/sourceFiles/phase3/moduleSystem.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase3/moduleSystem.js +166 -0
- package/dist/generators/sourceFiles/phase3/moduleSystem.js.map +1 -0
- package/dist/generators/sourceFiles/phase3/structuredLogging.d.ts +3 -0
- package/dist/generators/sourceFiles/phase3/structuredLogging.d.ts.map +1 -0
- package/dist/generators/sourceFiles/phase3/structuredLogging.js +155 -0
- package/dist/generators/sourceFiles/phase3/structuredLogging.js.map +1 -0
- package/dist/generators/sourceFiles/repositories/index.d.ts +3 -0
- package/dist/generators/sourceFiles/repositories/index.d.ts.map +1 -0
- package/dist/generators/sourceFiles/repositories/index.js +109 -0
- package/dist/generators/sourceFiles/repositories/index.js.map +1 -0
- package/dist/generators/sourceFiles/services/index.d.ts +3 -0
- package/dist/generators/sourceFiles/services/index.d.ts.map +1 -0
- package/dist/generators/sourceFiles/services/index.js +353 -0
- package/dist/generators/sourceFiles/services/index.js.map +1 -0
- package/dist/generators/sourceFiles.d.ts +1 -2
- package/dist/generators/sourceFiles.d.ts.map +1 -1
- package/dist/generators/sourceFiles.js +2 -1238
- package/dist/generators/sourceFiles.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +35 -0
- package/dist/prompts.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/jest.config.js +21 -0
- package/package.json +4 -1
- package/src/generators/docker.ts +61 -4
- package/src/generators/envExample.ts +28 -0
- package/src/generators/index.ts +1 -1
- package/src/generators/packageJson.ts +40 -1
- package/src/generators/sourceFiles/controllers/index.ts +157 -0
- package/src/generators/sourceFiles/core/configFiles.ts +158 -0
- package/src/generators/sourceFiles/core/index.ts +28 -0
- package/src/generators/sourceFiles/core/indexFile.ts +49 -0
- package/src/generators/sourceFiles/core/middlewares.ts +129 -0
- package/src/generators/sourceFiles/core/routes.ts +295 -0
- package/src/generators/sourceFiles/core/tests.ts +62 -0
- package/src/generators/sourceFiles/core/types.ts +14 -0
- package/src/generators/sourceFiles/core/utils.ts +178 -0
- package/src/generators/sourceFiles/core/validators.ts +39 -0
- package/src/generators/sourceFiles/features/fileUpload.ts +241 -0
- package/src/generators/sourceFiles/features/queue.ts +226 -0
- package/src/generators/sourceFiles/features/redis.ts +73 -0
- package/src/generators/sourceFiles/index.ts +125 -0
- package/src/generators/sourceFiles/phase1/cliGenerators.ts +338 -0
- package/src/generators/sourceFiles/phase1/seedersFactories.ts +97 -0
- package/src/generators/sourceFiles/phase2/dtos.ts +60 -0
- package/src/generators/sourceFiles/phase2/events.ts +80 -0
- package/src/generators/sourceFiles/phase2/exceptionHandling.ts +111 -0
- package/src/generators/sourceFiles/phase2/guards.ts +99 -0
- package/src/generators/sourceFiles/phase2/healthChecks.ts +81 -0
- package/src/generators/sourceFiles/phase2/scheduledTasks.ts +58 -0
- package/src/generators/sourceFiles/phase3/apiVersioning.ts +77 -0
- package/src/generators/sourceFiles/phase3/cliCommands.ts +110 -0
- package/src/generators/sourceFiles/phase3/configSystem.ts +64 -0
- package/src/generators/sourceFiles/phase3/dependencyInjection.ts +155 -0
- package/src/generators/sourceFiles/phase3/moduleSystem.ts +170 -0
- package/src/generators/sourceFiles/phase3/structuredLogging.ts +160 -0
- package/src/generators/sourceFiles/repositories/index.ts +114 -0
- package/src/generators/sourceFiles/services/index.ts +363 -0
- package/src/generators/sourceFiles.ts +2 -1317
- package/src/prompts.ts +36 -1
- package/src/types.ts +5 -0
- 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
|
+
}
|