nestcraftx 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/.gitattributes +6 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  4. package/.github/ISSUE_TEMPLATE/pull_request_template.md +24 -0
  5. package/CHANGELOG.fr.md +97 -97
  6. package/CHANGELOG.md +98 -98
  7. package/CLI_USAGE.fr.md +331 -331
  8. package/CLI_USAGE.md +364 -364
  9. package/DEMO.fr.md +292 -292
  10. package/DEMO.md +294 -294
  11. package/LICENSE +21 -21
  12. package/MIGRATION_GUIDE.fr.md +127 -127
  13. package/MIGRATION_GUIDE.md +124 -124
  14. package/QUICK_START.fr.md +152 -152
  15. package/QUICK_START.md +169 -169
  16. package/README.fr.md +653 -659
  17. package/SECURITY.md +10 -0
  18. package/bin/nestcraft.js +84 -64
  19. package/commands/demo.js +333 -330
  20. package/commands/generate.js +93 -0
  21. package/commands/generateConf.js +91 -0
  22. package/commands/help.js +78 -78
  23. package/commands/info.js +48 -48
  24. package/commands/new.js +338 -335
  25. package/commands/start.js +19 -19
  26. package/commands/test.js +7 -7
  27. package/package.json +41 -41
  28. package/readme.md +638 -643
  29. package/utils/cliParser.js +133 -76
  30. package/utils/colors.js +62 -62
  31. package/utils/configs/configureDocker.js +120 -120
  32. package/utils/configs/setupCleanArchitecture.js +563 -557
  33. package/utils/configs/setupLightArchitecture.js +701 -660
  34. package/utils/envGenerator.js +122 -122
  35. package/utils/file-utils/packageJsonUtils.js +49 -55
  36. package/utils/file-utils/saveProjectConfig.js +36 -0
  37. package/utils/fullModeInput.js +607 -607
  38. package/utils/generators/application/dtoUpdater.js +54 -0
  39. package/utils/generators/cleanModuleGenerator.js +475 -0
  40. package/utils/generators/database/setupDatabase.js +31 -0
  41. package/utils/generators/domain/entityUpdater.js +78 -0
  42. package/utils/generators/infrastructure/mapperUpdater.js +65 -0
  43. package/utils/generators/lightModuleGenerator.js +131 -0
  44. package/utils/generators/relation/relation.engine.js +64 -0
  45. package/utils/interactive/askEntityInputs.js +165 -0
  46. package/utils/lightModeInput.js +460 -460
  47. package/utils/loggers/logError.js +7 -7
  48. package/utils/loggers/logInfo.js +7 -7
  49. package/utils/loggers/logSuccess.js +7 -7
  50. package/utils/loggers/logWarning.js +7 -7
  51. package/utils/setups/orms/typeOrmSetup.js +630 -630
  52. package/utils/setups/projectSetup.js +46 -46
  53. package/utils/setups/setupAuth.js +973 -926
  54. package/utils/setups/setupDatabase.js +75 -75
  55. package/utils/setups/setupLogger.js +69 -59
  56. package/utils/setups/setupMongoose.js +377 -432
  57. package/utils/setups/setupPrisma.js +802 -630
  58. package/utils/setups/setupSwagger.js +97 -88
  59. package/utils/shell.js +32 -32
  60. package/utils/spinner.js +57 -57
  61. package/utils/systemCheck.js +124 -124
  62. package/utils/userInput.js +421 -421
  63. package/utils/utils.js +2197 -1762
@@ -1,76 +1,133 @@
1
- function parseCliArgs(args) {
2
- const parsed = {
3
- command: null,
4
- projectName: null,
5
- flags: {},
6
- positional: [],
7
- errors: []
8
- };
9
-
10
- for (let i = 2; i < args.length; i++) {
11
- const arg = args[i];
12
-
13
- if (i === 2 && !arg.startsWith('--')) {
14
- parsed.command = arg;
15
- continue;
16
- }
17
-
18
- if (i === 3 && !arg.startsWith('--') && parsed.command === 'new') {
19
- if (!isValidProjectName(arg)) {
20
- parsed.errors.push(`Nom de projet invalide: "${arg}". Utilisez uniquement des lettres, chiffres, tirets et underscores.`);
21
- }
22
- parsed.projectName = arg;
23
- continue;
24
- }
25
-
26
- if (arg.startsWith('--')) {
27
- const [key, value] = parseFlag(arg);
28
- const nextArg = args[i + 1];
29
-
30
- if (value !== null) {
31
- parsed.flags[key] = value;
32
- } else if (nextArg && !nextArg.startsWith('--')) {
33
- parsed.flags[key] = nextArg;
34
- i++;
35
- } else {
36
- parsed.flags[key] = true;
37
- }
38
- } else {
39
- parsed.positional.push(arg);
40
- }
41
- }
42
-
43
- validateFlags(parsed);
44
- return parsed;
45
- }
46
-
47
- function parseFlag(arg) {
48
- if (arg.includes('=')) {
49
- const [key, ...valueParts] = arg.slice(2).split('=');
50
- return [key, valueParts.join('=')];
51
- }
52
- return [arg.slice(2), null];
53
- }
54
-
55
- function isValidProjectName(name) {
56
- return /^[a-zA-Z0-9_-]+$/.test(name);
57
- }
58
-
59
- function validateFlags(parsed) {
60
- const validOrms = ['prisma', 'typeorm', 'mongoose'];
61
- const validModes = ['full', 'light'];
62
-
63
- if (parsed.flags.orm && !validOrms.includes(parsed.flags.orm)) {
64
- parsed.errors.push(`ORM invalide: "${parsed.flags.orm}". Valeurs acceptées: ${validOrms.join(', ')}`);
65
- }
66
-
67
- if (parsed.flags.mode && !validModes.includes(parsed.flags.mode)) {
68
- parsed.errors.push(`Mode invalide: "${parsed.flags.mode}". Valeurs acceptées: ${validModes.join(', ')}`);
69
- }
70
-
71
- if (parsed.flags.full && parsed.flags.light) {
72
- parsed.errors.push('Les flags --full et --light sont mutuellement exclusifs.');
73
- }
74
- }
75
-
76
- module.exports = { parseCliArgs };
1
+ /* function parseCliArgs(args) {
2
+ const parsed = {
3
+ command: null,
4
+ projectName: null,
5
+ flags: {},
6
+ positional: [],
7
+ errors: []
8
+ };
9
+
10
+ for (let i = 2; i < args.length; i++) {
11
+ const arg = args[i];
12
+
13
+ if (i === 2 && !arg.startsWith('--')) {
14
+ parsed.command = arg;
15
+ continue;
16
+ }
17
+
18
+ if (i === 3 && !arg.startsWith('--') && parsed.command === 'new') {
19
+ if (!isValidProjectName(arg)) {
20
+ parsed.errors.push(`Nom de projet invalide: "${arg}". Utilisez uniquement des lettres, chiffres, tirets et underscores.`);
21
+ }
22
+ parsed.projectName = arg;
23
+ continue;
24
+ }
25
+
26
+ if (arg.startsWith('--')) {
27
+ const [key, value] = parseFlag(arg);
28
+ const nextArg = args[i + 1];
29
+
30
+ if (value !== null) {
31
+ parsed.flags[key] = value;
32
+ } else if (nextArg && !nextArg.startsWith('--')) {
33
+ parsed.flags[key] = nextArg;
34
+ i++;
35
+ } else {
36
+ parsed.flags[key] = true;
37
+ }
38
+ } else {
39
+ parsed.positional.push(arg);
40
+ }
41
+ }
42
+
43
+ validateFlags(parsed);
44
+ return parsed;
45
+ } */
46
+
47
+ function parseCliArgs(args) {
48
+ const parsed = {
49
+ command: null,
50
+ projectName: null, // Pour 'new'
51
+ subCommand: null, // Pour 'generate' (module, auth, etc.)
52
+ targetName: null, // Pour 'generate' (User, Product, etc.)
53
+ flags: {},
54
+ positional: [],
55
+ errors: [],
56
+ };
57
+
58
+ for (let i = 2; i < args.length; i++) {
59
+ const arg = args[i];
60
+
61
+ // Commande principale (new, g, info...)
62
+ if (i === 2 && !arg.startsWith("--")) {
63
+ parsed.command = arg;
64
+ continue;
65
+ }
66
+
67
+ if (arg.startsWith("--")) {
68
+ const [key, value] = parseFlag(arg);
69
+ // ... logique des flags inchangée ...
70
+ const nextArg = args[i + 1];
71
+ if (value !== null) {
72
+ parsed.flags[key] = value;
73
+ } else if (nextArg && !nextArg.startsWith("--")) {
74
+ parsed.flags[key] = nextArg;
75
+ i++;
76
+ } else {
77
+ parsed.flags[key] = true;
78
+ }
79
+ } else {
80
+ parsed.positional.push(arg);
81
+ }
82
+ }
83
+
84
+ // Distribution des arguments selon la commande
85
+ if (parsed.command === "new") {
86
+ parsed.projectName = parsed.positional[0] || null;
87
+ if (parsed.projectName && !isValidProjectName(parsed.projectName)) {
88
+ parsed.errors.push(`Nom de projet invalide: "${parsed.projectName}".`);
89
+ }
90
+ } else if (parsed.command === "generate" || parsed.command === "g") {
91
+ parsed.subCommand = parsed.positional[0] || null; // ex: module
92
+ parsed.targetName = parsed.positional[1] || null; // ex: User
93
+ }
94
+
95
+ validateFlags(parsed);
96
+ return parsed;
97
+ }
98
+ function parseFlag(arg) {
99
+ if (arg.includes("=")) {
100
+ const [key, ...valueParts] = arg.slice(2).split("=");
101
+ return [key, valueParts.join("=")];
102
+ }
103
+ return [arg.slice(2), null];
104
+ }
105
+
106
+ function isValidProjectName(name) {
107
+ return /^[a-zA-Z0-9_-]+$/.test(name);
108
+ }
109
+
110
+ function validateFlags(parsed) {
111
+ const validOrms = ["prisma", "typeorm", "mongoose"];
112
+ const validModes = ["full", "light"];
113
+
114
+ if (parsed.flags.orm && !validOrms.includes(parsed.flags.orm)) {
115
+ parsed.errors.push(
116
+ `ORM invalide: "${parsed.flags.orm}". Valeurs acceptées: ${validOrms.join(", ")}`,
117
+ );
118
+ }
119
+
120
+ if (parsed.flags.mode && !validModes.includes(parsed.flags.mode)) {
121
+ parsed.errors.push(
122
+ `Mode invalide: "${parsed.flags.mode}". Valeurs acceptées: ${validModes.join(", ")}`,
123
+ );
124
+ }
125
+
126
+ if (parsed.flags.full && parsed.flags.light) {
127
+ parsed.errors.push(
128
+ "Les flags --full et --light sont mutuellement exclusifs.",
129
+ );
130
+ }
131
+ }
132
+
133
+ module.exports = { parseCliArgs };
package/utils/colors.js CHANGED
@@ -1,62 +1,62 @@
1
- const colors = {
2
- reset: '\x1b[0m',
3
- bold: '\x1b[1m',
4
- dim: '\x1b[2m',
5
-
6
- black: '\x1b[30m',
7
- red: '\x1b[31m',
8
- green: '\x1b[32m',
9
- yellow: '\x1b[33m',
10
- blue: '\x1b[34m',
11
- magenta: '\x1b[35m',
12
- cyan: '\x1b[36m',
13
- white: '\x1b[37m',
14
-
15
- bgBlack: '\x1b[40m',
16
- bgRed: '\x1b[41m',
17
- bgGreen: '\x1b[42m',
18
- bgYellow: '\x1b[43m',
19
- bgBlue: '\x1b[44m',
20
- bgMagenta: '\x1b[45m',
21
- bgCyan: '\x1b[46m',
22
- bgWhite: '\x1b[47m'
23
- };
24
-
25
- function colorize(text, color) {
26
- return `${colors[color]}${text}${colors.reset}`;
27
- }
28
-
29
- function success(text) {
30
- return colorize(text, 'green');
31
- }
32
-
33
- function error(text) {
34
- return colorize(text, 'red');
35
- }
36
-
37
- function warning(text) {
38
- return colorize(text, 'yellow');
39
- }
40
-
41
- function info(text) {
42
- return colorize(text, 'cyan');
43
- }
44
-
45
- function bold(text) {
46
- return `${colors.bold}${text}${colors.reset}`;
47
- }
48
-
49
- function dim(text) {
50
- return `${colors.dim}${text}${colors.reset}`;
51
- }
52
-
53
- module.exports = {
54
- colors,
55
- colorize,
56
- success,
57
- error,
58
- warning,
59
- info,
60
- bold,
61
- dim
62
- };
1
+ const colors = {
2
+ reset: '\x1b[0m',
3
+ bold: '\x1b[1m',
4
+ dim: '\x1b[2m',
5
+
6
+ black: '\x1b[30m',
7
+ red: '\x1b[31m',
8
+ green: '\x1b[32m',
9
+ yellow: '\x1b[33m',
10
+ blue: '\x1b[34m',
11
+ magenta: '\x1b[35m',
12
+ cyan: '\x1b[36m',
13
+ white: '\x1b[37m',
14
+
15
+ bgBlack: '\x1b[40m',
16
+ bgRed: '\x1b[41m',
17
+ bgGreen: '\x1b[42m',
18
+ bgYellow: '\x1b[43m',
19
+ bgBlue: '\x1b[44m',
20
+ bgMagenta: '\x1b[45m',
21
+ bgCyan: '\x1b[46m',
22
+ bgWhite: '\x1b[47m'
23
+ };
24
+
25
+ function colorize(text, color) {
26
+ return `${colors[color]}${text}${colors.reset}`;
27
+ }
28
+
29
+ function success(text) {
30
+ return colorize(text, 'green');
31
+ }
32
+
33
+ function error(text) {
34
+ return colorize(text, 'red');
35
+ }
36
+
37
+ function warning(text) {
38
+ return colorize(text, 'yellow');
39
+ }
40
+
41
+ function info(text) {
42
+ return colorize(text, 'cyan');
43
+ }
44
+
45
+ function bold(text) {
46
+ return `${colors.bold}${text}${colors.reset}`;
47
+ }
48
+
49
+ function dim(text) {
50
+ return `${colors.dim}${text}${colors.reset}`;
51
+ }
52
+
53
+ module.exports = {
54
+ colors,
55
+ colorize,
56
+ success,
57
+ error,
58
+ warning,
59
+ info,
60
+ bold,
61
+ dim
62
+ };
@@ -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 };