express-genix 1.1.4 ā 2.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.
- package/LICENSE +21 -0
- package/README.md +204 -259
- package/index.js +229 -113
- package/lib/cleanup.js +41 -129
- package/lib/features.js +239 -0
- package/lib/generator.js +286 -204
- package/lib/utils.js +43 -91
- package/package.json +81 -63
- package/templates/cicd/github-actions.yml.ejs +70 -0
- package/templates/config/database.mongo.js.ejs +29 -33
- package/templates/config/database.postgres.js.ejs +41 -40
- package/templates/config/database.prisma.js.ejs +26 -0
- package/templates/config/redis.js.ejs +28 -0
- package/templates/config/schema.prisma.ejs +20 -0
- package/templates/config/swagger.js.ejs +30 -0
- package/templates/config/websocket.js.ejs +62 -0
- package/templates/controllers/authController.js.ejs +152 -129
- package/templates/controllers/exampleController.js.ejs +92 -152
- package/templates/controllers/userController.js.ejs +52 -60
- package/templates/core/Dockerfile.ejs +41 -31
- package/templates/core/README.md.ejs +191 -179
- package/templates/core/app.js.ejs +114 -64
- package/templates/core/docker-compose.yml.ejs +59 -47
- package/templates/core/dockerignore.ejs +7 -0
- package/templates/core/env.ejs +25 -19
- package/templates/core/env.example.ejs +26 -0
- package/templates/core/eslintrc.json.ejs +50 -20
- package/templates/core/gitignore.ejs +51 -51
- package/templates/core/healthcheck.js.ejs +24 -24
- package/templates/core/jest.config.js.ejs +19 -22
- package/templates/core/package.json.ejs +70 -33
- package/templates/core/prettierrc.json.ejs +11 -11
- package/templates/core/server.js.ejs +64 -48
- package/templates/core/tsconfig.json.ejs +19 -0
- package/templates/middleware/auth.js.ejs +80 -66
- package/templates/middleware/cache.js.ejs +67 -0
- package/templates/middleware/errorHandler.js.ejs +50 -46
- package/templates/middleware/requestId.js.ejs +9 -0
- package/templates/middleware/validation.js.ejs +109 -47
- package/templates/migrations/create-users.js.ejs +50 -0
- package/templates/migrations/seed-users.js.ejs +34 -0
- package/templates/migrations/sequelizerc.ejs +8 -0
- package/templates/models/User.mongo.js.ejs +29 -29
- package/templates/models/User.postgres.js.ejs +40 -40
- package/templates/models/index.mongo.js.ejs +7 -7
- package/templates/models/index.postgres.js.ejs +11 -11
- package/templates/routes/authRoutes.js.ejs +222 -13
- package/templates/routes/exampleRoutes.js.ejs +100 -12
- package/templates/routes/index.js.ejs +34 -24
- package/templates/routes/userRoutes.js.ejs +78 -15
- package/templates/services/authService.js.ejs +111 -35
- package/templates/services/exampleService.js.ejs +112 -112
- package/templates/services/userService.mongodb.js.ejs +33 -33
- package/templates/services/userService.postgres.js.ejs +30 -30
- package/templates/services/userService.prisma.js.ejs +36 -0
- package/templates/tests/auth.test.js.ejs +83 -66
- package/templates/tests/example.test.js.ejs +109 -112
- package/templates/tests/setup.js.ejs +11 -11
- package/templates/tests/users.test.js.ejs +42 -42
- package/templates/utils/envValidator.js.ejs +23 -0
- package/templates/utils/errors.js.ejs +12 -12
- package/templates/utils/logger.js.ejs +37 -28
- package/templates/utils/response.js.ejs +28 -0
- package/templates/utils/validators.js.ejs +34 -34
- package/templates/config/swagger.json.ejs +0 -194
- package/templates/core/index.js.ejs +0 -24
package/index.js
CHANGED
|
@@ -1,114 +1,230 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const { program } = require('commander');
|
|
4
|
-
const inquirer = require('inquirer');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const
|
|
8
|
-
const {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
.
|
|
21
|
-
.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
const { runPostGenerationCleanup } = require('./lib/cleanup');
|
|
10
|
+
const { generateProject } = require('./lib/generator');
|
|
11
|
+
|
|
12
|
+
const pkg = require('./package.json');
|
|
13
|
+
const prompt = inquirer.createPromptModule();
|
|
14
|
+
|
|
15
|
+
const generateSecret = (length = 64) => crypto.randomBytes(length).toString('hex');
|
|
16
|
+
|
|
17
|
+
async function main() {
|
|
18
|
+
program
|
|
19
|
+
.name('express-genix')
|
|
20
|
+
.description('Production-grade CLI to generate Express.js applications')
|
|
21
|
+
.version(pkg.version);
|
|
22
|
+
|
|
23
|
+
program
|
|
24
|
+
.command('init')
|
|
25
|
+
.description('Initialize a new Express project')
|
|
26
|
+
.option('--skip-cleanup', 'Skip post-generation cleanup (for debugging)')
|
|
27
|
+
.option('--skip-install', 'Skip npm install (for CI/testing)')
|
|
28
|
+
.action(async (options) => {
|
|
29
|
+
const answers = await prompt([
|
|
30
|
+
{
|
|
31
|
+
type: 'input',
|
|
32
|
+
name: 'projectName',
|
|
33
|
+
message: 'Project name:',
|
|
34
|
+
default: 'my-express-app',
|
|
35
|
+
validate: (input) => {
|
|
36
|
+
if (!/^[a-zA-Z0-9-_]+$/.test(input)) {
|
|
37
|
+
return 'Project name can only contain letters, numbers, hyphens, and underscores';
|
|
38
|
+
}
|
|
39
|
+
if (input.length > 100) {
|
|
40
|
+
return 'Project name must be less than 100 characters';
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'list',
|
|
47
|
+
name: 'language',
|
|
48
|
+
message: 'Language:',
|
|
49
|
+
choices: [
|
|
50
|
+
{ name: 'JavaScript', value: 'javascript' },
|
|
51
|
+
{ name: 'TypeScript', value: 'typescript' },
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'list',
|
|
56
|
+
name: 'db',
|
|
57
|
+
message: 'Database:',
|
|
58
|
+
choices: [
|
|
59
|
+
{ name: 'MongoDB (with Mongoose)', value: 'mongodb' },
|
|
60
|
+
{ name: 'PostgreSQL (with Sequelize)', value: 'postgresql' },
|
|
61
|
+
{ name: 'PostgreSQL (with Prisma)', value: 'prisma' },
|
|
62
|
+
{ name: 'No Database (API without database)', value: 'none' },
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: 'checkbox',
|
|
67
|
+
name: 'features',
|
|
68
|
+
message: 'Select additional features:',
|
|
69
|
+
choices: [
|
|
70
|
+
{ name: 'JWT Authentication', value: 'auth', checked: true },
|
|
71
|
+
{ name: 'Rate Limiting', value: 'rateLimit', checked: true },
|
|
72
|
+
{ name: 'Swagger/OpenAPI Docs', value: 'swagger', checked: true },
|
|
73
|
+
{ name: 'Redis Token Blacklist', value: 'redis' },
|
|
74
|
+
{ name: 'Docker & Docker Compose', value: 'docker', checked: true },
|
|
75
|
+
{ name: 'CI/CD (GitHub Actions)', value: 'cicd' },
|
|
76
|
+
{ name: 'WebSocket (Socket.io)', value: 'websocket' },
|
|
77
|
+
{ name: 'Request ID / Correlation ID', value: 'requestId', checked: true },
|
|
78
|
+
],
|
|
79
|
+
when: (ans) => ans.db !== 'none',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: 'checkbox',
|
|
83
|
+
name: 'features',
|
|
84
|
+
message: 'Select additional features:',
|
|
85
|
+
choices: [
|
|
86
|
+
{ name: 'Rate Limiting', value: 'rateLimit', checked: true },
|
|
87
|
+
{ name: 'Swagger/OpenAPI Docs', value: 'swagger', checked: true },
|
|
88
|
+
{ name: 'Docker & Docker Compose', value: 'docker', checked: true },
|
|
89
|
+
{ name: 'CI/CD (GitHub Actions)', value: 'cicd' },
|
|
90
|
+
{ name: 'WebSocket (Socket.io)', value: 'websocket' },
|
|
91
|
+
{ name: 'Request ID / Correlation ID', value: 'requestId', checked: true },
|
|
92
|
+
],
|
|
93
|
+
when: (ans) => ans.db === 'none',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
type: 'list',
|
|
97
|
+
name: 'logger',
|
|
98
|
+
message: 'Logging library:',
|
|
99
|
+
choices: [
|
|
100
|
+
{ name: 'Winston (feature-rich, widely used)', value: 'winston' },
|
|
101
|
+
{ name: 'Pino (fast, low overhead)', value: 'pino' },
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
const features = answers.features || [];
|
|
107
|
+
const config = {
|
|
108
|
+
projectName: answers.projectName,
|
|
109
|
+
language: answers.language,
|
|
110
|
+
db: answers.db,
|
|
111
|
+
logger: answers.logger,
|
|
112
|
+
hasDatabase: answers.db !== 'none',
|
|
113
|
+
isNoDatabase: answers.db === 'none',
|
|
114
|
+
isPrisma: answers.db === 'prisma',
|
|
115
|
+
isTypescript: answers.language === 'typescript',
|
|
116
|
+
hasAuth: features.includes('auth') && answers.db !== 'none',
|
|
117
|
+
hasRateLimit: features.includes('rateLimit'),
|
|
118
|
+
hasSwagger: features.includes('swagger'),
|
|
119
|
+
hasDocker: features.includes('docker'),
|
|
120
|
+
hasCicd: features.includes('cicd'),
|
|
121
|
+
hasWebsocket: features.includes('websocket'),
|
|
122
|
+
hasRequestId: features.includes('requestId'),
|
|
123
|
+
hasRedis: features.includes('redis') && features.includes('auth') && answers.db !== 'none',
|
|
124
|
+
jwtSecret: generateSecret(),
|
|
125
|
+
jwtRefreshSecret: generateSecret(),
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const projectDir = path.join(process.cwd(), config.projectName);
|
|
129
|
+
|
|
130
|
+
if (fs.existsSync(projectDir)) {
|
|
131
|
+
console.error(`\nā Directory "${config.projectName}" already exists!`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const dbLabel = config.isNoDatabase ? 'no database' : config.db;
|
|
136
|
+
console.log(`\nš Creating ${config.projectName} (${config.language}, ${dbLabel})...\n`);
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
await generateProject(config, projectDir, options);
|
|
140
|
+
|
|
141
|
+
if (!options.skipCleanup) {
|
|
142
|
+
await runPostGenerationCleanup(projectDir, config);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Git init + initial commit
|
|
146
|
+
try {
|
|
147
|
+
execSync('git init', { cwd: projectDir, stdio: 'pipe' });
|
|
148
|
+
execSync('git add -A', { cwd: projectDir, stdio: 'pipe' });
|
|
149
|
+
execSync('git commit -m "Initial commit from express-genix"', {
|
|
150
|
+
cwd: projectDir,
|
|
151
|
+
stdio: 'pipe',
|
|
152
|
+
env: { ...process.env, GIT_COMMITTER_NAME: 'express-genix', GIT_COMMITTER_EMAIL: 'cli@express-genix.dev', GIT_AUTHOR_NAME: 'express-genix', GIT_AUTHOR_EMAIL: 'cli@express-genix.dev' },
|
|
153
|
+
});
|
|
154
|
+
console.log('š¦ Git repository initialized with initial commit');
|
|
155
|
+
} catch {
|
|
156
|
+
// Git not available ā skip silently
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const ext = config.isTypescript ? 'ts' : 'js';
|
|
160
|
+
console.log(`
|
|
161
|
+
ā
Project ${config.projectName} created successfully!
|
|
162
|
+
|
|
163
|
+
To get started:
|
|
164
|
+
cd ${config.projectName}
|
|
165
|
+
npm run dev
|
|
166
|
+
${config.hasSwagger ? `\nAPI Documentation: http://localhost:3000/api-docs` : ''}
|
|
167
|
+
Health Check: http://localhost:3000/health
|
|
168
|
+
|
|
169
|
+
Available scripts:
|
|
170
|
+
npm run dev Start development server
|
|
171
|
+
npm start Start production server
|
|
172
|
+
npm test Run tests
|
|
173
|
+
npm run lint Run ESLint
|
|
174
|
+
npm run lint:fix Fix ESLint issues
|
|
175
|
+
npm run format Format with Prettier${config.isTypescript ? '\n npm run build Compile TypeScript' : ''}
|
|
176
|
+
|
|
177
|
+
Configuration:
|
|
178
|
+
Language: ${config.isTypescript ? 'TypeScript' : 'JavaScript'}
|
|
179
|
+
Database: ${config.isNoDatabase ? 'None' : config.db}
|
|
180
|
+
Authentication: ${config.hasAuth ? 'JWT with refresh tokens' : 'None'}
|
|
181
|
+
Logger: ${config.logger}
|
|
182
|
+
Features: ${features.join(', ') || 'base'}
|
|
183
|
+
`);
|
|
184
|
+
|
|
185
|
+
} catch (error) {
|
|
186
|
+
// Rollback: remove partial project directory on failure
|
|
187
|
+
if (fs.existsSync(projectDir)) {
|
|
188
|
+
fs.rmSync(projectDir, { recursive: true, force: true });
|
|
189
|
+
console.error('\nš§¹ Rolled back partial project directory.');
|
|
190
|
+
}
|
|
191
|
+
console.error(`\nā Failed to create project: ${error.message}`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
program
|
|
197
|
+
.command('add <feature>')
|
|
198
|
+
.description('Add a feature to an existing express-genix project')
|
|
199
|
+
.action(async (feature) => {
|
|
200
|
+
const supportedFeatures = ['auth', 'websocket', 'docker', 'cicd', 'prisma'];
|
|
201
|
+
if (!supportedFeatures.includes(feature)) {
|
|
202
|
+
console.error(`ā Unknown feature: "${feature}"`);
|
|
203
|
+
console.log(`Supported features: ${supportedFeatures.join(', ')}`);
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const projectDir = process.cwd();
|
|
208
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
209
|
+
|
|
210
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
211
|
+
console.error('ā No package.json found. Run this command from your project root.');
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log(`Adding ${feature} to project...`);
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const { addFeature } = require('./lib/features');
|
|
219
|
+
await addFeature(feature, projectDir);
|
|
220
|
+
console.log(`ā
${feature} added successfully!`);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.error(`ā Failed to add feature: ${error.message}`);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
await program.parseAsync(process.argv);
|
|
228
|
+
}
|
|
229
|
+
|
|
114
230
|
main().catch(console.error);
|
package/lib/cleanup.js
CHANGED
|
@@ -1,129 +1,41 @@
|
|
|
1
|
-
const { execSync } = require('child_process');
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// Step 2:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (!packageJson.dependencies.validator) {
|
|
43
|
-
packageJson.dependencies.validator = '^13.11.0';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Add formatting and linting scripts
|
|
47
|
-
packageJson.scripts['lint:fix'] = 'eslint . --fix';
|
|
48
|
-
packageJson.scripts.format = 'prettier --write .';
|
|
49
|
-
packageJson.scripts['format:check'] = 'prettier --check .';
|
|
50
|
-
|
|
51
|
-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const setupPrettier = async (projectDir) => {
|
|
55
|
-
console.log('Installing and configuring Prettier...');
|
|
56
|
-
|
|
57
|
-
// Install Prettier
|
|
58
|
-
execSync(`cd "${projectDir}" && npm install --save-dev prettier`, { stdio: 'pipe' });
|
|
59
|
-
|
|
60
|
-
// Create Prettier config
|
|
61
|
-
const prettierConfig = {
|
|
62
|
-
semi: true,
|
|
63
|
-
trailingComma: 'es5',
|
|
64
|
-
singleQuote: true,
|
|
65
|
-
printWidth: 80,
|
|
66
|
-
tabWidth: 2,
|
|
67
|
-
useTabs: false,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
fs.writeFileSync(
|
|
71
|
-
path.join(projectDir, '.prettierrc'),
|
|
72
|
-
JSON.stringify(prettierConfig, null, 2)
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
// Install any missing dependencies
|
|
76
|
-
execSync(`cd "${projectDir}" && npm install`, { stdio: 'pipe' });
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const runEslintFix = async (projectDir) => {
|
|
80
|
-
console.log('Running eslint --fix...');
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
execSync(`cd "${projectDir}" && npm run lint:fix`, { stdio: 'pipe' });
|
|
84
|
-
console.log('ESLint auto-fixes applied');
|
|
85
|
-
} catch (error) {
|
|
86
|
-
console.log('Some ESLint issues need manual fixing');
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const formatWithPrettier = async (projectDir) => {
|
|
91
|
-
console.log('Formatting code with Prettier...');
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
execSync(`cd "${projectDir}" && npm run format`, { stdio: 'pipe' });
|
|
95
|
-
console.log('Code formatted with Prettier');
|
|
96
|
-
} catch (error) {
|
|
97
|
-
console.warn('Prettier formatting encountered issues');
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const validateOutput = async (projectDir) => {
|
|
102
|
-
console.log('Testing generated output against linting rules...');
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
execSync(`cd "${projectDir}" && npm run lint`, {
|
|
106
|
-
encoding: 'utf8',
|
|
107
|
-
stdio: 'pipe'
|
|
108
|
-
});
|
|
109
|
-
console.log('All linting checks passed!');
|
|
110
|
-
return true;
|
|
111
|
-
} catch (error) {
|
|
112
|
-
// Count remaining errors
|
|
113
|
-
const stdout = error.stdout || '';
|
|
114
|
-
const errorMatches = stdout.match(/(\d+) problems?/);
|
|
115
|
-
const errorCount = errorMatches ? errorMatches[1] : 'some';
|
|
116
|
-
|
|
117
|
-
console.log(`Validation complete: ${errorCount} issues remaining`);
|
|
118
|
-
|
|
119
|
-
if (parseInt(errorCount) < 20) {
|
|
120
|
-
console.log('Great improvement! Most issues have been resolved.');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
module.exports = {
|
|
128
|
-
runPostGenerationCleanup,
|
|
129
|
-
};
|
|
1
|
+
const { execSync } = require('child_process');
|
|
2
|
+
|
|
3
|
+
const runPostGenerationCleanup = async (projectDir) => {
|
|
4
|
+
console.log('\nš§ Running post-generation cleanup...');
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
// Step 1: Run eslint --fix
|
|
8
|
+
try {
|
|
9
|
+
execSync(`cd "${projectDir}" && npx eslint . --fix`, { stdio: 'pipe' });
|
|
10
|
+
console.log('ā
ESLint auto-fixes applied');
|
|
11
|
+
} catch {
|
|
12
|
+
console.log('ā ļø Some ESLint issues may need manual fixing');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Step 2: Format with Prettier
|
|
16
|
+
try {
|
|
17
|
+
execSync(`cd "${projectDir}" && npx prettier --write .`, { stdio: 'pipe' });
|
|
18
|
+
console.log('ā
Code formatted with Prettier');
|
|
19
|
+
} catch {
|
|
20
|
+
console.warn('ā ļø Prettier formatting encountered issues');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Step 3: Validate
|
|
24
|
+
try {
|
|
25
|
+
execSync(`cd "${projectDir}" && npx eslint .`, { encoding: 'utf8', stdio: 'pipe' });
|
|
26
|
+
console.log('ā
All linting checks passed');
|
|
27
|
+
} catch (error) {
|
|
28
|
+
const stdout = error.stdout || '';
|
|
29
|
+
const match = stdout.match(/(\d+) problems?/);
|
|
30
|
+
const count = match ? match[1] : 'some';
|
|
31
|
+
console.log(`ā ļø ${count} lint issues remaining (run "npm run lint:fix" to resolve)`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log('ā
Post-generation cleanup completed\n');
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.warn('ā ļø Some cleanup steps failed:', error.message);
|
|
37
|
+
console.log('You can manually run: npm run lint:fix && npm run format');
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
module.exports = { runPostGenerationCleanup };
|