backend-scaffold-cli 1.2.0 → 1.4.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 (2) hide show
  1. package/bin/cli.js +157 -5
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -37,6 +37,12 @@ program
37
37
  message: 'Include rate limiting?',
38
38
  default: true
39
39
  },
40
+ {
41
+ type: 'confirm',
42
+ name: 'useFileUpload',
43
+ message: 'Include file upload support (multer)?',
44
+ default: true
45
+ },
40
46
  {
41
47
  type: 'confirm',
42
48
  name: 'installDeps',
@@ -61,10 +67,13 @@ program
61
67
  console.log(chalk.blue(`Creating project in ${projectPath}\n`));
62
68
  fs.ensureDirSync(projectPath);
63
69
 
64
- createFolderStructure(projectPath);
70
+ createFolderStructure(projectPath, answers);
65
71
  createConfigFiles(projectPath, answers);
66
72
  createMiddlewareFiles(projectPath, answers);
67
73
  createRouteFiles(projectPath, answers);
74
+ if (answers.useAuth) {
75
+ createUserModel(projectPath);
76
+ }
68
77
 
69
78
  console.log(chalk.cyan(' Initializing git repository...'));
70
79
  execSync('git init', { cwd: projectPath });
@@ -91,7 +100,7 @@ program.parse();
91
100
 
92
101
 
93
102
 
94
- const createFolderStructure = (projectPath) => {
103
+ const createFolderStructure = (projectPath, answers) => {
95
104
  const folders = [
96
105
  'src/config',
97
106
  'src/middleware',
@@ -102,12 +111,15 @@ const createFolderStructure = (projectPath) => {
102
111
  'src/validation'
103
112
  ];
104
113
 
114
+ if (answers.useFileUpload) {
115
+ folders.push('uploads');
116
+ }
117
+
105
118
  folders.forEach(folder => {
106
119
  fs.ensureDirSync(path.join(projectPath, folder));
107
120
  });
108
121
 
109
122
  console.log(chalk.green(' Folder structure created'));
110
-
111
123
  }
112
124
 
113
125
 
@@ -133,9 +145,10 @@ const createConfigFiles = (projectPath, answers) => {
133
145
  mongoose: '^7.0.0',
134
146
  dotenv: '^16.0.3',
135
147
  cors: '^2.8.5',
136
- ...(answers.useAuth && { jsonwebtoken: '^9.0.0' }),
148
+ ...(answers.useAuth && { jsonwebtoken: '^9.0.0' , bcryptjs: '^2.4.3'}),
137
149
  ...(answers.useValidation && { joi: '^17.9.0' }),
138
150
  ...(answers.useRateLimit && { 'express-rate-limit': '^6.7.0' }),
151
+ ...(answers.useFileUpload && { multer: '^2.0.0' }),
139
152
 
140
153
  },
141
154
  devDependencies: {
@@ -182,7 +195,6 @@ LOG_LEVEL=debug
182
195
 
183
196
 
184
197
 
185
-
186
198
  const gitignore = `node_modules/
187
199
  .env
188
200
  .env.local
@@ -195,10 +207,14 @@ npm-debug.log*
195
207
  yarn-debug.log*
196
208
  .idea/
197
209
  .vscode/
210
+ ${answers.useFileUpload ? 'uploads/*\n!uploads/.gitkeep' : ''}
198
211
  `;
199
212
 
200
213
  fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore);
201
214
 
215
+ if(answers.useFileUpload){
216
+ fs.writeFileSync(path.join(projectPath, 'uploads/.gitkeep'), '');
217
+ }
202
218
  console.log(chalk.green(' Config files created'));
203
219
 
204
220
 
@@ -309,6 +325,57 @@ module.exports=limiter;
309
325
 
310
326
 
311
327
 
328
+ if(answers.useFileUpload){
329
+ const multerMiddleware= ` const multer = require('multer');
330
+ const path = require('path');
331
+
332
+ // Set storage engine
333
+ const storage = multer.diskStorage({
334
+ destination: function (req,file ,cb){
335
+ cb(null, 'uploads/');
336
+ },
337
+ filename: function (req, file, cb) {
338
+ const uniqueSuffix = Date.now() + '-' + Math.round(Math.random()*1E9);
339
+ cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname))
340
+ }
341
+
342
+ });
343
+
344
+
345
+ //file filter
346
+ const fileFilter = (req, file, cb) =>{
347
+ const allowedTypes = /jpeg|jpg|png|gif/;
348
+ const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
349
+ const mimetype = allowedTypes.test(file.mimetype);
350
+
351
+ if(extname && mimetype){
352
+ return cb(null,true);
353
+ }else{
354
+ cb(new Error('Error: Images Only!'));
355
+ }
356
+ };
357
+
358
+ const upload = multer({
359
+ storage: storage,
360
+ limits: { fileSize: 5 * 1024 * 1024 }, // 5MB limit
361
+ fileFilter: fileFilter
362
+
363
+ });
364
+
365
+ module.exports = upload;
366
+
367
+
368
+ `;
369
+
370
+
371
+ fs.writeFileSync(
372
+ path.join(projectPath, 'src/middleware/upload.js'),
373
+ multerMiddleware
374
+ )
375
+ }
376
+
377
+
378
+
312
379
 
313
380
 
314
381
 
@@ -387,6 +454,7 @@ const createRouteFiles = (projectPath, answers) => {
387
454
  const routes = `const express = require('express');
388
455
  const router = express.Router();
389
456
  ${answers.useAuth ? "const authenticateToken = require('../middleware/auth');" : ''}
457
+ ${answers.useFileUpload ? "const upload = require('../middleware/upload');" : ''}
390
458
 
391
459
  // Public routes
392
460
  router.get('/health', (req, res) => {
@@ -400,6 +468,28 @@ router.get('/protected', authenticateToken, (req, res) => {
400
468
  });
401
469
  ` : ''}
402
470
 
471
+ ${answers.useFileUpload ? `
472
+ // File upload route
473
+ router.post('/upload', upload.single('file'), (req,res) =>{
474
+ if(!req.file){
475
+ return res.status(400).json({
476
+ success: false,
477
+ message: 'No file uploaded'
478
+ })
479
+ }
480
+ res.json({
481
+ success: true,
482
+ message: 'File uploaded successfully',
483
+ file: req.file
484
+ });
485
+
486
+ });
487
+
488
+
489
+ `: ''}
490
+
491
+
492
+
403
493
  module.exports = router;
404
494
  `;
405
495
  fs.writeFileSync(
@@ -513,3 +603,65 @@ process.on('unhandledRejection', (err) => {
513
603
 
514
604
  console.log(chalk.green('Route and config files created'));
515
605
  }
606
+
607
+
608
+
609
+
610
+
611
+ function createUserModel(projectPath) {
612
+ const userModel = `const mongoose = require('mongoose');
613
+ const bcrypt = require('bcryptjs');
614
+
615
+ const userSchema = new mongoose.Schema(
616
+ {
617
+ name:{
618
+ type: String,
619
+ required: [true, 'Name is required'],
620
+ trim: true,
621
+ },
622
+ email: {
623
+ type: String,
624
+ required: [true, 'Email is required'],
625
+ unique: true,
626
+ lowercase: true,
627
+ trim: true,
628
+ match: [/.+@.+\\..+/, 'Please fill a valid email address'],
629
+ },
630
+ password: {
631
+ type: String,
632
+ required: [true, 'Password is required'],
633
+ minlength: [6, 'Password must be at least 6 characters long'],
634
+ select: false
635
+ },
636
+ },
637
+ { timestamps: true }
638
+
639
+ );
640
+
641
+
642
+ //hash password before saving
643
+ userSchema.pre('save', async function (next) {
644
+ if (!this.isModified('password')) {
645
+ return next();
646
+ }
647
+ this.password = await bcrypt.hash(this.password,10);
648
+ next();
649
+ });
650
+
651
+
652
+ //compare password method
653
+ userSchema.methods.comparePassword = async function(candidatePassword) {
654
+ return await bcrypt.compare(candidatePassword, this.password);
655
+ };
656
+
657
+ module.exports = mongoose.model('User', userSchema);
658
+
659
+ `;
660
+
661
+ fs.writeFileSync(
662
+ path.join(projectPath, 'src/models/User.js'),
663
+ userModel
664
+ )
665
+
666
+ console.log(chalk.green('User model created'));
667
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-scaffold-cli",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "CLI tool to scaffold Express.js backend projects with MongoDB, middleware, and common setup",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {