nestcraftx 0.3.0 → 1.0.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 (62) hide show
  1. package/.github/workflows/ci.yml +35 -0
  2. package/CHANGELOG.fr.md +74 -0
  3. package/CHANGELOG.md +74 -0
  4. package/PROGRESS.md +70 -67
  5. package/README.fr.md +60 -69
  6. package/bin/nestcraft.js +8 -0
  7. package/commands/demo.js +12 -46
  8. package/commands/generate.js +551 -2
  9. package/commands/generateConf.js +4 -4
  10. package/commands/help.js +11 -0
  11. package/commands/info.js +2 -3
  12. package/commands/list.js +93 -0
  13. package/commands/new.js +28 -56
  14. package/jest.config.js +9 -0
  15. package/package.json +7 -2
  16. package/readme.md +59 -68
  17. package/tests/e2e/generator.spec.js +71 -0
  18. package/tests/unit/appModuleUpdater.spec.js +111 -0
  19. package/tests/unit/cliParser.spec.js +74 -0
  20. package/tests/unit/controllerGenerator.spec.js +145 -0
  21. package/tests/unit/dtoGenerator.spec.js +87 -0
  22. package/tests/unit/entityGenerator.spec.js +65 -0
  23. package/tests/unit/generateCommand.spec.js +100 -0
  24. package/tests/unit/health.spec.js +69 -0
  25. package/tests/unit/listCommand.spec.js +91 -0
  26. package/tests/unit/middlewareGenerator.spec.js +64 -0
  27. package/tests/unit/newCommand.spec.js +88 -0
  28. package/tests/unit/relationCommand.spec.js +202 -0
  29. package/tests/unit/throttler.spec.js +117 -0
  30. package/utils/app-module.updater.js +6 -0
  31. package/utils/configs/setupCleanArchitecture.js +1 -1
  32. package/utils/configs/setupLightArchitecture.js +98 -26
  33. package/utils/envGenerator.js +9 -1
  34. package/utils/file-system.js +15 -0
  35. package/utils/file-utils/packageJsonUtils.js +6 -0
  36. package/utils/file-utils/saveProjectConfig.js +9 -0
  37. package/utils/fullModeInput.js +12 -229
  38. package/utils/generators/application/dtoGenerator.js +26 -8
  39. package/utils/generators/application/dtoUpdater.js +5 -0
  40. package/utils/generators/cleanModuleGenerator.js +40 -11
  41. package/utils/generators/domain/entityUpdater.js +5 -0
  42. package/utils/generators/infrastructure/mapperUpdater.js +5 -0
  43. package/utils/generators/infrastructure/middlewareGenerator.js +112 -315
  44. package/utils/generators/infrastructure/mongooseSchemaGenerator.js +114 -4
  45. package/utils/generators/infrastructure/repositoryGenerator.js +114 -14
  46. package/utils/generators/lightModuleGenerator.js +14 -0
  47. package/utils/generators/presentation/controllerGenerator.js +70 -19
  48. package/utils/helpers.js +8 -2
  49. package/utils/interactive/askEntityInputs.js +5 -68
  50. package/utils/interactive/askRelationCommand.js +98 -0
  51. package/utils/interactive/entityBuilder.js +411 -0
  52. package/utils/lightModeInput.js +22 -241
  53. package/utils/setups/orms/typeOrmSetup.js +42 -8
  54. package/utils/setups/projectSetup.js +88 -10
  55. package/utils/setups/setupAuth.js +335 -20
  56. package/utils/setups/setupDatabase.js +4 -1
  57. package/utils/setups/setupHealth.js +74 -0
  58. package/utils/setups/setupMongoose.js +84 -32
  59. package/utils/setups/setupPrisma.js +151 -4
  60. package/utils/setups/setupSwagger.js +15 -8
  61. package/utils/setups/setupThrottler.js +92 -0
  62. package/utils/shell.js +61 -9
package/commands/help.js CHANGED
@@ -59,6 +59,17 @@ async function helpCommand() {
59
59
  --auth Adds JWT Auth
60
60
  --swagger Adds Swagger UI
61
61
 
62
+ nestcraftx generate, g <subcommand> [target]
63
+ Generates modules or auth post-scaffolding
64
+ Subcommands:
65
+ module <name> Generates a new module (MVP or Clean Architecture)
66
+ auth Enables JWT Auth on an existing project
67
+ relation, r Creates a relation between two existing modules
68
+ (interactive: select source, target, and relation type)
69
+
70
+ nestcraftx list, l
71
+ Lists all scaffolded entities and their relationships
72
+
62
73
  nestcraftx test
63
74
  Checks system environment (Node, npm, Nest CLI, Docker, etc.)
64
75
 
package/commands/info.js CHANGED
@@ -27,11 +27,10 @@ async function infoCommand() {
27
27
  console.log(" " + packageJson.repository.url);
28
28
 
29
29
  console.log("\n📅 Upcoming:");
30
- console.log(" • Custom Middlewares");
30
+ console.log(" • MySQL & SQLite support");
31
+ console.log(" • Custom templates from GitHub");
31
32
  console.log(" • Microservices support");
32
- console.log(" • CI/CD Templates");
33
33
  console.log(" • GraphQL integration");
34
- console.log(" • Automated Tests");
35
34
 
36
35
  console.log("\n💡 Available Commands:");
37
36
  console.log(" nestcraftx new <name> [options] Create a project");
@@ -0,0 +1,93 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { logError } = require("../utils/loggers/logError");
4
+ const { logInfo } = require("../utils/loggers/logInfo");
5
+ const { logWarning } = require("../utils/loggers/logWarning");
6
+ const { bold } = require("../utils/colors");
7
+
8
+ async function listCommand() {
9
+ const configPath = path.join(process.cwd(), ".nestcraftx", ".nestcraftxrc");
10
+
11
+ if (!fs.existsSync(configPath)) {
12
+ logError("Aucun fichier de configuration NestcraftX trouvé.");
13
+ logInfo("Assurez-vous d'être à la racine d'un projet NestcraftX.");
14
+ return;
15
+ }
16
+
17
+ let projectConfig;
18
+ try {
19
+ const rawData = fs.readFileSync(configPath, "utf8");
20
+ projectConfig = JSON.parse(rawData);
21
+ } catch (err) {
22
+ logError("Erreur lors de la lecture du fichier .nestcraftxrc. Le JSON est peut-être corrompu.");
23
+ return;
24
+ }
25
+
26
+ const { name, mode, orm, database, entities = [], relations = [] } = projectConfig;
27
+
28
+ console.log("\n" + "=".repeat(74));
29
+ console.log(`📋 Project: ${bold(name)} | Mode: ${bold(mode ? mode.toUpperCase() : "FULL")} | ORM: ${bold(orm ? orm.toUpperCase() : "")} | DB: ${bold(database || "")}`);
30
+ console.log("=".repeat(74));
31
+
32
+ if (entities.length === 0) {
33
+ logWarning("Aucune entité configurée pour le moment.");
34
+ return;
35
+ }
36
+
37
+ // 1. Draw Entities Table
38
+ console.log("\n" + bold("ENTITIES"));
39
+ console.log("┌" + "─".repeat(20) + "┬" + "─".repeat(50) + "┐");
40
+ console.log("│ " + "Entity Name".padEnd(18) + " │ " + "Fields (Type)".padEnd(48) + " │");
41
+ console.log("├" + "─".repeat(20) + "┼" + "─".repeat(50) + "┤");
42
+
43
+ entities.forEach(entity => {
44
+ const nameStr = entity.name || "";
45
+ const fieldsStr = (entity.fields || []).map(f => `${f.name} (${f.type})`).join(", ");
46
+
47
+ // Chunk fields if they are too long to prevent table layout breakage
48
+ if (fieldsStr.length <= 48) {
49
+ console.log("│ " + nameStr.padEnd(18) + " │ " + fieldsStr.padEnd(48) + " │");
50
+ } else {
51
+ // Print first line
52
+ let chunk = fieldsStr.substring(0, 48);
53
+ let lastSpace = chunk.lastIndexOf(", ");
54
+ if (lastSpace > 30) {
55
+ chunk = fieldsStr.substring(0, lastSpace + 1);
56
+ }
57
+ console.log("│ " + nameStr.padEnd(18) + " │ " + chunk.padEnd(48) + " │");
58
+
59
+ let remaining = fieldsStr.substring(chunk.length).trim();
60
+ while (remaining.length > 0) {
61
+ let nextChunk = remaining.substring(0, 48);
62
+ if (remaining.length > 48) {
63
+ let spaceIndex = nextChunk.lastIndexOf(", ");
64
+ if (spaceIndex > 30) {
65
+ nextChunk = remaining.substring(0, spaceIndex + 1);
66
+ }
67
+ }
68
+ console.log("│ " + "".padEnd(18) + " │ " + nextChunk.padEnd(48) + " │");
69
+ remaining = remaining.substring(nextChunk.length).trim();
70
+ }
71
+ }
72
+ });
73
+
74
+ console.log("└" + "─".repeat(20) + "┴" + "─".repeat(50) + "┘");
75
+
76
+ // 2. Draw Relations Table
77
+ if (relations && relations.length > 0) {
78
+ console.log("\n" + bold("RELATIONSHIPS"));
79
+ console.log("┌" + "─".repeat(40) + "┬" + "─".repeat(15) + "┐");
80
+ console.log("│ " + "Relation".padEnd(38) + " │ " + "Type".padEnd(13) + " │");
81
+ console.log("├" + "─".repeat(40) + "┼" + "─".repeat(15) + "┤");
82
+
83
+ relations.forEach(rel => {
84
+ const relationStr = `${rel.from} ──► ${rel.to}`;
85
+ const typeStr = rel.type || "";
86
+ console.log("│ " + relationStr.padEnd(38) + " │ " + typeStr.padEnd(13) + " │");
87
+ });
88
+
89
+ console.log("└" + "─".repeat(40) + "┴" + "─".repeat(15) + "┘\n");
90
+ }
91
+ }
92
+
93
+ module.exports = listCommand;
package/commands/new.js CHANGED
@@ -1,26 +1,12 @@
1
1
  const { getFullModeInputs } = require("../utils/fullModeInput");
2
2
  const { getLightModeInputs } = require("../utils/lightModeInput");
3
- const { createProject } = require("../utils/setups/projectSetup");
4
- const {
5
- setupCleanArchitecture,
6
- } = require("../utils/configs/setupCleanArchitecture");
7
- const {
8
- setupLightArchitecture,
9
- } = require("../utils/configs/setupLightArchitecture");
10
- const { setupAuth } = require("../utils/setups/setupAuth");
11
- const { setupSwagger } = require("../utils/setups/setupSwagger");
12
- const { setupDatabase } = require("../utils/setups/setupDatabase");
13
- const { configureDocker } = require("../utils/configs/configureDocker");
14
- const { setupBootstrapLogger } = require("../utils/setups/setupLogger");
3
+ const { runProjectSetupPipeline } = require("../utils/setups/projectSetup");
15
4
  const { logSuccess } = require("../utils/loggers/logSuccess");
16
5
  const { logInfo } = require("../utils/loggers/logInfo");
17
6
  const { logError } = require("../utils/loggers/logError");
18
- const { generateEnvFile, writeEnvFile } = require("../utils/envGenerator");
19
7
  const readline = require("readline-sync");
20
8
  const { info, warning } = require("../utils/colors");
21
9
  const { logWarning } = require("../utils/loggers/logWarning");
22
- const { saveProjectConfig } = require("../utils/file-utils/saveProjectConfig");
23
- const { printSetupWarnings } = require("../utils/shell");
24
10
 
25
11
  async function newCommand(projectName, flags = {}) {
26
12
  if (!projectName) {
@@ -50,7 +36,11 @@ async function newCommand(projectName, flags = {}) {
50
36
  }
51
37
  }
52
38
 
53
- const inputs = await getFullModeInputs(currentProjectName, flags);
39
+ const mode = determineMode(flags);
40
+ const inputs =
41
+ mode === "light"
42
+ ? await buildLightModeInputs(currentProjectName, flags)
43
+ : await buildFullModeInputs(currentProjectName, flags);
54
44
  return executeProjectSetup(inputs);
55
45
  }
56
46
 
@@ -100,7 +90,8 @@ function hasAllLightModeFlags(flags) {
100
90
  if (flags.interactive === true) {
101
91
  return false;
102
92
  }
103
- return flags.orm !== undefined;
93
+ const hasMode = flags.mode !== undefined || flags.light === true || flags.full === true;
94
+ return flags.orm !== undefined && hasMode;
104
95
  }
105
96
 
106
97
  function buildLightModeFromFlags(projectName, flags) {
@@ -111,13 +102,19 @@ function buildLightModeFromFlags(projectName, flags) {
111
102
  logError(`Unrecognized ORM: ${orm}. Using Prisma by default.`);
112
103
  }
113
104
 
105
+ let packageManager = "npm";
106
+ if (flags.pnpm) packageManager = "pnpm";
107
+ else if (flags.yarn) packageManager = "yarn";
108
+ else if (flags.packageManager) packageManager = flags.packageManager.toLowerCase();
109
+
114
110
  const inputs = {
115
111
  projectName,
116
112
  mode: "light",
117
- useYarn: false,
113
+ useYarn: packageManager === "yarn",
118
114
  useDocker: flags.docker !== false,
119
115
  useAuth: !!flags.auth,
120
116
  useSwagger: !!flags.swagger,
117
+ useThrottler: !!flags.throttler,
121
118
  swaggerInputs: flags.swagger
122
119
  ? {
123
120
  title: `${projectName} API`,
@@ -126,7 +123,7 @@ function buildLightModeFromFlags(projectName, flags) {
126
123
  endpoint: "api/docs",
127
124
  }
128
125
  : undefined,
129
- packageManager: "npm",
126
+ packageManager: packageManager,
130
127
  entitiesData: {
131
128
  entities: [],
132
129
  relations: [],
@@ -169,7 +166,8 @@ function hasAllFullModeFlags(flags) {
169
166
  if (flags.interactive === true) {
170
167
  return false;
171
168
  }
172
- return flags.orm !== undefined;
169
+ const hasMode = flags.mode !== undefined || flags.light === true || flags.full === true;
170
+ return flags.orm !== undefined && hasMode;
173
171
  }
174
172
 
175
173
  function buildFullModeFromFlags(projectName, flags) {
@@ -178,7 +176,10 @@ function buildFullModeFromFlags(projectName, flags) {
178
176
  const validOrms = ["prisma", "typeorm", "mongoose"];
179
177
  const finalOrm = validOrms.includes(orm) ? orm : "prisma";
180
178
 
181
- const packageManager = flags.yarn ? "yarn" : "npm";
179
+ let packageManager = "npm";
180
+ if (flags.pnpm) packageManager = "pnpm";
181
+ else if (flags.yarn) packageManager = "yarn";
182
+ else if (flags.packageManager) packageManager = flags.packageManager.toLowerCase();
182
183
 
183
184
  const defaultDBConfig =
184
185
  finalOrm === "mongoose"
@@ -196,18 +197,20 @@ function buildFullModeFromFlags(projectName, flags) {
196
197
  POSTGRES_PORT: flags.dbPort || "5432",
197
198
  };
198
199
 
199
- const useAuth = flags.auth !== false;
200
- const useSwagger = flags.swagger !== false;
200
+ const useAuth = !!flags.auth;
201
+ const useSwagger = !!flags.swagger;
201
202
  const useDocker = flags.docker !== false;
203
+ const useThrottler = !!flags.throttler;
202
204
 
203
205
  const inputs = {
204
206
  projectName,
205
207
  mode: "full",
206
- useYarn: flags.yarn === true,
208
+ useYarn: packageManager === "yarn",
207
209
  packageManager: packageManager,
208
210
  useDocker: useDocker,
209
211
  useAuth: useAuth,
210
212
  useSwagger: useSwagger,
213
+ useThrottler: useThrottler,
211
214
  swaggerInputs: useSwagger
212
215
  ? {
213
216
  title: flags.swaggerTitle || `${projectName} API`,
@@ -240,40 +243,9 @@ function buildFullModeFromFlags(projectName, flags) {
240
243
 
241
244
  async function executeProjectSetup(inputs) {
242
245
  try {
243
- logInfo("Starting project generation...");
244
-
245
- await createProject(inputs);
246
-
247
- if (inputs.mode === "light") {
248
- await setupLightArchitecture(inputs);
249
- } else {
250
- await setupCleanArchitecture(inputs);
251
- }
252
-
253
- if (inputs.useAuth) await setupAuth(inputs);
254
-
255
- if (inputs.useSwagger) {
256
- await setupSwagger(inputs.swaggerInputs);
257
- } else {
258
- setupBootstrapLogger();
259
- }
260
-
261
- if (inputs.useDocker) await configureDocker(inputs);
262
-
263
- await setupDatabase(inputs);
264
-
265
- const envContent = await generateEnvFile(inputs);
266
- writeEnvFile(envContent);
267
-
268
- await saveProjectConfig(inputs);
269
-
270
- // Show any non-critical warnings accumulated during generation
271
- printSetupWarnings();
272
-
246
+ await runProjectSetupPipeline(inputs);
273
247
  printSuccessSummary(inputs);
274
248
  } catch (error) {
275
- // Erreur lors de la creation du projet: ${error.message}
276
- logError(`Error during project creation: ${error.message}`);
277
249
  throw error;
278
250
  }
279
251
  }
package/jest.config.js ADDED
@@ -0,0 +1,9 @@
1
+ module.exports = {
2
+ testEnvironment: 'node',
3
+ testMatch: ['**/tests/**/*.spec.js'],
4
+ verbose: true,
5
+ forceExit: true,
6
+ clearMocks: true,
7
+ resetMocks: true,
8
+ restoreMocks: true
9
+ };
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "nestcraftx",
3
- "version": "0.3.0",
3
+ "version": "1.0.0",
4
4
  "description": "Modern CLI to generate scalable NestJS projects with Clean Architecture (FULL) and MVP mode (LIGHT) - Enhanced with auto-generated .env secrets, complete ORM support, and entity relations",
5
5
  "main": "bin/nestcraft.js",
6
6
  "bin": {
7
7
  "nestcraftx": "bin/nestcraft.js"
8
8
  },
9
9
  "scripts": {
10
- "test": "nestcraftx test"
10
+ "test": "jest --runInBand tests/unit",
11
+ "test:unit": "jest --runInBand tests/unit",
12
+ "test:e2e": "jest --runInBand tests/e2e"
11
13
  },
12
14
  "repository": {
13
15
  "type": "git",
@@ -37,5 +39,8 @@
37
39
  "dependencies": {
38
40
  "inquirer": "^12.10.0",
39
41
  "readline-sync": "^1.4.10"
42
+ },
43
+ "devDependencies": {
44
+ "jest": "^30.4.2"
40
45
  }
41
46
  }
package/readme.md CHANGED
@@ -31,13 +31,13 @@ Key Features:
31
31
 
32
32
  - Smart Config: Automated Swagger decorators, auto-documented .env files, and pre-configured database connections.
33
33
 
34
- > **Version 0.2.5:** Major release Interactive generation via flags, Auth refactored with session management, professional templates (gitignore, README), and clean code standards maintained by the community!
34
+ > **Version 1.0.0 (Stable Release):** Production-grade NestJS scaffolding with Clean Architecture, JWT authentication, relations updater, conditional RBAC guards, global rate limiting, health checks, advanced pagination/filtering/sorting, Swagger UI, and Docker compose files!
35
35
 
36
36
  ---
37
37
 
38
38
  ## Table of Contents
39
39
 
40
- - [What's New in v0.2.5](#whats-new-in-v025)
40
+ - [What's New in v1.0.0](#whats-new-in-v100-stable-release)
41
41
  - [Project Objective](#project-objective)
42
42
  - [Prerequisites](#prerequisites)
43
43
  - [Installation](#installation)
@@ -52,59 +52,32 @@ Key Features:
52
52
 
53
53
  ---
54
54
 
55
- ## What's New in v0.2.5
55
+ ## What's New in v1.0.0 (Stable Release)
56
56
 
57
- ### Two Architecture Modes
57
+ ### 🔗 Standalone Relation Command (`nestcraftx g relation`)
58
+ - Create 1-n, n-1, 1-1, or n-n relations between **existing modules** at any time.
59
+ - Automatically updates domain entities (FK fields and getters), DTOs (Create and Update), and data mappers.
60
+ - Syncs database schemas (runs format, client generation, and migrations dev for Prisma; injects ObjectId references for Mongoose).
58
61
 
59
- **FULL Mode - Complete Architecture**
62
+ ### 🛡️ Conditional RBAC Guards & Swagger Integration
63
+ - Mutation endpoints (`POST`, `PATCH`, `DELETE`) are protected with `JwtAuthGuard` and `RolesGuard` (`@Roles('ADMIN')`) only if Auth is enabled.
64
+ - Read endpoints (`GET`, `GET :id`) are decorated with `@Public()`.
65
+ - Generates complete API documentation using `@ApiBearerAuth()` and standard error responses when Swagger is enabled.
60
66
 
61
- - Clean Architecture with use-cases, mappers, adapters
62
- - Strict separation: domain/application/infrastructure/presentation
63
- - Ideal for complex and scalable projects
67
+ ### 🚦 Global Rate Limiting (Throttler Module)
68
+ - Integrated `@nestjs/throttler` package with preconfigured global rate limiting policies (default: 10 requests per minute).
69
+ - Configurable via interactive prompts or CLI flag `--throttler`.
64
70
 
65
- **LIGHT Mode - MVP Architecture**
71
+ ### 🏥 Health Check Endpoint (`/health`)
72
+ - Exposes a native `/health` check route reporting global status (`ok`), timestamp, and application uptime (`process.uptime()`).
73
+ - Fully documented in Swagger UI, optimized with zero third-party packages for fast compilation and maximum safety.
66
74
 
67
- - Simplified structure: controllers services repositories
68
- - Quick start for prototypes
69
- - Perfect for small projects and MVPs
75
+ ### 🚀 Advanced Query Params (Pagination, Filtering, Sorting)
76
+ - Auto-injects paginated data retrieval (e.g. `?page=1&limit=10&search=...&sortBy=createdAt&sortOrder=desc`) into controllers and repository layers.
77
+ - Seamlessly maps incoming query params to Prisma, TypeORM, and Mongoose queries.
70
78
 
71
- ### Improved Demo Command
72
-
73
- - ✅ Flag options: `--light`, `--orm`, `--auth`, `--swagger`, `--docker`
74
- - ✅ Interactive mode: only asks questions for missing flags
75
- - ✅ Intelligent merging of flags and interactive responses
76
- - ✅ 3 pre-configured entities with relationships
77
- - ✅ Support for all ORMs (Prisma, TypeORM, Mongoose)
78
- - ✅ Separate instructions in [Demo Documentation](./DEMO.md)
79
-
80
- ### Modern CLI with Flags
81
-
82
- ```bash
83
- nestcraftx new <project-name> [options]
84
-
85
- Options:
86
- --light Simplified architecture mode
87
- --full Complete architecture mode (default)
88
- --db=<db> Database choice: postgresql|mongodb
89
- --orm=<orm> ORM choice: prisma|typeorm|mongoose
90
- --auth Enable JWT authentication
91
- --swagger Enable Swagger documentation
92
- --docker Enable Docker (default: true)
93
- ```
94
-
95
- ### Automatic Secret Generation
96
-
97
- - Auto-generated JWT secrets (64 secure characters)
98
- - Ready-to-use .env file
99
- - DATABASE_URL automatically configured
100
- - Sanitized .env.example file
101
-
102
- ### Improved UX
103
-
104
- - Colored messages (info, success, error)
105
- - Animated spinners for long operations
106
- - Detailed post-generation summary
107
- - Real-time validation of options
79
+ ### 📋 Interactive Scaffolding Report
80
+ - Out-of-the-box CLI report with ASCII borders after each module generation summarizing files generated, database schema updates, relations established, and clear next steps.
108
81
 
109
82
  ### Quick Examples
110
83
 
@@ -178,6 +151,21 @@ npm install
178
151
  npm link
179
152
  ```
180
153
 
154
+ ### Running Tests
155
+
156
+ We use Jest to run unit tests and E2E generator compiler tests:
157
+
158
+ ```bash
159
+ # Run unit tests (fast check)
160
+ npm run test:unit
161
+
162
+ # Run E2E integration tests (scaffolds project, runs npm install & tsc type checks)
163
+ npm run test:e2e
164
+
165
+ # Run all tests
166
+ npm test
167
+ ```
168
+
181
169
  ---
182
170
 
183
171
  ## Available Commands
@@ -548,31 +536,34 @@ open http://localhost:3000/api/docs
548
536
 
549
537
  ## Roadmap
550
538
 
551
- ### Version 0.2.x — Stabilization
539
+ ### Version 0.3.0 — Stabilization & UX (Completed)
540
+ - [x] CommonJS module system unification
541
+ - [x] Dynamic helper versioning and interactive flags checks
542
+ - [x] Dynamic package manager setup
552
543
 
553
- - [x] Light & Full architectures
554
- - [x] Interactive CLI
555
- - [x] Multi-ORM support (Prisma / TypeORM / Mongoose)
556
- - [ ] Comprehensive documentation & realistic examples
544
+ ### Version 0.4.0 Architecture Refactoring (Completed)
545
+ - [x] Split of monolithic files into dedicated generators
546
+ - [x] Interactive state-based `EntityBuilder` with revision menus
547
+ - [x] Dry-run simulation mode (`--dry-run`)
557
548
 
558
- ### Version 0.3.0 — Developer Experience
549
+ ### Version 0.5.0 — Quality & Security (Completed)
550
+ - [x] Persistent DB storage for OTPs & password reset tokens
551
+ - [x] Strict package version pinning
552
+ - [x] Contextual semantic Swagger DTO descriptions
559
553
 
560
- - [ ] `generate` command (scaffold modules/entities into existing projects)
561
- - [ ] SQLite support for zero-config demos & prototyping
562
- - [ ] Enhanced error handling & colored terminal logs
554
+ ### Version 0.6.0 Tests & CI/CD (Completed)
555
+ - [x] Unit test coverage using Jest
556
+ - [x] E2E compiler checks & resolution of upstream peer dependency conflicts
557
+ - [x] Multi-OS Node.js matrix GitHub Actions CI/CD pipeline
563
558
 
564
- ### Version 0.4.0 — Production Readiness
565
-
566
- - [ ] Pluggable session strategies (In-memory / Database / Redis)
567
- - [ ] Advanced data seeding templates
568
- - [ ] Project presets (API Only / Auth / Full CRUD)
559
+ ### Version 0.7.0 - 0.9.0 Missing Features (In Progress)
560
+ - [ ] Interactive `generate auth` and complete non-interactive execution
561
+ - [ ] API Pagination, filtering, rate limiting, and RBAC guards
562
+ - [ ] MySQL/SQLite support
569
563
 
570
564
  ### Version 1.0.0 — Stable Release
571
-
572
- - [ ] TypeScript-native CLI
573
- - [ ] Enforced conventions & stable API contracts
574
565
  - [ ] Official documentation website
575
- - [ ] Long-term support (LTS) guarantees
566
+ - [ ] Production audit and LTS guarantees
576
567
 
577
568
  ---
578
569
 
@@ -629,7 +620,7 @@ Thanks to all contributors and the NestJS community!
629
620
 
630
621
  ---
631
622
 
632
- **NestCraftX v0.2.5** - Clean Architecture Made Simple
623
+ **NestCraftX v0.6.0** - Clean Architecture Made Simple
633
624
 
634
625
  For more information:
635
626
 
@@ -0,0 +1,71 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { execSync } = require('child_process');
4
+ const demoCommand = require('../../commands/demo');
5
+
6
+ describe('E2E Generator - Compilation Check', () => {
7
+ const e2eDir = path.join(__dirname, '..', 'e2e-output');
8
+ const projectDir = path.join(e2eDir, 'blog-demo');
9
+ const originalCwd = process.cwd();
10
+
11
+ beforeAll(() => {
12
+ // S'assurer que le dossier temporaire e2e-output existe et est vide
13
+ if (fs.existsSync(e2eDir)) {
14
+ fs.rmSync(e2eDir, { recursive: true, force: true });
15
+ }
16
+ fs.mkdirSync(e2eDir, { recursive: true });
17
+ });
18
+
19
+ afterAll(() => {
20
+ // Restaurer le CWD original et nettoyer les dossiers générés
21
+ process.chdir(originalCwd);
22
+ if (fs.existsSync(e2eDir)) {
23
+ try {
24
+ fs.rmSync(e2eDir, { recursive: true, force: true });
25
+ } catch (err) {
26
+ console.warn('Cleanup warning (some files might be locked):', err.message);
27
+ }
28
+ }
29
+ });
30
+
31
+ it('should generate a project with Prisma, Auth, Swagger and compile successfully', async () => {
32
+ // Se déplacer dans le dossier e2e-output avant la génération
33
+ process.chdir(e2eDir);
34
+
35
+ console.log('Generating E2E project...');
36
+ // Exécuter demoCommand en passant les options pour éviter les prompts inquirer
37
+ await demoCommand({
38
+ light: false, // Full Clean Architecture
39
+ orm: 'prisma',
40
+ docker: false,
41
+ auth: true,
42
+ swagger: true,
43
+ packageManager: 'npm'
44
+ });
45
+
46
+ // Vérifier l'existence physique du projet et de fichiers clés
47
+ expect(fs.existsSync(projectDir)).toBe(true);
48
+ expect(fs.existsSync(path.join(projectDir, 'package.json'))).toBe(true);
49
+ expect(fs.existsSync(path.join(projectDir, 'prisma', 'schema.prisma'))).toBe(true);
50
+ expect(fs.existsSync(path.join(projectDir, 'src', 'app.module.ts'))).toBe(true);
51
+
52
+ // Se déplacer dans le dossier du projet généré
53
+ process.chdir(projectDir);
54
+
55
+ console.log('Running npm install in the generated project...');
56
+ // Lancer npm install avec --legacy-peer-deps pour installer les dépendances figées
57
+ execSync('npm install --legacy-peer-deps --no-audit --no-fund', { stdio: 'inherit' });
58
+
59
+ console.log('Running tsc --noEmit in the generated project...');
60
+ // Lancer la vérification de type TypeScript
61
+ let compilePassed = false;
62
+ try {
63
+ execSync('npx tsc --noEmit', { stdio: 'inherit' });
64
+ compilePassed = true;
65
+ } catch (error) {
66
+ console.error('TypeScript compilation failed:', error.message);
67
+ }
68
+
69
+ expect(compilePassed).toBe(true);
70
+ }, 300000); // 5 minutes timeout pour npm install + compilation
71
+ });