nestcraftx 0.2.4 → 0.2.6
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/.gitattributes +6 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/ISSUE_TEMPLATE/pull_request_template.md +24 -0
- package/CHANGELOG.fr.md +97 -97
- package/CHANGELOG.md +98 -98
- package/CLI_USAGE.fr.md +331 -331
- package/CLI_USAGE.md +364 -364
- package/DEMO.fr.md +292 -292
- package/DEMO.md +294 -294
- package/LICENSE +21 -21
- package/MIGRATION_GUIDE.fr.md +127 -127
- package/MIGRATION_GUIDE.md +124 -124
- package/QUICK_START.fr.md +152 -152
- package/QUICK_START.md +169 -169
- package/README.fr.md +653 -659
- package/SECURITY.md +10 -0
- package/bin/nestcraft.js +84 -64
- package/commands/demo.js +333 -330
- package/commands/generate.js +93 -0
- package/commands/generateConf.js +91 -0
- package/commands/help.js +78 -78
- package/commands/info.js +48 -48
- package/commands/new.js +338 -335
- package/commands/start.js +19 -19
- package/commands/test.js +7 -7
- package/package.json +41 -41
- package/readme.md +638 -643
- package/utils/cliParser.js +133 -76
- package/utils/colors.js +62 -62
- package/utils/configs/configureDocker.js +120 -120
- package/utils/configs/setupCleanArchitecture.js +563 -557
- package/utils/configs/setupLightArchitecture.js +701 -660
- package/utils/envGenerator.js +122 -122
- package/utils/file-utils/packageJsonUtils.js +49 -55
- package/utils/file-utils/saveProjectConfig.js +36 -0
- package/utils/fullModeInput.js +607 -607
- package/utils/generators/application/dtoUpdater.js +54 -0
- package/utils/generators/cleanModuleGenerator.js +475 -0
- package/utils/generators/database/setupDatabase.js +31 -0
- package/utils/generators/domain/entityUpdater.js +78 -0
- package/utils/generators/infrastructure/mapperUpdater.js +65 -0
- package/utils/generators/lightModuleGenerator.js +131 -0
- package/utils/generators/relation/relation.engine.js +64 -0
- package/utils/interactive/askEntityInputs.js +165 -0
- package/utils/lightModeInput.js +460 -460
- package/utils/loggers/logError.js +7 -7
- package/utils/loggers/logInfo.js +7 -7
- package/utils/loggers/logSuccess.js +7 -7
- package/utils/loggers/logWarning.js +7 -7
- package/utils/setups/orms/typeOrmSetup.js +630 -630
- package/utils/setups/projectSetup.js +46 -46
- package/utils/setups/setupAuth.js +973 -926
- package/utils/setups/setupDatabase.js +75 -75
- package/utils/setups/setupLogger.js +69 -59
- package/utils/setups/setupMongoose.js +377 -432
- package/utils/setups/setupPrisma.js +802 -630
- package/utils/setups/setupSwagger.js +97 -88
- package/utils/shell.js +32 -32
- package/utils/spinner.js +57 -57
- package/utils/systemCheck.js +124 -124
- package/utils/userInput.js +421 -421
- package/utils/utils.js +2197 -1762
|
@@ -1,660 +1,701 @@
|
|
|
1
|
-
const { logInfo } = require("../loggers/logInfo");
|
|
2
|
-
const { logSuccess } = require("../loggers/logSuccess");
|
|
3
|
-
const { logError } = require("../loggers/logError");
|
|
4
|
-
const {
|
|
5
|
-
createDirectory,
|
|
6
|
-
createFile,
|
|
7
|
-
updateFile,
|
|
8
|
-
safeUpdateAppModule,
|
|
9
|
-
} = require("../userInput");
|
|
10
|
-
const {
|
|
11
|
-
generateEntityFileContent,
|
|
12
|
-
generateDto,
|
|
13
|
-
generateMiddlewares,
|
|
14
|
-
generateMongooseSchemaFileContent,
|
|
15
|
-
pluralize,
|
|
16
|
-
} = require("../utils");
|
|
17
|
-
|
|
18
|
-
async function setupLightArchitecture(inputs) {
|
|
19
|
-
logInfo("Generating Light structure (MVP)");
|
|
20
|
-
const mode = "light";
|
|
21
|
-
|
|
22
|
-
const entitiesData = inputs.entitiesData;
|
|
23
|
-
const dbConfig = inputs.dbConfig;
|
|
24
|
-
const useSwagger = inputs.useSwagger;
|
|
25
|
-
const useAuth = inputs.useAuth;
|
|
26
|
-
|
|
27
|
-
const srcPath = "src";
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
// Créer le dossier common/enums pour les énums
|
|
31
|
-
await createDirectory("src/common/enums");
|
|
32
|
-
|
|
33
|
-
// Générer l'enum Role si l'entité User existe
|
|
34
|
-
const hasUserEntity = entitiesData.entities.some(
|
|
35
|
-
(entity) => entity.name.toLowerCase() === "user"
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
if (hasUserEntity) {
|
|
39
|
-
await createFile({
|
|
40
|
-
path: "src/common/enums/role.enum.ts",
|
|
41
|
-
contente: `export enum Role {
|
|
42
|
-
USER = 'USER',
|
|
43
|
-
ADMIN = 'ADMIN',
|
|
44
|
-
SUPER_ADMIN = 'SUPER_ADMIN',
|
|
45
|
-
}
|
|
46
|
-
`,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
await updateFile({
|
|
51
|
-
path: "src/app.module.ts",
|
|
52
|
-
pattern: "import { Module } from '@nestjs/common';",
|
|
53
|
-
replacement: `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';`,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
await updateFile({
|
|
57
|
-
path: "src/app.module.ts",
|
|
58
|
-
pattern: "imports: [",
|
|
59
|
-
replacement: `imports: [
|
|
60
|
-
ConfigModule.forRoot({
|
|
61
|
-
isGlobal: true, // Make ConfigModule globally accessible
|
|
62
|
-
envFilePath: '.env', // Load environment variables
|
|
63
|
-
}),`,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
for (const entity of entitiesData.entities) {
|
|
67
|
-
const entityNameCapitalized = capitalize(entity.name);
|
|
68
|
-
const entityNameLower = decapitalize(entity.name);
|
|
69
|
-
const entityPath = `${srcPath}/${entityNameLower}`;
|
|
70
|
-
|
|
71
|
-
if (entityNameLower == "session") continue;
|
|
72
|
-
|
|
73
|
-
await createDirectory(`${entityPath}/entities`);
|
|
74
|
-
await createDirectory(`${entityPath}/dtos`);
|
|
75
|
-
await createDirectory(`${entityPath}/services`);
|
|
76
|
-
await createDirectory(`${entityPath}/repositories`);
|
|
77
|
-
await createDirectory(`${entityPath}/controllers`);
|
|
78
|
-
|
|
79
|
-
if (dbConfig.orm === "mongoose") {
|
|
80
|
-
const mongooseSchemaContent = await generateMongooseSchemaFileContent(
|
|
81
|
-
entity
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
import {
|
|
154
|
-
import {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"
|
|
223
|
-
"
|
|
224
|
-
"
|
|
225
|
-
"
|
|
226
|
-
"
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
import {
|
|
254
|
-
import {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
private
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
raw.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
import {
|
|
313
|
-
import {
|
|
314
|
-
import {
|
|
315
|
-
import { ${entityName}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
raw.
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
import {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
async
|
|
407
|
-
const result = await this.model.
|
|
408
|
-
return
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
async findAll(): Promise<${entityName}Entity[]> {
|
|
419
|
-
const results = await this.model.find();
|
|
420
|
-
return results.map(r => this.toEntity(r));
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
|
|
424
|
-
const result = await this.model.findByIdAndUpdate(id, data, { new: true });
|
|
425
|
-
return result ? this.toEntity(result) : null;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
async delete(id: string): Promise<void> {
|
|
429
|
-
await this.model.findByIdAndDelete(id);
|
|
430
|
-
}
|
|
431
|
-
}`;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
return `/**
|
|
435
|
-
* PostRepository handles data persistence
|
|
436
|
-
* for the Post entity.
|
|
437
|
-
*
|
|
438
|
-
* This layer abstracts the database engine (Prisma/TypeORM)
|
|
439
|
-
* and provides a clean interface for data operations.
|
|
440
|
-
*/
|
|
441
|
-
|
|
442
|
-
import { Injectable, Logger } from '@nestjs/common';
|
|
443
|
-
import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
|
|
444
|
-
import { ${entityName}Entity } from '../entities/${entityLower}.entity';
|
|
445
|
-
|
|
446
|
-
@Injectable()
|
|
447
|
-
export class ${entityName}Repository {
|
|
448
|
-
private readonly logger = new Logger(${entityName}Repository.name);
|
|
449
|
-
|
|
450
|
-
async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
|
|
451
|
-
throw new Error('Repository not implemented');
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
async findById(id: string): Promise<${entityName}Entity | null> {
|
|
455
|
-
throw new Error('Repository not implemented');
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
${extraMethods}
|
|
459
|
-
|
|
460
|
-
async findAll(): Promise<${entityName}Entity[]> {
|
|
461
|
-
throw new Error('Repository not implemented');
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
|
|
465
|
-
throw new Error('Repository not implemented');
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
async delete(id: string): Promise<void> {
|
|
469
|
-
throw new Error('Repository not implemented');
|
|
470
|
-
}
|
|
471
|
-
}`;
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function generateLightService(entityName, entityLower) {
|
|
475
|
-
return `/**
|
|
476
|
-
* PostService handles business logic
|
|
477
|
-
* for the Post entity.
|
|
478
|
-
*
|
|
479
|
-
* It acts as a bridge between the Controller and the Repository.
|
|
480
|
-
* Responsibilities include:
|
|
481
|
-
* - Data validation and transformation
|
|
482
|
-
* - Orchestrating use cases
|
|
483
|
-
* - Managing transactions
|
|
484
|
-
*/
|
|
485
|
-
|
|
486
|
-
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
|
487
|
-
import { ${entityName}Repository } from '../repositories/${entityLower}.repository';
|
|
488
|
-
import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
|
|
489
|
-
import { ${entityName}Entity } from '../entities/${entityLower}.entity';
|
|
490
|
-
|
|
491
|
-
@Injectable()
|
|
492
|
-
export class ${entityName}Service {
|
|
493
|
-
private readonly logger = new Logger(${entityName}Service.name);
|
|
494
|
-
|
|
495
|
-
constructor(private readonly repository: ${entityName}Repository) {}
|
|
496
|
-
|
|
497
|
-
async create(dto: Create${entityName}Dto): Promise<${entityName}Entity> {
|
|
498
|
-
this.logger.log('Creating new ${
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
return
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
async
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
@
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
${
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
)
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
|
|
1
|
+
const { logInfo } = require("../loggers/logInfo");
|
|
2
|
+
const { logSuccess } = require("../loggers/logSuccess");
|
|
3
|
+
const { logError } = require("../loggers/logError");
|
|
4
|
+
const {
|
|
5
|
+
createDirectory,
|
|
6
|
+
createFile,
|
|
7
|
+
updateFile,
|
|
8
|
+
safeUpdateAppModule,
|
|
9
|
+
} = require("../userInput");
|
|
10
|
+
const {
|
|
11
|
+
generateEntityFileContent,
|
|
12
|
+
generateDto,
|
|
13
|
+
generateMiddlewares,
|
|
14
|
+
generateMongooseSchemaFileContent,
|
|
15
|
+
pluralize,
|
|
16
|
+
} = require("../utils");
|
|
17
|
+
|
|
18
|
+
async function setupLightArchitecture(inputs) {
|
|
19
|
+
logInfo("Generating Light structure (MVP)");
|
|
20
|
+
const mode = "light";
|
|
21
|
+
|
|
22
|
+
const entitiesData = inputs.entitiesData;
|
|
23
|
+
const dbConfig = inputs.dbConfig;
|
|
24
|
+
const useSwagger = inputs.useSwagger;
|
|
25
|
+
const useAuth = inputs.useAuth;
|
|
26
|
+
|
|
27
|
+
const srcPath = "src";
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
// Créer le dossier common/enums pour les énums
|
|
31
|
+
await createDirectory("src/common/enums");
|
|
32
|
+
|
|
33
|
+
// Générer l'enum Role si l'entité User existe
|
|
34
|
+
const hasUserEntity = entitiesData.entities.some(
|
|
35
|
+
(entity) => entity.name.toLowerCase() === "user",
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (hasUserEntity) {
|
|
39
|
+
await createFile({
|
|
40
|
+
path: "src/common/enums/role.enum.ts",
|
|
41
|
+
contente: `export enum Role {
|
|
42
|
+
USER = 'USER',
|
|
43
|
+
ADMIN = 'ADMIN',
|
|
44
|
+
SUPER_ADMIN = 'SUPER_ADMIN',
|
|
45
|
+
}
|
|
46
|
+
`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
await updateFile({
|
|
51
|
+
path: "src/app.module.ts",
|
|
52
|
+
pattern: "import { Module } from '@nestjs/common';",
|
|
53
|
+
replacement: `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';`,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
await updateFile({
|
|
57
|
+
path: "src/app.module.ts",
|
|
58
|
+
pattern: "imports: [",
|
|
59
|
+
replacement: `imports: [
|
|
60
|
+
ConfigModule.forRoot({
|
|
61
|
+
isGlobal: true, // Make ConfigModule globally accessible
|
|
62
|
+
envFilePath: '.env', // Load environment variables
|
|
63
|
+
}),`,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
for (const entity of entitiesData.entities) {
|
|
67
|
+
const entityNameCapitalized = capitalize(entity.name);
|
|
68
|
+
const entityNameLower = decapitalize(entity.name);
|
|
69
|
+
const entityPath = `${srcPath}/${entityNameLower}`;
|
|
70
|
+
|
|
71
|
+
if (entityNameLower == "session") continue;
|
|
72
|
+
|
|
73
|
+
await createDirectory(`${entityPath}/entities`);
|
|
74
|
+
await createDirectory(`${entityPath}/dtos`);
|
|
75
|
+
await createDirectory(`${entityPath}/services`);
|
|
76
|
+
await createDirectory(`${entityPath}/repositories`);
|
|
77
|
+
await createDirectory(`${entityPath}/controllers`);
|
|
78
|
+
|
|
79
|
+
if (dbConfig.orm === "mongoose") {
|
|
80
|
+
const mongooseSchemaContent = await generateMongooseSchemaFileContent(
|
|
81
|
+
entity,
|
|
82
|
+
entitiesData,
|
|
83
|
+
mode,
|
|
84
|
+
);
|
|
85
|
+
await createFile({
|
|
86
|
+
path: `${entityPath}/entities/${entityNameLower}.schema.ts`,
|
|
87
|
+
contente: mongooseSchemaContent,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const entityContent = await generateEntityFileContent(entity, mode);
|
|
92
|
+
await createFile({
|
|
93
|
+
path: `${entityPath}/entities/${entityNameLower}.entity.ts`,
|
|
94
|
+
contente: entityContent,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const dtoContent = await generateDto(entity, useSwagger, false, mode);
|
|
98
|
+
await createFile({
|
|
99
|
+
path: `${entityPath}/dtos/${entityNameLower}.dto.ts`,
|
|
100
|
+
contente: dtoContent,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const repositoryContent = generateLightRepository(
|
|
104
|
+
entityNameCapitalized,
|
|
105
|
+
entityNameLower,
|
|
106
|
+
dbConfig.orm,
|
|
107
|
+
entity,
|
|
108
|
+
);
|
|
109
|
+
await createFile({
|
|
110
|
+
path: `${entityPath}/repositories/${entityNameLower}.repository.ts`,
|
|
111
|
+
contente: repositoryContent,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const serviceContent = generateLightService(
|
|
115
|
+
entityNameCapitalized,
|
|
116
|
+
entityNameLower,
|
|
117
|
+
);
|
|
118
|
+
await createFile({
|
|
119
|
+
path: `${entityPath}/services/${entityNameLower}.service.ts`,
|
|
120
|
+
contente: serviceContent,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const controllerContent = generateLightController(
|
|
124
|
+
entityNameCapitalized,
|
|
125
|
+
entityNameLower,
|
|
126
|
+
useSwagger,
|
|
127
|
+
);
|
|
128
|
+
await createFile({
|
|
129
|
+
path: `${entityPath}/controllers/${entityNameLower}.controller.ts`,
|
|
130
|
+
contente: controllerContent,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const moduleContent = generateLightModule(
|
|
134
|
+
entityNameCapitalized,
|
|
135
|
+
entityNameLower,
|
|
136
|
+
entityPath,
|
|
137
|
+
dbConfig.orm,
|
|
138
|
+
useAuth,
|
|
139
|
+
);
|
|
140
|
+
await createFile({
|
|
141
|
+
path: `${entityPath}/${entityNameLower}.module.ts`,
|
|
142
|
+
contente: moduleContent,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
await safeUpdateAppModule(entityNameLower);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
await generateMiddlewares(dbConfig.orm);
|
|
149
|
+
|
|
150
|
+
const appModulePath = "src/app.module.ts";
|
|
151
|
+
await updateFile({
|
|
152
|
+
path: appModulePath,
|
|
153
|
+
pattern: `import { Module } from '@nestjs/common';`,
|
|
154
|
+
replacement: `import { Module } from '@nestjs/common';
|
|
155
|
+
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
|
|
156
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';`,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
await updateFile({
|
|
160
|
+
path: appModulePath,
|
|
161
|
+
pattern: `providers: \\[`,
|
|
162
|
+
replacement: `providers: [
|
|
163
|
+
{
|
|
164
|
+
provide: APP_INTERCEPTOR,
|
|
165
|
+
useClass: ResponseInterceptor,
|
|
166
|
+
},`,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
logSuccess(`Light structure successfully generated!`);
|
|
170
|
+
} catch (error) {
|
|
171
|
+
logError(`Error during light generation: ${error}`);
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function generateLightRepository(entityName, entityLower, orm, entity) {
|
|
177
|
+
// Générateur de méthode spécifique (ex: findByEmail pour Auth)
|
|
178
|
+
const isUser = entityLower === "user";
|
|
179
|
+
const getExtraMethods = (ormType) => {
|
|
180
|
+
if (!isUser) return "";
|
|
181
|
+
|
|
182
|
+
switch (ormType) {
|
|
183
|
+
case "typeorm":
|
|
184
|
+
return `
|
|
185
|
+
async findByEmail(email: string): Promise<${entityName}Entity | null> {
|
|
186
|
+
const result = await this.repository.findOne({ where: { email } as any });
|
|
187
|
+
return result ? this.toEntity(result) : null;
|
|
188
|
+
}`;
|
|
189
|
+
case "prisma":
|
|
190
|
+
return `
|
|
191
|
+
async findByEmail(email: string): Promise<${entityName}Entity | null> {
|
|
192
|
+
const result = await this.prisma.${entityLower}.findUnique({ where: { email } });
|
|
193
|
+
return result ? this.toEntity(result) : null;
|
|
194
|
+
}`;
|
|
195
|
+
case "mongoose":
|
|
196
|
+
return `
|
|
197
|
+
async findByEmail(email: string): Promise<${entityName}Entity | null> {
|
|
198
|
+
const result = await this.model.findOne({ email }).exec();
|
|
199
|
+
return result ? this.toEntity(result) : null;
|
|
200
|
+
}`;
|
|
201
|
+
case "sequelize":
|
|
202
|
+
return `
|
|
203
|
+
async findByEmail(email: string): Promise<${entityName}Entity | null> {
|
|
204
|
+
const record = await this.model.findOne({ where: { email } });
|
|
205
|
+
return record ? this.mapper.toDomain(record) : null;
|
|
206
|
+
}`;
|
|
207
|
+
default:
|
|
208
|
+
return `
|
|
209
|
+
async findByEmail(email: string): Promise<${entityName}Entity | null> {
|
|
210
|
+
throw new Error('Repository not implemented');
|
|
211
|
+
}`;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// 1. Liste des types à NE PAS inclure dans le constructeur (les relations)
|
|
216
|
+
const SCALAR_TYPES = [
|
|
217
|
+
"string",
|
|
218
|
+
"text",
|
|
219
|
+
"uuid",
|
|
220
|
+
"json",
|
|
221
|
+
"number",
|
|
222
|
+
"decimal",
|
|
223
|
+
"int",
|
|
224
|
+
"float",
|
|
225
|
+
"boolean",
|
|
226
|
+
"date",
|
|
227
|
+
"role",
|
|
228
|
+
"enum",
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
// 2. On filtre pour ne garder que les champs simples
|
|
232
|
+
const scalarFields = entity.fields.filter((f) => {
|
|
233
|
+
const cleanType = f.type.toLowerCase().replace("[]", "");
|
|
234
|
+
|
|
235
|
+
// On garde le champ seulement si c'est un type simple
|
|
236
|
+
// et que ce n'est pas une relation (les types qui commencent par une Majuscule et ne sont pas dans SCALAR_TYPES)
|
|
237
|
+
return SCALAR_TYPES.includes(cleanType);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const extraMethods = getExtraMethods(orm);
|
|
241
|
+
|
|
242
|
+
if (orm === "prisma") {
|
|
243
|
+
const fieldParams = scalarFields.map((f) => `raw.${f.name}`).join(", ");
|
|
244
|
+
|
|
245
|
+
return `/**
|
|
246
|
+
* PostRepository handles data persistence
|
|
247
|
+
* for the Post entity.
|
|
248
|
+
*
|
|
249
|
+
* This layer abstracts the database engine (Prisma/TypeORM)
|
|
250
|
+
* and provides a clean interface for data operations.
|
|
251
|
+
*/
|
|
252
|
+
|
|
253
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
254
|
+
import { PrismaService } from 'src/prisma/prisma.service';
|
|
255
|
+
import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
|
|
256
|
+
import { ${entityName}Entity } from '../entities/${entityLower}.entity';
|
|
257
|
+
|
|
258
|
+
@Injectable()
|
|
259
|
+
export class ${entityName}Repository {
|
|
260
|
+
private readonly logger = new Logger(${entityName}Repository.name);
|
|
261
|
+
|
|
262
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
263
|
+
|
|
264
|
+
private toEntity(raw: any): ${entityName}Entity {
|
|
265
|
+
return new ${entityName}Entity(
|
|
266
|
+
raw.id,
|
|
267
|
+
raw.createdAt,
|
|
268
|
+
raw.updatedAt,
|
|
269
|
+
${fieldParams}
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
|
|
274
|
+
const result = await this.prisma.${entityLower}.create({ data });
|
|
275
|
+
return this.toEntity(result);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async findById(id: string): Promise<${entityName}Entity | null> {
|
|
279
|
+
const result = await this.prisma.${entityLower}.findUnique({ where: { id } });
|
|
280
|
+
return result ? this.toEntity(result) : null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
${extraMethods}
|
|
284
|
+
|
|
285
|
+
async findAll(): Promise<${entityName}Entity[]> {
|
|
286
|
+
const results = await this.prisma.${entityLower}.findMany();
|
|
287
|
+
return results.map(r => this.toEntity(r));
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
|
|
291
|
+
const result = await this.prisma.${entityLower}.update({ where: { id }, data });
|
|
292
|
+
return this.toEntity(result);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async delete(id: string): Promise<void> {
|
|
296
|
+
await this.prisma.${entityLower}.delete({ where: { id } });
|
|
297
|
+
}
|
|
298
|
+
}`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (orm === "typeorm") {
|
|
302
|
+
const fieldParams = scalarFields.map((f) => `raw.${f.name}`).join(", ");
|
|
303
|
+
|
|
304
|
+
return `/**
|
|
305
|
+
* PostRepository handles data persistence
|
|
306
|
+
* for the Post entity.
|
|
307
|
+
*
|
|
308
|
+
* This layer abstracts the database engine (Prisma/TypeORM)
|
|
309
|
+
* and provides a clean interface for data operations.
|
|
310
|
+
*/
|
|
311
|
+
|
|
312
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
313
|
+
import { Repository } from 'typeorm';
|
|
314
|
+
import { InjectRepository } from '@nestjs/typeorm';
|
|
315
|
+
import { ${entityName} } from 'src/entities/${entityName}.entity';
|
|
316
|
+
import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
|
|
317
|
+
import { ${entityName}Entity } from '../entities/${entityLower}.entity';
|
|
318
|
+
|
|
319
|
+
@Injectable()
|
|
320
|
+
export class ${entityName}Repository {
|
|
321
|
+
private readonly logger = new Logger(${entityName}Repository.name);
|
|
322
|
+
|
|
323
|
+
constructor(
|
|
324
|
+
@InjectRepository(${entityName})
|
|
325
|
+
private readonly repository: Repository<${entityName}>
|
|
326
|
+
) {}
|
|
327
|
+
|
|
328
|
+
private toEntity(raw: any): ${entityName}Entity {
|
|
329
|
+
return new ${entityName}Entity(
|
|
330
|
+
raw.id,
|
|
331
|
+
raw.createdAt,
|
|
332
|
+
raw.updatedAt,
|
|
333
|
+
${fieldParams}
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
|
|
338
|
+
const result = await this.repository.save(data);
|
|
339
|
+
return this.toEntity(result);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async findById(id: string): Promise<${entityName}Entity | null> {
|
|
343
|
+
const result = await this.repository.findOne({ where: { id } });
|
|
344
|
+
return result ? this.toEntity(result) : null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
${extraMethods}
|
|
348
|
+
|
|
349
|
+
async findAll(): Promise<${entityName}Entity[]> {
|
|
350
|
+
const results = await this.repository.find();
|
|
351
|
+
return results.map(r => this.toEntity(r));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
|
|
355
|
+
await this.repository.update(id, data);
|
|
356
|
+
const result = await this.repository.findOne({ where: { id } });
|
|
357
|
+
return result ? this.toEntity(result) : null;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async delete(id: string): Promise<void> {
|
|
361
|
+
await this.repository.delete(id);
|
|
362
|
+
}
|
|
363
|
+
}`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (orm === "mongoose") {
|
|
367
|
+
const fieldParams = scalarFields
|
|
368
|
+
.filter((f) => f.name !== "role")
|
|
369
|
+
.map((f) => `obj.${f.name}`)
|
|
370
|
+
.join(", ");
|
|
371
|
+
|
|
372
|
+
return `/**
|
|
373
|
+
* PostRepository handles data persistence
|
|
374
|
+
* for the Post entity.
|
|
375
|
+
*
|
|
376
|
+
* This layer abstracts the database engine (Prisma/TypeORM)
|
|
377
|
+
* and provides a clean interface for data operations.
|
|
378
|
+
*/
|
|
379
|
+
|
|
380
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
381
|
+
import { InjectModel } from '@nestjs/mongoose';
|
|
382
|
+
import { Model } from 'mongoose';
|
|
383
|
+
import { ${entityName} } from '../entities/${entityLower}.schema';
|
|
384
|
+
import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
|
|
385
|
+
import { ${entityName}Entity } from '../entities/${entityLower}.entity';
|
|
386
|
+
|
|
387
|
+
@Injectable()
|
|
388
|
+
export class ${entityName}Repository {
|
|
389
|
+
private readonly logger = new Logger(${entityName}Repository.name);
|
|
390
|
+
|
|
391
|
+
constructor(
|
|
392
|
+
@InjectModel(${entityName}.name)
|
|
393
|
+
private readonly model: Model<${entityName}>
|
|
394
|
+
) {}
|
|
395
|
+
|
|
396
|
+
private toEntity(raw: any): ${entityName}Entity {
|
|
397
|
+
const obj = raw.toObject ? raw.toObject() : raw;
|
|
398
|
+
return new ${entityName}Entity(
|
|
399
|
+
obj._id.toString(),
|
|
400
|
+
obj.createdAt,
|
|
401
|
+
obj.updatedAt,
|
|
402
|
+
${fieldParams}${isUser ? ", obj.role" : ""}
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
|
|
407
|
+
const result = await this.model.create(data);
|
|
408
|
+
return this.toEntity(result);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async findById(id: string): Promise<${entityName}Entity | null> {
|
|
412
|
+
const result = await this.model.findById(id).exec();
|
|
413
|
+
return result ? this.toEntity(result) : null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
${extraMethods}
|
|
417
|
+
|
|
418
|
+
async findAll(): Promise<${entityName}Entity[]> {
|
|
419
|
+
const results = await this.model.find().exec();
|
|
420
|
+
return results.map(r => this.toEntity(r));
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
|
|
424
|
+
const result = await this.model.findByIdAndUpdate(id, data, { new: true }).exec();
|
|
425
|
+
return result ? this.toEntity(result) : null;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async delete(id: string): Promise<void> {
|
|
429
|
+
await this.model.findByIdAndDelete(id).exec();
|
|
430
|
+
}
|
|
431
|
+
}`;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return `/**
|
|
435
|
+
* PostRepository handles data persistence
|
|
436
|
+
* for the Post entity.
|
|
437
|
+
*
|
|
438
|
+
* This layer abstracts the database engine (Prisma/TypeORM)
|
|
439
|
+
* and provides a clean interface for data operations.
|
|
440
|
+
*/
|
|
441
|
+
|
|
442
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
443
|
+
import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
|
|
444
|
+
import { ${entityName}Entity } from '../entities/${entityLower}.entity';
|
|
445
|
+
|
|
446
|
+
@Injectable()
|
|
447
|
+
export class ${entityName}Repository {
|
|
448
|
+
private readonly logger = new Logger(${entityName}Repository.name);
|
|
449
|
+
|
|
450
|
+
async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
|
|
451
|
+
throw new Error('Repository not implemented');
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
async findById(id: string): Promise<${entityName}Entity | null> {
|
|
455
|
+
throw new Error('Repository not implemented');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
${extraMethods}
|
|
459
|
+
|
|
460
|
+
async findAll(): Promise<${entityName}Entity[]> {
|
|
461
|
+
throw new Error('Repository not implemented');
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
|
|
465
|
+
throw new Error('Repository not implemented');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async delete(id: string): Promise<void> {
|
|
469
|
+
throw new Error('Repository not implemented');
|
|
470
|
+
}
|
|
471
|
+
}`;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function generateLightService(entityName, entityLower) {
|
|
475
|
+
return `/**
|
|
476
|
+
* PostService handles business logic
|
|
477
|
+
* for the Post entity.
|
|
478
|
+
*
|
|
479
|
+
* It acts as a bridge between the Controller and the Repository.
|
|
480
|
+
* Responsibilities include:
|
|
481
|
+
* - Data validation and transformation
|
|
482
|
+
* - Orchestrating use cases
|
|
483
|
+
* - Managing transactions
|
|
484
|
+
*/
|
|
485
|
+
|
|
486
|
+
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
|
487
|
+
import { ${entityName}Repository } from '../repositories/${entityLower}.repository';
|
|
488
|
+
import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
|
|
489
|
+
import { ${entityName}Entity } from '../entities/${entityLower}.entity';
|
|
490
|
+
|
|
491
|
+
@Injectable()
|
|
492
|
+
export class ${entityName}Service {
|
|
493
|
+
private readonly logger = new Logger(${entityName}Service.name);
|
|
494
|
+
|
|
495
|
+
constructor(private readonly repository: ${entityName}Repository) {}
|
|
496
|
+
|
|
497
|
+
async create(dto: Create${entityName}Dto): Promise<${entityName}Entity> {
|
|
498
|
+
this.logger.log('Creating a new ${entityName}');
|
|
499
|
+
const result = await this.repository.create(dto);
|
|
500
|
+
this.logger.log(\`${entityName} created successfully with ID: \${result.getId()}\`);
|
|
501
|
+
return result;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async findById(id: string): Promise<${entityName}Entity> {
|
|
505
|
+
this.logger.log(\`Fetching ${entityName} with ID: \${id}\`);
|
|
506
|
+
const entity = await this.repository.findById(id);
|
|
507
|
+
|
|
508
|
+
if (!entity) {
|
|
509
|
+
this.logger.warn(\`${entityName} with ID: \${id} not found\`);
|
|
510
|
+
throw new NotFoundException(\`${entityName} with id \${id} not found\`);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return entity;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async findAll(): Promise<${entityName}Entity[]> {
|
|
517
|
+
this.logger.log('Fetching all ${entityName} records');
|
|
518
|
+
const results = await this.repository.findAll();
|
|
519
|
+
this.logger.log(\`Successfully retrieved \${results.length} ${entityName}(s)\`);
|
|
520
|
+
return results;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async update(id: string, dto: Update${entityName}Dto): Promise<${entityName}Entity> {
|
|
524
|
+
this.logger.log(\`Updating ${entityName} with ID: \${id}\`);
|
|
525
|
+
|
|
526
|
+
// Validate existence before update
|
|
527
|
+
await this.findById(id);
|
|
528
|
+
|
|
529
|
+
const updated = await this.repository.update(id, dto);
|
|
530
|
+
|
|
531
|
+
if (!updated) {
|
|
532
|
+
this.logger.error(\`Update failed for ${entityName} \${id} - entity disappeared\`);
|
|
533
|
+
throw new NotFoundException(\`${entityName} update failed\`);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
this.logger.log(\`${entityName} with ID: \${id} updated successfully\`);
|
|
537
|
+
return updated;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
async delete(id: string): Promise<void> {
|
|
541
|
+
this.logger.log(\`Deleting ${entityName} with ID: \${id}\`);
|
|
542
|
+
|
|
543
|
+
// Validate existence before deletion
|
|
544
|
+
await this.findById(id);
|
|
545
|
+
|
|
546
|
+
await this.repository.delete(id);
|
|
547
|
+
this.logger.log(\`${entityName} with ID: \${id} deleted successfully\`);
|
|
548
|
+
}
|
|
549
|
+
}`;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function generateLightController(entityName, entityLower, useSwagger) {
|
|
553
|
+
const entityCap = capitalize(entityName);
|
|
554
|
+
const pluralName = pluralize(entityLower);
|
|
555
|
+
|
|
556
|
+
const swaggerImports = useSwagger
|
|
557
|
+
? `import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';\n`
|
|
558
|
+
: "";
|
|
559
|
+
|
|
560
|
+
const swaggerDecorators = useSwagger
|
|
561
|
+
? `@ApiTags('${capitalize(pluralName)}')\n`
|
|
562
|
+
: "";
|
|
563
|
+
|
|
564
|
+
return `import { Controller, Get, Post, Patch, Delete, Body, Param, Logger, HttpCode, HttpStatus } from '@nestjs/common';
|
|
565
|
+
${swaggerImports}import { ${entityCap}Service } from '../services/${entityLower}.service';
|
|
566
|
+
import { Create${entityCap}Dto, Update${entityCap}Dto } from '../dtos/${entityLower}.dto';
|
|
567
|
+
|
|
568
|
+
${swaggerDecorators}@Controller('${pluralName}')
|
|
569
|
+
export class ${entityCap}Controller {
|
|
570
|
+
private readonly logger = new Logger(${entityCap}Controller.name);
|
|
571
|
+
|
|
572
|
+
constructor(private readonly service: ${entityCap}Service) {}
|
|
573
|
+
|
|
574
|
+
@Post()
|
|
575
|
+
${
|
|
576
|
+
useSwagger
|
|
577
|
+
? `@ApiOperation({ summary: 'Create a new ${entityLower}' })\n @ApiResponse({ status: 201, description: 'The record has been successfully created.' })`
|
|
578
|
+
: ""
|
|
579
|
+
}
|
|
580
|
+
async create(@Body() dto: Create${entityCap}Dto) {
|
|
581
|
+
this.logger.log(\`Creating a new ${entityLower}\`);
|
|
582
|
+
await this.service.create(dto);
|
|
583
|
+
return {
|
|
584
|
+
message: '${entityCap} created successfully',
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
@Get()
|
|
589
|
+
${
|
|
590
|
+
useSwagger
|
|
591
|
+
? `@ApiOperation({ summary: 'Get all ${pluralName}' })\n @ApiResponse({ status: 200, description: 'List of records retrieved.' })`
|
|
592
|
+
: ""
|
|
593
|
+
}
|
|
594
|
+
async findAll() {
|
|
595
|
+
this.logger.log(\`Fetching all ${pluralName}\`);
|
|
596
|
+
return await this.service.findAll();
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
@Get(':id')
|
|
600
|
+
${
|
|
601
|
+
useSwagger
|
|
602
|
+
? `@ApiOperation({ summary: 'Get ${entityLower} by id' })\n @ApiParam({ name: 'id', type: String })\n @ApiResponse({ status: 200, description: 'Record found.' })`
|
|
603
|
+
: ""
|
|
604
|
+
}
|
|
605
|
+
async findById(@Param('id') id: string) {
|
|
606
|
+
this.logger.log(\`Fetching ${entityLower} with id: \${id}\`);
|
|
607
|
+
return await this.service.findById(id);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
@Patch(':id')
|
|
611
|
+
${
|
|
612
|
+
useSwagger
|
|
613
|
+
? `@ApiOperation({ summary: 'Update ${entityLower}' })\n @ApiParam({ name: 'id', type: String })\n @ApiResponse({ status: 200, description: 'Record updated.' })`
|
|
614
|
+
: ""
|
|
615
|
+
}
|
|
616
|
+
async update(@Param('id') id: string, @Body() dto: Update${entityCap}Dto) {
|
|
617
|
+
this.logger.log(\`Updating ${entityLower} with id: \${id}\`);
|
|
618
|
+
await this.service.update(id, dto);
|
|
619
|
+
return { message: '${entityCap} updated successfully' };
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
@Delete(':id')
|
|
623
|
+
@HttpCode(HttpStatus.NO_CONTENT)
|
|
624
|
+
${
|
|
625
|
+
useSwagger
|
|
626
|
+
? `@ApiOperation({ summary: 'Delete ${entityLower}' })\n @ApiParam({ name: 'id', type: String })\n @ApiResponse({ status: 204, description: 'Record deleted.' })`
|
|
627
|
+
: ""
|
|
628
|
+
}
|
|
629
|
+
async delete(@Param('id') id: string) {
|
|
630
|
+
this.logger.log(\`Deleting ${entityLower} with id: \${id}\`);
|
|
631
|
+
await this.service.delete(id);
|
|
632
|
+
return {
|
|
633
|
+
message: '${entityCap} deleted successfully',
|
|
634
|
+
};;
|
|
635
|
+
}
|
|
636
|
+
}`;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function generateLightModule(
|
|
640
|
+
entityName,
|
|
641
|
+
entityLower,
|
|
642
|
+
entityPath,
|
|
643
|
+
orm,
|
|
644
|
+
useAuth = false,
|
|
645
|
+
) {
|
|
646
|
+
let importsBlock = [];
|
|
647
|
+
let providersBlock = [`${entityName}Service`, `${entityName}Repository`];
|
|
648
|
+
let extraImports = "";
|
|
649
|
+
let forwardRefImport = "";
|
|
650
|
+
|
|
651
|
+
if (orm === "prisma") {
|
|
652
|
+
extraImports = `import { PrismaModule } from 'src/prisma/prisma.module';`;
|
|
653
|
+
importsBlock.push("PrismaModule");
|
|
654
|
+
} else if (orm === "typeorm") {
|
|
655
|
+
extraImports = `import { ${entityName} } from 'src/entities/${entityName}.entity';
|
|
656
|
+
import { TypeOrmModule } from '@nestjs/typeorm';`;
|
|
657
|
+
importsBlock.push(`TypeOrmModule.forFeature([${entityName}])`);
|
|
658
|
+
} else if (orm === "mongoose") {
|
|
659
|
+
extraImports = `import { MongooseModule } from '@nestjs/mongoose';
|
|
660
|
+
import { ${entityName}, ${entityName}Schema } from '${entityPath}/entities/${entityLower}.schema';`;
|
|
661
|
+
importsBlock.push(
|
|
662
|
+
`MongooseModule.forFeature([{ name: ${entityName}.name, schema: ${entityName}Schema }])`,
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (entityLower == "user" && useAuth) {
|
|
667
|
+
extraImports += "\nimport { AuthModule } from 'src/auth/auth.module';";
|
|
668
|
+
importsBlock.push("forwardRef(() => AuthModule)");
|
|
669
|
+
forwardRefImport = " forwardRef,";
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
return `import {${forwardRefImport} Module } from '@nestjs/common';
|
|
673
|
+
${extraImports}
|
|
674
|
+
import { ${entityName}Controller } from '${entityPath}/controllers/${entityLower}.controller';
|
|
675
|
+
import { ${entityName}Service } from '${entityPath}/services/${entityLower}.service';
|
|
676
|
+
import { ${entityName}Repository } from '${entityPath}/repositories/${entityLower}.repository';
|
|
677
|
+
|
|
678
|
+
@Module({
|
|
679
|
+
imports: [${importsBlock.join(", ")}],
|
|
680
|
+
controllers: [${entityName}Controller],
|
|
681
|
+
providers: [${providersBlock.join(", ")}],
|
|
682
|
+
exports: [${entityName}Service, ${entityName}Repository]
|
|
683
|
+
})
|
|
684
|
+
export class ${entityName}Module {}`;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function capitalize(str) {
|
|
688
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
function decapitalize(str) {
|
|
692
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
module.exports = {
|
|
696
|
+
setupLightArchitecture,
|
|
697
|
+
generateLightRepository,
|
|
698
|
+
generateLightService,
|
|
699
|
+
generateLightController,
|
|
700
|
+
generateLightModule,
|
|
701
|
+
};
|