UNPKG

boil-cli-tool

Version:

CLI tool - boilerplate template manager and generator

115 lines (113 loc) 6.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); // packages const command_1 = require("@oclif/command"); const inquirer = tslib_1.__importStar(require("inquirer")); // utils const utils_1 = require("../utils"); const up_spec_1 = require("./up.spec"); class Up extends command_1.Command { async run() { const { args } = this.parse(Up); const { template } = args; // 1. check that '.boilerplate' directory exists if (!utils_1.boilerplateExists()) { return this.log(utils_1.printError(`looks like you don't have a '.boilerplate' directory - run 'boil init' to start a new project`)); } // 2. If there's no template directory matching the user template then throw an error if (!utils_1.templateExists(template)) { return this.log(utils_1.printError(`looks like there isn't a template called '${template}' in the '.boilerplate' directory`)); } // 3. Extract all template args (___*___) from the template directory const allArgs = up_spec_1.getTemplateArgs(template); const { templateArgs, functionalArgs } = up_spec_1.splitArgs(allArgs); // 4. Check the local args and global args to see if all template args are defined - if some are not then prompt the user which are missing and throw an error const definedArgs = up_spec_1.localAndGlobalArgs(template); const undefinedTemplateArgs = templateArgs.filter((arg) => !Object.keys(definedArgs).includes(arg)); if (undefinedTemplateArgs.length > 0) { this.log(utils_1.printError(`looks like your template has template args that haven't been defined \n\nplease define the args below in either global.args.yml or local.args.yml `)); undefinedTemplateArgs.forEach((arg) => this.log(utils_1.print(` - ${arg}`, "red"))); return; } // 5. check all functional args (*.js files) have been defined in '.boilerplate' directory const undefinedFunctionalArgs = up_spec_1.undefinedFunctions(functionalArgs); if (undefinedFunctionalArgs.length > 0) { this.log(utils_1.printError(`looks like your template has functional args that haven't been defined \n\nplease define the functions below in the '.boilerplate' directory`)); undefinedFunctionalArgs.forEach((arg) => this.log(utils_1.print(` - ${arg}`, "red"))); return; } /* 6. If all template args have been defined then check if the user has provided all the args. If some are missing then first check if the args have default values. If some args are still missing, or the user picks a value not in the arg options array, then throw an error and show the template help prompt */ const userArgs = up_spec_1.userProvidedArgs(template); // check that user flags begin with either -- or - const invalidFlags = Object.keys(userArgs).some((arg) => !arg.match(/^--/g) && !arg.match(/^-/g)); if (invalidFlags) { return this.log(utils_1.printError(`all your arg flags should begin with --(name) or -(shorthand)`)); } // extract functional input args, e.g. greeting(name, surname) -> name & surname const functionInputArgs = up_spec_1.extractFunctionInputArgs(functionalArgs); // match user input args to defined args const allRequiredArgs = [...templateArgs, ...functionInputArgs]; const requiredArgs = allRequiredArgs.reduce((obj, arg) => ({ ...obj, [arg]: { ...definedArgs[arg], name: arg } }), {}); // check that the required args have been provided by the user (either by the full name or the shorthand method) const matchRequiredToUserInputs = up_spec_1.compareUserRequiredArgs(requiredArgs, userArgs); // if a user hasn't provided all args then check if any of the required args have default values. // also, if the arg has an options array check the input value is a valid option const validatedArgs = up_spec_1.validateArgs(matchRequiredToUserInputs, requiredArgs); const notAllValid = validatedArgs.some((arg) => !arg.valid); if (notAllValid) { this.log(utils_1.printError(`your args don't match the template requirements`)); utils_1.templateArgsTable(Object.values(requiredArgs), "up", template); return; } // 7. Prompt the user where to save the boilerplate files and/or folders (and verify the directory exists) let source; // bypass prompt for tests if (process.env.TS_NODE_FILES) { source = "./"; } else { const promptValue = await inquirer.prompt([ { name: "source", message: "where would you like to save the boilerplate files and/or folders?", type: "input", default: "./", }, ]); source = promptValue.source; } // if source is missing root ('./...') then add it const formattedSource = source.slice(0, 2) === "./" ? source : `./${source}`; if (!up_spec_1.dirExists(formattedSource)) { return this.log(utils_1.printError(`'${formattedSource}' does not exist`)); } // 8. generate the files and folders, switching out all the arg placeholders with the user-provided values const argInputs = validatedArgs.reduce((output, { name, value }) => ({ ...output, [name]: value }), {}); // call functional arguments and record values const functionalValues = up_spec_1.getFunctionValues(functionalArgs, argInputs); const allArgInputValues = { ...argInputs, ...functionalValues }; up_spec_1.generateBoilerplate(template, formattedSource, allArgInputValues); } } exports.default = Up; Up.description = "generate boilerplate from one of the templates"; Up.strict = false; // allow any user inputs Up.flags = { help: command_1.flags.help({ char: "h" }), }; Up.args = [ { name: "template", required: true, description: `call up a template defined in the '.boilerplate' directory`, }, ]; Up.examples = [ `$ boil up component ${utils_1.print("--name")} App ${utils_1.print("--filetype")} js`, `$ boil up component ${utils_1.print("-n")} App ${utils_1.print("-ft")} js run ${utils_1.print("boil list")} to see all available boilerplate templates`, ];