nestcraftx 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/bin/nestcraft.js +24 -0
- package/commands/start.js +8 -0
- package/nestcraft-0.1.0.tgz +0 -0
- package/package.json +31 -0
- package/readme +181 -0
- package/setup.js +33 -0
- package/unutils.txt +173 -0
- package/utils/configs/configureDocker.js +16 -0
- package/utils/configs/setupCleanArchitecture.js +579 -0
- package/utils/loggers/logError.js +5 -0
- package/utils/loggers/logInfo.js +4 -0
- package/utils/loggers/logSuccess.js +4 -0
- package/utils/setups/orms/typeOrmSetup.js +120 -0
- package/utils/setups/projectSetup.js +29 -0
- package/utils/setups/setupAuth.js +452 -0
- package/utils/setups/setupDatabase.js +73 -0
- package/utils/setups/setupPrisma.js +226 -0
- package/utils/setups/setupSwagger.js +87 -0
- package/utils/shell.js +19 -0
- package/utils/userInput.js +517 -0
- package/utils/utils.js +723 -0
|
@@ -0,0 +1,579 @@
|
|
|
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
|
+
} = require("../utils");
|
|
17
|
+
|
|
18
|
+
async function setupCleanArchitecture(inputs) {
|
|
19
|
+
logInfo("Génération de la structure Clean Architecture");
|
|
20
|
+
// log("inputs entitiesData: ", inputs.entitiesData.entities);
|
|
21
|
+
|
|
22
|
+
const entitiesData = inputs.entitiesData;
|
|
23
|
+
const dbConfig = inputs.dbConfig;
|
|
24
|
+
|
|
25
|
+
const srcPath = "src";
|
|
26
|
+
const baseFolders = [
|
|
27
|
+
"application/use-cases",
|
|
28
|
+
"application/dtos",
|
|
29
|
+
"application/interfaces",
|
|
30
|
+
"domain/entities",
|
|
31
|
+
"domain/enums",
|
|
32
|
+
"domain/mappers",
|
|
33
|
+
"infrastructure/repositories",
|
|
34
|
+
"infrastructure/services",
|
|
35
|
+
"infrastructure/adapters",
|
|
36
|
+
"presentation/controllers",
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
// modifier app module pour exporter configService globalement
|
|
41
|
+
const appModuleTsPath = "src/app.module.ts";
|
|
42
|
+
// let mainTs = fs.readFileSync(mainTsPath, "utf8");
|
|
43
|
+
|
|
44
|
+
/* await createDirectory("src");
|
|
45
|
+
await createFile({
|
|
46
|
+
path: appModuleTsPath,
|
|
47
|
+
contente: `import { Module } from '@nestjs/common';
|
|
48
|
+
@Module({
|
|
49
|
+
imports: [],
|
|
50
|
+
controllers: [],
|
|
51
|
+
providers: [],
|
|
52
|
+
})
|
|
53
|
+
export class AppModule {}`,
|
|
54
|
+
}); */
|
|
55
|
+
|
|
56
|
+
// ajouter l'import configModule
|
|
57
|
+
await updateFile({
|
|
58
|
+
path: "src/app.module.ts",
|
|
59
|
+
pattern: "import { Module } from '@nestjs/common';",
|
|
60
|
+
replacement: `import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';`,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// configurer configservice
|
|
64
|
+
await updateFile({
|
|
65
|
+
path: "src/app.module.ts",
|
|
66
|
+
pattern: "imports: [",
|
|
67
|
+
replacement: `imports: [
|
|
68
|
+
ConfigModule.forRoot({
|
|
69
|
+
isGlobal: true, // Rendre ConfigModule accessible globalement
|
|
70
|
+
envFilePath: '.env', // Charger les variables d'environnement
|
|
71
|
+
}),`,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
for (const entity of entitiesData.entities) {
|
|
75
|
+
const entityNameCapitalized = capitalize(entity.name);
|
|
76
|
+
const entityNameLower = decapitalize(entity.name);
|
|
77
|
+
|
|
78
|
+
const entityPath = `${srcPath}/${entityNameLower}`;
|
|
79
|
+
|
|
80
|
+
for (const folder of baseFolders) {
|
|
81
|
+
await createDirectory(`${entityPath}/${folder}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 📌 1. Entité
|
|
85
|
+
const entityContent = await generateEntityFileContent(entity);
|
|
86
|
+
await createFile({
|
|
87
|
+
path: `${entityPath}/domain/entities/${entityNameLower}.entity.ts`,
|
|
88
|
+
contente: entityContent,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// 📌 2. Interface Repository
|
|
92
|
+
await createFile({
|
|
93
|
+
path: `${entityPath}/application/interfaces/${entityNameLower}.repository.interface.ts`,
|
|
94
|
+
contente: `import { Create${entityNameCapitalized}Dto, Update${entityNameCapitalized}Dto } from 'src/${entityNameLower}/application/dtos/${entityNameLower}.dto';
|
|
95
|
+
import { ${entityNameCapitalized}Entity } from 'src/${entityNameLower}/domain/entities/${entityNameLower}.entity';
|
|
96
|
+
|
|
97
|
+
export interface I${entityNameCapitalized}Repository {
|
|
98
|
+
create(data: Create${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity>;
|
|
99
|
+
findById(id: string): Promise<${entityNameCapitalized}Entity | null>;
|
|
100
|
+
findAll(): Promise<${entityNameCapitalized}Entity[]>;
|
|
101
|
+
update(id: string, data: Update${entityNameCapitalized}Dto): Promise<${entityNameCapitalized}Entity | null>;
|
|
102
|
+
delete(id: string): Promise<void>;
|
|
103
|
+
}`,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// 📌 3. Repository Implémentation
|
|
107
|
+
await generateRepository(entity.name, dbConfig.orm);
|
|
108
|
+
/* await createFile({
|
|
109
|
+
path: `${entityPath}/infrastructure/repositories/${entityNameLower}.repository.ts`,
|
|
110
|
+
contente: repositoryContent,
|
|
111
|
+
}); */
|
|
112
|
+
|
|
113
|
+
// 📌 4. Use Cases
|
|
114
|
+
const useCases = ["Create", "GetById", "GetAll", "Update", "Delete"];
|
|
115
|
+
useCases.forEach(async (useCase) => {
|
|
116
|
+
let content = "";
|
|
117
|
+
|
|
118
|
+
switch (useCase) {
|
|
119
|
+
case "Create":
|
|
120
|
+
content = `/**
|
|
121
|
+
* Use Case pour créer un ${capitalize(entity.name)}.
|
|
122
|
+
*/
|
|
123
|
+
import { Inject } from '@nestjs/common';
|
|
124
|
+
import { Create${capitalize(entity.name)}Dto } from 'src/${
|
|
125
|
+
entity.name
|
|
126
|
+
}/application/dtos/${entity.name}.dto';
|
|
127
|
+
import { I${capitalize(entity.name)}Repository } from 'src/${
|
|
128
|
+
entity.name
|
|
129
|
+
}/application/interfaces/${entity.name}.repository.interface';
|
|
130
|
+
|
|
131
|
+
export class ${useCase}${capitalize(entity.name)}UseCase {
|
|
132
|
+
constructor(
|
|
133
|
+
@Inject("I${capitalize(entity.name)}Repository")
|
|
134
|
+
private readonly ${decapitalize(entity.name)}Repository: I${capitalize(
|
|
135
|
+
entity.name
|
|
136
|
+
)}Repository,
|
|
137
|
+
) {}
|
|
138
|
+
|
|
139
|
+
execute(data: Create${capitalize(entity.name)}Dto) {
|
|
140
|
+
return this.${decapitalize(entity.name)}Repository.create(data);
|
|
141
|
+
}
|
|
142
|
+
}`;
|
|
143
|
+
break;
|
|
144
|
+
|
|
145
|
+
case "GetById":
|
|
146
|
+
content = `/**
|
|
147
|
+
* Use Case pour récupérer un ${capitalize(entity.name)} par son ID.
|
|
148
|
+
*/
|
|
149
|
+
import { Inject } from '@nestjs/common';
|
|
150
|
+
import { I${capitalize(entity.name)}Repository } from 'src/${
|
|
151
|
+
entity.name
|
|
152
|
+
}/application/interfaces/${entity.name}.repository.interface';
|
|
153
|
+
|
|
154
|
+
export class ${useCase}${capitalize(entity.name)}UseCase {
|
|
155
|
+
constructor(
|
|
156
|
+
@Inject("I${capitalize(entity.name)}Repository")
|
|
157
|
+
private readonly ${decapitalize(entity.name)}Repository: I${capitalize(
|
|
158
|
+
entity.name
|
|
159
|
+
)}Repository,
|
|
160
|
+
) {}
|
|
161
|
+
|
|
162
|
+
execute(id: string) {
|
|
163
|
+
return this.${decapitalize(entity.name)}Repository.findById(id);
|
|
164
|
+
}
|
|
165
|
+
}`;
|
|
166
|
+
break;
|
|
167
|
+
|
|
168
|
+
case "GetAll":
|
|
169
|
+
content = `/**
|
|
170
|
+
* Use Case pour récupérer tous les ${capitalize(entity.name)}s.
|
|
171
|
+
*/
|
|
172
|
+
import { Inject } from '@nestjs/common';
|
|
173
|
+
import { I${capitalize(entity.name)}Repository } from 'src/${
|
|
174
|
+
entity.name
|
|
175
|
+
}/application/interfaces/${entity.name}.repository.interface';
|
|
176
|
+
|
|
177
|
+
export class ${useCase}${capitalize(entity.name)}UseCase {
|
|
178
|
+
constructor(
|
|
179
|
+
@Inject("I${capitalize(entity.name)}Repository")
|
|
180
|
+
private readonly ${decapitalize(entity.name)}Repository: I${capitalize(
|
|
181
|
+
entity.name
|
|
182
|
+
)}Repository,
|
|
183
|
+
) {}
|
|
184
|
+
|
|
185
|
+
execute() {
|
|
186
|
+
return this.${decapitalize(entity.name)}Repository.findAll();
|
|
187
|
+
}
|
|
188
|
+
}`;
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
case "Update":
|
|
192
|
+
content = `/**
|
|
193
|
+
* Use Case pour mettre à jour un ${capitalize(entity.name)} existant.
|
|
194
|
+
*/
|
|
195
|
+
import { Inject } from '@nestjs/common';
|
|
196
|
+
import { Update${capitalize(entity.name)}Dto } from 'src/${
|
|
197
|
+
entity.name
|
|
198
|
+
}/application/dtos/${entity.name}.dto';
|
|
199
|
+
import { I${capitalize(entity.name)}Repository } from 'src/${
|
|
200
|
+
entity.name
|
|
201
|
+
}/application/interfaces/${entity.name}.repository.interface';
|
|
202
|
+
|
|
203
|
+
export class ${useCase}${capitalize(entity.name)}UseCase {
|
|
204
|
+
constructor(
|
|
205
|
+
@Inject("I${capitalize(entity.name)}Repository")
|
|
206
|
+
private readonly ${decapitalize(entity.name)}Repository: I${capitalize(
|
|
207
|
+
entity.name
|
|
208
|
+
)}Repository,
|
|
209
|
+
) {}
|
|
210
|
+
|
|
211
|
+
execute(id: string, data: Update${capitalize(entity.name)}Dto) {
|
|
212
|
+
return this.${decapitalize(entity.name)}Repository.update(id, data);
|
|
213
|
+
}
|
|
214
|
+
}`;
|
|
215
|
+
break;
|
|
216
|
+
|
|
217
|
+
case "Delete":
|
|
218
|
+
content = `/**
|
|
219
|
+
* Use Case pour supprimer un ${capitalize(entity.name)}.
|
|
220
|
+
*/
|
|
221
|
+
import { Inject } from '@nestjs/common';
|
|
222
|
+
import { I${capitalize(entity.name)}Repository } from 'src/${
|
|
223
|
+
entity.name
|
|
224
|
+
}/application/interfaces/${entity.name}.repository.interface';
|
|
225
|
+
|
|
226
|
+
export class ${useCase}${capitalize(entity.name)}UseCase {
|
|
227
|
+
constructor(
|
|
228
|
+
@Inject("I${capitalize(entity.name)}Repository")
|
|
229
|
+
private readonly ${decapitalize(entity.name)}Repository: I${capitalize(
|
|
230
|
+
entity.name
|
|
231
|
+
)}Repository,
|
|
232
|
+
) {}
|
|
233
|
+
|
|
234
|
+
execute(id: string) {
|
|
235
|
+
return this.${decapitalize(entity.name)}Repository.delete(id);
|
|
236
|
+
}
|
|
237
|
+
}`;
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
await createFile({
|
|
242
|
+
path: `${entityPath}/application/use-cases/${decapitalize(useCase)}-${
|
|
243
|
+
entity.name
|
|
244
|
+
}.use-case.ts`,
|
|
245
|
+
contente: content.trim(),
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// 📌 5. DTOs
|
|
250
|
+
const DtoFileContent = await generateDto(entity);
|
|
251
|
+
await createFile({
|
|
252
|
+
path: `${entityPath}/application/dtos/${entity.name}.dto.ts`,
|
|
253
|
+
contente: DtoFileContent,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// 📌 6. Enums
|
|
257
|
+
await createFile({
|
|
258
|
+
path: `${entityPath}/domain/enums/${entityNameLower}.enum.ts`,
|
|
259
|
+
contente: `// Enumération des différents états possibles pour ${entityNameCapitalized}
|
|
260
|
+
export enum ${entityNameCapitalized}Enum {
|
|
261
|
+
// Décommentez et ajustez les valeurs de l'énumération selon les besoins de votre entité.
|
|
262
|
+
// Exemple :
|
|
263
|
+
// ACTIVE = 'ACTIVE', // Représente l'état actif de l'entité
|
|
264
|
+
// INACTIVE = 'INACTIVE', // Représente l'état inactif de l'entité
|
|
265
|
+
// Vous pouvez ajouter d'autres états si nécessaire, comme 'PENDING', 'ARCHIVED', etc.
|
|
266
|
+
}
|
|
267
|
+
`,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
if (entity.name.toLowerCase() === "user") {
|
|
271
|
+
await createFile({
|
|
272
|
+
path: `${entityPath}/domain/enums/role.enum.ts`,
|
|
273
|
+
contente: `// Enumération des rôles utilisateurs
|
|
274
|
+
export enum Role {
|
|
275
|
+
USER = 'USER',
|
|
276
|
+
ADMIN = 'ADMIN',
|
|
277
|
+
SUPER_ADMIN = 'SUPER_ADMIN',
|
|
278
|
+
}
|
|
279
|
+
`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// 📌 7. Mapper
|
|
284
|
+
const mapperFileContent = await generateMapper(entity);
|
|
285
|
+
await createFile({
|
|
286
|
+
path: `${entityPath}/domain/mappers/${entity.name}.mapper.ts`,
|
|
287
|
+
contente: mapperFileContent,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// 📌 8. Service
|
|
291
|
+
await createFile({
|
|
292
|
+
path: `${entityPath}/infrastructure/services/${entityNameLower}.service.ts`,
|
|
293
|
+
contente: `
|
|
294
|
+
// Le service est responsable de la logique métier de l'application. Il agit comme un orchestrateur entre
|
|
295
|
+
// différents composants tels que les repositories, les use cases et les adaptateurs.
|
|
296
|
+
|
|
297
|
+
import { Inject } from '@nestjs/common';
|
|
298
|
+
import { I${entityNameCapitalized}Repository } from 'src/${entityNameLower}/application/interfaces/${entityNameLower}.repository.interface';
|
|
299
|
+
|
|
300
|
+
export class ${entityNameCapitalized}Service {
|
|
301
|
+
constructor(
|
|
302
|
+
@Inject("I${entityNameCapitalized}Repository")
|
|
303
|
+
private readonly repository: I${entityNameCapitalized}Repository,
|
|
304
|
+
) {}
|
|
305
|
+
|
|
306
|
+
// La méthode 'process' prend en charge la logique pour traiter les données.
|
|
307
|
+
async process(data: any) {
|
|
308
|
+
if (!data || !data.id) {
|
|
309
|
+
throw new Error('Données invalides, ID requis');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const entityFromDb = await this.repository.findById(data.id);
|
|
313
|
+
|
|
314
|
+
if (!entityFromDb) {
|
|
315
|
+
throw new Error('Entité non trouvée avec cet ID');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const processedData = {
|
|
319
|
+
...entityFromDb,
|
|
320
|
+
updatedAt: new Date(),
|
|
321
|
+
processedBy: 'System',
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
return processedData;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Vous pouvez ajouter d'autres méthodes métier ici si nécessaire.
|
|
328
|
+
async create(data: any) {
|
|
329
|
+
// Logique pour créer une nouvelle entité
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async update(id: string, data: any) {
|
|
333
|
+
// Logique pour mettre à jour une entité existante
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
async delete(id: string) {
|
|
337
|
+
// Logique pour supprimer une entité
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
`,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// 📌 9. Adapter
|
|
344
|
+
await createFile({
|
|
345
|
+
path: `${entityPath}/infrastructure/adapters/${entityNameLower}.adapter.ts`,
|
|
346
|
+
contente: `
|
|
347
|
+
// L'adaptateur permet de transformer ou d'adapter les données d'un format source vers un format cible.
|
|
348
|
+
// Cela est particulièrement utile lorsque nous devons interagir avec des API externes ou des services ayant des structures de données différentes.
|
|
349
|
+
|
|
350
|
+
export class ${entityNameCapitalized}Adapter {
|
|
351
|
+
// La méthode 'adapt' prend des données brutes d'un format spécifique et les transforme
|
|
352
|
+
// en un format qui est attendu par le système de notre domaine.
|
|
353
|
+
adapt(data: any) {
|
|
354
|
+
// Exemple d'adaptation des données - ceci est un exemple générique.
|
|
355
|
+
// Nous transformons les données pour que le format interne du système soit respecté.
|
|
356
|
+
|
|
357
|
+
const adaptedData = {
|
|
358
|
+
// Assurez-vous que vous mappez les propriétés nécessaires et les transformez.
|
|
359
|
+
id: data.id, // Mapping de l'ID de la donnée source à notre format interne
|
|
360
|
+
name: data.fullName || data.name, // Exemple de transformation de champ
|
|
361
|
+
description: data.details || data.description, // Gestion des données optionnelles
|
|
362
|
+
createdAt: new Date(data.createdAt), // Transformation de la date
|
|
363
|
+
updatedAt: new Date(data.updatedAt), // Idem pour la date de mise à jour
|
|
364
|
+
// Vous pouvez adapter d'autres champs en fonction des exigences spécifiques
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// Retournez les données adaptées dans un format compréhensible pour le système
|
|
368
|
+
return adaptedData;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
`,
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// 📌 10. Controller
|
|
375
|
+
await createFile({
|
|
376
|
+
path: `${entityPath}/presentation/controllers/${entityNameLower}.controller.ts`,
|
|
377
|
+
contente: `
|
|
378
|
+
/**
|
|
379
|
+
* ${entityNameCapitalized}Controller gère les endpoints de l'API pour l'entité ${entityNameCapitalized}.
|
|
380
|
+
* Il utilise les cas d'utilisation (Use Cases) pour orchestrer les différentes actions métiers liées à l'entité.
|
|
381
|
+
* Ce contrôleur est responsable des actions HTTP telles que la création, la mise à jour, la récupération, et la suppression de ${entityNameCapitalized}.
|
|
382
|
+
*/
|
|
383
|
+
|
|
384
|
+
import { Controller, Get, Post, Body, Param, Put, Delete, Injectable } from "@nestjs/common";
|
|
385
|
+
import { ApiTags, ApiOperation } from '@nestjs/swagger';
|
|
386
|
+
// Importation des cas d'utilisation (Use Cases) spécifiques à ${entityNameCapitalized}
|
|
387
|
+
import { Create${entityNameCapitalized}UseCase } from "${entityPath}/application/use-cases/create-${entityNameLower}.use-case";
|
|
388
|
+
import { Update${entityNameCapitalized}UseCase } from "${entityPath}/application/use-cases/update-${entityNameLower}.use-case";
|
|
389
|
+
import { GetById${entityNameCapitalized}UseCase } from "${entityPath}/application/use-cases/getById-${entityNameLower}.use-case";
|
|
390
|
+
import { GetAll${entityNameCapitalized}UseCase } from "${entityPath}/application/use-cases/getAll-${entityNameLower}.use-case";
|
|
391
|
+
import { Delete${entityNameCapitalized}UseCase } from "${entityPath}/application/use-cases/delete-${entityNameLower}.use-case";
|
|
392
|
+
// Importation des DTOs pour la validation et la transformation des données entrantes
|
|
393
|
+
import { Create${entityNameCapitalized}Dto, Update${entityNameCapitalized}Dto } from 'src/${entityNameLower}/application/dtos/${entityNameLower}.dto';
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Le contrôleur est annoté avec @ApiTags pour la documentation Swagger.
|
|
397
|
+
* Il regroupe les opérations HTTP relatives à l'entité ${entityNameCapitalized}.
|
|
398
|
+
*/
|
|
399
|
+
@Injectable()
|
|
400
|
+
@ApiTags('${entityNameCapitalized}')
|
|
401
|
+
@Controller('${entityNameLower}')
|
|
402
|
+
export class ${entityNameCapitalized}Controller {
|
|
403
|
+
constructor(
|
|
404
|
+
private readonly createUseCase: Create${entityNameCapitalized}UseCase,
|
|
405
|
+
private readonly updateUseCase: Update${entityNameCapitalized}UseCase,
|
|
406
|
+
private readonly getByIdUseCase: GetById${entityNameCapitalized}UseCase,
|
|
407
|
+
private readonly getAllUseCase: GetAll${entityNameCapitalized}UseCase,
|
|
408
|
+
private readonly deleteUseCase: Delete${entityNameCapitalized}UseCase,
|
|
409
|
+
) {}
|
|
410
|
+
|
|
411
|
+
// 📌 Créer un ${entityNameLower}
|
|
412
|
+
@Post()
|
|
413
|
+
@ApiOperation({ summary: 'Create a new ${entityNameLower}' })
|
|
414
|
+
async create${entityNameCapitalized}(
|
|
415
|
+
@Body() create${entityNameCapitalized}Dto: Create${entityNameCapitalized}Dto,
|
|
416
|
+
) {
|
|
417
|
+
return this.createUseCase.execute(create${entityNameCapitalized}Dto);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 📌 Mettre à jour un ${entityNameLower}
|
|
421
|
+
@Put(':id')
|
|
422
|
+
@ApiOperation({ summary: 'Update a ${entityNameLower}' })
|
|
423
|
+
async update${entityNameCapitalized}(
|
|
424
|
+
@Param('id') id: string,
|
|
425
|
+
@Body() update${entityNameCapitalized}Dto: Update${entityNameCapitalized}Dto,
|
|
426
|
+
) {
|
|
427
|
+
return this.updateUseCase.execute(id, update${entityNameCapitalized}Dto);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// 📌 Récupérer un ${entityNameLower} par ID
|
|
431
|
+
@Get(':id')
|
|
432
|
+
@ApiOperation({ summary: 'Get a ${entityNameLower} by ID' })
|
|
433
|
+
async getById${entityNameCapitalized}(@Param('id') id: string) {
|
|
434
|
+
return this.getByIdUseCase.execute(id);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// 📌 Récupérer tous les ${entityNameLower}s
|
|
438
|
+
@Get()
|
|
439
|
+
@ApiOperation({ summary: 'Get all ${entityNameLower}s' })
|
|
440
|
+
async getAll${entityNameCapitalized}() {
|
|
441
|
+
return this.getAllUseCase.execute();
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// 📌 Supprimer un ${entityNameLower}
|
|
445
|
+
@Delete(':id')
|
|
446
|
+
@ApiOperation({ summary: 'Delete a ${entityNameLower} by ID' })
|
|
447
|
+
async delete${entityNameCapitalized}(@Param('id') id: string) {
|
|
448
|
+
return this.deleteUseCase.execute(id);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
`,
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// 📌 11. Module
|
|
455
|
+
let Import = "";
|
|
456
|
+
let prismaProvider = "";
|
|
457
|
+
let importTormM = `imports: [
|
|
458
|
+
TypeOrmModule.forFeature([${entityNameCapitalized}]), // Injection de l'entité
|
|
459
|
+
],`;
|
|
460
|
+
|
|
461
|
+
if (dbConfig.orm === "prisma") {
|
|
462
|
+
prismaImport = `import { PrismaService } from 'src/prisma/prisma.service';`;
|
|
463
|
+
prismaProvider = ` PrismaService,`;
|
|
464
|
+
} else if (dbConfig.orm === "typeorm") {
|
|
465
|
+
Import = `import { ${entityNameCapitalized} } from 'src/entities/${entityNameCapitalized}.entity';`;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
await createFile({
|
|
469
|
+
path: `${entityPath}/${entityNameLower}.module.ts`,
|
|
470
|
+
contente: `
|
|
471
|
+
/**
|
|
472
|
+
* ${entityNameCapitalized}Module est le module principal qui gère l'entité ${entityNameCapitalized}.
|
|
473
|
+
* Il regroupe tous les composants nécessaires pour traiter cette entité :
|
|
474
|
+
* - Contrôleur
|
|
475
|
+
* - Répository
|
|
476
|
+
* - Use Cases
|
|
477
|
+
* - Mapper
|
|
478
|
+
*/
|
|
479
|
+
import { Module } from '@nestjs/common';
|
|
480
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
481
|
+
import { ${entityNameCapitalized}Controller } from '${entityPath}/presentation/controllers/${entityNameLower}.controller';
|
|
482
|
+
import { ${entityNameCapitalized}Repository } from '${entityPath}/infrastructure/repositories/${entityNameLower}.repository';
|
|
483
|
+
import { Create${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/create-${entityNameLower}.use-case';
|
|
484
|
+
import { Update${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/update-${entityNameLower}.use-case';
|
|
485
|
+
import { GetById${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/getById-${entityNameLower}.use-case';
|
|
486
|
+
import { GetAll${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/getAll-${entityNameLower}.use-case';
|
|
487
|
+
import { Delete${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/delete-${entityNameLower}.use-case';
|
|
488
|
+
import { ${entityNameCapitalized}Mapper } from '${entityPath}/domain/mappers/${entityNameLower}.mapper';
|
|
489
|
+
${Import}
|
|
490
|
+
|
|
491
|
+
@Module({
|
|
492
|
+
|
|
493
|
+
${importTormM}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Déclare le contrôleur qui gère les requêtes HTTP relatives à ${entityNameCapitalized}.
|
|
497
|
+
* Ce contrôleur contient les actions d'API pour manipuler l'entité ${entityNameCapitalized}.
|
|
498
|
+
*/
|
|
499
|
+
controllers: [${entityNameCapitalized}Controller],
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Liste des providers nécessaires à la gestion de ${entityNameCapitalized}.
|
|
503
|
+
* Cela inclut :
|
|
504
|
+
* - Repository : Fournisseur pour accéder aux données de ${entityNameCapitalized}.
|
|
505
|
+
* - Use Cases : Logique métier pour la gestion de ${entityNameCapitalized}.
|
|
506
|
+
* - Mapper : Permet la transformation entre les DTOs et les entités.
|
|
507
|
+
*/
|
|
508
|
+
providers: [
|
|
509
|
+
${prismaProvider}
|
|
510
|
+
|
|
511
|
+
// Repository : Permet d'interagir avec la base de données
|
|
512
|
+
{
|
|
513
|
+
provide: 'I${entityNameCapitalized}Repository', // Interface du repository
|
|
514
|
+
useClass: ${entityNameCapitalized}Repository, // Classe qui implémente l'interface
|
|
515
|
+
},
|
|
516
|
+
${entityNameCapitalized}Repository, // Fournisseur pour l'accès aux données
|
|
517
|
+
|
|
518
|
+
// Use Cases : Logique métier pour la gestion de ${entityNameCapitalized}
|
|
519
|
+
Create${entityNameCapitalized}UseCase, // Use Case pour créer un ${entityNameLower}
|
|
520
|
+
Update${entityNameCapitalized}UseCase, // Use Case pour mettre à jour un ${entityNameLower}
|
|
521
|
+
GetById${entityNameCapitalized}UseCase, // Use Case pour récupérer un ${entityNameLower} par son ID
|
|
522
|
+
GetAll${entityNameCapitalized}UseCase, // Use Case pour récupérer tous les ${entityNameLower}s
|
|
523
|
+
Delete${entityNameCapitalized}UseCase, // Use Case pour supprimer un ${entityNameLower}
|
|
524
|
+
|
|
525
|
+
// Mapper : Convertit entre les entités et les DTOs
|
|
526
|
+
${entityNameCapitalized}Mapper, // Mapper pour la transformation des données
|
|
527
|
+
],
|
|
528
|
+
})
|
|
529
|
+
/**
|
|
530
|
+
* Le module ${entityNameCapitalized} est une unité logique regroupant toutes les dépendances nécessaires
|
|
531
|
+
* pour le bon fonctionnement de l'entité ${entityNameCapitalized}.
|
|
532
|
+
* Il gère l'injection des services, les actions métier, ainsi que la transformation des données.
|
|
533
|
+
*/
|
|
534
|
+
export class ${entityNameCapitalized}Module {}
|
|
535
|
+
`.trim(),
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
await safeUpdateAppModule(entityNameLower);
|
|
539
|
+
}
|
|
540
|
+
await generateMiddlewares();
|
|
541
|
+
|
|
542
|
+
// modification de AppModule
|
|
543
|
+
const appModulePath = "src/app.module.ts";
|
|
544
|
+
|
|
545
|
+
// Étape 1 : Ajouter les imports nécessaires
|
|
546
|
+
await updateFile({
|
|
547
|
+
path: appModulePath,
|
|
548
|
+
pattern: `import { Module } from '@nestjs/common';`,
|
|
549
|
+
replacement: `import { Module } from '@nestjs/common';
|
|
550
|
+
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
|
|
551
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';`,
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
// Étape 2 : Ajouter le provider APP_INTERCEPTOR dans providers[]
|
|
555
|
+
await updateFile({
|
|
556
|
+
path: appModulePath,
|
|
557
|
+
pattern: `providers: \\[`,
|
|
558
|
+
replacement: `providers: [
|
|
559
|
+
{
|
|
560
|
+
provide: APP_INTERCEPTOR,
|
|
561
|
+
useClass: ResponseInterceptor,
|
|
562
|
+
},`,
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
logSuccess("structure Clean Architecture générée avec succès !");
|
|
566
|
+
} catch (error) {
|
|
567
|
+
logError(`process currency have error: ${error}`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function capitalize(str) {
|
|
572
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function decapitalize(str) {
|
|
576
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
module.exports = { setupCleanArchitecture };
|