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
@@ -0,0 +1,54 @@
1
+ // src/utils/generators/application/dtoUpdater.js
2
+ const fs = require("fs");
3
+ const { updateFile, capitalize } = require("../../userInput");
4
+
5
+ async function patchDtoWithRelation(source, targetName, useSwagger, mode) {
6
+ let dtoPath;
7
+ if (mode === "full") {
8
+ dtoPath = `src/${source.toLowerCase()}/application/dtos/${source.toLowerCase()}.dto.ts`;
9
+ } else {
10
+ dtoPath = `src/${source.toLowerCase()}/dtos/${source.toLowerCase()}.dto.ts`;
11
+ }
12
+ const targetLow = targetName.toLowerCase();
13
+ const targetCap = capitalize(targetName);
14
+
15
+ // 1. Préparation du bloc de code selon Swagger
16
+ let fieldCode = "";
17
+
18
+ if (useSwagger) {
19
+ fieldCode = `
20
+ @ApiProperty({
21
+ example: '550e8400-e29b-41d4-a716-446655440000',
22
+ description: 'The unique identifier of the related ${targetCap}',
23
+ })
24
+ @IsUUID()
25
+ ${targetLow}Id!: string;`;
26
+ } else {
27
+ fieldCode = `
28
+ @IsUUID()
29
+ ${targetLow}Id!: string;`;
30
+ }
31
+
32
+ // 2. Injection dans CreateDto
33
+ // On injecte juste après l'ouverture de la classe
34
+ await updateFile({
35
+ path: dtoPath,
36
+ pattern: new RegExp(`export class Create${capitalize(source)}Dto {`),
37
+ replacement: `export class Create${capitalize(source)}Dto {${fieldCode}\n`,
38
+ });
39
+
40
+ // 3. Injection dans UpdateDto (Optionnel mais recommandé si non géré par PartialType)
41
+ // Si ton UpdateDto n'utilise pas PartialType(CreateDto), il faut aussi patcher l'Update
42
+ const fileContent = fs.readFileSync(dtoPath, "utf8");
43
+ if (!fileContent.includes("extends PartialType")) {
44
+ const updateFieldCode = fieldCode
45
+ .replace("@IsUUID()", "@IsOptional()\n @IsUUID()")
46
+ .replace("Id!: string", "Id?: string");
47
+ await updateFile({
48
+ path: dtoPath,
49
+ pattern: new RegExp(`export class Update${capitalize(source)}Dto {`),
50
+ replacement: `export class Update${capitalize(source)}Dto {${updateFieldCode}\n`,
51
+ });
52
+ }
53
+ }
54
+ module.exports = { patchDtoWithRelation };
@@ -0,0 +1,475 @@
1
+ const {
2
+ createDirectory,
3
+ createFile,
4
+ safeUpdateAppModule,
5
+ capitalize,
6
+ decapitalize,
7
+ } = require("../userInput");
8
+ const { logInfo } = require("../loggers/logInfo");
9
+ const { logSuccess } = require("../loggers/logSuccess");
10
+ const {
11
+ generateEntityFileContent,
12
+ generateDto,
13
+ generateMapper,
14
+ generateController,
15
+ generateRepository,
16
+ generateMongooseSchemaFileContent,
17
+ } = require("../utils");
18
+ const { updateExistingEntityRelation } = require("./domain/entityUpdater");
19
+ const { applyRelationPatches } = require("./relation/relation.engine");
20
+ const setupDatabase = require("./database/setupDatabase");
21
+
22
+ async function generateCleanModule(name, config, entityData) {
23
+ const entityNameCapitalized = capitalize(name);
24
+ const entityNameLower = decapitalize(name);
25
+ const entityPath = `src/${entityNameLower}`;
26
+ const mode = "full";
27
+
28
+ // Chemins de la Clean Architecture
29
+ const folders = [
30
+ "application/use-cases",
31
+ "application/dtos",
32
+ "domain/interfaces",
33
+ "domain/entities",
34
+ "infrastructure/mappers",
35
+ "infrastructure/repositories",
36
+ "application/services",
37
+ "infrastructure/adapters",
38
+ "presentation/controllers",
39
+ ];
40
+
41
+ logInfo(
42
+ ` Building Clean Architecture layers for module: ${entityNameCapitalized}`,
43
+ );
44
+
45
+ // 1. Création des dossiers
46
+ for (const folder of folders) {
47
+ await createDirectory(`${entityPath}/${folder}`);
48
+ }
49
+
50
+ // 2. Génération de l'Entité de Domaine
51
+ const entityContent = await generateEntityFileContent(entityData);
52
+ await createFile({
53
+ path: `${entityPath}/domain/entities/${entityNameLower}.entity.ts`,
54
+ contente: entityContent,
55
+ });
56
+
57
+ // 3. Génération de l'Interface Repository
58
+ await createFile({
59
+ path: `${entityPath}/domain/interfaces/${entityNameLower}.repository.interface.ts`,
60
+ contente: getRepositoryInterfaceTemplate(
61
+ entityNameCapitalized,
62
+ entityNameLower,
63
+ ),
64
+ });
65
+
66
+ // 4. Génération du Repository (Implementation)
67
+ await generateRepository(name, config.orm);
68
+
69
+ // 5. Génération des Use Cases (Create, Get, Update, Delete)
70
+ await generateUseCases(entityPath, entityNameCapitalized, entityNameLower);
71
+
72
+ // 6. Génération des DTOs
73
+ const dtoContent = await generateDto(entityData, config.swagger);
74
+ await createFile({
75
+ path: `${entityPath}/application/dtos/${entityNameLower}.dto.ts`,
76
+ contente: dtoContent,
77
+ });
78
+
79
+ // 7. Génération du Mapper
80
+ const mapperContent = await generateMapper(entityData);
81
+ await createFile({
82
+ path: `${entityPath}/infrastructure/mappers/${entityNameLower}.mapper.ts`,
83
+ contente: mapperContent,
84
+ });
85
+
86
+ // ÉTAPE RELATIONS : Patching des fichiers si une relation existe
87
+ if (
88
+ entityData.relation &&
89
+ (entityData.relation.type != "1-n" || entityData.relation.type != "n-n")
90
+ ) {
91
+ const { target, type } = entityData.relation;
92
+ logInfo(
93
+ `🔗 Linking ${entityNameCapitalized} with ${capitalize(target)} (${type})...`,
94
+ );
95
+
96
+ await updateExistingEntityRelation(target, name, type);
97
+
98
+ /* if (type === "n-1" || type === "1-1") {
99
+ await patchDtoWithRelation(name, target, config.swagger);
100
+ await patchMapperWithRelation(name, target);
101
+ } */
102
+
103
+ await applyRelationPatches(name, target, type, config.swagger, mode);
104
+ }
105
+
106
+ // 8. Génération du Service, Adapter et Controller
107
+ await generateServiceAndAdapter(
108
+ entityPath,
109
+ entityNameCapitalized,
110
+ entityNameLower,
111
+ );
112
+
113
+ const controllerContent = await generateController(
114
+ name,
115
+ entityPath,
116
+ config.swagger,
117
+ );
118
+ await createFile({
119
+ path: `${entityPath}/presentation/controllers/${entityNameLower}.controller.ts`,
120
+ contente: controllerContent,
121
+ });
122
+
123
+ // 9. Génération du Module NestJS
124
+ const moduleContent = getModuleTemplate(
125
+ entityNameCapitalized,
126
+ entityNameLower,
127
+ entityPath,
128
+ config,
129
+ );
130
+ await createFile({
131
+ path: `${entityPath}/${entityNameLower}.module.ts`,
132
+ contente: moduleContent,
133
+ });
134
+
135
+ // 10. Auto-enregistrement dans AppModule
136
+ await safeUpdateAppModule(entityNameLower);
137
+
138
+ // 11.
139
+ await setupDatabase(config, entityData);
140
+
141
+ logSuccess(
142
+ ` ✨ Module ${entityNameCapitalized} generated and registered successfully!`,
143
+ );
144
+ }
145
+
146
+ // --- HELPERS DE TEMPLATES (Extraits de ton setup original) ---
147
+
148
+ function getRepositoryInterfaceTemplate(cap, low) {
149
+ return `import { Create${cap}Dto, Update${cap}Dto } from 'src/${low}/application/dtos/${low}.dto';
150
+ import { ${cap}Entity } from 'src/${low}/domain/entities/${low}.entity';
151
+
152
+ export const I${cap}RepositoryName = 'I${cap}Repository';
153
+
154
+ export interface I${cap}Repository {
155
+ create(data: Create${cap}Dto): Promise<${cap}Entity>;
156
+ findById(id: string): Promise<${cap}Entity | null>;
157
+ findAll(): Promise<${cap}Entity[]>;
158
+ update(id: string, data: Update${cap}Dto): Promise<${cap}Entity | null>;
159
+ delete(id: string): Promise<void>;
160
+ }`;
161
+ }
162
+
163
+ ///////////////////
164
+ async function generateUseCases(entityPath, cap, low) {
165
+ const useCases = ["Create", "GetById", "GetAll", "Update", "Delete"];
166
+
167
+ for (const useCase of useCases) {
168
+ let content = "";
169
+ const fileName = `${decapitalize(useCase)}-${low}.use-case.ts`;
170
+ const fullPath = `${entityPath}/application/use-cases/${fileName}`;
171
+
172
+ switch (useCase) {
173
+ case "Create":
174
+ content = `
175
+ import { Inject, Logger } from '@nestjs/common';
176
+ import { Create${cap}Dto } from 'src/${low}/application/dtos/${low}.dto';
177
+ import { I${cap}RepositoryName, type I${cap}Repository } from 'src/${low}/domain/interfaces/${low}.repository.interface';
178
+ import { ${cap}Entity } from 'src/${low}/domain/entities/${low}.entity';
179
+
180
+ export class Create${cap}UseCase {
181
+ private readonly logger = new Logger(Create${cap}UseCase.name);
182
+
183
+ constructor(
184
+ @Inject(I${cap}RepositoryName)
185
+ private readonly repository: I${cap}Repository,
186
+ ) {}
187
+
188
+ async execute(data: Create${cap}Dto): Promise<${cap}Entity> {
189
+ this.logger.log('Starting creation process for ${cap}');
190
+ const result = await this.repository.create(data);
191
+ this.logger.log(\`Successfully created ${cap} (ID: \${result.getId()})\`);
192
+ return result;
193
+ }
194
+ }`;
195
+ break;
196
+
197
+ case "GetById":
198
+ content = `
199
+ import { Inject, Logger, NotFoundException } from '@nestjs/common';
200
+ import { I${cap}RepositoryName, type I${cap}Repository } from 'src/${low}/domain/interfaces/${low}.repository.interface';
201
+ import { ${cap}Entity } from 'src/${low}/domain/entities/${low}.entity';
202
+
203
+ export class GetById${cap}UseCase {
204
+ private readonly logger = new Logger(GetById${cap}UseCase.name);
205
+
206
+ constructor(
207
+ @Inject(I${cap}RepositoryName)
208
+ private readonly repository: I${cap}Repository,
209
+ ) {}
210
+
211
+ async execute(id: string): Promise<${cap}Entity> {
212
+ this.logger.log(\`Fetching ${cap} (ID: \${id})\`);
213
+ const result = await this.repository.findById(id);
214
+
215
+ if (!result) {
216
+ this.logger.warn(\`${cap} \${id} not found\`);
217
+ throw new NotFoundException(\`${cap} not found\`);
218
+ }
219
+
220
+ this.logger.log(\`Successfully retrieved ${cap}\`);
221
+ return result;
222
+ }
223
+ }`;
224
+ break;
225
+
226
+ case "GetAll":
227
+ content = `
228
+ import { Inject, Logger } from '@nestjs/common';
229
+ import { I${cap}RepositoryName, type I${cap}Repository } from 'src/${low}/domain/interfaces/${low}.repository.interface';
230
+ import { ${cap}Entity } from 'src/${low}/domain/entities/${low}.entity';
231
+
232
+ export class GetAll${cap}UseCase {
233
+ private readonly logger = new Logger(GetAll${cap}UseCase.name);
234
+
235
+ constructor(
236
+ @Inject(I${cap}RepositoryName)
237
+ private readonly repository: I${cap}Repository,
238
+ ) {}
239
+
240
+ async execute(): Promise<${cap}Entity[]> {
241
+ this.logger.log('Requesting all ${cap} records');
242
+ const results = await this.repository.findAll();
243
+ this.logger.log(\`Retrieved \${results.length} ${cap}(s)\`);
244
+ return results;
245
+ }
246
+ }`;
247
+ break;
248
+
249
+ case "Update":
250
+ content = `
251
+ import { Inject, Logger, NotFoundException } from '@nestjs/common';
252
+ import { Update${cap}Dto } from 'src/${low}/application/dtos/${low}.dto';
253
+ import { I${cap}RepositoryName, type I${cap}Repository } from 'src/${low}/domain/interfaces/${low}.repository.interface';
254
+ import { ${cap}Entity } from 'src/${low}/domain/entities/${low}.entity';
255
+
256
+ export class Update${cap}UseCase {
257
+ private readonly logger = new Logger(Update${cap}UseCase.name);
258
+
259
+ constructor(
260
+ @Inject(I${cap}RepositoryName)
261
+ private readonly repository: I${cap}Repository,
262
+ ) {}
263
+
264
+ async execute(id: string, data: Update${cap}Dto): Promise<${cap}Entity> {
265
+ this.logger.log(\`Updating ${cap} (ID: \${id})\`);
266
+ const existing = await this.repository.findById(id);
267
+ if (!existing) throw new NotFoundException(\`${cap} not found\`);
268
+
269
+ const result = await this.repository.update(id, data);
270
+ if (!result) {
271
+ this.logger.error(\`Update failed for ${cap} \${id} - entity disappeared\`);
272
+ throw new NotFoundException(\`${cap} update failed\`);
273
+ }
274
+
275
+ this.logger.log(\`Successfully updated ${cap} \${id}\`);
276
+ return result;
277
+ }
278
+ }`;
279
+ break;
280
+
281
+ case "Delete":
282
+ content = `
283
+ import { Inject, Logger, NotFoundException } from '@nestjs/common';
284
+ import { I${cap}RepositoryName, type I${cap}Repository } from 'src/${low}/domain/interfaces/${low}.repository.interface';
285
+
286
+ export class Delete${cap}UseCase {
287
+ private readonly logger = new Logger(Delete${cap}UseCase.name);
288
+
289
+ constructor(
290
+ @Inject(I${cap}RepositoryName)
291
+ private readonly repository: I${cap}Repository,
292
+ ) {}
293
+
294
+ async execute(id: string): Promise<void> {
295
+ this.logger.log(\`Deleting ${cap} (ID: \${id})\`);
296
+ const existing = await this.repository.findById(id);
297
+ if (!existing) throw new NotFoundException(\`${cap} not found\`);
298
+
299
+ await this.repository.delete(id);
300
+ this.logger.log(\`Successfully deleted ${cap} \${id}\`);
301
+ }
302
+ }`;
303
+ break;
304
+ }
305
+
306
+ await createFile({
307
+ path: fullPath,
308
+ contente: content.trim(),
309
+ });
310
+ }
311
+ }
312
+
313
+ //////////////////
314
+ function getModuleTemplate(cap, low, entityPath, config) {
315
+ let importsBlock = [];
316
+ let providersBlock = [];
317
+ let extraImports = "";
318
+ let forwardRefImport = "";
319
+
320
+ // Gestion de l'ORM pour les imports du Module
321
+ if (config.orm === "prisma") {
322
+ extraImports += `import { PrismaModule } from 'src/prisma/prisma.module';\n`;
323
+ importsBlock.push("PrismaModule");
324
+ } else if (config.orm === "typeorm") {
325
+ extraImports += `import { ${cap} } from 'src/entities/${cap}.entity';\nimport { TypeOrmModule } from '@nestjs/typeorm';\n`;
326
+ importsBlock.push(`TypeOrmModule.forFeature([${cap}])`);
327
+ } else if (config.orm === "mongoose") {
328
+ extraImports += `import { MongooseModule } from '@nestjs/mongoose';\nimport { ${cap}, ${cap}Schema } from 'src/${low}/infrastructure/persistence/mongoose/${low}.schema';\n`;
329
+ importsBlock.push(
330
+ `MongooseModule.forFeature([{ name: ${cap}.name, schema: ${cap}Schema }])`,
331
+ );
332
+ }
333
+
334
+ // Support Auth si nécessaire (User module)
335
+ if (low === "user" && config.auth) {
336
+ extraImports += "import { AuthModule } from 'src/auth/auth.module';\n";
337
+ importsBlock.push("forwardRef(() => AuthModule)");
338
+ forwardRefImport = " forwardRef,";
339
+ }
340
+
341
+ // Providers standard pour la Clean Arch
342
+ providersBlock.push(
343
+ `{ provide: 'I${cap}Repository', useClass: ${cap}Repository }`,
344
+ `${cap}Service`,
345
+ `Create${cap}UseCase`,
346
+ `Update${cap}UseCase`,
347
+ `GetById${cap}UseCase`,
348
+ `GetAll${cap}UseCase`,
349
+ `Delete${cap}UseCase`,
350
+ `${cap}Mapper`,
351
+ );
352
+
353
+ return `
354
+ import {${forwardRefImport} Module } from '@nestjs/common';
355
+ ${extraImports}
356
+ import { ${cap}Service } from 'src/${low}/application/services/${low}.service';
357
+ import { ${cap}Controller } from 'src/${low}/presentation/controllers/${low}.controller';
358
+ import { ${cap}Repository } from 'src/${low}/infrastructure/repositories/${low}.repository';
359
+ import { Create${cap}UseCase } from 'src/${low}/application/use-cases/create-${low}.use-case';
360
+ import { Update${cap}UseCase } from 'src/${low}/application/use-cases/update-${low}.use-case';
361
+ import { GetById${cap}UseCase } from 'src/${low}/application/use-cases/getById-${low}.use-case';
362
+ import { GetAll${cap}UseCase } from 'src/${low}/application/use-cases/getAll-${low}.use-case';
363
+ import { Delete${cap}UseCase } from 'src/${low}/application/use-cases/delete-${low}.use-case';
364
+ import { ${cap}Mapper } from 'src/${low}/infrastructure/mappers/${low}.mapper';
365
+
366
+ @Module({
367
+ imports: [
368
+ ${importsBlock.join(",\n ")}
369
+ ],
370
+ controllers: [
371
+ ${cap}Controller
372
+ ],
373
+ providers: [
374
+ ${providersBlock.join(",\n ")}
375
+ ],
376
+ exports: [
377
+ ${cap}Service,
378
+ 'I${cap}Repository'
379
+ ]
380
+ })
381
+ export class ${cap}Module {}
382
+ `.trim();
383
+ }
384
+
385
+ ////////////////
386
+ async function generateServiceAndAdapter(
387
+ entityPath,
388
+ entityNameCapitalized,
389
+ entityNameLower,
390
+ ) {
391
+ // 8. Service
392
+ await createFile({
393
+ path: `${entityPath}/application/services/${entityNameLower}.service.ts`,
394
+ contente: `/**
395
+ * PostService handles business logic
396
+ * for the Post entity.
397
+ *
398
+ * It acts as a bridge between the Controller and the Repository.
399
+ * Responsibilities include:
400
+ * - Data validation and transformation
401
+ * - Orchestrating use cases
402
+ * - Managing transactions
403
+ */
404
+
405
+ import { Injectable } from '@nestjs/common';
406
+ import { Create${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/create-${entityNameLower}.use-case';
407
+ import { Update${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/update-${entityNameLower}.use-case';
408
+ import { GetById${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/getById-${entityNameLower}.use-case';
409
+ import { GetAll${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/getAll-${entityNameLower}.use-case';
410
+ import { Delete${entityNameCapitalized}UseCase } from 'src/${entityNameLower}/application/use-cases/delete-${entityNameLower}.use-case';
411
+ import { Create${entityNameCapitalized}Dto, Update${entityNameCapitalized}Dto } from 'src/${entityNameLower}/application/dtos/${entityNameLower}.dto';
412
+ import { ${entityNameCapitalized}Entity } from 'src/${entityNameLower}/domain/entities/${entityNameLower}.entity';
413
+
414
+ @Injectable()
415
+ export class ${entityNameCapitalized}Service {
416
+ constructor(
417
+ private readonly createUseCase: Create${entityNameCapitalized}UseCase,
418
+ private readonly updateUseCase: Update${entityNameCapitalized}UseCase,
419
+ private readonly getByIdUseCase: GetById${entityNameCapitalized}UseCase,
420
+ private readonly getAllUseCase: GetAll${entityNameCapitalized}UseCase,
421
+ private readonly deleteUseCase: Delete${entityNameCapitalized}UseCase,
422
+ ) {}
423
+
424
+ async create(dto: Create${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity> {
425
+ return await this.createUseCase.execute(dto);
426
+ }
427
+ async update(id: string, dto: Update${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity | null> {
428
+ return await this.updateUseCase.execute(id, dto);
429
+ }
430
+ async getById(id: string): Promise<${entityNameCapitalized}Entity | null> {
431
+ return await this.getByIdUseCase.execute(id);
432
+ }
433
+ async getAll(): Promise<${entityNameCapitalized}Entity[]> {
434
+ return await this.getAllUseCase.execute();
435
+ }
436
+ async delete(id: string): Promise<void> {
437
+ return await this.deleteUseCase.execute(id);
438
+ }
439
+ }
440
+ `.trim(),
441
+ });
442
+
443
+ // 9. Adapter
444
+ await createFile({
445
+ path: `${entityPath}/infrastructure/adapters/${entityNameLower}.adapter.ts`,
446
+ contente: `
447
+ // L'adaptateur permet de transformer ou d'adapter les données d'un format source vers un format cible.
448
+ // Cela est particulièrement utile lorsque nous devons interagir avec des API externes ou des services ayant des structures de données différentes.
449
+
450
+ export class ${entityNameCapitalized}Adapter {
451
+ // La méthode 'adapt' prend des données brutes d'un format spécifique et les transforme
452
+ // en un format qui est attendu par le système de notre domaine.
453
+ adapt(data: any) {
454
+ // Exemple d'adaptation des données - ceci est un exemple générique.
455
+ // Nous transformons les données pour que le format interne du système soit respecté.
456
+
457
+ const adaptedData = {
458
+ // Assurez-vous que vous mappez les propriétés nécessaires et les transformez.
459
+ id: data.id, // Mapping de l'ID de la donnée source à notre format interne
460
+ name: data.fullName || data.name, // Exemple de transformation de champ
461
+ description: data.details || data.description, // Gestion des données optionnelles
462
+ createdAt: new Date(data.createdAt), // Transformation de la date
463
+ updatedAt: new Date(data.updatedAt), // Idem pour la date de mise à jour
464
+ // Vous pouvez adapter d'autres champs en fonction des exigences spécifiques
465
+ };
466
+
467
+ // Retournez les données adaptées dans un format compréhensible pour le système
468
+ return adaptedData;
469
+ }
470
+ }
471
+ `,
472
+ });
473
+ }
474
+
475
+ module.exports = generateCleanModule;
@@ -0,0 +1,31 @@
1
+ const { logInfo } = require("../../loggers/logInfo");
2
+ const { updatePrismaSchema } = require("../../setups/setupPrisma");
3
+
4
+ async function setupDatabase(config, entityData) {
5
+ logInfo("Configuring the database...");
6
+
7
+ switch (config.orm) {
8
+ case "prisma":
9
+ await updatePrismaSchema(entityData);
10
+ break;
11
+ case "typeorm":
12
+ await setupMySQL(inputs);
13
+ break;
14
+ case "mongoose":
15
+ await setupMongoDB(inputs); // MongoDB Configuration
16
+ break;
17
+ case "sqlite":
18
+ await setupSQLite(inputs); // SQLite Configuration
19
+ break;
20
+ case "firebase":
21
+ await setupFirebase(inputs); // Firebase Configuration
22
+ break;
23
+ case "redis":
24
+ await setupRedis(inputs); // Redis Configuration
25
+ break;
26
+ default:
27
+ throw new Error("Unsupported database.");
28
+ }
29
+ }
30
+
31
+ module.exports = setupDatabase;
@@ -0,0 +1,78 @@
1
+ // src/utils/generators/domain/entityUpdater.js
2
+ const { updateFile, capitalize } = require("../../userInput");
3
+ const fs = require("fs");
4
+
5
+ async function updateExistingEntityRelation(
6
+ targetName,
7
+ newEntityName,
8
+ relationType,
9
+ mode,
10
+ ) {
11
+ const targetLow = targetName.toLowerCase();
12
+ const newCap = capitalize(newEntityName);
13
+ const newLow = newEntityName.toLowerCase();
14
+
15
+ const entityPath =
16
+ mode === "full"
17
+ ? `src/${targetLow}/domain/entities/${targetLow}.entity.ts`
18
+ : `src/${targetLow}/entities/${targetLow}.entity.ts`;
19
+
20
+ if (!fs.existsSync(entityPath)) return;
21
+
22
+ // Déterminer le champ à ajouter selon la relation
23
+ let fieldToAdd = "";
24
+ let typeToAdd = "";
25
+
26
+ switch (relationType) {
27
+ case "n-1": // L'inverse d'un n-1 est un 1-n (donc une liste)
28
+ /* fieldToAdd = `${newLow}s`;
29
+ typeToAdd = `${newCap}Entity[]`; */
30
+ break;
31
+ case "1-n": // L'inverse d'un 1-n est un n-1 (donc un ID ou l'objet)
32
+ fieldToAdd = `${newLow}Id`;
33
+ typeToAdd = `string`;
34
+ break;
35
+ case "1-1":
36
+ fieldToAdd = `${newLow}Id`;
37
+ typeToAdd = `string`;
38
+ break;
39
+ case "n-n":
40
+ /* fieldToAdd = `${newLow}s`;
41
+ typeToAdd = `${newCap}Entity[]`; */
42
+ break;
43
+ }
44
+
45
+ // 1. Ajouter l'import de la nouvelle entité au début du fichier (si c'est un type complexe)
46
+ if (typeToAdd.includes("Entity")) {
47
+ const importLine = `import { ${newCap}Entity } from 'src/${newLow}/domain/entities/${newLow}.entity';\n`;
48
+ await updateFile({
49
+ path: entityPath,
50
+ pattern: /^/, // Début du fichier
51
+ replacement: importLine,
52
+ });
53
+ }
54
+
55
+ // 2. Injecter dans le constructeur (avant la parenthèse fermante)
56
+ await updateFile({
57
+ path: entityPath,
58
+ pattern: /(constructor\([\s\S]*?)\n\s+\)/m,
59
+ replacement: `$1\n private readonly ${fieldToAdd}?: ${typeToAdd}, \n )`,
60
+ });
61
+
62
+ // 3. Injecter le Getter (avant la méthode toJSON)
63
+ const getterMethod = `\n get${capitalize(fieldToAdd)}(): ${typeToAdd} | undefined {\n return this.${fieldToAdd};\n }\n`;
64
+ await updateFile({
65
+ path: entityPath,
66
+ pattern: /toJSON\(\)/,
67
+ replacement: `${getterMethod}\n toJSON()`,
68
+ });
69
+
70
+ // 4. Injecter dans toJSON
71
+ await updateFile({
72
+ path: entityPath,
73
+ pattern: /(toJSON\(\) \{[\s\S]*?return \{[\s\S]*?)\n\s+\};/m,
74
+ replacement: `$1\n ${fieldToAdd}: this.${fieldToAdd},}`,
75
+ });
76
+ }
77
+
78
+ module.exports = { updateExistingEntityRelation };