UNPKG

@mail-core/cli

Version:

Инструментарий для написания cli-скриптов

212 lines 8.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.initCLI = exports.execCommand = exports.getActiveConsole = exports.createCommand = void 0; const fs_1 = require("fs"); const color_1 = require("../color"); const path_1 = require("path"); const yargs = require("yargs"); const interactive_1 = require("../interactive/interactive"); const exit_1 = require("../process/exit"); const console_1 = require("../console/console"); const spinner_1 = require("../console/spinner"); const pkg_1 = require("../pkg"); const boxen = require("boxen"); const summary_1 = require("../process/summary"); const Chalk = require("chalk"); const { command, parse, demandCommand, recommendCommands } = yargs; const { strictCommands } = yargs; const defaultActiveConsole = console_1.createPackageExtendedConsole(__dirname, process.argv.includes('--yes')); let activeCommand = null; let activeCommandArgv = null; let activeCommandEnv = null; function createCommand(cmd) { console_1.verbose(`[createCommand] ${cmd.name} (${cmd.describe})`); return cmd; } exports.createCommand = createCommand; function getActiveConsole() { return (activeCommandEnv === null || activeCommandEnv === void 0 ? void 0 : activeCommandEnv.console) || defaultActiveConsole; } exports.getActiveConsole = getActiveConsole; async function execCommand(cmd, argv) { if (Array.isArray(argv)) { console_1.verbose(`[execCommand.raw.arv] ${cmd.name} (${cmd.describe}):`, argv); argv = parse(argv); } console_1.verbose(`[execCommand] ${cmd.name} (${cmd.describe}):`, argv); const env = createEnv(argv, cmd); cmd.check && cmd.check(argv); await cmd.handler(argv, env); } exports.execCommand = execCommand; function printErrorReason(console, reason) { console.hr(); if (reason instanceof Error) { console.verbose('error:', reason); console.raw.error(color_1.bold.red(reason.stack || `${reason.name}: ${reason.message}`)); } else if (reason && reason.stderr) { if (reason.stdout) { console.raw.log(reason.stdout); console.hr(); } console.raw.error(color_1.red(reason.stderr)); process.exit(reason.code || 1); } else { console.raw.error(typeof reason === 'string' ? color_1.red(reason) : reason); } } function initCLI(env, ...scheme) { const pkg = pkg_1.readPackageJson(env.__dirname); const showProcessSummary = summary_1.startProcessSummary(); console_1.verbose(`[initCLI] env:`, env, scheme); console_1.verbose(`[initCLI] process.version:`, process.version); // v12+ if (!/^v([0-9]+[2-9]|[2-9][0-9]+)/.test(process.version)) { console.warn(boxen(color_1.bold.yellow(`${color_1.underline(pkg.name)}: NodeJS ${process.version} not supported, try: \`nvm use 12\``), { padding: 1, borderStyle: 'bold', borderColor: 'yellow', margin: 1 })); } scheme.forEach(cmdOrMap => { if (isCommandDescriptor(cmdOrMap)) { initCommand(cmdOrMap); } else { Object.entries(cmdOrMap).forEach(([scope, list]) => { list.forEach((cmd) => { initCommand(cmd, scope); }); }); } }); demandCommand(1, ''); recommendCommands(); strictCommands(); exit_1.addProcessExitListener((evt) => { const console = getActiveConsole(); const exit = () => { if (evt.type === 'uncaughtException') { console.verbose('uncaughtException:', evt.reason); showProcessSummary(); printErrorReason(console, evt.reason); process.exit(1); } else if (evt.type !== 'exit') { console.verbose(`Command exit by "${evt.type}": ${evt.signal}`); showProcessSummary(); process.exit(); } else { showProcessSummary(); } }; if (activeCommand && activeCommand.exitHandler && activeCommandArgv && activeCommandEnv) { const val = activeCommand.exitHandler(evt, activeCommandArgv, activeCommandEnv); val && val .catch((reason) => { printErrorReason(console, reason); }) .then(() => { showProcessSummary(); process.exit(0); }); } else { exit(); } }); return parse(); } exports.initCLI = initCLI; function isCommandDescriptor(x) { return typeof x === 'object' && !!x && ('options' in x); } function initCommand(cmd, scope) { console_1.verbose(`[initCommand] ${cmd.name} (${cmd.describe}), scope: ${scope}`); const options = Object.entries(cmd.options); const name = (scope ? `${scope}-${cmd.name}` : cmd.name) + options.reduce((list, [name, opt]) => { if ('positional' in opt) { if (opt.demandOption) { return `${list} <${name}${opt.array ? '..' : ''}>`; } return `${list} [${name}${opt.array ? '..' : ''}]`; } return list; }, ''); command({ command: name, aliases: cmd.aliases, builder(yargs) { options.forEach(([name, opt]) => { if ('positional' in opt) { yargs.positional(name, opt); } else { yargs.option(name, opt); } }); return yargs .check(cmd.check || (() => true)) .alias('help', 'h'); }, describe: cmd.hidden ? undefined : cmd.describe || '<<description undefined>>', async handler(argv) { const env = createEnv(argv, cmd); env.console.verbose(`[handler] ${cmd.name} (${cmd.describe}):`, argv); activeCommand = cmd; activeCommandArgv = argv; activeCommandEnv = env; try { await interactiveOptions(argv, options); await cmd.handler(argv, env); } catch (err) { spinner_1.stopAllSpinners('fail'); env.console.fail(`Command "${cmd.name}" failed`); printErrorReason(env.console, err); throw err; } }, }); } async function interactiveOptions(argv, options) { for (const [key, opt] of options) { const type = opt.type === 'string' ? 'input' : 'confirm'; if (opt.interactive && !argv[key]) { do { const { value } = await interactive_1.interactive({ value: { message: `Enter "${opt.describe || key}":`, type, value: opt.default, }, }); argv[key] = value; } while (type === 'input' && !argv[key]); } } } function createEnv(argv, cmd) { let cwd = process.cwd(); if (argv.$0) { if (fs_1.existsSync(argv.$0)) { cwd = fs_1.realpathSync(argv.$0); } else { cwd = fs_1.realpathSync(argv.$0.split(path_1.sep).slice(0, -1).join(path_1.sep)); } } console_1.verbose(`[createEnv] ${cmd.name} (${cmd.describe}): cwd = ${cwd}`); const console = console_1.createPackageExtendedConsole(cwd ? fs_1.realpathSync(cwd) : cwd, !!argv.yes); const options = Object .entries(cmd.options) .reduce((map, [name, props]) => (Object.assign(Object.assign({}, map), { [name]: Object.assign(Object.assign({}, props), { name, value: argv[name] }) })), {}); ; return Object.assign(Object.assign({ style: Chalk, console, exit(code) { process.exit(code); }, fail(err) { console.fail(`→ ${cmd.describe} failed:`, err); process.exit(1); } }, cmd), { options }); } //# sourceMappingURL=command.js.map