UNPKG

miryala

Version:

A production-ready TypeScript Express.js backend generator with MongoDB or PostgreSQL support

192 lines (165 loc) 8.99 kB
const fs = require('fs'); const path = require('path'); const createFolders = (folders, projectRoot = process.cwd()) => { folders.forEach((folder) => { const folderPath = path.join(projectRoot, folder); if (!fs.existsSync(folderPath)) { fs.mkdirSync(folderPath, { recursive: true }); console.log(`Created folder: ${folder}`); } else { console.log(`Folder already exists: ${folder}`); } }); }; const createFile = (fileName, content, projectRoot = process.cwd()) => { const filePath = path.join(projectRoot, fileName); if (!fs.existsSync(filePath)) { fs.writeFileSync(filePath, content); console.log(`Created file: ${fileName}`); } else { console.log(`File already exists: ${fileName}`); } }; const generateEnvFileContent = (dbChoice) => { const mongoDb = dbChoice === 'mongodb' ? `MONGO_DATABASE_URL=mongodb://localhost:27017/myapp` : `DATABASE_URL=postgresql://user:password@localhost:5432/mydb`; return `PORT=5000 NODE_ENV=development # NODE_ENV=production # NODE_ENV=seed # Database ${mongoDb} # JWT JWT_ACCESS_TOKEN_SECRET=40051dc52aa534598646248e692db2d70224cf751507a782daee7742f45e92486ca3de2ce447ff10a2ca76032f07bd57624e7f12e38c1d6966438944f04fc4352 JWT_REFRESH_TOKEN_SECRET=037258be634643ed41ace736e5b3a1b4628e6d69889ef3275f4a3097307f3b522db381dda5e477d58f8519fc0e8e32c984497bf3adaa4d228a2e0459743 JWT_ACCESS_TOKEN_EXPIRES_IN=15m JWT_REFRESH_TOKEN_EXPIRES_IN=30d BCRYPT_SALT_ROUNDS=10 # Email EMAIL_HOST_PROVIDER_NAME=smtp.gmail.com EMAIL_HOST_PROVIDER_PORT=587 EMAIL_SENDER_EMAIL=example@gmail.com EMAIL_SENDER_EMAIL_APP_PASS=your_app_password EMAIL_SENDER_NAME=Your App Name EMAIL_REPLY_TO=example@gmail.com EMAIL_TEST_RECIPIENTS=example@gmail.com # Client & Backend URLs CLIENT_SIDE_URL=http://localhost:5173 # CLIENT_SIDE_URL=your.client.domain.com BACKEND_SIDE_URL=http://localhost:5000 # BACKEND_SIDE_URL=your.api.domain.com `; }; const createFiles = (dbChoice) => { const templatesDir = path.join(__dirname, '../templates'); const serverTemplate = fs.readFileSync(path.join(templatesDir, 'server.js.template'), 'utf-8'); const appTemplate = fs.readFileSync(path.join(templatesDir, 'app.js.template'), 'utf-8'); createFile('server.js', serverTemplate.replace('{{DB_FILE}}', `./db/${dbChoice}.js`)); createFile('app.js', appTemplate); createFile('.env', generateEnvFileContent(dbChoice)); }; // ─── Advanced Structure ─────────────────────────────────────────────────────── const createAdvancedStructure = async (dbChoice, projectRoot = process.cwd()) => { const templatesDir = path.join(__dirname, '../templates/advanced'); const folders = [ 'src/app', 'src/builder', 'src/config', 'src/constants', 'src/errors', 'src/helpers', 'src/interfaces', 'src/lib', 'src/middlewares', 'src/modules/demo_module', 'src/routers', 'src/schemas', 'src/seed', 'src/shared', 'src/types', 'src/utils', ]; if (dbChoice === 'postgresql') folders.push('prisma', 'generated/prisma'); createFolders(folders, projectRoot); const read = (name) => fs.readFileSync(path.join(templatesDir, name), 'utf-8'); const write = (fileName, content) => createFile(fileName, content, projectRoot); // Root files write('.env', generateEnvFileContent(dbChoice)); write('.env.example', generateEnvFileContent(dbChoice)); write('.gitignore', read('gitignore.template')); write('.prettierrc.json', read('prettierrc.template')); write('tsconfig.json', read('tsconfig.template')); write('eslint.config.mjs', read('eslint.template')); // src/ write('src/app.ts', read('app.ts.template')); write('src/server.ts', read('server.ts.template').replace('{{DB_IMPORT}}', dbChoice === 'mongodb' ? read('db_import_mongo.template') : read('db_import_prisma.template'))); // src/config/ write('src/config/index.ts', read('config.ts.template')); // src/constants/ write('src/constants/userRole_constant.ts', read('userRole_constant.ts.template')); // src/errors/ write('src/errors/AppError.ts', read('AppError.ts.template')); write('src/errors/globalErrorHandler.ts', read(dbChoice === 'mongodb' ? 'globalErrorHandler_mongo.ts.template' : 'globalErrorHandler_prisma.ts.template')); if (dbChoice === 'mongodb') { write('src/errors/handleMongooseCastError.ts', read('handleMongooseCastError.ts.template')); write('src/errors/handleMongooseDuplicateError.ts', read('handleMongooseDuplicateError.ts.template')); write('src/errors/handleMongooseValidationError.ts', read('handleMongooseValidationError.ts.template')); } else { write('src/errors/handlePrismaCastError.ts', read('handlePrismaCastError.ts.template')); write('src/errors/handlePrismaDuplicateError.ts', read('handlePrismaDuplicateError.ts.template')); write('src/errors/handlePrismaValidationError.ts', read('handlePrismaValidationError.ts.template')); } // src/interfaces/ write('src/interfaces/errors.ts', read('errors_interface.ts.template')); write('src/interfaces/index.d.ts', read('index.d.ts.template')); write('src/interfaces/emailFormat.ts', read('emailFormat.ts.template')); write('src/interfaces/jwtToken_interface.ts', read('jwtToken_interface.ts.template')); write('src/interfaces/userRole_type.ts', read('userRole_type.ts.template')); // src/middlewares/ write('src/middlewares/auth.ts', read('auth.ts.template')); write('src/middlewares/notFound.ts', read('notFound.ts.template')); write('src/middlewares/validateRequest.ts', read('validateRequest.ts.template')); write('src/middlewares/rateLimitingHandler.ts', read('rateLimitingHandler.ts.template')); write('src/middlewares/handleFileUpload.ts', read('handleFileUpload.ts.template')); write('src/middlewares/bigIntSerializer.ts', read('bigIntSerializer.ts.template')); write('src/middlewares/formDataToSetJSONformatData.ts', read('formDataToSetJSONformatData.ts.template')); write('src/middlewares/morganMiddleware.ts', read('morganMiddleware.ts.template')); // src/utils/ write('src/utils/catchAsync.ts', read('catchAsync.ts.template')); write('src/utils/sendResponse.ts', read('sendResponse.ts.template')); write('src/utils/commonUtils.ts', read('commonUtils.ts.template')); write('src/utils/sendEmail.ts', read('sendEmail.ts.template')); write('src/utils/node_cache.ts', read('node_cache.ts.template')); write('src/utils/logger.ts', read('logger.ts.template')); write('src/utils/removeUploadedFiles.ts', read('removeUploadedFiles.ts.template')); // src/builder/ if (dbChoice === 'mongodb') { write('src/builder/QueryBuilder.ts', read('MongooseQueryBuilder.ts.template')); } else { write('src/builder/QueryBuilder.ts', read('PrismaQueryBuilder.ts.template')); write('src/shared/prisma.ts', read('prisma_shared.template')); write('prisma/schema.prisma', read('schema.prisma.template')); } // src/routers/ write('src/routers/index.ts', read('routers_index.ts.template')); // src/modules/demo_module/ write('src/modules/demo_module/demo_module.route.ts', read('demo_route.ts.template')); write('src/modules/demo_module/demo_module.controller.ts', read('demo_controller.ts.template')); write('src/modules/demo_module/demo_module.service.ts', read('demo_service.ts.template')); if (dbChoice === 'mongodb') { write('src/modules/demo_module/demo_module.model.ts', read('demo_model_mongo.ts.template')); } write('src/modules/demo_module/demo_module.validation.ts', read('demo_validation.ts.template')); write('src/modules/demo_module/demo_module.constant.ts', read('demo_module_constant.ts.template')); write('src/modules/demo_module/demo_module.interface.ts', read('demo_module_interface.ts.template')); write('src/modules/demo_module/demo_module.helpers.ts', read('demo_module_helpers.ts.template')); write('src/modules/demo_module/demo_module.lib.ts', read('demo_module_lib.ts.template')); write('src/modules/demo_module/demo_module.utils.ts', read('demo_module_utils.ts.template')); // uploads/ createFolders(['uploads/images', 'uploads/videos'], projectRoot); write('uploads/images/.gitkeep', ''); write('uploads/videos/.gitkeep', ''); console.log('✅ Advanced TypeScript project structure created successfully.'); }; module.exports = { createFolders, createFile, createFiles, createAdvancedStructure };