UNPKG

build-express-api

Version:

Command line interface for instantly building an express rest api

363 lines (303 loc) 14 kB
// Implementations of actions const fs = require('fs'); const config = require('./config'); const helpers = require('./helpers'); var actions = {}; const path = require('path'); var globalModulePath = path.join(__dirname, '..') /** * Initializes the current directory with all the files needed. */ actions.init = () => { var initSuccessful = true; if(!fs.existsSync('./rest')) { // Create folder structure fs.mkdirSync('./rest'); fs.mkdirSync('./rest/models'); fs.mkdirSync('./rest/controllers'); // Create package.json if(!fs.existsSync('package.json')) { var packageJsonText = fs.readFileSync(globalModulePath+'/templates/packageTemplate.json'); fs.writeFileSync('package.json',packageJsonText); } // Create server.js var serverText = fs.readFileSync(globalModulePath+'/templates/serverTemplate.js'); fs.writeFileSync('./rest/server.js',serverText); helpers.createBeaConfig(); } else initSuccessful = false; if(initSuccessful) { // Print succesfull console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.green,'✔ Initialization successful'); console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.white, 'Please check beaConfig.js if you want a different folder structure, provide the path to the server.js/app.js, controllers/routes folder and models folder.'); return true; } else { console.log(config.terminal_colors.red,"✖ Directory 'rest' already exists."); console.log(config.terminal_colors.white); return false; } } /** * Creates a new plain api controller in rest/controllers with get and post * @param {*String} controllerName */ actions.createPlainController = (controllerName) => { // First load the config file to know where to create controllers var beaConfig = helpers.loadBeaConfig(); // If /rest/controllers doesn't exist return if(!fs.existsSync(beaConfig.controllersPath)) { console.log(config.terminal_colors.red,"✖ Missing directory "+beaConfig.controllersPath+", please check whether that directory exists."); console.log(config.terminal_colors.white); return; } var success = true; var fullControllerName; // get fullControllerName to contain Controller if(!controllerName.includes('Controller')) { fullControllerName = controllerName.toLowerCase()+'Controller'; } else fullControllerName = controllerName; // Only create controller if it doesn't exist already if(!fs.existsSync(beaConfig.controllersPath+'/'+fullControllerName+'.js')) { var plainControllerText = fs.readFileSync(globalModulePath+'/templates/plainControllerTemplate.js'); // get plain controller name eg foodController -> food var routeName = fullControllerName.replace('Controller',''); plainControllerText = plainControllerText.toString().replace(new RegExp('{{controllerName}}','g'), routeName); // Create controller fs.writeFileSync(beaConfig.controllersPath+'/'+fullControllerName+'.js',plainControllerText); // Use this controller in server.js var serverText = fs.readFileSync(beaConfig.serverPath).toString(); var arrayOfLines = serverText.split("\n"); var index; arrayOfLines.forEach((line,i) => { if(line.includes('= express();')) { index = i; } }) arrayOfLines.splice(++index,0,"\n"); var splitCount = beaConfig.controllersPath.split('/').length; var controllersPath = splitCount > 2 ? "./" + beaConfig.controllersPath.split('/')[splitCount-1] : beaConfig.controllersPath; arrayOfLines.splice(++index,0,"var "+ fullControllerName + " = require('"+controllersPath+"/"+fullControllerName+"');"); arrayOfLines.splice(++index,0,"app.use('/api/"+routeName+"', "+fullControllerName+");"); var newServerText = arrayOfLines.join('\n'); fs.writeFileSync(beaConfig.serverPath,newServerText); } else success = false; if(success) { console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.green,'✔ '+fullControllerName+' created successfully, check '+beaConfig.controllersPath+'/'+fullControllerName+'.js'); console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.white); return true; } else { console.log(config.terminal_colors.red,"✖ Controller "+fullControllerName+" already exists."); console.log(config.terminal_colors.white); return false; } } /** * * @param {*String} controllerName * @param {*Object} routes */ actions.createControllerWithCustomRoutes = (controllerName, routes) => { // First load the config file to know where to create controllers var beaConfig = helpers.loadBeaConfig(); if(!fs.existsSync(beaConfig.controllersPath)) { console.log(config.terminal_colors.red,"✖ Missing directory "+beaConfig.controllersPath+", please check whether that directory exists."); console.log(config.terminal_colors.white); return; } var success = true; var fullControllerName; // get fullControllerName to contain Controller if(!controllerName.includes('Controller')) { fullControllerName = controllerName.toLowerCase()+'Controller'; } else fullControllerName = controllerName; // Only create controller if it doesn't exist already if(!fs.existsSync(beaConfig.controllersPath+'/'+fullControllerName+'.js')) { var basicControllerName = fullControllerName.replace('Controller',''); var routesString = ''; // Go through all of the routes and create them for(var prop in routes) { var lowercaseProp = prop.toLowerCase(); var lowercaseMethod = routes[prop].toLowerCase(); routesString += `// ${lowercaseMethod} /api/${basicControllerName}/${lowercaseProp} router.${lowercaseMethod}('/${lowercaseProp}',(req,res) => { res.send('${lowercaseMethod} ${lowercaseProp}'); }); `; } // Push the routes in the rest var routesControllerText = `// ${basicControllerName} controller routes var express = require('express'); var router = express.Router(); ${routesString} module.exports = router; `; fs.writeFileSync(beaConfig.controllersPath+'/'+fullControllerName+'.js',routesControllerText); // Use this controller in server.js var serverText = fs.readFileSync(beaConfig.serverPath).toString(); var arrayOfLines = serverText.split("\n"); var index; arrayOfLines.forEach((line,i) => { if(line.includes('= express();')) { index = i; } }) arrayOfLines.splice(++index,0,"\n"); var splitCount = beaConfig.controllersPath.split('/').length; var controllersPath = splitCount > 2 ? "./" + beaConfig.controllersPath.split('/')[splitCount-1] : beaConfig.controllersPath; arrayOfLines.splice(++index,0,"var "+ fullControllerName + " = require('"+controllersPath+"/"+fullControllerName+"');"); arrayOfLines.splice(++index,0,"app.use('/api/"+basicControllerName+"', "+fullControllerName+");"); var newServerText = arrayOfLines.join('\n'); fs.writeFileSync(beaConfig.serverPath,newServerText); } else success = false; if(success) { console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.green,'✔ '+fullControllerName+' created successfully, check '+beaConfig.controllersPath+'/'+fullControllerName+'.js'); console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.white); return true; } else { console.log(config.terminal_colors.red,"✖ Controller "+fullControllerName+" already exists."); console.log(config.terminal_colors.white); return false; } } /** * Adds the routes to the controller provided * @param {*String} controllerName * @param {*Object} routes */ actions.addRoutes = (controllerName,routes) => { // First load the config file to know where to create controllers var beaConfig = helpers.loadBeaConfig(); var fullControllerName; if(!controllerName.includes('Controller')) { fullControllerName = controllerName+'Controller'; } else fullControllerName = controllerName; if(!fs.existsSync(beaConfig.controllersPath+'/'+fullControllerName+'.js')) { console.log(config.terminal_colors.red,"✖ Controller with that name ("+fullControllerName+") doesn't exist, please chect "+beaConfig.controllersPath+" and provide an existing controller."); console.log(config.terminal_colors.white); return false; } var routesString = ''; var basicControllerName = fullControllerName.replace('Controller',''); console.log(routesString); // Go through controller.js and add routes to the end var controllerText = fs.readFileSync(beaConfig.controllersPath+'/'+fullControllerName+'.js').toString(); var arrayOfLines = controllerText.split("\n"); var index; arrayOfLines.forEach((line,i) => { if(line.includes('module.exports = router')) { index = i; } }) // Go through all of the routes and create them for(var prop in routes) { var lowercaseProp = prop.toLowerCase(); var lowercaseMethod = routes[prop].toLowerCase(); arrayOfLines.splice(index,0,`// ${lowercaseMethod} /api/${basicControllerName}/${lowercaseProp}`); arrayOfLines.splice(++index,0,`router.${lowercaseMethod}('/${lowercaseProp}',(req,res) => {`); arrayOfLines.splice(++index,0," "); arrayOfLines.splice(++index,0,'});\n'); index++; } var newControllerText = arrayOfLines.join('\n'); fs.writeFileSync(beaConfig.controllersPath+'/'+fullControllerName+'.js',newControllerText); console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.green,'✔ Routes added successfully, check '+beaConfig.controllersPath+'/'+fullControllerName+'.js'); console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.white); return true; } /** * Creates new model in rest/models * @param {*String} name * @param {*String} props */ actions.createModel = (name,props) => { // First load the config file to know where to create controllers var beaConfig = helpers.loadBeaConfig(); if(!fs.existsSync(beaConfig.modelsPath)) { console.log(config.terminal_colors.red,"✖ Missing directory"+beaConfig.modelsPath+", please check whether that directory exists."); console.log(config.terminal_colors.white); return false; } name = name.charAt(0).toUpperCase() + name.slice(1); if (fs.existsSync(beaConfig.modelsPath+'/'+name+'.js')) { console.log(config.terminal_colors.red,"✖ Model "+name+" already exists."); console.log(config.terminal_colors.white); return false; } var modelTemplateText = fs.readFileSync(globalModulePath+'/templates/modelTemplate.js').toString(); modelTemplateText = modelTemplateText.replace(new RegExp('modelname','g'), name); props = props.replace(new RegExp(',', 'g'), ',\n '); props = props.replace(new RegExp('{', 'g'), '{\n '); props = props.replace(new RegExp('}', 'g'), '\n }'); modelTemplateText = modelTemplateText.replace('PROPS',props); fs.writeFileSync(beaConfig.modelsPath+'/'+name+'.js',modelTemplateText); console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.green,'✔ Model '+name+' created successfully, check '+beaConfig.modelsPath+'/'+name+'.js'); console.log(config.terminal_colors.green,'----------------------------'); console.log(config.terminal_colors.white); return true; } /** * Creates beaConfig.json in root directory */ actions.createConfig = () => { var created = helpers.createBeaConfig(); if (!created) { console.log(config.terminal_colors.red,"✖ beaConfig.json already exists"); console.log(config.terminal_colors.white); } else { console.log(config.terminal_colors.green,'✔ Created beaConfig.json'); console.log(config.terminal_colors.white); } return created; } actions.buildSchema = () => { var schema = helpers.getProperty('schema'); if(!helpers.validateSchema(schema)) { console.log(config.terminal_colors.red,"✖ Schema is not in valid format, please check beaConfig.json, or https://github.com/ognjengt/build-express-api documentation to see how to write schema in a correct format."); console.log(config.terminal_colors.white); return false; } var result = true; // Create controllers if (schema.controllers != null) { schema.controllers.forEach(function(controller) { if(controller.routes === "plain") { actions.createPlainController(controller.name); } else if (controller.routes instanceof Object) { actions.createControllerWithCustomRoutes(controller.name, controller.routes); } else { console.log(config.terminal_colors.red,"✖ Schema is not in valid format, please check beaConfig.json, or https://github.com/ognjengt/build-express-api documentation to see how to write schema in a correct format. Additional message: Some controller routes aren't in correct format."); console.log(config.terminal_colors.white); result = false; return; } }) } if (!result) { return false; } // Create models if (schema.models != null) { schema.models.forEach(function(model) { actions.createModel(model.name, model.props); }) } return result; } module.exports = actions;