backend-scaffold-cli 1.1.0 → 1.2.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/bin/cli.js +193 -153
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
const { program } = require('commander');
|
|
@@ -8,133 +8,153 @@ const fs = require('fs-extra');
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const { execSync } = require('child_process');
|
|
10
10
|
|
|
11
|
-
const version= '1.0.0';
|
|
11
|
+
const version = '1.0.0';
|
|
12
12
|
|
|
13
13
|
program
|
|
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
|
-
const projectPath = path.resolve(process.cwd(), projectName);
|
|
49
|
-
|
|
50
|
-
if (fs.existsSync(projectPath)) {
|
|
51
|
-
console.log(chalk.red(`Error: Directory ${projectName} already exists.`));
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
console.log(chalk.blue(`Creating project in ${projectPath}\n`));
|
|
56
|
-
fs.ensureDirSync(projectPath);
|
|
57
|
-
|
|
58
|
-
createFolderStructure(projectPath);
|
|
59
|
-
createConfigFiles(projectPath, answers);
|
|
60
|
-
createMiddlewareFiles(projectPath, answers);
|
|
61
|
-
createRouteFiles(projectPath, answers);
|
|
62
|
-
|
|
63
|
-
console.log(chalk.cyan(' Initializing git repository...'));
|
|
64
|
-
execSync('git init', { cwd: projectPath });
|
|
65
|
-
|
|
66
|
-
if (answers.installDeps) {
|
|
67
|
-
console.log(chalk.cyan(' Installing dependencies...\n'));
|
|
68
|
-
execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
console.log(chalk.green.bold('\n Project created successfully!\n'));
|
|
72
|
-
console.log(chalk.cyan('Next steps:'));
|
|
73
|
-
console.log(chalk.white(` cd ${projectName}`));
|
|
74
|
-
console.log(chalk.white(' cp .env.example .env'));
|
|
75
|
-
console.log(chalk.white(' npm start\n'));
|
|
76
|
-
}catch (error) {
|
|
77
|
-
console.error(chalk.red('\n Error creating project:'), error.message);
|
|
78
|
-
process.exit(1);
|
|
14
|
+
.version(version)
|
|
15
|
+
.description('Create a new Express.js backend application')
|
|
16
|
+
.argument('<project-name>', 'Name of the project')
|
|
17
|
+
.action(async (projectName) => {
|
|
18
|
+
try {
|
|
19
|
+
console.log(chalk.blue(`Creating a new Express.js backend application: ${projectName}`));
|
|
20
|
+
|
|
21
|
+
const answers = await inquirer.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: 'confirm',
|
|
24
|
+
name: 'useAuth',
|
|
25
|
+
message: 'Include JWT authentication?',
|
|
26
|
+
default: true
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: 'confirm',
|
|
30
|
+
name: 'useValidation',
|
|
31
|
+
message: 'Include input validation?',
|
|
32
|
+
default: true
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
type: 'confirm',
|
|
36
|
+
name: 'useRateLimit',
|
|
37
|
+
message: 'Include rate limiting?',
|
|
38
|
+
default: true
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
type: 'confirm',
|
|
42
|
+
name: 'installDeps',
|
|
43
|
+
message: 'Install dependencies now?',
|
|
44
|
+
default: true
|
|
79
45
|
}
|
|
80
|
-
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const projectPath = path.resolve(process.cwd(), projectName);
|
|
55
|
+
|
|
56
|
+
if (fs.existsSync(projectPath)) {
|
|
57
|
+
console.log(chalk.red(`Error: Directory ${projectName} already exists.`));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(chalk.blue(`Creating project in ${projectPath}\n`));
|
|
62
|
+
fs.ensureDirSync(projectPath);
|
|
63
|
+
|
|
64
|
+
createFolderStructure(projectPath);
|
|
65
|
+
createConfigFiles(projectPath, answers);
|
|
66
|
+
createMiddlewareFiles(projectPath, answers);
|
|
67
|
+
createRouteFiles(projectPath, answers);
|
|
68
|
+
|
|
69
|
+
console.log(chalk.cyan(' Initializing git repository...'));
|
|
70
|
+
execSync('git init', { cwd: projectPath });
|
|
71
|
+
|
|
72
|
+
if (answers.installDeps) {
|
|
73
|
+
console.log(chalk.cyan(' Installing dependencies...\n'));
|
|
74
|
+
execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(chalk.green.bold('\n Project created successfully!\n'));
|
|
78
|
+
console.log(chalk.cyan('Next steps:'));
|
|
79
|
+
console.log(chalk.white(` cd ${projectName}`));
|
|
80
|
+
console.log(chalk.white(' cp .env.example .env'));
|
|
81
|
+
console.log(chalk.white(' npm start\n'));
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error(chalk.red('\n Error creating project:'), error.message);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
81
87
|
|
|
82
88
|
program.parse();
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
const createFolderStructure = (projectPath) => {
|
|
95
|
+
const folders = [
|
|
96
|
+
'src/config',
|
|
97
|
+
'src/middleware',
|
|
98
|
+
'src/routes',
|
|
99
|
+
'src/controllers',
|
|
100
|
+
'src/models',
|
|
101
|
+
'src/utils',
|
|
102
|
+
'src/validation'
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
folders.forEach(folder => {
|
|
106
|
+
fs.ensureDirSync(path.join(projectPath, folder));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
console.log(chalk.green(' Folder structure created'));
|
|
100
110
|
|
|
101
111
|
}
|
|
102
112
|
|
|
103
113
|
|
|
104
|
-
const createConfigFiles= (projectPath,answers) =>{
|
|
105
|
-
const packageJson={
|
|
106
|
-
name: path.basename(projectPath),
|
|
107
|
-
version: '1.0.0',
|
|
108
|
-
main: 'src/server.js',
|
|
109
|
-
scripts: {
|
|
110
|
-
start: 'node src/server.js',
|
|
111
|
-
dev: 'nodemon src/server.js',
|
|
112
|
-
test: 'jest'
|
|
113
|
-
},
|
|
114
|
-
keywords: ['express', 'nodejs', 'backend'],
|
|
115
|
-
author: '',
|
|
116
|
-
license: 'MIT',
|
|
117
|
-
dependencies: {
|
|
118
|
-
express: '^4.18.2',
|
|
119
|
-
mongoose: '^7.0.0',
|
|
120
|
-
dotenv: '^16.0.3',
|
|
121
|
-
cors: '^2.8.5',
|
|
122
|
-
'express-rate-limit': '^6.7.0',
|
|
123
|
-
...(answers.useAuth && { jsonwebtoken: '^9.0.0' }),
|
|
124
|
-
...(answers.useValidation && { joi: '^17.9.0' })
|
|
125
|
-
},
|
|
126
|
-
devDependencies: {
|
|
127
|
-
nodemon: '^2.0.22',
|
|
128
|
-
}
|
|
129
114
|
|
|
130
|
-
};
|
|
131
115
|
|
|
132
|
-
fs.writeFileSync(
|
|
133
|
-
path.join(projectPath, 'package.json'),
|
|
134
|
-
JSON.stringify(packageJson, null, 2)
|
|
135
|
-
);
|
|
136
116
|
|
|
137
|
-
|
|
117
|
+
|
|
118
|
+
const createConfigFiles = (projectPath, answers) => {
|
|
119
|
+
const packageJson = {
|
|
120
|
+
name: path.basename(projectPath),
|
|
121
|
+
version: '1.0.0',
|
|
122
|
+
main: 'src/server.js',
|
|
123
|
+
scripts: {
|
|
124
|
+
start: 'node src/server.js',
|
|
125
|
+
dev: 'nodemon src/server.js',
|
|
126
|
+
test: 'jest'
|
|
127
|
+
},
|
|
128
|
+
keywords: ['express', 'nodejs', 'backend'],
|
|
129
|
+
author: '',
|
|
130
|
+
license: 'MIT',
|
|
131
|
+
dependencies: {
|
|
132
|
+
express: '^4.18.2',
|
|
133
|
+
mongoose: '^7.0.0',
|
|
134
|
+
dotenv: '^16.0.3',
|
|
135
|
+
cors: '^2.8.5',
|
|
136
|
+
...(answers.useAuth && { jsonwebtoken: '^9.0.0' }),
|
|
137
|
+
...(answers.useValidation && { joi: '^17.9.0' }),
|
|
138
|
+
...(answers.useRateLimit && { 'express-rate-limit': '^6.7.0' }),
|
|
139
|
+
|
|
140
|
+
},
|
|
141
|
+
devDependencies: {
|
|
142
|
+
nodemon: '^2.0.22',
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
fs.writeFileSync(
|
|
148
|
+
path.join(projectPath, 'package.json'),
|
|
149
|
+
JSON.stringify(packageJson, null, 2)
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
const env = `# Server Configuration
|
|
138
158
|
PORT=5000
|
|
139
159
|
NODE_ENV=development
|
|
140
160
|
|
|
@@ -158,10 +178,12 @@ CORS_ORIGIN=http://localhost:3000
|
|
|
158
178
|
LOG_LEVEL=debug
|
|
159
179
|
`;
|
|
160
180
|
|
|
161
|
-
|
|
181
|
+
fs.writeFileSync(path.join(projectPath, '.env.example'), env);
|
|
162
182
|
|
|
163
183
|
|
|
164
|
-
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
const gitignore = `node_modules/
|
|
165
187
|
.env
|
|
166
188
|
.env.local
|
|
167
189
|
.env.*.local
|
|
@@ -175,9 +197,9 @@ yarn-debug.log*
|
|
|
175
197
|
.vscode/
|
|
176
198
|
`;
|
|
177
199
|
|
|
178
|
-
|
|
200
|
+
fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore);
|
|
179
201
|
|
|
180
|
-
|
|
202
|
+
console.log(chalk.green(' Config files created'));
|
|
181
203
|
|
|
182
204
|
|
|
183
205
|
};
|
|
@@ -185,6 +207,8 @@ yarn-debug.log*
|
|
|
185
207
|
|
|
186
208
|
|
|
187
209
|
|
|
210
|
+
|
|
211
|
+
|
|
188
212
|
function createMiddlewareFiles(projectPath, answers) {
|
|
189
213
|
const errorHandler = `// Middleware for handling errors
|
|
190
214
|
class ErrorHandler extends Error {
|
|
@@ -223,15 +247,16 @@ const errorMiddleware = (err, req, res, next) => {
|
|
|
223
247
|
module.exports = { errorMiddleware, ErrorHandler };
|
|
224
248
|
`;
|
|
225
249
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
250
|
+
fs.writeFileSync(
|
|
251
|
+
path.join(projectPath, 'src/middleware/errorHandler.js'),
|
|
252
|
+
errorHandler
|
|
253
|
+
);
|
|
230
254
|
|
|
231
255
|
|
|
232
256
|
|
|
233
257
|
|
|
234
|
-
|
|
258
|
+
|
|
259
|
+
const logger = `// Simple logging middleware
|
|
235
260
|
const loggerMiddleware = (req, res, next) => {
|
|
236
261
|
const start = Date.now();
|
|
237
262
|
|
|
@@ -248,19 +273,24 @@ const loggerMiddleware = (req, res, next) => {
|
|
|
248
273
|
module.exports = loggerMiddleware;
|
|
249
274
|
`;
|
|
250
275
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
276
|
+
fs.writeFileSync(
|
|
277
|
+
path.join(projectPath, 'src/middleware/logger.js'),
|
|
278
|
+
logger
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
|
|
255
282
|
|
|
256
283
|
|
|
257
284
|
|
|
258
|
-
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
if (answers.useRateLimit) {
|
|
288
|
+
const rateLimiter = `const ratelimit= require('express-rate-limit');
|
|
259
289
|
|
|
260
290
|
const limiter=ratelimit({
|
|
261
291
|
windowMs: 15 * 60 * 1000,
|
|
262
292
|
max: 100,
|
|
263
|
-
message: 'Too many requests from this IP, please try again after 15 minutes'
|
|
293
|
+
message: 'Too many requests from this IP, please try again after 15 minutes',
|
|
264
294
|
standardHeaders: true,
|
|
265
295
|
legacyHeaders: false,
|
|
266
296
|
});
|
|
@@ -271,13 +301,19 @@ module.exports=limiter;
|
|
|
271
301
|
`;
|
|
272
302
|
|
|
273
303
|
fs.writeFileSync(
|
|
274
|
-
|
|
275
|
-
|
|
304
|
+
path.join(projectPath, 'src/middleware/rateLimiter.js'),
|
|
305
|
+
rateLimiter
|
|
276
306
|
);
|
|
277
307
|
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
278
312
|
|
|
279
|
-
|
|
280
|
-
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
if (answers.useAuth) {
|
|
316
|
+
const auth = `const jwt = require('jsonwebtoken');
|
|
281
317
|
const { ErrorHandler } = require('./errorHandler');
|
|
282
318
|
|
|
283
319
|
const authenticateToken = (req, res, next) => {
|
|
@@ -300,15 +336,16 @@ module.exports = authenticateToken;
|
|
|
300
336
|
`;
|
|
301
337
|
|
|
302
338
|
fs.writeFileSync(
|
|
303
|
-
|
|
304
|
-
|
|
339
|
+
path.join(projectPath, 'src/middleware/auth.js'),
|
|
340
|
+
auth
|
|
305
341
|
);
|
|
306
342
|
}
|
|
307
343
|
|
|
308
344
|
|
|
309
345
|
|
|
310
|
-
|
|
311
|
-
|
|
346
|
+
|
|
347
|
+
if (answers.useValidation) {
|
|
348
|
+
const validation = `const Joi = require('joi');
|
|
312
349
|
|
|
313
350
|
const validateRequest = (schema) => {
|
|
314
351
|
return (req, res, next) => {
|
|
@@ -334,8 +371,8 @@ module.exports = validateRequest;
|
|
|
334
371
|
`;
|
|
335
372
|
|
|
336
373
|
fs.writeFileSync(
|
|
337
|
-
|
|
338
|
-
|
|
374
|
+
path.join(projectPath, 'src/middleware/validation.js'),
|
|
375
|
+
validation
|
|
339
376
|
);
|
|
340
377
|
}
|
|
341
378
|
|
|
@@ -365,14 +402,16 @@ router.get('/protected', authenticateToken, (req, res) => {
|
|
|
365
402
|
|
|
366
403
|
module.exports = router;
|
|
367
404
|
`;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
405
|
+
fs.writeFileSync(
|
|
406
|
+
path.join(projectPath, 'src/routes/index.js'),
|
|
407
|
+
routes
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
|
|
372
412
|
|
|
373
|
-
|
|
374
413
|
|
|
375
|
-
const dbConfig = `const mongoose = require('mongoose');
|
|
414
|
+
const dbConfig = `const mongoose = require('mongoose');
|
|
376
415
|
const dns = require('dns');
|
|
377
416
|
|
|
378
417
|
// Set DNS servers
|
|
@@ -406,15 +445,16 @@ const connectDB = async () => {
|
|
|
406
445
|
module.exports = connectDB;
|
|
407
446
|
`;
|
|
408
447
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
448
|
+
fs.writeFileSync(
|
|
449
|
+
path.join(projectPath, 'src/config/db.js'),
|
|
450
|
+
dbConfig
|
|
451
|
+
);
|
|
452
|
+
|
|
413
453
|
|
|
414
454
|
|
|
415
455
|
|
|
416
456
|
|
|
417
|
-
const server = `require('dotenv').config();
|
|
457
|
+
const server = `require('dotenv').config();
|
|
418
458
|
const express = require('express');
|
|
419
459
|
const cors = require('cors');
|
|
420
460
|
const connectDB = require('./config/db');
|
|
@@ -423,7 +463,7 @@ const loggerMiddleware = require('./middleware/logger');
|
|
|
423
463
|
const { errorMiddleware } = require('./middleware/errorHandler');
|
|
424
464
|
|
|
425
465
|
const app = express();
|
|
426
|
-
const limiter = require('./middleware/rateLimiter');
|
|
466
|
+
${answers.useRateLimit ? "const limiter = require('./middleware/rateLimiter');" : ''}
|
|
427
467
|
const PORT = process.env.PORT || 5000;
|
|
428
468
|
|
|
429
469
|
// Connect to MongoDB
|
|
@@ -437,7 +477,7 @@ app.use(cors({
|
|
|
437
477
|
app.use(express.json());
|
|
438
478
|
app.use(express.urlencoded({ extended: true }));
|
|
439
479
|
app.use(loggerMiddleware);
|
|
440
|
-
app.use(limiter);
|
|
480
|
+
${answers.useRateLimit ? 'app.use(limiter);' : ''}
|
|
441
481
|
|
|
442
482
|
|
|
443
483
|
// Routes
|