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.
Files changed (63) hide show
  1. package/.gitattributes +6 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  4. package/.github/ISSUE_TEMPLATE/pull_request_template.md +24 -0
  5. package/CHANGELOG.fr.md +97 -97
  6. package/CHANGELOG.md +98 -98
  7. package/CLI_USAGE.fr.md +331 -331
  8. package/CLI_USAGE.md +364 -364
  9. package/DEMO.fr.md +292 -292
  10. package/DEMO.md +294 -294
  11. package/LICENSE +21 -21
  12. package/MIGRATION_GUIDE.fr.md +127 -127
  13. package/MIGRATION_GUIDE.md +124 -124
  14. package/QUICK_START.fr.md +152 -152
  15. package/QUICK_START.md +169 -169
  16. package/README.fr.md +653 -659
  17. package/SECURITY.md +10 -0
  18. package/bin/nestcraft.js +84 -64
  19. package/commands/demo.js +333 -330
  20. package/commands/generate.js +93 -0
  21. package/commands/generateConf.js +91 -0
  22. package/commands/help.js +78 -78
  23. package/commands/info.js +48 -48
  24. package/commands/new.js +338 -335
  25. package/commands/start.js +19 -19
  26. package/commands/test.js +7 -7
  27. package/package.json +41 -41
  28. package/readme.md +638 -643
  29. package/utils/cliParser.js +133 -76
  30. package/utils/colors.js +62 -62
  31. package/utils/configs/configureDocker.js +120 -120
  32. package/utils/configs/setupCleanArchitecture.js +563 -557
  33. package/utils/configs/setupLightArchitecture.js +701 -660
  34. package/utils/envGenerator.js +122 -122
  35. package/utils/file-utils/packageJsonUtils.js +49 -55
  36. package/utils/file-utils/saveProjectConfig.js +36 -0
  37. package/utils/fullModeInput.js +607 -607
  38. package/utils/generators/application/dtoUpdater.js +54 -0
  39. package/utils/generators/cleanModuleGenerator.js +475 -0
  40. package/utils/generators/database/setupDatabase.js +31 -0
  41. package/utils/generators/domain/entityUpdater.js +78 -0
  42. package/utils/generators/infrastructure/mapperUpdater.js +65 -0
  43. package/utils/generators/lightModuleGenerator.js +131 -0
  44. package/utils/generators/relation/relation.engine.js +64 -0
  45. package/utils/interactive/askEntityInputs.js +165 -0
  46. package/utils/lightModeInput.js +460 -460
  47. package/utils/loggers/logError.js +7 -7
  48. package/utils/loggers/logInfo.js +7 -7
  49. package/utils/loggers/logSuccess.js +7 -7
  50. package/utils/loggers/logWarning.js +7 -7
  51. package/utils/setups/orms/typeOrmSetup.js +630 -630
  52. package/utils/setups/projectSetup.js +46 -46
  53. package/utils/setups/setupAuth.js +973 -926
  54. package/utils/setups/setupDatabase.js +75 -75
  55. package/utils/setups/setupLogger.js +69 -59
  56. package/utils/setups/setupMongoose.js +377 -432
  57. package/utils/setups/setupPrisma.js +802 -630
  58. package/utils/setups/setupSwagger.js +97 -88
  59. package/utils/shell.js +32 -32
  60. package/utils/spinner.js +57 -57
  61. package/utils/systemCheck.js +124 -124
  62. package/utils/userInput.js +421 -421
  63. 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
- await createFile({
84
- path: `${entityPath}/entities/${entityNameLower}.schema.ts`,
85
- contente: mongooseSchemaContent,
86
- });
87
- }
88
-
89
- const entityContent = await generateEntityFileContent(entity, mode);
90
- await createFile({
91
- path: `${entityPath}/entities/${entityNameLower}.entity.ts`,
92
- contente: entityContent,
93
- });
94
-
95
- const dtoContent = await generateDto(entity, useSwagger, false, mode);
96
- await createFile({
97
- path: `${entityPath}/dtos/${entityNameLower}.dto.ts`,
98
- contente: dtoContent,
99
- });
100
-
101
- const repositoryContent = generateLightRepository(
102
- entityNameCapitalized,
103
- entityNameLower,
104
- dbConfig.orm,
105
- entity
106
- );
107
- await createFile({
108
- path: `${entityPath}/repositories/${entityNameLower}.repository.ts`,
109
- contente: repositoryContent,
110
- });
111
-
112
- const serviceContent = generateLightService(
113
- entityNameCapitalized,
114
- entityNameLower
115
- );
116
- await createFile({
117
- path: `${entityPath}/services/${entityNameLower}.service.ts`,
118
- contente: serviceContent,
119
- });
120
-
121
- const controllerContent = generateLightController(
122
- entityNameCapitalized,
123
- entityNameLower,
124
- useSwagger
125
- );
126
- await createFile({
127
- path: `${entityPath}/controllers/${entityNameLower}.controller.ts`,
128
- contente: controllerContent,
129
- });
130
-
131
- const moduleContent = generateLightModule(
132
- entityNameCapitalized,
133
- entityNameLower,
134
- entityPath,
135
- dbConfig.orm,
136
- useAuth
137
- );
138
- await createFile({
139
- path: `${entityPath}/${entityNameLower}.module.ts`,
140
- contente: moduleContent,
141
- });
142
-
143
- await safeUpdateAppModule(entityNameLower);
144
- }
145
-
146
- await generateMiddlewares(dbConfig.orm);
147
-
148
- const appModulePath = "src/app.module.ts";
149
- await updateFile({
150
- path: appModulePath,
151
- pattern: `import { Module } from '@nestjs/common';`,
152
- replacement: `import { Module } from '@nestjs/common';
153
- import { ResponseInterceptor } from './common/interceptors/response.interceptor';
154
- import { APP_INTERCEPTOR } from '@nestjs/core';`,
155
- });
156
-
157
- await updateFile({
158
- path: appModulePath,
159
- pattern: `providers: \\[`,
160
- replacement: `providers: [
161
- {
162
- provide: APP_INTERCEPTOR,
163
- useClass: ResponseInterceptor,
164
- },`,
165
- });
166
-
167
- logSuccess(`Light structure successfully generated!`);
168
- } catch (error) {
169
- logError(`Error during light generation: ${error}`);
170
- throw error;
171
- }
172
- }
173
-
174
- function generateLightRepository(entityName, entityLower, orm, entity) {
175
- // Générateur de méthode spécifique (ex: findByEmail pour Auth)
176
- const isUser = entityLower === "user";
177
- const getExtraMethods = (ormType) => {
178
- if (!isUser) return "";
179
-
180
- switch (ormType) {
181
- case "typeorm":
182
- return `
183
- async findByEmail(email: string): Promise<${entityName}Entity | null> {
184
- const result = await this.repository.findOne({ where: { email } as any });
185
- return result ? this.toEntity(result) : null;
186
- }`;
187
- case "prisma":
188
- return `
189
- async findByEmail(email: string): Promise<${entityName}Entity | null> {
190
- const result = await this.prisma.${entityLower}.findUnique({ where: { email } });
191
- return result ? this.toEntity(result) : null;
192
- }`;
193
- case "mongoose":
194
- return `
195
- async findByEmail(email: string): Promise<${entityName}Entity | null> {
196
- const result = await this.model.findOne({ email }).exec();
197
- return result ? this.toEntity(result) : null;
198
- }`;
199
- case "sequelize":
200
- return `
201
- async findByEmail(email: string): Promise<${entityName}Entity | null> {
202
- const record = await this.model.findOne({ where: { email } });
203
- return record ? this.mapper.toDomain(record) : null;
204
- }`;
205
- default:
206
- return `
207
- async findByEmail(email: string): Promise<${entityName}Entity | null> {
208
- throw new Error('Repository not implemented');
209
- }`;
210
- }
211
- };
212
-
213
- // 1. Liste des types à NE PAS inclure dans le constructeur (les relations)
214
- const SCALAR_TYPES = [
215
- "string",
216
- "text",
217
- "uuid",
218
- "json",
219
- "number",
220
- "decimal",
221
- "int",
222
- "float",
223
- "boolean",
224
- "date",
225
- "role",
226
- "enum",
227
- ];
228
-
229
- // 2. On filtre pour ne garder que les champs simples
230
- const scalarFields = entity.fields.filter((f) => {
231
- const cleanType = f.type.toLowerCase().replace("[]", "");
232
-
233
- // On garde le champ seulement si c'est un type simple
234
- // et que ce n'est pas une relation (les types qui commencent par une Majuscule et ne sont pas dans SCALAR_TYPES)
235
- return SCALAR_TYPES.includes(cleanType);
236
- });
237
-
238
- const extraMethods = getExtraMethods(orm);
239
-
240
- if (orm === "prisma") {
241
- const fieldParams = scalarFields.map((f) => `raw.${f.name}`).join(", ");
242
-
243
- return `/**
244
- * PostRepository handles data persistence
245
- * for the Post entity.
246
- *
247
- * This layer abstracts the database engine (Prisma/TypeORM)
248
- * and provides a clean interface for data operations.
249
- */
250
-
251
- import { Injectable, Logger } from '@nestjs/common';
252
- import { PrismaService } from 'src/prisma/prisma.service';
253
- import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
254
- import { ${entityName}Entity } from '../entities/${entityLower}.entity';
255
-
256
- @Injectable()
257
- export class ${entityName}Repository {
258
- private readonly logger = new Logger(${entityName}Repository.name);
259
-
260
- constructor(private readonly prisma: PrismaService) {}
261
-
262
- private toEntity(raw: any): ${entityName}Entity {
263
- return new ${entityName}Entity(
264
- raw.id,
265
- raw.createdAt,
266
- raw.updatedAt,
267
- ${fieldParams}
268
- );
269
- }
270
-
271
- async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
272
- const result = await this.prisma.${entityLower}.create({ data });
273
- return this.toEntity(result);
274
- }
275
-
276
- async findById(id: string): Promise<${entityName}Entity | null> {
277
- const result = await this.prisma.${entityLower}.findUnique({ where: { id } });
278
- return result ? this.toEntity(result) : null;
279
- }
280
-
281
- ${extraMethods}
282
-
283
- async findAll(): Promise<${entityName}Entity[]> {
284
- const results = await this.prisma.${entityLower}.findMany();
285
- return results.map(r => this.toEntity(r));
286
- }
287
-
288
- async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
289
- const result = await this.prisma.${entityLower}.update({ where: { id }, data });
290
- return this.toEntity(result);
291
- }
292
-
293
- async delete(id: string): Promise<void> {
294
- await this.prisma.${entityLower}.delete({ where: { id } });
295
- }
296
- }`;
297
- }
298
-
299
- if (orm === "typeorm") {
300
- const fieldParams = scalarFields.map((f) => `raw.${f.name}`).join(", ");
301
-
302
- return `/**
303
- * PostRepository handles data persistence
304
- * for the Post entity.
305
- *
306
- * This layer abstracts the database engine (Prisma/TypeORM)
307
- * and provides a clean interface for data operations.
308
- */
309
-
310
- import { Injectable, Logger } from '@nestjs/common';
311
- import { Repository } from 'typeorm';
312
- import { InjectRepository } from '@nestjs/typeorm';
313
- import { ${entityName} } from 'src/entities/${entityName}.entity';
314
- import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
315
- import { ${entityName}Entity } from '../entities/${entityLower}.entity';
316
-
317
- @Injectable()
318
- export class ${entityName}Repository {
319
- private readonly logger = new Logger(${entityName}Repository.name);
320
-
321
- constructor(
322
- @InjectRepository(${entityName})
323
- private readonly repository: Repository<${entityName}>
324
- ) {}
325
-
326
- private toEntity(raw: any): ${entityName}Entity {
327
- return new ${entityName}Entity(
328
- raw.id,
329
- raw.createdAt,
330
- raw.updatedAt,
331
- ${fieldParams}
332
- );
333
- }
334
-
335
- async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
336
- const result = await this.repository.save(data);
337
- return this.toEntity(result);
338
- }
339
-
340
- async findById(id: string): Promise<${entityName}Entity | null> {
341
- const result = await this.repository.findOne({ where: { id } });
342
- return result ? this.toEntity(result) : null;
343
- }
344
-
345
- ${extraMethods}
346
-
347
- async findAll(): Promise<${entityName}Entity[]> {
348
- const results = await this.repository.find();
349
- return results.map(r => this.toEntity(r));
350
- }
351
-
352
- async update(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
353
- await this.repository.update(id, data);
354
- const result = await this.repository.findOne({ where: { id } });
355
- return result ? this.toEntity(result) : null;
356
- }
357
-
358
- async delete(id: string): Promise<void> {
359
- await this.repository.delete(id);
360
- }
361
- }`;
362
- }
363
-
364
- if (orm === "mongoose") {
365
- const fieldParams = scalarFields.map((f) => `obj.${f.name}`).join(", ");
366
-
367
- return `/**
368
- * PostRepository handles data persistence
369
- * for the Post entity.
370
- *
371
- * This layer abstracts the database engine (Prisma/TypeORM)
372
- * and provides a clean interface for data operations.
373
- */
374
-
375
- import { Injectable, Logger } from '@nestjs/common';
376
- import { InjectModel } from '@nestjs/mongoose';
377
- import { Model } from 'mongoose';
378
- import { ${entityName} } from '../entities/${entityLower}.schema';
379
- import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
380
- import { ${entityName}Entity } from '../entities/${entityLower}.entity';
381
-
382
- @Injectable()
383
- export class ${entityName}Repository {
384
- private readonly logger = new Logger(${entityName}Repository.name);
385
-
386
- constructor(
387
- @InjectModel(${entityName}.name)
388
- private readonly model: Model<${entityName}>
389
- ) {}
390
-
391
- private toEntity(raw: any): ${entityName}Entity {
392
- const obj = raw.toObject ? raw.toObject() : raw;
393
- return new ${entityName}Entity(
394
- obj._id.toString(),
395
- obj.createdAt,
396
- obj.updatedAt,
397
- ${fieldParams}
398
- );
399
- }
400
-
401
- async create(data: Create${entityName}Dto): Promise<${entityName}Entity> {
402
- const result = await this.model.create(data);
403
- return this.toEntity(result);
404
- }
405
-
406
- async findById(id: string): Promise<${entityName}Entity | null> {
407
- const result = await this.model.findById(id);
408
- return result ? this.toEntity(result) : null;
409
- }
410
-
411
- ${extraMethods}
412
-
413
- async findByEmail(email: string): Promise<${entityName}Entity | null> {
414
- const result = await this.model.findOne({ email }).exec();
415
- return result ? this.toEntity(result) : null;
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 ${entityLower}');
499
- return await this.repository.create(dto);
500
- }
501
-
502
- async findById(id: string): Promise<${entityName}Entity> {
503
- const entity = await this.repository.findById(id);
504
- if (!entity) {
505
- throw new NotFoundException(\`${entityName} with id \${id} not found\`);
506
- }
507
- return entity;
508
- }
509
-
510
- async findAll(): Promise<${entityName}Entity[]> {
511
- return await this.repository.findAll();
512
- }
513
-
514
- async update(id: string, dto: Update${entityName}Dto): Promise<${entityName}Entity> {
515
- await this.findById(id);
516
- const updated = await this.repository.update(id, dto);
517
- if (!updated) {
518
- throw new NotFoundException(\`Failed to update ${entityName}\`);
519
- }
520
- return updated;
521
- }
522
-
523
- async delete(id: string): Promise<void> {
524
- await this.findById(id);
525
- await this.repository.delete(id);
526
- }
527
- }`;
528
- }
529
-
530
- function generateLightController(entityName, entityLower, useSwagger) {
531
- const swaggerImports = useSwagger
532
- ? `import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';\n`
533
- : "";
534
- const swaggerDecorators = useSwagger ? `@ApiTags('${entityLower}')\n` : "";
535
-
536
- return `import { Controller, Get, Post, Put, Delete, Body, Param, Logger } from '@nestjs/common';
537
- ${swaggerImports}import { ${entityName}Service } from '../services/${entityLower}.service';
538
- import { Create${entityName}Dto, Update${entityName}Dto } from '../dtos/${entityLower}.dto';
539
-
540
- ${swaggerDecorators}@Controller('${entityLower}')
541
- export class ${entityName}Controller {
542
- private readonly logger = new Logger(${entityName}Controller.name);
543
-
544
- constructor(private readonly service: ${entityName}Service) {}
545
- ${
546
- useSwagger
547
- ? `
548
- @ApiOperation({ summary: 'Create a new ${entityLower}' })
549
- @ApiResponse({ status: 201, description: 'Created' })`
550
- : ""
551
- }
552
- @Post()
553
- async create(@Body() dto: Create${entityName}Dto) {
554
- return await this.service.create(dto);
555
- }
556
- ${
557
- useSwagger
558
- ? `
559
- @ApiOperation({ summary: 'Get all ${entityLower}s' })
560
- @ApiResponse({ status: 200, description: 'Success' })`
561
- : ""
562
- }
563
- @Get()
564
- async findAll() {
565
- return await this.service.findAll();
566
- }
567
- ${
568
- useSwagger
569
- ? `
570
- @ApiOperation({ summary: 'Get ${entityLower} by id' })
571
- @ApiResponse({ status: 200, description: 'Success' })`
572
- : ""
573
- }
574
- @Get(':id')
575
- async findById(@Param('id') id: string) {
576
- return await this.service.findById(id);
577
- }
578
- ${
579
- useSwagger
580
- ? `
581
- @ApiOperation({ summary: 'Update ${entityLower}' })
582
- @ApiResponse({ status: 200, description: 'Updated' })`
583
- : ""
584
- }
585
- @Put(':id')
586
- async update(@Param('id') id: string, @Body() dto: Update${entityName}Dto) {
587
- return await this.service.update(id, dto);
588
- }
589
- ${
590
- useSwagger
591
- ? `
592
- @ApiOperation({ summary: 'Delete ${entityLower}' })
593
- @ApiResponse({ status: 200, description: 'Deleted' })`
594
- : ""
595
- }
596
- @Delete(':id')
597
- async delete(@Param('id') id: string) {
598
- await this.service.delete(id);
599
- return { message: '${entityName} deleted successfully' };
600
- }
601
- }`;
602
- }
603
-
604
- function generateLightModule(
605
- entityName,
606
- entityLower,
607
- entityPath,
608
- orm,
609
- useAuth = false
610
- ) {
611
- let importsBlock = [];
612
- let providersBlock = [`${entityName}Service`, `${entityName}Repository`];
613
- let extraImports = "";
614
- let forwardRefImport = "";
615
-
616
- if (orm === "prisma") {
617
- extraImports = `import { PrismaModule } from 'src/prisma/prisma.module';`;
618
- importsBlock.push("PrismaModule");
619
- } else if (orm === "typeorm") {
620
- extraImports = `import { ${entityName} } from 'src/entities/${entityName}.entity';
621
- import { TypeOrmModule } from '@nestjs/typeorm';`;
622
- importsBlock.push(`TypeOrmModule.forFeature([${entityName}])`);
623
- } else if (orm === "mongoose") {
624
- extraImports = `import { MongooseModule } from '@nestjs/mongoose';
625
- import { ${entityName}, ${entityName}Schema } from '${entityPath}/entities/${entityLower}.schema';`;
626
- importsBlock.push(
627
- `MongooseModule.forFeature([{ name: ${entityName}.name, schema: ${entityName}Schema }])`
628
- );
629
- }
630
-
631
- if (entityLower == "user" && useAuth) {
632
- extraImports += "\nimport { AuthModule } from 'src/auth/auth.module';";
633
- importsBlock.push("forwardRef(() => AuthModule)");
634
- forwardRefImport = " forwardRef,";
635
- }
636
-
637
- return `import {${forwardRefImport} Module } from '@nestjs/common';
638
- ${extraImports}
639
- import { ${entityName}Controller } from '${entityPath}/controllers/${entityLower}.controller';
640
- import { ${entityName}Service } from '${entityPath}/services/${entityLower}.service';
641
- import { ${entityName}Repository } from '${entityPath}/repositories/${entityLower}.repository';
642
-
643
- @Module({
644
- imports: [${importsBlock.join(", ")}],
645
- controllers: [${entityName}Controller],
646
- providers: [${providersBlock.join(", ")}],
647
- exports: [${entityName}Service, ${entityName}Repository]
648
- })
649
- export class ${entityName}Module {}`;
650
- }
651
-
652
- function capitalize(str) {
653
- return str.charAt(0).toUpperCase() + str.slice(1);
654
- }
655
-
656
- function decapitalize(str) {
657
- return str.charAt(0).toLowerCase() + str.slice(1);
658
- }
659
-
660
- module.exports = { setupLightArchitecture };
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
+ };