UNPKG

@artus-cli/artus-cli

Version:

CLI framework with modern features

179 lines (178 loc) 6.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseCommand = exports.parseArgvWithPositional = exports.parseArgvToArgs = exports.parseArgvKeySimple = void 0; const tslib_1 = require("tslib"); const yargs_parser_1 = tslib_1.__importDefault(require("yargs-parser")); const utils_1 = require("../utils"); const lodash_1 = require("lodash"); const errors_1 = require("../errors"); /** convert argv to camelCase key simpliy */ function parseArgvKeySimple(argv) { const list = (0, lodash_1.flatten)((Array.isArray(argv) ? argv : [argv]).map(arg => arg.split(/\s+/))); const newList = []; for (const arg of list) { if (arg === '--') break; if (!arg.match(/^\-+[^\-]/i)) continue; const raw = arg.split('=')[0]; newList.push({ raw, parsed: yargs_parser_1.default.camelCase(raw.replace(/^\-{2}no\-/, '')) }); } return newList; } exports.parseArgvKeySimple = parseArgvKeySimple; /** parse argv to args, base on yargs-parser */ function parseArgvToArgs(argv, option = {}) { const requiredOptions = []; const parserOption = { configuration: { "populate--": true }, }; if (option.optionConfig) { for (const key in option.optionConfig) { const opt = option.optionConfig[key]; if (opt.required) requiredOptions.push(key); if (!(0, utils_1.isNil)(opt.alias)) { parserOption.alias = parserOption.alias || {}; parserOption.alias[key] = opt.alias; } if (!(0, utils_1.isNil)(opt.type)) { parserOption[opt.type] = parserOption[opt.type] || []; parserOption[opt.type].push(key); } if (!(0, utils_1.isNil)(opt.default)) { parserOption.default = parserOption.default || {}; parserOption.default[key] = opt.default; } if (!(0, utils_1.isNil)(opt.array)) { parserOption.array = parserOption.array || []; parserOption.array.push(key); } } } const parseResult = yargs_parser_1.default.detailed(argv, parserOption); let error; const requiredNilOptions = requiredOptions.filter(k => (0, utils_1.isNil)(parseResult.argv[k])); if (requiredNilOptions.length) { // check required option error = errors_1.errors.required_options(requiredNilOptions); } else if (option.optionConfig && option.strictOptions) { // checking for strict options const argvs = parseArgvKeySimple(argv); const notSupportArgvs = new Set(); Object.keys(parseResult.argv).forEach(key => { var _a; // _ and -- is built-in key if (key === '_' || key === '--') return; // checking with alias list const alias = (parseResult.aliases[key] || []).concat(key); if (alias.every(n => !notSupportArgvs.has(n) && !option.optionConfig[n])) { const flag = (_a = argvs.find(a => a.parsed === key || a.raw === key)) === null || _a === void 0 ? void 0 : _a.raw; if (flag) notSupportArgvs.add(flag); } }); // check unknown by yargs-parser argvs.forEach(a => { if (parseResult.argv[a.parsed] === undefined) notSupportArgvs.add(a.raw); }); if (notSupportArgvs.size) { error = errors_1.errors.unknown_options(Array.from(notSupportArgvs)); } } else if (parseResult.error) { error = errors_1.errors.unknown(parseResult.error.message); } return { args: parseResult.argv, error, }; } exports.parseArgvToArgs = parseArgvToArgs; /** parse `<options>` or `[option]` and collect args */ function parseArgvWithPositional(argv, pos, options) { let nextIndex = pos.length; const result = {}; const unmatchPositionals = pos.filter((positional, index) => { // `bin <files..>` match `bin file1 file2 file3` => { files: [ "file1", "file2", "file3" ] } // `bin <file> [baseDir]` match `bin file1 ./` => { file: "file1", baseDir: "./" } let r; if (positional.variadic) { r = argv.slice(index); nextIndex = argv.length; // variadic means the last } else { r = argv[index]; } // check arguments option const argOpt = options ? options[positional.cmd] : undefined; if (argOpt) { r = (0, utils_1.isNil)(r) ? argOpt.default : r; if (argOpt.type) r = (0, utils_1.convertValue)(r, argOpt.type); } result[positional.cmd] = r; return (0, utils_1.isNil)(r); }); return { result, unknownArgv: argv.slice(nextIndex), unmatchPositionals, }; } exports.parseArgvWithPositional = parseArgvWithPositional; /** parse command string to struct */ function parseCommand(cmd, binName) { const extraSpacesStrippedCommand = cmd.replace(/\s{2,}/g, ' '); const splitCommand = extraSpacesStrippedCommand.split(/\s+(?![^[]*]|[^<]*>)/); const bregex = /\.*[\][<>]\.*/g; if (!splitCommand.length) throw new Error(`No command found in: ${cmd}`); if (splitCommand[0] === binName) splitCommand.shift(); let command; if (!splitCommand[0] || splitCommand[0].match(bregex)) { command = [binName, ...splitCommand].join(' '); } else { command = splitCommand.join(' '); } const parsedCommand = { uid: '', cmd: '', cmds: [binName], command, demanded: [], optional: [], }; splitCommand.forEach((cmd, i) => { let variadic = false; cmd = cmd.replace(/\s/g, ''); // <file...> or [file...] if (i === splitCommand.length - 1 && /(\.+[\]>])|([\[<]\.+)/.test(cmd)) variadic = true; const result = cmd.match(/^(\[|\<)/); if (result) { if (result[1] === '[') { // [options] parsedCommand.optional.push({ cmd: cmd.replace(bregex, ''), variadic }); } else { // <options> parsedCommand.demanded.push({ cmd: cmd.replace(bregex, ''), variadic }); } } else { // command without [] or <> parsedCommand.cmds.push(cmd); } }); // last cmd is the command parsedCommand.cmd = parsedCommand.cmds[parsedCommand.cmds.length - 1]; parsedCommand.uid = parsedCommand.cmds.join(' '); return parsedCommand; } exports.parseCommand = parseCommand;