boil-cli-tool
Version:
CLI tool - boilerplate template manager and generator
115 lines (113 loc) • 6.53 kB
JavaScript
;
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`,
];