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.
- package/AUDIT_ROADMAP.md +798 -0
- package/CHANGELOG.fr.md +22 -0
- package/CHANGELOG.md +22 -0
- package/CLI_USAGE.fr.md +331 -331
- package/CLI_USAGE.md +364 -364
- package/LICENSE +21 -21
- package/PROGRESS.md +258 -0
- package/bin/nestcraft.js +84 -64
- package/commands/demo.js +337 -330
- package/commands/generate.js +94 -0
- package/commands/generateConf.js +91 -0
- package/commands/help.js +29 -2
- package/commands/info.js +48 -48
- package/commands/new.js +340 -335
- package/commands/start.js +19 -19
- package/commands/test.js +7 -7
- package/package.json +1 -1
- package/utils/app-module.updater.js +96 -0
- package/utils/cliParser.js +88 -76
- package/utils/colors.js +62 -62
- package/utils/configs/configureDocker.js +120 -120
- package/utils/configs/setupCleanArchitecture.js +17 -15
- package/utils/configs/setupLightArchitecture.js +15 -9
- package/utils/file-system.js +75 -0
- package/utils/file-utils/saveProjectConfig.js +36 -0
- package/utils/fullModeInput.js +607 -607
- package/utils/generators/application/dtoGenerator.js +251 -0
- package/utils/generators/application/dtoUpdater.js +54 -0
- package/utils/generators/cleanModuleGenerator.js +475 -0
- package/utils/generators/database/setupDatabase.js +49 -0
- package/utils/generators/domain/entityGenerator.js +126 -0
- package/utils/generators/domain/entityUpdater.js +78 -0
- package/utils/generators/infrastructure/mapperGenerator.js +114 -0
- package/utils/generators/infrastructure/mapperUpdater.js +65 -0
- package/utils/generators/infrastructure/middlewareGenerator.js +645 -0
- package/utils/generators/infrastructure/mongooseSchemaGenerator.js +196 -0
- package/utils/generators/infrastructure/repositoryGenerator.js +334 -0
- package/utils/generators/lightModuleGenerator.js +131 -0
- package/utils/generators/presentation/controllerGenerator.js +142 -0
- package/utils/generators/relation/relation.engine.js +64 -0
- package/utils/helpers.js +109 -0
- package/utils/interactive/askEntityInputs.js +165 -0
- package/utils/loggers/logError.js +7 -7
- package/utils/loggers/logInfo.js +7 -7
- package/utils/loggers/logSuccess.js +7 -7
- package/utils/loggers/logWarning.js +7 -7
- package/utils/setups/orms/typeOrmSetup.js +630 -630
- package/utils/setups/setupAuth.js +33 -20
- package/utils/setups/setupDatabase.js +76 -75
- package/utils/setups/setupMongoose.js +22 -5
- package/utils/setups/setupPrisma.js +748 -630
- package/utils/shell.js +112 -32
- package/utils/spinner.js +57 -57
- package/utils/systemCheck.js +124 -124
- package/utils/userInput.js +357 -421
- 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
|
-
|
|
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:
|
|
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,
|
|
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 = {
|
|
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 };
|