UNPKG

@newos/cli

Version:
169 lines 6.92 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.register = exports.generateSignature = void 0; const inquirer_1 = __importDefault(require("inquirer")); const prompt_1 = require("./prompts/prompt"); const telemetry_1 = __importDefault(require("./telemetry")); function generateSignature(name, args) { return [name, ...args.map(a => `[${a.name}${a.variadic ? '...' : ''}]`)].join(' '); } exports.generateSignature = generateSignature; function register(program, spec, getAction) { validateSpec(spec); const signature = generateSignature(spec.name, spec.args); const command = program .command(signature, undefined, { noHelp: true }) .description(spec.description) .action(async (...actionArgs) => { const { preAction, action } = await getAction(); const [cmd, params] = getCommandParams(...actionArgs); const abort = await (preAction === null || preAction === void 0 ? void 0 : preAction(params)); if (abort) { return abort(); } await promptOrValidateAll(cmd, spec, params); telemetry_1.default.report(cmd.name(), params, !!params.interactive); await action(params); process.exit(0); }); for (const opt of spec.options) { command.option(opt.format, opt.description, opt.default); } } exports.register = register; // Unifies both options and positional arguments under the same interface of name + Param. function* allParams(cmd, spec) { var _a; for (const opt of spec.options) { // An option's name is determined by Commander by removing the leading // dashes and camel-casing the flag. In order to avoid accidental // differences in the algorithm we look it up in the command and use // whatever Commander says. const name = (_a = cmd.options.find(o => o.flags === opt.format)) === null || _a === void 0 ? void 0 : _a.attributeName(); if (name === undefined) { // Just a sanity check. Should never happen. throw new Error('Could not find option: ' + opt.format); } yield [name, opt]; } for (const arg of spec.args) { yield [arg.name, arg]; } } async function promptOrValidateAll(cmd, spec, params) { var _a; for (const [name, param] of allParams(cmd, spec)) { if (param.variadic === true) { await promptOrValidateVariadic(name, param, params); } else { await promptOrValidateSimple(name, param, params); } await ((_a = param.after) === null || _a === void 0 ? void 0 : _a.call(param, params)); } } async function promptOrValidateVariadic(name, param, params) { var _a, _b; const values = params[name]; if (!Array.isArray(values)) { throw new Error(`Expected multiple values for ${name}`); } const details = await ((_a = param.details) === null || _a === void 0 ? void 0 : _a.call(param, params)); if (details) { if (values.length === 0 && ((_b = details === null || details === void 0 ? void 0 : details[0]) === null || _b === void 0 ? void 0 : _b.prompt) !== undefined) { const values = []; for (const d of details) { if (!params.interactive || prompt_1.DISABLE_INTERACTIVITY) { throw new Error(`Missing required parameters ${name}`); } values.push(await askQuestion(name, d)); } params[name] = values; } else { if (details.length !== values.length) { throw new Error(`Expected ${details.length} values for ${name} but got ${values.length}`); } for (const [i, d] of details.entries()) { throwIfInvalid(values[i], name, d); } } } } async function promptOrValidateSimple(name, param, params) { var _a; const value = params[name]; const details = await ((_a = param.details) === null || _a === void 0 ? void 0 : _a.call(param, params)); if (details) { if (value === undefined && (details === null || details === void 0 ? void 0 : details.prompt) !== undefined) { if (!params.interactive || prompt_1.DISABLE_INTERACTIVITY) { throw new Error(`Missing required parameter ${name}`); } params[name] = await askQuestion(name, details); } else { throwIfInvalid(value, name, details); } } } async function askQuestion(name, details) { var _a; const { prompt, choices, validationError } = details; const type = (_a = details.promptType) !== null && _a !== void 0 ? _a : (choices === undefined ? 'input' : 'list'); const validate = value => { var _a; return (_a = validationError === null || validationError === void 0 ? void 0 : validationError(value)) !== null && _a !== void 0 ? _a : true; }; const answers = await inquirer_1.default.prompt({ name: 'question', type, message: prompt, choices, validate, default: details.preselect, }); const value = answers.question; // Inquirer doesn't run validations for confirm (yes/no) prompts, but we do // want to validate because in some cases only one answer is acceptable. // (e.g. --migrate-manifest) if (type === 'confirm' && validationError) { const error = validationError(value); if (error) { throw new Error(error); } } return value; } function throwIfInvalid(value, name, details) { const { validationError, choices } = details !== null && details !== void 0 ? details : {}; let error; if (validationError) { error = validationError(value); } else if (choices) { if (!choices.some(c => (typeof c === 'object' && 'value' in c ? c.value === value : c === value))) { error = `Invalid ${name} '${value}'`; } } if (error) { throw new Error(error); } } // Converts the arguments that Commander passes to an action into an object // where the key-value pairs correspond to positional arguments and options, // and extracts the Command object. function getCommandParams(...args) { const cmd = args.pop(); const params = Object.assign({}, cmd.opts()); for (let i = 0; i < cmd._args.length; i++) { params[cmd._args[i].name] = args[i]; } return [cmd, params]; } function validateSpec(spec) { const firstVariadic = spec.args.findIndex(arg => arg.variadic); if (firstVariadic !== -1 && firstVariadic < spec.args.length - 1) { throw new Error('Only the last positional argument can be variadic'); } } //# sourceMappingURL=register-command.js.map