@sachin-thakur/create-nodejs-app 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.
@@ -0,0 +1,890 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ async function generateMVCStructure(srcPath, config) {
5
+ const ext = config.language === 'typescript' ? 'ts' : 'js';
6
+ const isTS = config.language === 'typescript';
7
+
8
+ // Create directory structure
9
+ const dirs = ['config', 'controllers', 'models', 'routes', 'middlewares', 'services', 'utils'];
10
+ for (const dir of dirs) {
11
+ await fs.ensureDir(path.join(srcPath, dir));
12
+ }
13
+
14
+ // Generate main index file
15
+ await generateIndexFile(srcPath, config, ext, isTS);
16
+
17
+ // Generate config files
18
+ await generateConfigFiles(path.join(srcPath, 'config'), config, ext, isTS);
19
+
20
+ // Generate middleware files
21
+ await generateMiddlewareFiles(path.join(srcPath, 'middlewares'), config, ext, isTS);
22
+
23
+ // Generate utility files
24
+ await generateUtilityFiles(path.join(srcPath, 'utils'), config, ext, isTS);
25
+
26
+ // Generate controllers
27
+ await generateControllers(path.join(srcPath, 'controllers'), config, ext, isTS);
28
+
29
+ // Generate routes
30
+ await generateRoutes(path.join(srcPath, 'routes'), config, ext, isTS);
31
+
32
+ // Generate models
33
+ if (config.database !== 'none') {
34
+ await generateModels(path.join(srcPath, 'models'), config, ext, isTS);
35
+ }
36
+
37
+ // Generate services
38
+ await generateServices(path.join(srcPath, 'services'), config, ext, isTS);
39
+ }
40
+
41
+ async function generateIndexFile(srcPath, config, ext, isTS) {
42
+ const imports = isTS
43
+ ? `import express, { Application } from 'express';
44
+ import dotenv from 'dotenv';
45
+ import cors from 'cors';
46
+ ${config.features.includes('logging') ? "import morgan from 'morgan';" : ''}
47
+ ${config.features.includes('rate-limit') ? "import rateLimit from 'express-rate-limit';" : ''}
48
+ import { errorHandler } from './middlewares/errorHandler';
49
+ ${config.features.includes('logging') ? "import logger from './config/logger';" : ''}
50
+ ${config.database !== 'none' ? "import { connectDatabase } from './config/database';" : ''}
51
+ import routes from './routes';
52
+ ${config.features.includes('swagger') ? "import { setupSwagger } from './config/swagger';" : ''}`
53
+ : `const express = require('express');
54
+ const dotenv = require('dotenv');
55
+ const cors = require('cors');
56
+ ${config.features.includes('logging') ? "const morgan = require('morgan');" : ''}
57
+ ${config.features.includes('rate-limit') ? "const rateLimit = require('express-rate-limit');" : ''}
58
+ const { errorHandler } = require('./middlewares/errorHandler');
59
+ ${config.features.includes('logging') ? "const logger = require('./config/logger');" : ''}
60
+ ${config.database !== 'none' ? "const { connectDatabase } = require('./config/database');" : ''}
61
+ const routes = require('./routes');
62
+ ${config.features.includes('swagger') ? "const { setupSwagger } = require('./config/swagger');" : ''}`;
63
+
64
+ const indexContent = `${imports}
65
+
66
+ // Load environment variables
67
+ dotenv.config();
68
+
69
+ const app${isTS ? ': Application' : ''} = express();
70
+ const PORT = process.env.PORT || 3000;
71
+
72
+ // Middleware
73
+ app.use(express.json());
74
+ app.use(express.urlencoded({ extended: true }));
75
+ app.use(cors(${config.features.includes('cors') ? `{
76
+ origin: process.env.CORS_ORIGIN || '*',
77
+ credentials: true,
78
+ }` : ''}));
79
+
80
+ ${config.features.includes('logging') ? `// Request logging
81
+ app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
82
+ ` : ''}
83
+ ${config.features.includes('rate-limit') ? `// Rate limiting
84
+ const limiter = rateLimit({
85
+ windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'),
86
+ max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100'),
87
+ message: 'Too many requests from this IP, please try again later.',
88
+ });
89
+ app.use('/api/', limiter);
90
+ ` : ''}
91
+ // Routes
92
+ app.use('/api', routes);
93
+
94
+ // Health check
95
+ app.get('/health', (req, res) => {
96
+ res.status(200).json({ status: 'OK', timestamp: new Date().toISOString() });
97
+ });
98
+
99
+ ${config.features.includes('swagger') ? `// API Documentation
100
+ setupSwagger(app);
101
+ ` : ''}
102
+ // Error handling middleware (must be last)
103
+ app.use(errorHandler);
104
+
105
+ // Start server
106
+ async function startServer() {
107
+ try {
108
+ ${config.database !== 'none' ? ` // Connect to database
109
+ await connectDatabase();
110
+ ` : ''}
111
+ app.listen(PORT, () => {
112
+ ${config.features.includes('logging') ? `logger.info(\`Server running on port \${PORT}\`);` : `console.log(\`Server running on port \${PORT}\`);`}
113
+ ${config.features.includes('swagger') ? `console.log(\`API Documentation: http://localhost:\${PORT}/api-docs\`);` : ''}
114
+ });
115
+ } catch (error) {
116
+ ${config.features.includes('logging') ? `logger.error('Failed to start server:', error);` : `console.error('Failed to start server:', error);`}
117
+ process.exit(1);
118
+ }
119
+ }
120
+
121
+ startServer();
122
+
123
+ ${isTS ? 'export default app;' : 'module.exports = app;'}
124
+ `;
125
+
126
+ await fs.writeFile(path.join(srcPath, `index.${ext}`), indexContent);
127
+ }
128
+
129
+ async function generateConfigFiles(configPath, config, ext, isTS) {
130
+ // Database config
131
+ if (config.database === 'postgresql') {
132
+ const dbConfig = isTS
133
+ ? `import { Pool } from 'pg';
134
+ import logger from './logger';
135
+
136
+ const pool = new Pool({
137
+ host: process.env.DB_HOST || 'localhost',
138
+ port: parseInt(process.env.DB_PORT || '5432'),
139
+ database: process.env.DB_NAME,
140
+ user: process.env.DB_USER,
141
+ password: process.env.DB_PASSWORD,
142
+ });
143
+
144
+ pool.on('connect', () => {
145
+ logger.info('Connected to PostgreSQL database');
146
+ });
147
+
148
+ pool.on('error', (err) => {
149
+ logger.error('Unexpected error on PostgreSQL client', err);
150
+ });
151
+
152
+ export async function connectDatabase(): Promise<void> {
153
+ try {
154
+ await pool.query('SELECT NOW()');
155
+ logger.info('Database connection established');
156
+ } catch (error) {
157
+ logger.error('Failed to connect to database:', error);
158
+ throw error;
159
+ }
160
+ }
161
+
162
+ export { pool };
163
+ export default pool;`
164
+ : `const { Pool } = require('pg');
165
+ ${config.features.includes('logging') ? "const logger = require('./logger');" : ''}
166
+
167
+ const pool = new Pool({
168
+ host: process.env.DB_HOST || 'localhost',
169
+ port: parseInt(process.env.DB_PORT || '5432'),
170
+ database: process.env.DB_NAME,
171
+ user: process.env.DB_USER,
172
+ password: process.env.DB_PASSWORD,
173
+ });
174
+
175
+ pool.on('connect', () => {
176
+ ${config.features.includes('logging') ? "logger.info('Connected to PostgreSQL database');" : "console.log('Connected to PostgreSQL database');"}
177
+ });
178
+
179
+ pool.on('error', (err) => {
180
+ ${config.features.includes('logging') ? "logger.error('Unexpected error on PostgreSQL client', err);" : "console.error('Unexpected error on PostgreSQL client', err);"}
181
+ });
182
+
183
+ async function connectDatabase() {
184
+ try {
185
+ await pool.query('SELECT NOW()');
186
+ ${config.features.includes('logging') ? "logger.info('Database connection established');" : "console.log('Database connection established');"}
187
+ } catch (error) {
188
+ ${config.features.includes('logging') ? "logger.error('Failed to connect to database:', error);" : "console.error('Failed to connect to database:', error);"}
189
+ throw error;
190
+ }
191
+ }
192
+
193
+ module.exports = { pool, connectDatabase };`;
194
+
195
+ await fs.writeFile(path.join(configPath, `database.${ext}`), dbConfig);
196
+ } else if (config.database === 'mongodb') {
197
+ const dbConfig = isTS
198
+ ? `import mongoose from 'mongoose';
199
+ import logger from './logger';
200
+
201
+ export async function connectDatabase(): Promise<void> {
202
+ try {
203
+ const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/myapp';
204
+ await mongoose.connect(uri);
205
+ logger.info('Connected to MongoDB');
206
+ } catch (error) {
207
+ logger.error('MongoDB connection error:', error);
208
+ throw error;
209
+ }
210
+ }
211
+
212
+ mongoose.connection.on('disconnected', () => {
213
+ logger.warn('MongoDB disconnected');
214
+ });
215
+
216
+ export default mongoose;`
217
+ : `const mongoose = require('mongoose');
218
+ ${config.features.includes('logging') ? "const logger = require('./logger');" : ''}
219
+
220
+ async function connectDatabase() {
221
+ try {
222
+ const uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/myapp';
223
+ await mongoose.connect(uri);
224
+ ${config.features.includes('logging') ? "logger.info('Connected to MongoDB');" : "console.log('Connected to MongoDB');"}
225
+ } catch (error) {
226
+ ${config.features.includes('logging') ? "logger.error('MongoDB connection error:', error);" : "console.error('MongoDB connection error:', error);"}
227
+ throw error;
228
+ }
229
+ }
230
+
231
+ mongoose.connection.on('disconnected', () => {
232
+ ${config.features.includes('logging') ? "logger.warn('MongoDB disconnected');" : "console.log('MongoDB disconnected');"}
233
+ });
234
+
235
+ module.exports = { connectDatabase, mongoose };`;
236
+
237
+ await fs.writeFile(path.join(configPath, `database.${ext}`), dbConfig);
238
+ }
239
+
240
+ // Logger config
241
+ if (config.features.includes('logging')) {
242
+ const loggerConfig = isTS
243
+ ? `import winston from 'winston';
244
+ import path from 'path';
245
+
246
+ const logger = winston.createLogger({
247
+ level: process.env.LOG_LEVEL || 'info',
248
+ format: winston.format.combine(
249
+ winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
250
+ winston.format.errors({ stack: true }),
251
+ winston.format.splat(),
252
+ winston.format.json()
253
+ ),
254
+ defaultMeta: { service: 'app' },
255
+ transports: [
256
+ new winston.transports.File({
257
+ filename: path.join('logs', 'error.log'),
258
+ level: 'error',
259
+ }),
260
+ new winston.transports.File({
261
+ filename: path.join('logs', 'combined.log'),
262
+ }),
263
+ ],
264
+ });
265
+
266
+ if (process.env.NODE_ENV !== 'production') {
267
+ logger.add(
268
+ new winston.transports.Console({
269
+ format: winston.format.combine(
270
+ winston.format.colorize(),
271
+ winston.format.simple()
272
+ ),
273
+ })
274
+ );
275
+ }
276
+
277
+ export default logger;`
278
+ : `const winston = require('winston');
279
+ const path = require('path');
280
+
281
+ const logger = winston.createLogger({
282
+ level: process.env.LOG_LEVEL || 'info',
283
+ format: winston.format.combine(
284
+ winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
285
+ winston.format.errors({ stack: true }),
286
+ winston.format.splat(),
287
+ winston.format.json()
288
+ ),
289
+ defaultMeta: { service: 'app' },
290
+ transports: [
291
+ new winston.transports.File({
292
+ filename: path.join('logs', 'error.log'),
293
+ level: 'error',
294
+ }),
295
+ new winston.transports.File({
296
+ filename: path.join('logs', 'combined.log'),
297
+ }),
298
+ ],
299
+ });
300
+
301
+ if (process.env.NODE_ENV !== 'production') {
302
+ logger.add(
303
+ new winston.transports.Console({
304
+ format: winston.format.combine(
305
+ winston.format.colorize(),
306
+ winston.format.simple()
307
+ ),
308
+ })
309
+ );
310
+ }
311
+
312
+ module.exports = logger;`;
313
+
314
+ await fs.writeFile(path.join(configPath, `logger.${ext}`), loggerConfig);
315
+ }
316
+
317
+ // Swagger config
318
+ if (config.features.includes('swagger')) {
319
+ const swaggerConfig = isTS
320
+ ? `import swaggerJsdoc from 'swagger-jsdoc';
321
+ import swaggerUi from 'swagger-ui-express';
322
+ import { Application } from 'express';
323
+
324
+ const options = {
325
+ definition: {
326
+ openapi: '3.0.0',
327
+ info: {
328
+ title: 'API Documentation',
329
+ version: '1.0.0',
330
+ description: 'API documentation for the application',
331
+ },
332
+ servers: [
333
+ {
334
+ url: \`http://localhost:\${process.env.PORT || 3000}\`,
335
+ description: 'Development server',
336
+ },
337
+ ],
338
+ components: {
339
+ securitySchemes: {
340
+ bearerAuth: {
341
+ type: 'http',
342
+ scheme: 'bearer',
343
+ bearerFormat: 'JWT',
344
+ },
345
+ },
346
+ },
347
+ },
348
+ apis: ['./src/routes/*.${ext}'],
349
+ };
350
+
351
+ const specs = swaggerJsdoc(options);
352
+
353
+ export function setupSwagger(app: Application): void {
354
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
355
+ }
356
+
357
+ export default specs;`
358
+ : `const swaggerJsdoc = require('swagger-jsdoc');
359
+ const swaggerUi = require('swagger-ui-express');
360
+
361
+ const options = {
362
+ definition: {
363
+ openapi: '3.0.0',
364
+ info: {
365
+ title: 'API Documentation',
366
+ version: '1.0.0',
367
+ description: 'API documentation for the application',
368
+ },
369
+ servers: [
370
+ {
371
+ url: \`http://localhost:\${process.env.PORT || 3000}\`,
372
+ description: 'Development server',
373
+ },
374
+ ],
375
+ components: {
376
+ securitySchemes: {
377
+ bearerAuth: {
378
+ type: 'http',
379
+ scheme: 'bearer',
380
+ bearerFormat: 'JWT',
381
+ },
382
+ },
383
+ },
384
+ },
385
+ apis: ['./src/routes/*.${ext}'],
386
+ };
387
+
388
+ const specs = swaggerJsdoc(options);
389
+
390
+ function setupSwagger(app) {
391
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));
392
+ }
393
+
394
+ module.exports = { setupSwagger, specs };`;
395
+
396
+ await fs.writeFile(path.join(configPath, `swagger.${ext}`), swaggerConfig);
397
+ }
398
+ }
399
+
400
+ async function generateMiddlewareFiles(middlewarePath, config, ext, isTS) {
401
+ // Error handler
402
+ const errorHandler = isTS
403
+ ? `import { Request, Response, NextFunction } from 'express';
404
+ ${config.features.includes('logging') ? "import logger from '../config/logger';" : ''}
405
+
406
+ export class AppError extends Error {
407
+ statusCode: number;
408
+ isOperational: boolean;
409
+
410
+ constructor(message: string, statusCode: number = 500) {
411
+ super(message);
412
+ this.statusCode = statusCode;
413
+ this.isOperational = true;
414
+ Error.captureStackTrace(this, this.constructor);
415
+ }
416
+ }
417
+
418
+ export function errorHandler(
419
+ err: AppError | Error,
420
+ req: Request,
421
+ res: Response,
422
+ next: NextFunction
423
+ ): void {
424
+ const statusCode = 'statusCode' in err ? err.statusCode : 500;
425
+ const message = err.message || 'Internal Server Error';
426
+
427
+ ${config.features.includes('logging') ? `logger.error({
428
+ message: err.message,
429
+ stack: err.stack,
430
+ url: req.url,
431
+ method: req.method,
432
+ });` : `console.error('Error:', {
433
+ message: err.message,
434
+ stack: err.stack,
435
+ url: req.url,
436
+ method: req.method,
437
+ });`}
438
+
439
+ res.status(statusCode).json({
440
+ success: false,
441
+ message,
442
+ ...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
443
+ });
444
+ }`
445
+ : `${config.features.includes('logging') ? "const logger = require('../config/logger');" : ''}
446
+
447
+ class AppError extends Error {
448
+ constructor(message, statusCode = 500) {
449
+ super(message);
450
+ this.statusCode = statusCode;
451
+ this.isOperational = true;
452
+ Error.captureStackTrace(this, this.constructor);
453
+ }
454
+ }
455
+
456
+ function errorHandler(err, req, res, next) {
457
+ const statusCode = err.statusCode || 500;
458
+ const message = err.message || 'Internal Server Error';
459
+
460
+ ${config.features.includes('logging') ? `logger.error({
461
+ message: err.message,
462
+ stack: err.stack,
463
+ url: req.url,
464
+ method: req.method,
465
+ });` : `console.error('Error:', {
466
+ message: err.message,
467
+ stack: err.stack,
468
+ url: req.url,
469
+ method: req.method,
470
+ });`}
471
+
472
+ res.status(statusCode).json({
473
+ success: false,
474
+ message,
475
+ ...(process.env.NODE_ENV === 'development' && { stack: err.stack }),
476
+ });
477
+ }
478
+
479
+ module.exports = { errorHandler, AppError };`;
480
+
481
+ await fs.writeFile(path.join(middlewarePath, `errorHandler.${ext}`), errorHandler);
482
+
483
+ // Auth middleware (if auth feature is enabled)
484
+ if (config.features.includes('auth')) {
485
+ const authMiddleware = isTS
486
+ ? `import { Request, Response, NextFunction } from 'express';
487
+ import jwt from 'jsonwebtoken';
488
+ import { AppError } from './errorHandler';
489
+
490
+ export interface AuthRequest extends Request {
491
+ user?: any;
492
+ }
493
+
494
+ export function authenticate(
495
+ req: AuthRequest,
496
+ res: Response,
497
+ next: NextFunction
498
+ ): void {
499
+ try {
500
+ const token = req.headers.authorization?.split(' ')[1];
501
+
502
+ if (!token) {
503
+ throw new AppError('No token provided', 401);
504
+ }
505
+
506
+ const decoded = jwt.verify(token, process.env.JWT_SECRET || 'secret');
507
+ req.user = decoded;
508
+ next();
509
+ } catch (error) {
510
+ next(new AppError('Invalid or expired token', 401));
511
+ }
512
+ }`
513
+ : `const jwt = require('jsonwebtoken');
514
+ const { AppError } = require('./errorHandler');
515
+
516
+ function authenticate(req, res, next) {
517
+ try {
518
+ const token = req.headers.authorization?.split(' ')[1];
519
+
520
+ if (!token) {
521
+ throw new AppError('No token provided', 401);
522
+ }
523
+
524
+ const decoded = jwt.verify(token, process.env.JWT_SECRET || 'secret');
525
+ req.user = decoded;
526
+ next();
527
+ } catch (error) {
528
+ next(new AppError('Invalid or expired token', 401));
529
+ }
530
+ }
531
+
532
+ module.exports = { authenticate };`;
533
+
534
+ await fs.writeFile(path.join(middlewarePath, `auth.${ext}`), authMiddleware);
535
+ }
536
+
537
+ // Validation middleware (if validation feature is enabled)
538
+ if (config.features.includes('validation')) {
539
+ const validationMiddleware = isTS
540
+ ? `import { Request, Response, NextFunction } from 'express';
541
+ import { AnyZodObject, ZodError } from 'zod';
542
+ import { AppError } from './errorHandler';
543
+
544
+ export function validate(schema: AnyZodObject) {
545
+ return async (req: Request, res: Response, next: NextFunction) => {
546
+ try {
547
+ await schema.parseAsync({
548
+ body: req.body,
549
+ query: req.query,
550
+ params: req.params,
551
+ });
552
+ next();
553
+ } catch (error) {
554
+ if (error instanceof ZodError) {
555
+ const message = error.errors.map((e) => e.message).join(', ');
556
+ next(new AppError(message, 400));
557
+ } else {
558
+ next(error);
559
+ }
560
+ }
561
+ };
562
+ }`
563
+ : `const { AppError } = require('./errorHandler');
564
+
565
+ function validate(schema) {
566
+ return async (req, res, next) => {
567
+ try {
568
+ await schema.parseAsync({
569
+ body: req.body,
570
+ query: req.query,
571
+ params: req.params,
572
+ });
573
+ next();
574
+ } catch (error) {
575
+ if (error.name === 'ZodError') {
576
+ const message = error.errors.map((e) => e.message).join(', ');
577
+ next(new AppError(message, 400));
578
+ } else {
579
+ next(error);
580
+ }
581
+ }
582
+ };
583
+ }
584
+
585
+ module.exports = { validate };`;
586
+
587
+ await fs.writeFile(path.join(middlewarePath, `validation.${ext}`), validationMiddleware);
588
+ }
589
+ }
590
+
591
+ async function generateUtilityFiles(utilsPath, config, ext, isTS) {
592
+ // Response helper
593
+ const responseHelper = isTS
594
+ ? `import { Response } from 'express';
595
+
596
+ export function sendSuccess(res: Response, data: any, message: string = 'Success', statusCode: number = 200): void {
597
+ res.status(statusCode).json({
598
+ success: true,
599
+ message,
600
+ data,
601
+ });
602
+ }
603
+
604
+ export function sendError(res: Response, message: string, statusCode: number = 500): void {
605
+ res.status(statusCode).json({
606
+ success: false,
607
+ message,
608
+ });
609
+ }`
610
+ : `function sendSuccess(res, data, message = 'Success', statusCode = 200) {
611
+ res.status(statusCode).json({
612
+ success: true,
613
+ message,
614
+ data,
615
+ });
616
+ }
617
+
618
+ function sendError(res, message, statusCode = 500) {
619
+ res.status(statusCode).json({
620
+ success: false,
621
+ message,
622
+ });
623
+ }
624
+
625
+ module.exports = { sendSuccess, sendError };`;
626
+
627
+ await fs.writeFile(path.join(utilsPath, `response.${ext}`), responseHelper);
628
+ }
629
+
630
+ async function generateControllers(controllersPath, config, ext, isTS) {
631
+ const healthController = isTS
632
+ ? `import { Request, Response, NextFunction } from 'express';
633
+ import { sendSuccess } from '../utils/response';
634
+
635
+ export async function getHealth(req: Request, res: Response, next: NextFunction): Promise<void> {
636
+ try {
637
+ sendSuccess(res, {
638
+ status: 'healthy',
639
+ timestamp: new Date().toISOString(),
640
+ uptime: process.uptime(),
641
+ }, 'Service is healthy');
642
+ } catch (error) {
643
+ next(error);
644
+ }
645
+ }`
646
+ : `const { sendSuccess } = require('../utils/response');
647
+
648
+ async function getHealth(req, res, next) {
649
+ try {
650
+ sendSuccess(res, {
651
+ status: 'healthy',
652
+ timestamp: new Date().toISOString(),
653
+ uptime: process.uptime(),
654
+ }, 'Service is healthy');
655
+ } catch (error) {
656
+ next(error);
657
+ }
658
+ }
659
+
660
+ module.exports = { getHealth };`;
661
+
662
+ await fs.writeFile(path.join(controllersPath, `health.controller.${ext}`), healthController);
663
+ }
664
+
665
+ async function generateRoutes(routesPath, config, ext, isTS) {
666
+ const indexRoutes = isTS
667
+ ? `import { Router } from 'express';
668
+ import healthRoutes from './health.routes';
669
+
670
+ const router = Router();
671
+
672
+ router.use('/health', healthRoutes);
673
+
674
+ export default router;`
675
+ : `const express = require('express');
676
+ const healthRoutes = require('./health.routes');
677
+
678
+ const router = express.Router();
679
+
680
+ router.use('/health', healthRoutes);
681
+
682
+ module.exports = router;`;
683
+
684
+ await fs.writeFile(path.join(routesPath, `index.${ext}`), indexRoutes);
685
+
686
+ const healthRoutes = isTS
687
+ ? `import { Router } from 'express';
688
+ import { getHealth } from '../controllers/health.controller';
689
+
690
+ const router = Router();
691
+
692
+ /**
693
+ * @swagger
694
+ * /api/health:
695
+ * get:
696
+ * summary: Check API health
697
+ * tags: [Health]
698
+ * responses:
699
+ * 200:
700
+ * description: API is healthy
701
+ */
702
+ router.get('/', getHealth);
703
+
704
+ export default router;`
705
+ : `const express = require('express');
706
+ const { getHealth } = require('../controllers/health.controller');
707
+
708
+ const router = express.Router();
709
+
710
+ /**
711
+ * @swagger
712
+ * /api/health:
713
+ * get:
714
+ * summary: Check API health
715
+ * tags: [Health]
716
+ * responses:
717
+ * 200:
718
+ * description: API is healthy
719
+ */
720
+ router.get('/', getHealth);
721
+
722
+ module.exports = router;`;
723
+
724
+ await fs.writeFile(path.join(routesPath, `health.routes.${ext}`), healthRoutes);
725
+ }
726
+
727
+ async function generateModels(modelsPath, config, ext, isTS) {
728
+ // Generate example model based on database type
729
+ if (config.database === 'mongodb') {
730
+ const userModel = isTS
731
+ ? `import mongoose, { Schema, Document } from 'mongoose';
732
+
733
+ export interface IUser extends Document {
734
+ username: string;
735
+ email: string;
736
+ password: string;
737
+ createdAt: Date;
738
+ updatedAt: Date;
739
+ }
740
+
741
+ const userSchema = new Schema<IUser>(
742
+ {
743
+ username: { type: String, required: true, unique: true },
744
+ email: { type: String, required: true, unique: true },
745
+ password: { type: String, required: true },
746
+ },
747
+ {
748
+ timestamps: true,
749
+ }
750
+ );
751
+
752
+ export default mongoose.model<IUser>('User', userSchema);`
753
+ : `const mongoose = require('mongoose');
754
+
755
+ const userSchema = new mongoose.Schema(
756
+ {
757
+ username: { type: String, required: true, unique: true },
758
+ email: { type: String, required: true, unique: true },
759
+ password: { type: String, required: true },
760
+ },
761
+ {
762
+ timestamps: true,
763
+ }
764
+ );
765
+
766
+ module.exports = mongoose.model('User', userSchema);`;
767
+
768
+ await fs.writeFile(path.join(modelsPath, `user.model.${ext}`), userModel);
769
+ } else if (config.database === 'postgresql') {
770
+ const userModel = isTS
771
+ ? `import { pool } from '../config/database';
772
+
773
+ export interface IUser {
774
+ id?: number;
775
+ username: string;
776
+ email: string;
777
+ password: string;
778
+ created_at?: Date;
779
+ updated_at?: Date;
780
+ }
781
+
782
+ export class User {
783
+ static async findById(id: number): Promise<IUser | null> {
784
+ const result = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
785
+ return result.rows[0] || null;
786
+ }
787
+
788
+ static async findByEmail(email: string): Promise<IUser | null> {
789
+ const result = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
790
+ return result.rows[0] || null;
791
+ }
792
+
793
+ static async create(user: IUser): Promise<IUser> {
794
+ const result = await pool.query(
795
+ 'INSERT INTO users (username, email, password) VALUES ($1, $2, $3) RETURNING *',
796
+ [user.username, user.email, user.password]
797
+ );
798
+ return result.rows[0];
799
+ }
800
+
801
+ static async update(id: number, updates: Partial<IUser>): Promise<IUser | null> {
802
+ const fields = Object.keys(updates);
803
+ const values = Object.values(updates);
804
+ const setClause = fields.map((field, i) => \`\${field} = $\${i + 2}\`).join(', ');
805
+
806
+ const result = await pool.query(
807
+ \`UPDATE users SET \${setClause}, updated_at = NOW() WHERE id = $1 RETURNING *\`,
808
+ [id, ...values]
809
+ );
810
+ return result.rows[0] || null;
811
+ }
812
+
813
+ static async delete(id: number): Promise<boolean> {
814
+ const result = await pool.query('DELETE FROM users WHERE id = $1', [id]);
815
+ return result.rowCount! > 0;
816
+ }
817
+ }`
818
+ : `const { pool } = require('../config/database');
819
+
820
+ class User {
821
+ static async findById(id) {
822
+ const result = await pool.query('SELECT * FROM users WHERE id = $1', [id]);
823
+ return result.rows[0] || null;
824
+ }
825
+
826
+ static async findByEmail(email) {
827
+ const result = await pool.query('SELECT * FROM users WHERE email = $1', [email]);
828
+ return result.rows[0] || null;
829
+ }
830
+
831
+ static async create(user) {
832
+ const result = await pool.query(
833
+ 'INSERT INTO users (username, email, password) VALUES ($1, $2, $3) RETURNING *',
834
+ [user.username, user.email, user.password]
835
+ );
836
+ return result.rows[0];
837
+ }
838
+
839
+ static async update(id, updates) {
840
+ const fields = Object.keys(updates);
841
+ const values = Object.values(updates);
842
+ const setClause = fields.map((field, i) => \`\${field} = $\${i + 2}\`).join(', ');
843
+
844
+ const result = await pool.query(
845
+ \`UPDATE users SET \${setClause}, updated_at = NOW() WHERE id = $1 RETURNING *\`,
846
+ [id, ...values]
847
+ );
848
+ return result.rows[0] || null;
849
+ }
850
+
851
+ static async delete(id) {
852
+ const result = await pool.query('DELETE FROM users WHERE id = $1', [id]);
853
+ return result.rowCount > 0;
854
+ }
855
+ }
856
+
857
+ module.exports = User;`;
858
+
859
+ await fs.writeFile(path.join(modelsPath, `user.model.${ext}`), userModel);
860
+ }
861
+ }
862
+
863
+ async function generateServices(servicesPath, config, ext, isTS) {
864
+ // Generate a placeholder service file
865
+ const exampleService = isTS
866
+ ? `${config.features.includes('logging') ? "import logger from '../config/logger';" : ''}
867
+
868
+ export class ExampleService {
869
+ static async performAction(data: any): Promise<any> {
870
+ ${config.features.includes('logging') ? "logger.info('Performing action with data:', data);" : "console.log('Performing action with data:', data);"}
871
+ // Add your business logic here
872
+ return { success: true, data };
873
+ }
874
+ }`
875
+ : `${config.features.includes('logging') ? "const logger = require('../config/logger');" : ''}
876
+
877
+ class ExampleService {
878
+ static async performAction(data) {
879
+ ${config.features.includes('logging') ? "logger.info('Performing action with data:', data);" : "console.log('Performing action with data:', data);"}
880
+ // Add your business logic here
881
+ return { success: true, data };
882
+ }
883
+ }
884
+
885
+ module.exports = ExampleService;`;
886
+
887
+ await fs.writeFile(path.join(servicesPath, `example.service.${ext}`), exampleService);
888
+ }
889
+
890
+ module.exports = { generateMVCStructure };