nestcraftx 0.2.5 → 0.3.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.
Files changed (56) hide show
  1. package/AUDIT_ROADMAP.md +798 -0
  2. package/CHANGELOG.fr.md +22 -0
  3. package/CHANGELOG.md +22 -0
  4. package/CLI_USAGE.fr.md +331 -331
  5. package/CLI_USAGE.md +364 -364
  6. package/LICENSE +21 -21
  7. package/PROGRESS.md +258 -0
  8. package/bin/nestcraft.js +84 -64
  9. package/commands/demo.js +337 -330
  10. package/commands/generate.js +94 -0
  11. package/commands/generateConf.js +91 -0
  12. package/commands/help.js +29 -2
  13. package/commands/info.js +48 -48
  14. package/commands/new.js +340 -335
  15. package/commands/start.js +19 -19
  16. package/commands/test.js +7 -7
  17. package/package.json +1 -1
  18. package/utils/app-module.updater.js +96 -0
  19. package/utils/cliParser.js +88 -76
  20. package/utils/colors.js +62 -62
  21. package/utils/configs/configureDocker.js +120 -120
  22. package/utils/configs/setupCleanArchitecture.js +17 -15
  23. package/utils/configs/setupLightArchitecture.js +15 -9
  24. package/utils/file-system.js +75 -0
  25. package/utils/file-utils/saveProjectConfig.js +36 -0
  26. package/utils/fullModeInput.js +607 -607
  27. package/utils/generators/application/dtoGenerator.js +251 -0
  28. package/utils/generators/application/dtoUpdater.js +54 -0
  29. package/utils/generators/cleanModuleGenerator.js +475 -0
  30. package/utils/generators/database/setupDatabase.js +49 -0
  31. package/utils/generators/domain/entityGenerator.js +126 -0
  32. package/utils/generators/domain/entityUpdater.js +78 -0
  33. package/utils/generators/infrastructure/mapperGenerator.js +114 -0
  34. package/utils/generators/infrastructure/mapperUpdater.js +65 -0
  35. package/utils/generators/infrastructure/middlewareGenerator.js +645 -0
  36. package/utils/generators/infrastructure/mongooseSchemaGenerator.js +196 -0
  37. package/utils/generators/infrastructure/repositoryGenerator.js +334 -0
  38. package/utils/generators/lightModuleGenerator.js +131 -0
  39. package/utils/generators/presentation/controllerGenerator.js +142 -0
  40. package/utils/generators/relation/relation.engine.js +64 -0
  41. package/utils/helpers.js +109 -0
  42. package/utils/interactive/askEntityInputs.js +165 -0
  43. package/utils/loggers/logError.js +7 -7
  44. package/utils/loggers/logInfo.js +7 -7
  45. package/utils/loggers/logSuccess.js +7 -7
  46. package/utils/loggers/logWarning.js +7 -7
  47. package/utils/setups/orms/typeOrmSetup.js +630 -630
  48. package/utils/setups/setupAuth.js +33 -20
  49. package/utils/setups/setupDatabase.js +76 -75
  50. package/utils/setups/setupMongoose.js +22 -5
  51. package/utils/setups/setupPrisma.js +748 -630
  52. package/utils/shell.js +112 -32
  53. package/utils/spinner.js +57 -57
  54. package/utils/systemCheck.js +124 -124
  55. package/utils/userInput.js +357 -421
  56. package/utils/utils.js +29 -2164
@@ -1,120 +1,120 @@
1
- const fs = require("fs");
2
- const { logInfo } = require("../loggers/logInfo");
3
- const { logSuccess } = require("../loggers/logSuccess");
4
- const { createFile } = require("../userInput");
5
-
6
- async function configureDocker(inputs) {
7
- logInfo("Generating Docker files...");
8
-
9
- const dockerfileContent = `
10
- # ------------------ Stage 1: Build & Dependencies ------------------
11
- FROM node:20-alpine AS builder
12
-
13
- # Set working directory
14
- WORKDIR /app
15
-
16
- # Copy package files first to leverage Docker cache
17
- COPY package.json package-lock.json ./
18
-
19
- # Install dependencies (Node dependencies and global tools like Prisma if needed)
20
- # The 'production' flag ensures only production dependencies are installed if applicable.
21
- # 'npm ci' is recommended for CI/CD/Docker builds instead of 'npm install'
22
- RUN ${
23
- inputs.packageManager === "npm"
24
- ? "npm ci"
25
- : `${inputs.packageManager} install --frozen-lockfile`
26
- }
27
-
28
- # Copy the rest of the application source code
29
- COPY . .
30
-
31
- # Build the NestJS application (if TypeScript is used)
32
- RUN ${inputs.packageManager} run build
33
-
34
- # ------------------ Stage 2: Production Runtime ------------------
35
- FROM node:20-alpine AS production
36
-
37
- # Set working directory
38
- WORKDIR /app
39
-
40
- # Copy production node_modules from the builder stage
41
- COPY --from=builder /app/node_modules ./node_modules
42
-
43
- # Copy built application and start scripts (dist and package.json)
44
- COPY --from=builder /app/dist ./dist
45
- COPY --from=builder /app/package.json ./package.json
46
-
47
- # Expose the application port (usually 3000 for NestJS)
48
- EXPOSE 3000
49
-
50
- # Run the application using the built files (production environment)
51
- # Use 'start:prod' if available, otherwise fall back to 'start'
52
- CMD [ "${inputs.packageManager}", "run", "start:prod" ]
53
- `;
54
- await createFile({
55
- path: "Dockerfile",
56
- contente: dockerfileContent.trim(),
57
- });
58
- const dockerComposeContent = `
59
- version: '3.8'
60
-
61
- services:
62
- # Application Service (NestJS)
63
- app:
64
- build:
65
- context: .
66
- dockerfile: Dockerfile
67
- # Links the container to the internal network
68
- networks:
69
- - backend_network
70
- # Maps internal port 3000 (EXPOSE in Dockerfile) to external port 3000
71
- ports:
72
- - "3000:3000"
73
- # Mount .env file (for local dev, not recommended for prod)
74
- env_file:
75
- - .env
76
- # Restart policy
77
- restart: always
78
- # Wait for the DB to be ready (requires 'wait-for-it' or similar)
79
- depends_on:
80
- - db
81
-
82
- # Database Service (PostgreSQL - generic image for example)
83
- db:
84
- image: postgres:15-alpine
85
- container_name: ${inputs.projectName}_db
86
- networks:
87
- - backend_network
88
- environment:
89
- POSTGRES_USER: ${inputs.dbConfig.POSTGRES_USER || "postgres"}
90
- POSTGRES_PASSWORD: ${inputs.dbConfig.POSTGRES_PASSWORD || "secret"}
91
- POSTGRES_DB: ${inputs.dbConfig.POSTGRES_DB || "mydatabase"}
92
- # Optional: Set timezone
93
- TZ: Europe/Paris
94
- # For dev purposes: map DB port externally (optional)
95
- ports:
96
- - "5432:5432"
97
- # Persist database data
98
- volumes:
99
- - postgres_data:/var/lib/postgresql/data
100
- restart: always
101
-
102
- # Networks definition
103
- networks:
104
- backend_network:
105
- driver: bridge
106
-
107
- # Volumes definition
108
- volumes:
109
- postgres_data:
110
- `;
111
-
112
- await createFile({
113
- path: "docker-compose.yml",
114
- contente: dockerComposeContent.trim(),
115
- });
116
-
117
- logSuccess("Docker successfully configured with enhanced settings");
118
- }
119
-
120
- module.exports = { configureDocker };
1
+ const fs = require("fs");
2
+ const { logInfo } = require("../loggers/logInfo");
3
+ const { logSuccess } = require("../loggers/logSuccess");
4
+ const { createFile } = require("../userInput");
5
+
6
+ async function configureDocker(inputs) {
7
+ logInfo("Generating Docker files...");
8
+
9
+ const dockerfileContent = `
10
+ # ------------------ Stage 1: Build & Dependencies ------------------
11
+ FROM node:20-alpine AS builder
12
+
13
+ # Set working directory
14
+ WORKDIR /app
15
+
16
+ # Copy package files first to leverage Docker cache
17
+ COPY package.json package-lock.json ./
18
+
19
+ # Install dependencies (Node dependencies and global tools like Prisma if needed)
20
+ # The 'production' flag ensures only production dependencies are installed if applicable.
21
+ # 'npm ci' is recommended for CI/CD/Docker builds instead of 'npm install'
22
+ RUN ${
23
+ inputs.packageManager === "npm"
24
+ ? "npm ci"
25
+ : `${inputs.packageManager} install --frozen-lockfile`
26
+ }
27
+
28
+ # Copy the rest of the application source code
29
+ COPY . .
30
+
31
+ # Build the NestJS application (if TypeScript is used)
32
+ RUN ${inputs.packageManager} run build
33
+
34
+ # ------------------ Stage 2: Production Runtime ------------------
35
+ FROM node:20-alpine AS production
36
+
37
+ # Set working directory
38
+ WORKDIR /app
39
+
40
+ # Copy production node_modules from the builder stage
41
+ COPY --from=builder /app/node_modules ./node_modules
42
+
43
+ # Copy built application and start scripts (dist and package.json)
44
+ COPY --from=builder /app/dist ./dist
45
+ COPY --from=builder /app/package.json ./package.json
46
+
47
+ # Expose the application port (usually 3000 for NestJS)
48
+ EXPOSE 3000
49
+
50
+ # Run the application using the built files (production environment)
51
+ # Use 'start:prod' if available, otherwise fall back to 'start'
52
+ CMD [ "${inputs.packageManager}", "run", "start:prod" ]
53
+ `;
54
+ await createFile({
55
+ path: "Dockerfile",
56
+ contente: dockerfileContent.trim(),
57
+ });
58
+ const dockerComposeContent = `
59
+ version: '3.8'
60
+
61
+ services:
62
+ # Application Service (NestJS)
63
+ app:
64
+ build:
65
+ context: .
66
+ dockerfile: Dockerfile
67
+ # Links the container to the internal network
68
+ networks:
69
+ - backend_network
70
+ # Maps internal port 3000 (EXPOSE in Dockerfile) to external port 3000
71
+ ports:
72
+ - "3000:3000"
73
+ # Mount .env file (for local dev, not recommended for prod)
74
+ env_file:
75
+ - .env
76
+ # Restart policy
77
+ restart: always
78
+ # Wait for the DB to be ready (requires 'wait-for-it' or similar)
79
+ depends_on:
80
+ - db
81
+
82
+ # Database Service (PostgreSQL - generic image for example)
83
+ db:
84
+ image: postgres:15-alpine
85
+ container_name: ${inputs.projectName}_db
86
+ networks:
87
+ - backend_network
88
+ environment:
89
+ POSTGRES_USER: ${inputs.dbConfig.POSTGRES_USER || "postgres"}
90
+ POSTGRES_PASSWORD: ${inputs.dbConfig.POSTGRES_PASSWORD || "secret"}
91
+ POSTGRES_DB: ${inputs.dbConfig.POSTGRES_DB || "mydatabase"}
92
+ # Optional: Set timezone
93
+ TZ: Europe/Paris
94
+ # For dev purposes: map DB port externally (optional)
95
+ ports:
96
+ - "5432:5432"
97
+ # Persist database data
98
+ volumes:
99
+ - postgres_data:/var/lib/postgresql/data
100
+ restart: always
101
+
102
+ # Networks definition
103
+ networks:
104
+ backend_network:
105
+ driver: bridge
106
+
107
+ # Volumes definition
108
+ volumes:
109
+ postgres_data:
110
+ `;
111
+
112
+ await createFile({
113
+ path: "docker-compose.yml",
114
+ contente: dockerComposeContent.trim(),
115
+ });
116
+
117
+ logSuccess("Docker successfully configured with enhanced settings");
118
+ }
119
+
120
+ module.exports = { configureDocker };
@@ -79,7 +79,7 @@ async function setupCleanArchitecture(inputs) {
79
79
  const mongooseSchemaContent = await generateMongooseSchemaFileContent(
80
80
  entity,
81
81
  entitiesData,
82
- mode
82
+ mode,
83
83
  );
84
84
 
85
85
  const schemaPath = `src/${entity.name}/infrastructure/persistence/mongoose`;
@@ -128,7 +128,7 @@ async function setupCleanArchitecture(inputs) {
128
128
 
129
129
  // 4. Use Cases
130
130
  const useCases = ["Create", "GetById", "GetAll", "Update", "Delete"];
131
- useCases.forEach(async (useCase) => {
131
+ for (const useCase of useCases) {
132
132
  let content = "";
133
133
  const entityName = capitalize(entity.name);
134
134
  const entityNameLower = decapitalize(entity.name);
@@ -141,7 +141,7 @@ async function setupCleanArchitecture(inputs) {
141
141
 
142
142
  import { Inject, Logger } from '@nestjs/common';
143
143
  import { Create${entityName}Dto } from 'src/${entity.name}/application/dtos/${entity.name}.dto';
144
- import { I${entityName}RepositoryName, I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
144
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
145
145
  import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
146
146
 
147
147
  export class Create${entityName}UseCase {
@@ -168,7 +168,7 @@ export class Create${entityName}UseCase {
168
168
  */
169
169
 
170
170
  import { Inject, Logger, NotFoundException } from '@nestjs/common';
171
- import { I${entityName}RepositoryName, I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
171
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
172
172
  import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
173
173
 
174
174
  export class GetById${entityName}UseCase {
@@ -201,7 +201,7 @@ export class GetById${entityName}UseCase {
201
201
  */
202
202
 
203
203
  import { Inject, Logger } from '@nestjs/common';
204
- import { I${entityName}RepositoryName, I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
204
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
205
205
  import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
206
206
 
207
207
  export class GetAll${entityName}UseCase {
@@ -229,7 +229,7 @@ export class GetAll${entityName}UseCase {
229
229
 
230
230
  import { Inject, Logger, NotFoundException } from '@nestjs/common';
231
231
  import { Update${entityName}Dto } from 'src/${entity.name}/application/dtos/${entity.name}.dto';
232
- import { I${entityName}RepositoryName, I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
232
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
233
233
  import { ${entityName}Entity } from 'src/${entity.name}/domain/entities/${entityNameLower}.entity';
234
234
 
235
235
  export class Update${entityName}UseCase {
@@ -269,7 +269,7 @@ export class Update${entityName}UseCase {
269
269
  */
270
270
 
271
271
  import { Inject, Logger, NotFoundException } from '@nestjs/common';
272
- import { I${entityName}RepositoryName, I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
272
+ import { I${entityName}RepositoryName, type I${entityName}Repository } from 'src/${entity.name}/domain/interfaces/${entity.name}.repository.interface';
273
273
 
274
274
  export class Delete${entityName}UseCase {
275
275
  private readonly logger = new Logger(Delete${entityName}UseCase.name);
@@ -302,7 +302,7 @@ export class Delete${entityName}UseCase {
302
302
  }.use-case.ts`,
303
303
  contente: content.trim(),
304
304
  });
305
- });
305
+ }
306
306
 
307
307
  // 5. DTOs
308
308
  const DtoFileContent = await generateDto(entity, useSwagger);
@@ -419,7 +419,7 @@ export class ${entityNameCapitalized}Adapter {
419
419
  const controllerContente = await generateController(
420
420
  entity.name,
421
421
  entityPath,
422
- useSwagger
422
+ useSwagger,
423
423
  );
424
424
  await createFile({
425
425
  path: `${entityPath}/presentation/controllers/${entityNameLower}.controller.ts`,
@@ -438,13 +438,13 @@ export class ${entityNameCapitalized}Adapter {
438
438
  } else if (dbConfig.orm === "typeorm") {
439
439
  extraImports = `import { ${entityNameCapitalized} } from 'src/entities/${entityNameCapitalized}.entity';\nimport { TypeOrmModule } from '@nestjs/typeorm';`;
440
440
  importsBlock.push(
441
- `TypeOrmModule.forFeature([${entityNameCapitalized}])`
441
+ `TypeOrmModule.forFeature([${entityNameCapitalized}])`,
442
442
  );
443
443
  } else if (dbConfig.orm === "mongoose") {
444
444
  extraImports = `import { MongooseModule } from '@nestjs/mongoose';
445
445
  import { ${entityNameCapitalized}, ${entityNameCapitalized}Schema } from '${entityPath}/infrastructure/persistence/mongoose/${entityNameLower}.schema';`;
446
446
  importsBlock.push(
447
- `MongooseModule.forFeature([{ name: ${entityNameCapitalized}.name, schema: ${entityNameCapitalized}Schema }])`
447
+ `MongooseModule.forFeature([{ name: ${entityNameCapitalized}.name, schema: ${entityNameCapitalized}Schema }])`,
448
448
  );
449
449
  }
450
450
 
@@ -460,7 +460,7 @@ import { ${entityNameCapitalized}, ${entityNameCapitalized}Schema } from '${enti
460
460
  // Always necessary providers
461
461
  providersBlock.push(
462
462
  `{
463
- provide: 'I${entityNameCapitalized}Repository',
463
+ provide: I${entityNameCapitalized}RepositoryName,
464
464
  useClass: ${entityNameCapitalized}Repository,
465
465
  }`,
466
466
  `${entityNameCapitalized}Service`,
@@ -469,7 +469,7 @@ import { ${entityNameCapitalized}, ${entityNameCapitalized}Schema } from '${enti
469
469
  `GetById${entityNameCapitalized}UseCase`,
470
470
  `GetAll${entityNameCapitalized}UseCase`,
471
471
  `Delete${entityNameCapitalized}UseCase`,
472
- `${entityNameCapitalized}Mapper`
472
+ `${entityNameCapitalized}Mapper`,
473
473
  );
474
474
 
475
475
  await createFile({
@@ -494,6 +494,8 @@ import { GetById${entityNameCapitalized}UseCase } from '${entityPath}/applicatio
494
494
  import { GetAll${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/getAll-${entityNameLower}.use-case';
495
495
  import { Delete${entityNameCapitalized}UseCase } from '${entityPath}/application/use-cases/delete-${entityNameLower}.use-case';
496
496
  import { ${entityNameCapitalized}Mapper } from '${entityPath}/infrastructure/mappers/${entityNameLower}.mapper';
497
+ import { I${entityNameCapitalized}RepositoryName } from './domain/interfaces/${entityNameLower}.repository.interface';
498
+
497
499
 
498
500
  @Module({
499
501
  imports: [
@@ -506,7 +508,7 @@ import { ${entityNameCapitalized}Mapper } from '${entityPath}/infrastructure/map
506
508
  ${providersBlock.join(",\n ")}
507
509
  ],
508
510
  exports: [
509
- ${entityNameCapitalized}Service, 'I${entityNameCapitalized}Repository'
511
+ ${entityNameCapitalized}Service, I${entityNameCapitalized}RepositoryName
510
512
  ]
511
513
  })
512
514
  export class ${entityNameCapitalized}Module {}
@@ -544,7 +546,7 @@ import { APP_INTERCEPTOR } from '@nestjs/core';`,
544
546
  logSuccess(`Structure generated successfully!`);
545
547
  } catch (error) {
546
548
  logError(
547
- `Process encountered an error during Clean Architecture setup: ${error}`
549
+ `Process encountered an error during Clean Architecture setup: ${error}`,
548
550
  );
549
551
  throw error;
550
552
  }
@@ -32,7 +32,7 @@ async function setupLightArchitecture(inputs) {
32
32
 
33
33
  // Générer l'enum Role si l'entité User existe
34
34
  const hasUserEntity = entitiesData.entities.some(
35
- (entity) => entity.name.toLowerCase() === "user"
35
+ (entity) => entity.name.toLowerCase() === "user",
36
36
  );
37
37
 
38
38
  if (hasUserEntity) {
@@ -80,7 +80,7 @@ async function setupLightArchitecture(inputs) {
80
80
  const mongooseSchemaContent = await generateMongooseSchemaFileContent(
81
81
  entity,
82
82
  entitiesData,
83
- mode
83
+ mode,
84
84
  );
85
85
  await createFile({
86
86
  path: `${entityPath}/entities/${entityNameLower}.schema.ts`,
@@ -104,7 +104,7 @@ async function setupLightArchitecture(inputs) {
104
104
  entityNameCapitalized,
105
105
  entityNameLower,
106
106
  dbConfig.orm,
107
- entity
107
+ entity,
108
108
  );
109
109
  await createFile({
110
110
  path: `${entityPath}/repositories/${entityNameLower}.repository.ts`,
@@ -113,7 +113,7 @@ async function setupLightArchitecture(inputs) {
113
113
 
114
114
  const serviceContent = generateLightService(
115
115
  entityNameCapitalized,
116
- entityNameLower
116
+ entityNameLower,
117
117
  );
118
118
  await createFile({
119
119
  path: `${entityPath}/services/${entityNameLower}.service.ts`,
@@ -123,7 +123,7 @@ async function setupLightArchitecture(inputs) {
123
123
  const controllerContent = generateLightController(
124
124
  entityNameCapitalized,
125
125
  entityNameLower,
126
- useSwagger
126
+ useSwagger,
127
127
  );
128
128
  await createFile({
129
129
  path: `${entityPath}/controllers/${entityNameLower}.controller.ts`,
@@ -135,7 +135,7 @@ async function setupLightArchitecture(inputs) {
135
135
  entityNameLower,
136
136
  entityPath,
137
137
  dbConfig.orm,
138
- useAuth
138
+ useAuth,
139
139
  );
140
140
  await createFile({
141
141
  path: `${entityPath}/${entityNameLower}.module.ts`,
@@ -641,7 +641,7 @@ function generateLightModule(
641
641
  entityLower,
642
642
  entityPath,
643
643
  orm,
644
- useAuth = false
644
+ useAuth = false,
645
645
  ) {
646
646
  let importsBlock = [];
647
647
  let providersBlock = [`${entityName}Service`, `${entityName}Repository`];
@@ -659,7 +659,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';`;
659
659
  extraImports = `import { MongooseModule } from '@nestjs/mongoose';
660
660
  import { ${entityName}, ${entityName}Schema } from '${entityPath}/entities/${entityLower}.schema';`;
661
661
  importsBlock.push(
662
- `MongooseModule.forFeature([{ name: ${entityName}.name, schema: ${entityName}Schema }])`
662
+ `MongooseModule.forFeature([{ name: ${entityName}.name, schema: ${entityName}Schema }])`,
663
663
  );
664
664
  }
665
665
 
@@ -692,4 +692,10 @@ function decapitalize(str) {
692
692
  return str.charAt(0).toLowerCase() + str.slice(1);
693
693
  }
694
694
 
695
- module.exports = { setupLightArchitecture };
695
+ module.exports = {
696
+ setupLightArchitecture,
697
+ generateLightRepository,
698
+ generateLightService,
699
+ generateLightController,
700
+ generateLightModule,
701
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * utils/file-system.js
3
+ *
4
+ * Fonctions d'accès au système de fichiers utilisées par tous les générateurs.
5
+ * Extraites de userInput.js pour centraliser les opérations I/O.
6
+ *
7
+ * Les fichiers qui importent depuis userInput.js continuent de fonctionner
8
+ * sans modification grâce aux ré-exports dans userInput.js.
9
+ */
10
+
11
+ const fs = require("fs");
12
+
13
+ /**
14
+ * Crée un répertoire de manière récursive s'il n'existe pas déjà.
15
+ * @param {string} directoryPath - Le chemin du répertoire à créer.
16
+ */
17
+ async function createDirectory(directoryPath) {
18
+ try {
19
+ if (!fs.existsSync(directoryPath)) {
20
+ fs.mkdirSync(directoryPath, { recursive: true });
21
+ }
22
+ } catch (error) {
23
+ console.error(
24
+ `Erreur lors de la création du dossier ${directoryPath}:`,
25
+ error,
26
+ );
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Crée un fichier avec le contenu fourni.
32
+ * Si le fichier existe déjà :
33
+ * - Si `fileData.overwrite === false` : skip silencieusement
34
+ * - Sinon : écrase le fichier existant
35
+ *
36
+ * @param {{ path: string, contente: string, overwrite?: boolean }} fileData
37
+ */
38
+ async function createFile(fileData) {
39
+ try {
40
+ if (!fs.existsSync(fileData.path)) {
41
+ fs.writeFileSync(`${fileData.path}`, `${fileData.contente}`);
42
+ } else {
43
+ if (fileData.overwrite === false) {
44
+ console.log(`File already exists, skipping: ${fileData.path}`);
45
+ return;
46
+ }
47
+ console.log(`Existing file : ${fileData.path}`);
48
+ fs.writeFileSync(`${fileData.path}`, `${fileData.contente}`);
49
+ }
50
+ } catch (error) {
51
+ console.error(`Erreur creating file ${fileData.path}:`, error);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Met à jour un fichier existant en remplaçant un pattern par un remplacement.
57
+ * Utilise `String.prototype.replace` : supporte les chaînes et les RegExp.
58
+ *
59
+ * @param {{ path: string, pattern: string|RegExp, replacement: string }} options
60
+ */
61
+ async function updateFile({ path, pattern, replacement }) {
62
+ try {
63
+ let mainTs = fs.readFileSync(path, "utf8");
64
+ const updatedContent = mainTs.replace(pattern, replacement);
65
+ fs.writeFileSync(path, updatedContent, "utf-8");
66
+ } catch (error) {
67
+ console.error(` Error updating file ${path}:`, error);
68
+ }
69
+ }
70
+
71
+ module.exports = {
72
+ createDirectory,
73
+ createFile,
74
+ updateFile,
75
+ };
@@ -0,0 +1,36 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * Lit le package.json, fusionne les scripts et les dépendances, et réécrit le fichier.
6
+ *
7
+ * @param {object} inputs Les inputs du CLI (pour le chemin du projet et le nom)
8
+ *
9
+ */
10
+ async function saveProjectConfig(inputs) {
11
+ const configDir = path.join(process.cwd(), ".nestcraftx");
12
+ const configFile = path.join(configDir, ".nestcraftxrc");
13
+
14
+ const configData = {
15
+ name: inputs.projectName,
16
+ mode: inputs.mode,
17
+ orm: inputs.dbConfig.orm,
18
+ database: inputs.selectedDB,
19
+ auth: inputs.useAuth,
20
+ swagger: inputs.useSwagger,
21
+ packageManager: inputs.packageManager,
22
+ docker: inputs.useDocker,
23
+ generatedAt: new Date().toISOString(),
24
+ };
25
+
26
+ try {
27
+ if (!fs.existsSync(configDir)) {
28
+ fs.mkdirSync(configDir, { recursive: true });
29
+ }
30
+ fs.writeFileSync(configFile, JSON.stringify(configData, null, 2));
31
+ } catch (error) {
32
+ logWarning("Could not save project configuration file.");
33
+ }
34
+ }
35
+
36
+ module.exports = { saveProjectConfig };