UNPKG

takin

Version:

Front end engineering base toolchain and scaffold

370 lines 12.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Cli = exports.Command = void 0; const events_1 = require("events"); const mri_1 = __importDefault(require("mri")); const command_1 = __importStar(require("./command")); exports.Command = command_1.default; const node_1 = require("./node"); const utils_1 = require("./utils"); class Cli extends events_1.EventEmitter { /** * @param name The program name to display in help and version message */ constructor(name = '', runner) { super(); this.pluginName = ''; this.name = name; this.runner = runner; this.commands = new Map(); this.rawArgs = []; this.args = []; this.options = {}; this.globalCommand = new command_1.GlobalCommand(this); this.globalCommand.usage('<command> [options]'); } /** * Add a global usage text. * * This is not used by sub-commands. */ usage(text) { this.globalCommand.usage(text); return this; } /** * 添加子命令 */ command(rawName, description, config) { var _a; const name = (0, utils_1.removeBrackets)(rawName); if (this.commands.has(name)) { return (_a = this.commands.get(name)) === null || _a === void 0 ? void 0 : _a.command; } const command = new command_1.default(rawName, description || '', config || {}, this); const pluginName = this.pluginName; command.globalCommand = this.globalCommand; this.commands.set(command.name, { pluginName, command }); return command; } /** * Add a global CLI option. * * Which is also applied to sub-commands. */ option(rawName, description, config) { this.globalCommand.option(rawName, description, config); return this; } /** * Show help message when `-h, --help` flags appear. * */ help(callback) { this.globalCommand.option('-h, --help', '显示帮助信息'); this.globalCommand.helpCallback = callback; this.showHelpOnExit = true; return this; } /** * Show version number when `-v, --version` flags appear. * */ version(version, customFlags = '-v, --version') { this.globalCommand.version(version, customFlags); this.showVersionOnExit = true; return this; } /** * Add a global example. * * This example added here will not be used by sub-commands. */ example(example) { this.globalCommand.example(example); return this; } /** * Output the corresponding help message * When a sub-command is matched, output the help message for the command * Otherwise output the global one. * */ outputHelp() { if (this.matchedCommand) { this.matchedCommand.outputHelp(); } else { this.globalCommand.outputHelp(); } } /** * Output the version number. * */ outputVersion() { this.globalCommand.outputVersion(); } setParsedInfo({ args, options }, matchedCommand, matchedCommandName) { this.args = args; this.options = options; if (matchedCommand) { this.matchedCommand = matchedCommand; } if (matchedCommandName) { this.matchedCommandName = matchedCommandName; } return this; } /** * 自定义 setParsedInfo * @param param0 - ParsedArgv 已解析的 argv * @param matchedCommand - 匹配的 命令实例 * @param matchedCommandName - 匹配的命令名称 */ setParsedInfo2({ args, options }, matchedCommand, matchedCommandName) { this.args = args; this.options = options; if (matchedCommand) { this.matchedCommand = matchedCommand; } if (matchedCommandName) { this.matchedCommandName = matchedCommandName; } } unsetMatchedCommand() { this.matchedCommand = undefined; this.matchedCommandName = undefined; } /** * Parse argv */ parse(argv = node_1.processArgs, { /** Whether to run the action for matched command */ run = true } = {}) { this.rawArgs = argv; if (!this.name) { this.name = argv[1] ? (0, utils_1.getFileName)(argv[1]) : 'cli'; } let shouldParse = true; // Search sub-commands for (const [, { command }] of this.commands) { const parsed = this.mri(argv.slice(2), command); const commandName = parsed.args[0]; if (command.isMatched(commandName)) { shouldParse = false; const parsedInfo = { ...parsed, args: parsed.args.slice(1) }; this.setParsedInfo(parsedInfo, command, commandName); this.emit(`command:${commandName}`, command); } } if (shouldParse) { // Search the default command for (const [, { command }] of this.commands) { if (command.name === '') { shouldParse = false; const parsed = this.mri(argv.slice(2), command); this.setParsedInfo(parsed, command); this.emit(`command:!`, command); } } } if (shouldParse) { const parsed = this.mri(argv.slice(2)); this.setParsedInfo(parsed); } if (this.options.help && this.showHelpOnExit) { this.outputHelp(); run = false; this.unsetMatchedCommand(); } if (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) { this.outputVersion(); run = false; this.unsetMatchedCommand(); } const parsedArgv = { args: this.args, options: this.options }; if (run) { this.runMatchedCommand(); } if (!this.matchedCommand && this.args[0]) { this.emit('command:*'); } return parsedArgv; } // 直接解析指定的命令 parseByCommand(command) { let shouldParse = true; const { name: commandName = '', args = [], options = {} } = command; const parsedInfo = { args, options }; for (const [, { command }] of this.commands) { if (command.isMatched(commandName)) { shouldParse = false; this.setParsedInfo2(parsedInfo, command, commandName); this.emit(`command:${commandName}`, command); } } if (shouldParse) { for (const [, { command }] of this.commands) { if (command.name === '') { shouldParse = false; this.setParsedInfo2(parsedInfo, command); this.emit(`command:!`, command); } } } if (shouldParse) { this.setParsedInfo2(parsedInfo); } if (this.options.help && this.showHelpOnExit) { this.outputHelp(); this.unsetMatchedCommand(); } if (this.options.version && this.showVersionOnExit) { this.outputVersion(); this.unsetMatchedCommand(); } const parsedArgv = { args: this.args, options: this.options }; if (!this.matchedCommand && this.args[0]) { this.emit('command:*'); } return parsedArgv; } /** * 准备匹配的命令选项 * @returns 匹配的命令选项 */ prepareMatchedCommandAndArgs() { const { args, options = {}, matchedCommand: command } = this; // 如果没有命中的 command // 则仅返回 args 和 options if (!command || !command.commandAction) { return { name: undefined, args, options }; } command.checkUnknownOptions(); command.checkOptionValue(); command.checkRequiredArgs(); const actionArgs = []; command.args.forEach((arg, index) => { if (arg.variadic) { actionArgs.push(args.slice(index)); } else { actionArgs.push(args[index]); } }); return { name: command === null || command === void 0 ? void 0 : command.name, args: actionArgs, options }; } mri(argv, /** Matched command */ command) { // All added options const cliOptions = [ ...this.globalCommand.options, ...(command ? command.options : []) ]; const mriOptions = (0, utils_1.getMriOptions)(cliOptions); // Extract everything after `--` since mri doesn't support it let argsAfterDoubleDashes = []; const doubleDashesIndex = argv.indexOf('--'); if (doubleDashesIndex > -1) { argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1); argv = argv.slice(0, doubleDashesIndex); } let parsed = (0, mri_1.default)(argv, mriOptions); parsed = Object.keys(parsed).reduce((res, name) => { return { ...res, [(0, utils_1.camelcaseOptionName)(name)]: parsed[name] }; }, { _: [] }); const args = parsed._; const options = { '--': argsAfterDoubleDashes }; // Set option default value const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue; const transforms = Object.create(null); for (const cliOption of cliOptions) { if (!ignoreDefault && cliOption.config.default !== undefined) { for (const name of cliOption.names) { options[name] = cliOption.config.default; } } // If options type is defined if (Array.isArray(cliOption.config.type)) { if (transforms[cliOption.name] === undefined) { transforms[cliOption.name] = Object.create(null); transforms[cliOption.name]['shouldTransform'] = true; transforms[cliOption.name]['transformFunction'] = cliOption.config.type[0]; } } } // Set option values (support dot-nested property name) for (const key of Object.keys(parsed)) { if (key !== '_') { const keys = key.split('.'); (0, utils_1.setDotProp)(options, keys, parsed[key]); (0, utils_1.setByType)(options, transforms); } } return { args, options }; } runMatchedCommand() { const { args, options, matchedCommand: command } = this; if (!command || !command.commandAction) return; command.checkUnknownOptions(); command.checkOptionValue(); command.checkRequiredArgs(); const actionArgs = []; command.args.forEach((arg, index) => { if (arg.variadic) { actionArgs.push(args.slice(index)); } else { actionArgs.push(args[index]); } }); actionArgs.push(options); return command.commandAction.apply(this, actionArgs); } } exports.Cli = Cli; //# sourceMappingURL=index.js.map