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,557 +1,563 @@
1
- const { logInfo } = require("../loggers/logInfo");
2
- const {
3
- createDirectory,
4
- createFile,
5
- updateFile,
6
- safeUpdateAppModule,
7
- } = require("../userInput");
8
- const { logError } = require("../loggers/logError");
9
- const { logSuccess } = require("../loggers/logSuccess");
10
- const {
11
- generateEntityFileContent,
12
- generateMapper,
13
- generateDto,
14
- generateMiddlewares,
15
- generateRepository,
16
- generateController,
17
- generateMongooseSchemaFileContent,
18
- } = require("../utils");
19
-
20
- async function setupCleanArchitecture(inputs) {
21
- logInfo("Generating Clean Architecture structure");
22
-
23
- const entitiesData = inputs.entitiesData;
24
- const dbConfig = inputs.dbConfig;
25
- const useSwagger = inputs.useSwagger;
26
- const useAuth = inputs.useAuth;
27
-
28
- const srcPath = "src";
29
- const baseFolders = [
30
- "application/use-cases",
31
- "application/dtos",
32
- "domain/interfaces",
33
- "domain/entities",
34
- "domain/enums",
35
- "infrastructure/mappers",
36
- "infrastructure/repositories",
37
- "application/services",
38
- "infrastructure/adapters",
39
- "presentation/controllers",
40
- ];
41
-
42
- try {
43
- // modifier app module pour exporter configService globalement
44
- const appModuleTsPath = "src/app.module.ts";
45
-
46
- // ajouter l'import configModule
47
- await updateFile({
48
- path: "src/app.module.ts",
49
- pattern: "import { Module } from '@nestjs/common';",
50
- replacement: `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';`,
51
- });
52
-
53
- // configurer configservice
54
- await updateFile({
55
- path: "src/app.module.ts",
56
- pattern: "imports: [",
57
- replacement: `imports: [
58
- ConfigModule.forRoot({
59
- isGlobal: true, // Make ConfigModule globally accessible
60
- envFilePath: '.env', // Load environment variables
61
- }),`,
62
- });
63
-
64
- for (const entity of entitiesData.entities) {
65
- const entityNameCapitalized = capitalize(entity.name);
66
- const entityNameLower = decapitalize(entity.name);
67
-
68
- if (entityNameLower == "session") continue;
69
-
70
- const entityPath = `${srcPath}/${entityNameLower}`;
71
-
72
- for (const folder of baseFolders) {
73
- await createDirectory(`${entityPath}/${folder}`);
74
- }
75
-
76
- if (dbConfig.orm === "mongoose") {
77
- const mongooseSchemaContent = await generateMongooseSchemaFileContent(
78
- entity
79
- );
80
- await createFile({
81
- path: `src/${entity.name}/domain/entities/${entity.name}.schema.ts`,
82
- contente: mongooseSchemaContent,
83
- });
84
- }
85
-
86
- // 1. Entité
87
- const entityContent = await generateEntityFileContent(entity);
88
- await createFile({
89
- path: `${entityPath}/domain/entities/${entityNameLower}.entity.ts`,
90
- contente: entityContent,
91
- });
92
-
93
- let findByEmailMethod = "";
94
- if (entityNameLower == "user") {
95
- findByEmailMethod = `
96
- findByEmail(email: string): Promise<${entityNameCapitalized}Entity | null>;
97
- `;
98
- }
99
-
100
- // 2. Interface Repository
101
- await createFile({
102
- path: `${entityPath}/domain/interfaces/${entityNameLower}.repository.interface.ts`,
103
- contente: `import { Create${entityNameCapitalized}Dto, Update${entityNameCapitalized}Dto } from 'src/${entityNameLower}/application/dtos/${entityNameLower}.dto';
104
- import { ${entityNameCapitalized}Entity } from 'src/${entityNameLower}/domain/entities/${entityNameLower}.entity';
105
-
106
- export interface I${entityNameCapitalized}Repository {
107
- create(data: Create${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity>;
108
- findById(id: string): Promise<${entityNameCapitalized}Entity | null>;
109
- findAll(): Promise<${entityNameCapitalized}Entity[]>;
110
- update(id: string, data: Update${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity | null>;
111
- delete(id: string): Promise<void>;
112
- ${findByEmailMethod}
113
- }`,
114
- });
115
-
116
- // 3. Repository Implémentation
117
- await generateRepository(entity.name, dbConfig.orm);
118
-
119
- // 4. Use Cases
120
- const useCases = ["Create", "GetById", "GetAll", "Update", "Delete"];
121
- useCases.forEach(async (useCase) => {
122
- let content = "";
123
- const entityName = capitalize(entity.name);
124
- const entityNameLower = decapitalize(entity.name);
125
-
126
- switch (useCase) {
127
- case "Create":
128
- content = `/**
129
- * Use Case pour créer un ${entityName}.
130
- */
131
- import { Inject, Logger } from '@nestjs/common';
132
- import { Create${entityName}Dto } from 'src/${entity.name}/application/dtos/${entity.name}.dto';
133
- import { I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
134
- import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
135
-
136
- export class Create${entityName}UseCase {
137
- private readonly logger = new Logger(Create${entityName}UseCase.name);
138
-
139
- constructor(
140
- @Inject("I${entityName}Repository")
141
- private readonly ${entityNameLower}Repository: I${entityName}Repository,
142
- ) {}
143
-
144
- async execute(data: Create${entityName}Dto): Promise<${entityName}Entity> {
145
- this.logger.log('Début création ${entityName}');
146
- try {
147
- const result = await this.${entityNameLower}Repository.create(data);
148
- this.logger.log('Création réussie: ', result.getId());
149
- return result;
150
- } catch (error) {
151
- this.logger.error('Erreur lors de la création', error.stack);
152
- throw error;
153
- }
154
- }
155
- }
156
- `;
157
- break;
158
-
159
- case "GetById":
160
- content = `/**
161
- * Use Case pour récupérer un ${entityName} par son ID.
162
- */
163
- import { Inject, Logger } from '@nestjs/common';
164
- import { I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
165
- import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
166
-
167
- export class GetById${entityName}UseCase {
168
- private readonly logger = new Logger(GetById${entityName}UseCase.name);
169
-
170
- constructor(
171
- @Inject("I${entityName}Repository")
172
- private readonly ${entityNameLower}Repository: I${entityName}Repository,
173
- ) {}
174
-
175
- async execute(id: string): Promise<${entityName}Entity | null> {
176
- // this.logger.log(\`Recherche de ${entityName} par id: \${id}\`);
177
- try {
178
- const result = await this.${entityNameLower}Repository.findById(id);
179
- this.logger.log('Recherche réussie');
180
- return result;
181
- } catch (error) {
182
- this.logger.error('Erreur lors de la recherche', error.stack);
183
- throw error;
184
- }
185
- }
186
- }
187
- `;
188
- break;
189
-
190
- case "GetAll":
191
- content = `/**
192
- * Use Case pour récupérer tous les ${entityName}s.
193
- */
194
- import { Inject, Logger } from '@nestjs/common';
195
- import { I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
196
- import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
197
-
198
- export class GetAll${entityName}UseCase {
199
- private readonly logger = new Logger(GetAll${entityName}UseCase.name);
200
-
201
- constructor(
202
- @Inject("I${entityName}Repository")
203
- private readonly ${entityNameLower}Repository: I${entityName}Repository,
204
- ) {}
205
-
206
- async execute(): Promise<${entityName}Entity[]> {
207
- // this.logger.log('Récupération de tous les ${entityName}s');
208
- try {
209
- const result = await this.${entityNameLower}Repository.findAll();
210
- this.logger.log('Récupération réussie');
211
- return result;
212
- } catch (error) {
213
- this.logger.error('Erreur lors de la récupération', error.stack);
214
- throw error;
215
- }
216
- }
217
- }
218
- `;
219
- break;
220
-
221
- case "Update":
222
- content = `/**
223
- * Use Case pour mettre à jour un ${entityName} existant.
224
- */
225
- import { Inject, Logger } from '@nestjs/common';
226
- import { Update${entityName}Dto } from 'src/${entity.name}/application/dtos/${entity.name}.dto';
227
- import { I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
228
- import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
229
-
230
- export class Update${entityName}UseCase {
231
- private readonly logger = new Logger(Update${entityName}UseCase.name);
232
-
233
- constructor(
234
- @Inject("I${entityName}Repository")
235
- private readonly ${entityNameLower}Repository: I${entityName}Repository,
236
- ) {}
237
-
238
- async execute(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity | null> {
239
- // this.logger.log(\`Mise à jour de ${entityName} id: \${id}\`);
240
-
241
- try {
242
- // Vérifier l'existence de l'élément
243
- const existing = await this.${entityNameLower}Repository.findById(id);
244
- if (!existing) {
245
- this.logger.warn(\`${entityName} avec l'id \${id} non trouvé pour la mise à jour\`);
246
- throw new Error('${entityName} non trouvé');
247
- }
248
- const result = await this.${entityNameLower}Repository.update(id, data);
249
- this.logger.log('Mise à jour réussie');
250
- return result;
251
- } catch (error) {
252
- this.logger.error('Erreur lors de la mise à jour', error.stack);
253
- throw error;
254
- }
255
- }
256
- }
257
- `;
258
- break;
259
-
260
- case "Delete":
261
- content = `/**
262
- * Use Case pour supprimer un ${entityName}.
263
- */
264
- import { Inject, Logger } from '@nestjs/common';
265
- import { I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
266
-
267
- export class Delete${entityName}UseCase {
268
- private readonly logger = new Logger(Delete${entityName}UseCase.name);
269
-
270
- constructor(
271
- @Inject("I${entityName}Repository")
272
- private readonly ${entityNameLower}Repository: I${entityName}Repository,
273
- ) {}
274
-
275
- async execute(id: string): Promise<void> {
276
- // this.logger.log(\`Suppression de ${entityName} id: \${id}\`);
277
- try {
278
- // Vérifier l'existence de l'élément
279
- const existing = await this.${entityNameLower}Repository.findById(id);
280
- if (!existing) {
281
- this.logger.warn(\`${entityName} avec l'id \${id} non trouvé !\`);
282
- throw new Error('${entityName} non trouvé');
283
- }
284
- await this.${entityNameLower}Repository.delete(id);
285
- this.logger.log('Suppression réussie');
286
- } catch (error) {
287
- this.logger.error('Erreur lors de la suppression', error.stack);
288
- throw error;
289
- }
290
- }
291
- }
292
- `;
293
- break;
294
- }
295
-
296
- await createFile({
297
- path: `${entityPath}/application/use-cases/${decapitalize(useCase)}-${
298
- entity.name
299
- }.use-case.ts`,
300
- contente: content.trim(),
301
- });
302
- });
303
-
304
- // 5. DTOs
305
- const DtoFileContent = await generateDto(entity, useSwagger);
306
- await createFile({
307
- path: `${entityPath}/application/dtos/${entity.name}.dto.ts`,
308
- contente: DtoFileContent,
309
- });
310
-
311
- if (entity.name.toLowerCase() === "user") {
312
- await createFile({
313
- path: `${entityPath}/domain/enums/role.enum.ts`,
314
- contente: `// Enumération des rôles utilisateurs
315
- export enum Role {
316
- USER = 'USER',
317
- ADMIN = 'ADMIN',
318
- SUPER_ADMIN = 'SUPER_ADMIN',
319
- }
320
- `,
321
- });
322
- }
323
-
324
- // 7. Mapper
325
- const mapperFileContent = await generateMapper(entity);
326
- await createFile({
327
- path: `${entityPath}/infrastructure/mappers/${entityNameLower}.mapper.ts`,
328
- contente: mapperFileContent,
329
- });
330
-
331
- // 8. Service
332
- await createFile({
333
- path: `${entityPath}/application/services/${entityNameLower}.service.ts`,
334
- contente: `/**
335
- * PostService handles business logic
336
- * for the Post entity.
337
- *
338
- * It acts as a bridge between the Controller and the Repository.
339
- * Responsibilities include:
340
- * - Data validation and transformation
341
- * - Orchestrating use cases
342
- * - Managing transactions
343
- */
344
-
345
- import { Injectable } from '@nestjs/common';
346
- import { Create${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/create-${entityNameLower}.use-case';
347
- import { Update${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/update-${entityNameLower}.use-case';
348
- import { GetById${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/getById-${entityNameLower}.use-case';
349
- import { GetAll${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/getAll-${entityNameLower}.use-case';
350
- import { Delete${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/delete-${entityNameLower}.use-case';
351
- import { Create${entityNameCapitalized}Dto, Update${entityNameCapitalized}Dto } from 'src/${entityNameLower}/application/dtos/${entityNameLower}.dto';
352
- import { ${entityNameCapitalized}Entity } from 'src/${entityNameLower}/domain/entities/${entityNameLower}.entity';
353
-
354
- @Injectable()
355
- export class ${entityNameCapitalized}Service {
356
- constructor(
357
- private readonly createUseCase: Create${entityNameCapitalized}UseCase,
358
- private readonly updateUseCase: Update${entityNameCapitalized}UseCase,
359
- private readonly getByIdUseCase: GetById${entityNameCapitalized}UseCase,
360
- private readonly getAllUseCase: GetAll${entityNameCapitalized}UseCase,
361
- private readonly deleteUseCase: Delete${entityNameCapitalized}UseCase,
362
- ) {}
363
-
364
- async create(dto: Create${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity> {
365
- return await this.createUseCase.execute(dto);
366
- }
367
- async update(id: string, dto: Update${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity | null> {
368
- return await this.updateUseCase.execute(id, dto);
369
- }
370
- async getById(id: string): Promise<${entityNameCapitalized}Entity | null> {
371
- return await this.getByIdUseCase.execute(id);
372
- }
373
- async getAll(): Promise<${entityNameCapitalized}Entity[]> {
374
- return await this.getAllUseCase.execute();
375
- }
376
- async delete(id: string): Promise<void> {
377
- return await this.deleteUseCase.execute(id);
378
- }
379
- }
380
- `.trim(),
381
- });
382
-
383
- // 9. Adapter
384
- await createFile({
385
- path: `${entityPath}/infrastructure/adapters/${entityNameLower}.adapter.ts`,
386
- contente: `
387
- // L'adaptateur permet de transformer ou d'adapter les données d'un format source vers un format cible.
388
- // Cela est particulièrement utile lorsque nous devons interagir avec des API externes ou des services ayant des structures de données différentes.
389
-
390
- export class ${entityNameCapitalized}Adapter {
391
- // La méthode 'adapt' prend des données brutes d'un format spécifique et les transforme
392
- // en un format qui est attendu par le système de notre domaine.
393
- adapt(data: any) {
394
- // Exemple d'adaptation des données - ceci est un exemple générique.
395
- // Nous transformons les données pour que le format interne du système soit respecté.
396
-
397
- const adaptedData = {
398
- // Assurez-vous que vous mappez les propriétés nécessaires et les transformez.
399
- id: data.id, // Mapping de l'ID de la donnée source à notre format interne
400
- name: data.fullName || data.name, // Exemple de transformation de champ
401
- description: data.details || data.description, // Gestion des données optionnelles
402
- createdAt: new Date(data.createdAt), // Transformation de la date
403
- updatedAt: new Date(data.updatedAt), // Idem pour la date de mise à jour
404
- // Vous pouvez adapter d'autres champs en fonction des exigences spécifiques
405
- };
406
-
407
- // Retournez les données adaptées dans un format compréhensible pour le système
408
- return adaptedData;
409
- }
410
- }
411
- `,
412
- });
413
-
414
- // 10. Controller
415
- const controllerContente = await generateController(
416
- entity.name,
417
- entityPath,
418
- useSwagger
419
- );
420
- await createFile({
421
- path: `${entityPath}/presentation/controllers/${entityNameLower}.controller.ts`,
422
- contente: controllerContente,
423
- });
424
-
425
- // 11. Module
426
- let importsBlock = [];
427
- let providersBlock = [];
428
- let extraImports = "";
429
- let forwardRefImport = "";
430
-
431
- if (dbConfig.orm === "prisma") {
432
- extraImports = `import { PrismaModule } from 'src/prisma/prisma.module';`;
433
- importsBlock.push("PrismaModule");
434
- } else if (dbConfig.orm === "typeorm") {
435
- extraImports = `import { ${entityNameCapitalized} } from 'src/entities/${entityNameCapitalized}.entity';\nimport { TypeOrmModule } from '@nestjs/typeorm';`;
436
- importsBlock.push(
437
- `TypeOrmModule.forFeature([${entityNameCapitalized}])`
438
- );
439
- } else if (dbConfig.orm === "mongoose") {
440
- extraImports = `import { MongooseModule } from '@nestjs/mongoose';
441
- import { ${entityNameCapitalized}, ${entityNameCapitalized}Schema } from '${entityPath}/domain/entities/${entityNameLower}.schema';`;
442
- importsBlock.push(
443
- `MongooseModule.forFeature([{ name: ${entityNameCapitalized}.name, schema: ${entityNameCapitalized}Schema }])`
444
- );
445
- }
446
-
447
- if (entityNameLower == "user" && useAuth) {
448
- extraImports += "\nimport { AuthModule } from 'src/auth/auth.module';";
449
- importsBlock.push("forwardRef(() => AuthModule)");
450
- forwardRefImport = " forwardRef,";
451
- }
452
-
453
- // Ajoute l'import du service
454
- extraImports += `\nimport { ${entityNameCapitalized}Service } from '${entityPath}/application/services/${entityNameLower}.service';`;
455
-
456
- // Always necessary providers
457
- providersBlock.push(
458
- `{
459
- provide: 'I${entityNameCapitalized}Repository',
460
- useClass: ${entityNameCapitalized}Repository,
461
- }`,
462
- `${entityNameCapitalized}Service`,
463
- `Create${entityNameCapitalized}UseCase`,
464
- `Update${entityNameCapitalized}UseCase`,
465
- `GetById${entityNameCapitalized}UseCase`,
466
- `GetAll${entityNameCapitalized}UseCase`,
467
- `Delete${entityNameCapitalized}UseCase`,
468
- `${entityNameCapitalized}Mapper`
469
- );
470
-
471
- await createFile({
472
- path: `${entityPath}/${entityNameLower}.module.ts`,
473
- contente: `
474
- /**
475
- * ${entityNameCapitalized}Module est le module principal qui gère l'entité ${entityNameCapitalized}.
476
- * Il regroupe tous les composants nécessaires pour traiter cette entité :
477
- * - Contrôleur
478
- * - Repository
479
- * - Use Cases
480
- * - Mapper
481
- * - Service
482
- */
483
- import {${forwardRefImport} Module } from '@nestjs/common';
484
- ${extraImports}
485
- import { ${entityNameCapitalized}Controller } from '${entityPath}/presentation/controllers/${entityNameLower}.controller';
486
- import { ${entityNameCapitalized}Repository } from '${entityPath}/infrastructure/repositories/${entityNameLower}.repository';
487
- import { Create${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/create-${entityNameLower}.use-case';
488
- import { Update${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/update-${entityNameLower}.use-case';
489
- import { GetById${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/getById-${entityNameLower}.use-case';
490
- import { GetAll${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/getAll-${entityNameLower}.use-case';
491
- import { Delete${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/delete-${entityNameLower}.use-case';
492
- import { ${entityNameCapitalized}Mapper } from '${entityPath}/infrastructure/mappers/${entityNameLower}.mapper';
493
-
494
- @Module({
495
- imports: [
496
- ${importsBlock.join(",\n ")}
497
- ],
498
- controllers: [
499
- ${entityNameCapitalized}Controller
500
- ],
501
- providers: [
502
- ${providersBlock.join(",\n ")}
503
- ],
504
- exports: [
505
- ${entityNameCapitalized}Service, 'I${entityNameCapitalized}Repository'
506
- ]
507
- })
508
- export class ${entityNameCapitalized}Module {}
509
- `.trim(),
510
- });
511
-
512
- await safeUpdateAppModule(entityNameLower);
513
- }
514
-
515
- await generateMiddlewares(dbConfig.orm);
516
-
517
- // modification de AppModule
518
- const appModulePath = "src/app.module.ts";
519
-
520
- // Étape 1 : Ajouter les imports nécessaires
521
- await updateFile({
522
- path: appModulePath,
523
- pattern: `import { Module } from '@nestjs/common';`,
524
- replacement: `import { Module } from '@nestjs/common';
525
- import { ResponseInterceptor } from './common/interceptors/response.interceptor';
526
- import { APP_INTERCEPTOR } from '@nestjs/core';`,
527
- });
528
-
529
- // Étape 2 : Ajouter le provider APP_INTERCEPTOR dans providers[]
530
- await updateFile({
531
- path: appModulePath,
532
- pattern: `providers: \\[`,
533
- replacement: `providers: [
534
- {
535
- provide: APP_INTERCEPTOR,
536
- useClass: ResponseInterceptor,
537
- },`,
538
- });
539
-
540
- logSuccess(`Structure generated successfully!`);
541
- } catch (error) {
542
- logError(
543
- `Process encountered an error during Clean Architecture setup: ${error}`
544
- );
545
- throw error;
546
- }
547
- }
548
-
549
- function capitalize(str) {
550
- return str.charAt(0).toUpperCase() + str.slice(1);
551
- }
552
-
553
- function decapitalize(str) {
554
- return str.charAt(0).toLowerCase() + str.slice(1);
555
- }
556
-
557
- module.exports = { setupCleanArchitecture };
1
+ const { logInfo } = require("../loggers/logInfo");
2
+ const {
3
+ createDirectory,
4
+ createFile,
5
+ updateFile,
6
+ safeUpdateAppModule,
7
+ } = require("../userInput");
8
+ const { logError } = require("../loggers/logError");
9
+ const { logSuccess } = require("../loggers/logSuccess");
10
+ const {
11
+ generateEntityFileContent,
12
+ generateMapper,
13
+ generateDto,
14
+ generateMiddlewares,
15
+ generateRepository,
16
+ generateController,
17
+ generateMongooseSchemaFileContent,
18
+ pluralize,
19
+ } = require("../utils");
20
+
21
+ async function setupCleanArchitecture(inputs) {
22
+ logInfo("Generating Clean Architecture structure");
23
+
24
+ const entitiesData = inputs.entitiesData;
25
+ const dbConfig = inputs.dbConfig;
26
+ const useSwagger = inputs.useSwagger;
27
+ const useAuth = inputs.useAuth;
28
+ const mode = "full";
29
+
30
+ const srcPath = "src";
31
+ const baseFolders = [
32
+ "application/use-cases",
33
+ "application/dtos",
34
+ "domain/interfaces",
35
+ "domain/entities",
36
+ // "domain/enums",
37
+ "infrastructure/mappers",
38
+ "infrastructure/repositories",
39
+ "application/services",
40
+ "infrastructure/adapters",
41
+ "presentation/controllers",
42
+ ];
43
+
44
+ try {
45
+ // modifier app module pour exporter configService globalement
46
+ const appModuleTsPath = "src/app.module.ts";
47
+
48
+ // ajouter l'import configModule
49
+ await updateFile({
50
+ path: appModuleTsPath,
51
+ pattern: "import { Module } from '@nestjs/common';",
52
+ replacement: `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';`,
53
+ });
54
+
55
+ // configurer configservice
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
+
70
+ if (entityNameLower == "session") continue;
71
+
72
+ const entityPath = `${srcPath}/${entityNameLower}`;
73
+
74
+ for (const folder of baseFolders) {
75
+ await createDirectory(`${entityPath}/${folder}`);
76
+ }
77
+
78
+ if (dbConfig.orm === "mongoose") {
79
+ const mongooseSchemaContent = await generateMongooseSchemaFileContent(
80
+ entity,
81
+ entitiesData,
82
+ mode,
83
+ );
84
+
85
+ const schemaPath = `src/${entity.name}/infrastructure/persistence/mongoose`;
86
+ await createDirectory(schemaPath);
87
+
88
+ await createFile({
89
+ path: `${schemaPath}/${entity.name}.schema.ts`,
90
+ contente: mongooseSchemaContent,
91
+ });
92
+ }
93
+
94
+ // 1. Entité
95
+ const entityContent = await generateEntityFileContent(entity);
96
+ await createFile({
97
+ path: `${entityPath}/domain/entities/${entityNameLower}.entity.ts`,
98
+ contente: entityContent,
99
+ });
100
+
101
+ let findByEmailMethod = "";
102
+ if (entityNameLower == "user") {
103
+ findByEmailMethod = `
104
+ findByEmail(email: string): Promise<${entityNameCapitalized}Entity | null>;
105
+ `;
106
+ }
107
+
108
+ // 2. Interface Repository
109
+ await createFile({
110
+ path: `${entityPath}/domain/interfaces/${entityNameLower}.repository.interface.ts`,
111
+ contente: `import { Create${entityNameCapitalized}Dto, Update${entityNameCapitalized}Dto } from 'src/${entityNameLower}/application/dtos/${entityNameLower}.dto';
112
+ import { ${entityNameCapitalized}Entity } from 'src/${entityNameLower}/domain/entities/${entityNameLower}.entity';
113
+
114
+ export const I${entityNameCapitalized}RepositoryName = 'I${entityNameCapitalized}Repository';
115
+
116
+ export interface I${entityNameCapitalized}Repository {
117
+ create(data: Create${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity>;
118
+ findById(id: string): Promise<${entityNameCapitalized}Entity | null>;
119
+ findAll(): Promise<${entityNameCapitalized}Entity[]>;
120
+ update(id: string, data: Update${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity | null>;
121
+ delete(id: string): Promise<void>;
122
+ ${findByEmailMethod}
123
+ }`,
124
+ });
125
+
126
+ // 3. Repository Implémentation
127
+ await generateRepository(entity.name, dbConfig.orm);
128
+
129
+ // 4. Use Cases
130
+ const useCases = ["Create", "GetById", "GetAll", "Update", "Delete"];
131
+ useCases.forEach(async (useCase) => {
132
+ let content = "";
133
+ const entityName = capitalize(entity.name);
134
+ const entityNameLower = decapitalize(entity.name);
135
+
136
+ switch (useCase) {
137
+ case "Create":
138
+ content = `/**
139
+ * Use case to handle the creation of a new ${entityName}.
140
+ */
141
+
142
+ import { Inject, Logger } from '@nestjs/common';
143
+ import { Create${entityName}Dto } from 'src/${entity.name}/application/dtos/${entity.name}.dto';
144
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
145
+ import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
146
+
147
+ export class Create${entityName}UseCase {
148
+ private readonly logger = new Logger(Create${entityName}UseCase.name);
149
+
150
+ constructor(
151
+ @Inject(I${entityName}RepositoryName)
152
+ private readonly ${entityNameLower}Repository: I${entityName}Repository,
153
+ ) {}
154
+
155
+ async execute(data: Create${entityName}Dto): Promise<${entityName}Entity> {
156
+ this.logger.log('Starting creation process for ${entityName}');
157
+ const result = await this.${entityNameLower}Repository.create(data);
158
+ this.logger.log(\`Successfully created ${entityName} (ID: \${result.getId()})\`);
159
+ return result;
160
+ }
161
+ }
162
+ `;
163
+ break;
164
+
165
+ case "GetById":
166
+ content = `/**
167
+ * Use case to retrieve a specific ${entityName} by its unique identifier.
168
+ */
169
+
170
+ import { Inject, Logger, NotFoundException } from '@nestjs/common';
171
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
172
+ import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
173
+
174
+ export class GetById${entityName}UseCase {
175
+ private readonly logger = new Logger(GetById${entityName}UseCase.name);
176
+
177
+ constructor(
178
+ @Inject(I${entityName}RepositoryName)
179
+ private readonly ${entityNameLower}Repository: I${entityName}Repository,
180
+ ) {}
181
+
182
+ async execute(id: string): Promise<${entityName}Entity> {
183
+ this.logger.log(\`Fetching ${entityName} (ID: \${id})\`);
184
+ const result = await this.${entityNameLower}Repository.findById(id);
185
+
186
+ if (!result) {
187
+ this.logger.warn(\`${entityName} \${id} not found\`);
188
+ throw new NotFoundException(\`${entityName} not found\`);
189
+ }
190
+
191
+ this.logger.log(\`Successfully retrieved ${entityName}\`);
192
+ return result;
193
+ }
194
+ }
195
+ `;
196
+ break;
197
+
198
+ case "GetAll":
199
+ content = `/**
200
+ * Use case to retrieve all ${entityName} records from the database.
201
+ */
202
+
203
+ import { Inject, Logger } from '@nestjs/common';
204
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
205
+ import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
206
+
207
+ export class GetAll${entityName}UseCase {
208
+ private readonly logger = new Logger(GetAll${entityName}UseCase.name);
209
+
210
+ constructor(
211
+ @Inject(I${entityName}RepositoryName)
212
+ private readonly ${entityNameLower}Repository: I${entityName}Repository,
213
+ ) {}
214
+
215
+ async execute(): Promise<${entityName}Entity[]> {
216
+ this.logger.log('Requesting all ${entityName} records');
217
+ const results = await this.${entityNameLower}Repository.findAll();
218
+ this.logger.log(\`Retrieved \${results.length} ${entityName}(s)\`);
219
+ return results;
220
+ }
221
+ }
222
+ `;
223
+ break;
224
+
225
+ case "Update":
226
+ content = `/**
227
+ * Use case to update the data of an existing ${entityName}.
228
+ */
229
+
230
+ import { Inject, Logger, NotFoundException } from '@nestjs/common';
231
+ import { Update${entityName}Dto } from 'src/${entity.name}/application/dtos/${entity.name}.dto';
232
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
233
+ import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
234
+
235
+ export class Update${entityName}UseCase {
236
+ private readonly logger = new Logger(Update${entityName}UseCase.name);
237
+
238
+ constructor(
239
+ @Inject(I${entityName}RepositoryName)
240
+ private readonly ${entityNameLower}Repository: I${entityName}Repository,
241
+ ) {}
242
+
243
+ async execute(id: string, data: Update${entityName}Dto): Promise<${entityName}Entity> {
244
+ this.logger.log(\`Updating ${entityName} (ID: \${id})\`);
245
+
246
+ const existing = await this.${entityNameLower}Repository.findById(id);
247
+ if (!existing) {
248
+ this.logger.warn(\`${entityName} \${id} not found for update\`);
249
+ throw new NotFoundException(\`${entityName} not found\`);
250
+ }
251
+
252
+ const result = await this.${entityNameLower}Repository.update(id, data);
253
+
254
+ if (!result) {
255
+ this.logger.error(\`Update failed for ${entityName} \${id} - entity disappeared\`);
256
+ throw new NotFoundException(\`${entityName} update failed\`);
257
+ }
258
+
259
+ this.logger.log(\`Successfully updated ${entityName} \${id}\`);
260
+ return result;
261
+ }
262
+ }
263
+ `;
264
+ break;
265
+
266
+ case "Delete":
267
+ content = `/**
268
+ * Use case to permanently remove an ${entityName} from the system.
269
+ */
270
+
271
+ import { Inject, Logger, NotFoundException } from '@nestjs/common';
272
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
273
+
274
+ export class Delete${entityName}UseCase {
275
+ private readonly logger = new Logger(Delete${entityName}UseCase.name);
276
+
277
+ constructor(
278
+ @Inject(I${entityName}RepositoryName)
279
+ private readonly ${entityNameLower}Repository: I${entityName}Repository,
280
+ ) {}
281
+
282
+ async execute(id: string): Promise<void> {
283
+ this.logger.log(\`Deleting ${entityName} (ID: \${id})\`);
284
+
285
+ const existing = await this.${entityNameLower}Repository.findById(id);
286
+ if (!existing) {
287
+ this.logger.warn(\`${entityName} \${id} not found for deletion\`);
288
+ throw new NotFoundException(\`${entityName} not found\`);
289
+ }
290
+
291
+ await this.${entityNameLower}Repository.delete(id);
292
+ this.logger.log(\`Successfully deleted ${entityName} \${id}\`);
293
+ }
294
+ }
295
+ `;
296
+ break;
297
+ }
298
+
299
+ await createFile({
300
+ path: `${entityPath}/application/use-cases/${decapitalize(useCase)}-${
301
+ entity.name
302
+ }.use-case.ts`,
303
+ contente: content.trim(),
304
+ });
305
+ });
306
+
307
+ // 5. DTOs
308
+ const DtoFileContent = await generateDto(entity, useSwagger);
309
+ await createFile({
310
+ path: `${entityPath}/application/dtos/${entity.name}.dto.ts`,
311
+ contente: DtoFileContent,
312
+ });
313
+
314
+ if (entity.name.toLowerCase() === "user") {
315
+ await createDirectory(`${entityPath}/domain/enums`);
316
+ await createFile({
317
+ path: `${entityPath}/domain/enums/role.enum.ts`,
318
+ contente: `// Enumération des rôles utilisateurs
319
+ export enum Role {
320
+ USER = 'USER',
321
+ ADMIN = 'ADMIN',
322
+ SUPER_ADMIN = 'SUPER_ADMIN',
323
+ }
324
+ `,
325
+ });
326
+ }
327
+
328
+ // 7. Mapper
329
+ const mapperFileContent = await generateMapper(entity);
330
+ await createFile({
331
+ path: `${entityPath}/infrastructure/mappers/${entityNameLower}.mapper.ts`,
332
+ contente: mapperFileContent,
333
+ });
334
+
335
+ // 8. Service
336
+ await createFile({
337
+ path: `${entityPath}/application/services/${entityNameLower}.service.ts`,
338
+ contente: `/**
339
+ * PostService handles business logic
340
+ * for the Post entity.
341
+ *
342
+ * It acts as a bridge between the Controller and the Repository.
343
+ * Responsibilities include:
344
+ * - Data validation and transformation
345
+ * - Orchestrating use cases
346
+ * - Managing transactions
347
+ */
348
+
349
+ import { Injectable } from '@nestjs/common';
350
+ import { Create${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/create-${entityNameLower}.use-case';
351
+ import { Update${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/update-${entityNameLower}.use-case';
352
+ import { GetById${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/getById-${entityNameLower}.use-case';
353
+ import { GetAll${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/getAll-${entityNameLower}.use-case';
354
+ import { Delete${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/delete-${entityNameLower}.use-case';
355
+ import { Create${entityNameCapitalized}Dto, Update${entityNameCapitalized}Dto } from 'src/${entityNameLower}/application/dtos/${entityNameLower}.dto';
356
+ import { ${entityNameCapitalized}Entity } from 'src/${entityNameLower}/domain/entities/${entityNameLower}.entity';
357
+
358
+ @Injectable()
359
+ export class ${entityNameCapitalized}Service {
360
+ constructor(
361
+ private readonly createUseCase: Create${entityNameCapitalized}UseCase,
362
+ private readonly updateUseCase: Update${entityNameCapitalized}UseCase,
363
+ private readonly getByIdUseCase: GetById${entityNameCapitalized}UseCase,
364
+ private readonly getAllUseCase: GetAll${entityNameCapitalized}UseCase,
365
+ private readonly deleteUseCase: Delete${entityNameCapitalized}UseCase,
366
+ ) {}
367
+
368
+ async create(dto: Create${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity> {
369
+ return await this.createUseCase.execute(dto);
370
+ }
371
+ async update(id: string, dto: Update${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity | null> {
372
+ return await this.updateUseCase.execute(id, dto);
373
+ }
374
+ async getById(id: string): Promise<${entityNameCapitalized}Entity | null> {
375
+ return await this.getByIdUseCase.execute(id);
376
+ }
377
+ async getAll(): Promise<${entityNameCapitalized}Entity[]> {
378
+ return await this.getAllUseCase.execute();
379
+ }
380
+ async delete(id: string): Promise<void> {
381
+ return await this.deleteUseCase.execute(id);
382
+ }
383
+ }
384
+ `.trim(),
385
+ });
386
+
387
+ // 9. Adapter
388
+ await createFile({
389
+ path: `${entityPath}/infrastructure/adapters/${entityNameLower}.adapter.ts`,
390
+ contente: `
391
+ // L'adaptateur permet de transformer ou d'adapter les données d'un format source vers un format cible.
392
+ // Cela est particulièrement utile lorsque nous devons interagir avec des API externes ou des services ayant des structures de données différentes.
393
+
394
+ export class ${entityNameCapitalized}Adapter {
395
+ // La méthode 'adapt' prend des données brutes d'un format spécifique et les transforme
396
+ // en un format qui est attendu par le système de notre domaine.
397
+ adapt(data: any) {
398
+ // Exemple d'adaptation des données - ceci est un exemple générique.
399
+ // Nous transformons les données pour que le format interne du système soit respecté.
400
+
401
+ const adaptedData = {
402
+ // Assurez-vous que vous mappez les propriétés nécessaires et les transformez.
403
+ id: data.id, // Mapping de l'ID de la donnée source à notre format interne
404
+ name: data.fullName || data.name, // Exemple de transformation de champ
405
+ description: data.details || data.description, // Gestion des données optionnelles
406
+ createdAt: new Date(data.createdAt), // Transformation de la date
407
+ updatedAt: new Date(data.updatedAt), // Idem pour la date de mise à jour
408
+ // Vous pouvez adapter d'autres champs en fonction des exigences spécifiques
409
+ };
410
+
411
+ // Retournez les données adaptées dans un format compréhensible pour le système
412
+ return adaptedData;
413
+ }
414
+ }
415
+ `,
416
+ });
417
+
418
+ // 10. Controller
419
+ const controllerContente = await generateController(
420
+ entity.name,
421
+ entityPath,
422
+ useSwagger,
423
+ );
424
+ await createFile({
425
+ path: `${entityPath}/presentation/controllers/${entityNameLower}.controller.ts`,
426
+ contente: controllerContente,
427
+ });
428
+
429
+ // 11. Module
430
+ let importsBlock = [];
431
+ let providersBlock = [];
432
+ let extraImports = "";
433
+ let forwardRefImport = "";
434
+
435
+ if (dbConfig.orm === "prisma") {
436
+ extraImports = `import { PrismaModule } from 'src/prisma/prisma.module';`;
437
+ importsBlock.push("PrismaModule");
438
+ } else if (dbConfig.orm === "typeorm") {
439
+ extraImports = `import { ${entityNameCapitalized} } from 'src/entities/${entityNameCapitalized}.entity';\nimport { TypeOrmModule } from '@nestjs/typeorm';`;
440
+ importsBlock.push(
441
+ `TypeOrmModule.forFeature([${entityNameCapitalized}])`,
442
+ );
443
+ } else if (dbConfig.orm === "mongoose") {
444
+ extraImports = `import { MongooseModule } from '@nestjs/mongoose';
445
+ import { ${entityNameCapitalized}, ${entityNameCapitalized}Schema } from '${entityPath}/infrastructure/persistence/mongoose/${entityNameLower}.schema';`;
446
+ importsBlock.push(
447
+ `MongooseModule.forFeature([{ name: ${entityNameCapitalized}.name, schema: ${entityNameCapitalized}Schema }])`,
448
+ );
449
+ }
450
+
451
+ if (entityNameLower == "user" && useAuth) {
452
+ extraImports += "\nimport { AuthModule } from 'src/auth/auth.module';";
453
+ importsBlock.push("forwardRef(() => AuthModule)");
454
+ forwardRefImport = " forwardRef,";
455
+ }
456
+
457
+ // Ajoute l'import du service
458
+ extraImports += `\nimport { ${entityNameCapitalized}Service } from '${entityPath}/application/services/${entityNameLower}.service';`;
459
+
460
+ // Always necessary providers
461
+ providersBlock.push(
462
+ `{
463
+ provide: I${entityNameCapitalized}RepositoryName,
464
+ useClass: ${entityNameCapitalized}Repository,
465
+ }`,
466
+ `${entityNameCapitalized}Service`,
467
+ `Create${entityNameCapitalized}UseCase`,
468
+ `Update${entityNameCapitalized}UseCase`,
469
+ `GetById${entityNameCapitalized}UseCase`,
470
+ `GetAll${entityNameCapitalized}UseCase`,
471
+ `Delete${entityNameCapitalized}UseCase`,
472
+ `${entityNameCapitalized}Mapper`,
473
+ );
474
+
475
+ await createFile({
476
+ path: `${entityPath}/${entityNameLower}.module.ts`,
477
+ contente: `
478
+ /**
479
+ * ${entityNameCapitalized}Module est le module principal qui gère l'entité ${entityNameCapitalized}.
480
+ * Il regroupe tous les composants nécessaires pour traiter cette entité :
481
+ * - Contrôleur
482
+ * - Repository
483
+ * - Use Cases
484
+ * - Mapper
485
+ * - Service
486
+ */
487
+ import {${forwardRefImport} Module } from '@nestjs/common';
488
+ ${extraImports}
489
+ import { ${entityNameCapitalized}Controller } from '${entityPath}/presentation/controllers/${entityNameLower}.controller';
490
+ import { ${entityNameCapitalized}Repository } from '${entityPath}/infrastructure/repositories/${entityNameLower}.repository';
491
+ import { Create${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/create-${entityNameLower}.use-case';
492
+ import { Update${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/update-${entityNameLower}.use-case';
493
+ import { GetById${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/getById-${entityNameLower}.use-case';
494
+ import { GetAll${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/getAll-${entityNameLower}.use-case';
495
+ import { Delete${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/delete-${entityNameLower}.use-case';
496
+ import { ${entityNameCapitalized}Mapper } from '${entityPath}/infrastructure/mappers/${entityNameLower}.mapper';
497
+ import { I${entityNameCapitalized}RepositoryName } from './domain/interfaces/${entityNameLower}.repository.interface';
498
+
499
+
500
+ @Module({
501
+ imports: [
502
+ ${importsBlock.join(",\n ")}
503
+ ],
504
+ controllers: [
505
+ ${entityNameCapitalized}Controller
506
+ ],
507
+ providers: [
508
+ ${providersBlock.join(",\n ")}
509
+ ],
510
+ exports: [
511
+ ${entityNameCapitalized}Service, I${entityNameCapitalized}RepositoryName
512
+ ]
513
+ })
514
+ export class ${entityNameCapitalized}Module {}
515
+ `.trim(),
516
+ });
517
+
518
+ await safeUpdateAppModule(entityNameLower);
519
+ }
520
+
521
+ await generateMiddlewares(dbConfig.orm);
522
+
523
+ // modification de AppModule
524
+ const appModulePath = "src/app.module.ts";
525
+
526
+ // Étape 1 : Ajouter les imports nécessaires
527
+ await updateFile({
528
+ path: appModulePath,
529
+ pattern: `import { Module } from '@nestjs/common';`,
530
+ replacement: `import { Module } from '@nestjs/common';
531
+ import { ResponseInterceptor } from './common/interceptors/response.interceptor';
532
+ import { APP_INTERCEPTOR } from '@nestjs/core';`,
533
+ });
534
+
535
+ // Étape 2 : Ajouter le provider APP_INTERCEPTOR dans providers[]
536
+ await updateFile({
537
+ path: appModulePath,
538
+ pattern: `providers: \\[`,
539
+ replacement: `providers: [
540
+ {
541
+ provide: APP_INTERCEPTOR,
542
+ useClass: ResponseInterceptor,
543
+ },`,
544
+ });
545
+
546
+ logSuccess(`Structure generated successfully!`);
547
+ } catch (error) {
548
+ logError(
549
+ `Process encountered an error during Clean Architecture setup: ${error}`,
550
+ );
551
+ throw error;
552
+ }
553
+ }
554
+
555
+ function capitalize(str) {
556
+ return str.charAt(0).toUpperCase() + str.slice(1);
557
+ }
558
+
559
+ function decapitalize(str) {
560
+ return str.charAt(0).toLowerCase() + str.slice(1);
561
+ }
562
+
563
+ module.exports = { setupCleanArchitecture };