UNPKG

commandos

Version:

Command line parser, compatible with DOS style command

284 lines (215 loc) 10.3 kB
# commandos __命令字符串分析工具__ 其他语言 / [英语](./README.md) 包名 *commandos* 的灵感来自于经典策略游戏 *Commandos: Behind Enemy Lines*,但在此处,其真实意义是单词 *command**DOS* 的合体。__commandos__ 是一个轻量级的命令行分析工具,令你可以更加轻松地使用 Node.js 开发 CLI 应用程序。 ## 目录 * [快速开始](#快速开始) * [API](#api) * [进阶](#进阶) * [示例](#示例) * [起源](#起源) * [关于](#关于) * [参考](#参考) ## 链接 * [更新日志](./CHANGELOG.md) * [项目主页](https://github.com/YounGoat/nodejs.commandos) ## 快速开始 ```javascript const commandos = require('commandos'); // -- example 1 -- // Parse the command line of current process with default settings. const cmd = commandos.parse(); // -- example 2 -- // Parse command line with default settings. const cmdline = 'foo -v 1.0 --name JACK'; const cmd = commandos.parse(cmdline); // RETURN { v, name, $: [] }; // -- example 3 -- // Parse command line with customised settings. const cmdline = 'foo -v 1.0 --name JACK'; const options = [ '--version -v', '--name -n' ]; const cmd = commandos.parse(cmdline, options); // RETURN { version, name, $: [] } ``` 如果需要更强大的设置,请阅读 [API: commandos.parse()](#commandosparse) 一节。 ### 返回对象 如无意外,`commandos.parse()` 将返回一个 JSON 对象: * 它的属性或与命令行 `cmdline` 中的选项(`-``--` 前导)同名,或由 `settings.options` 决定(见下例); * 此外,返回对象中还包括一个数组类型、名为 `$` 的属性,它将包括命令行 `cmdline` 中所有不属于任何选项的片断(通常附加在命令行的最后)。 ```javascript const cmdline = 'foo -v 1.0 --name JACK bar quz'; const options = [ '--version -v', '--name -n' ]; const settings = { options }; const cmd = commandos.parse(cmdline, settings); // RETURN { version, name, $: ['bar', 'quz'] } ``` ### 例外 以下情形将导致 `commandos.parse()` 出现例外: * 参数 *cmdline* 中包含 *settings.options* 中未声明的选项,与此同时参数 *settings.explicit* 设为 `true`* 参数 *cmdline* 中出现非法选项。例如,`--no-foo=bar` 即为非法选项,因为开关量是不可以赋值的; * 参数 *cmdline* 中包含的选项与 *settings**settings.options* 中声明的选项特征相冲突。 出现异常时,如果通过 *settings.catcher* 指定了异常捕获函数,则该函数将被调用,而相应异常(`Error` 实例)将作为唯一的参数。否则,该异常将被直接抛出: ```javascript let catcher = (ex) => { console.warn(ex.message); }; // The exception will be catched and passed into *catcher*. commandos.parse('foo --no-foo=bar', { catcher }); ``` ### 选项组 假如 *cmdline* 可能存在多种不同形式,我们当然可以通过多次运行 `commandos.parse()` 以正确获取命令行携带的参数。不过,通过参数 *settings.groups* 声明选项组是一个更优雅的方式。 ```javascript // Option groups. const settings = { explicit: true, groups: [ [ '--version -v' ], [ '--name -n', '--gender -g' ] ] }; commandos.parse('foo -v 1.0', settings); // RETURN { version, $ } commandos.parse('foo -n JACK -g male', settings); // RETURN { name, gender, $ } ``` 注意:如果 *settings.explicit* 未明确赋值为 `true`,最好在选项组中的选项声明中合理使用 `'REQUIRED'` 关键字。下面是一个反模式: ```javascript // -- ANTI PATTERN -- // Option groups. const settings = { explicit: false, groups: [ [ '--version -v' ], [ '--name -n', '--gender -g' ] ] }; commandos.parse('foo -n JACK -g male', settings); // RETURN { $ } // The first option group matched, becuase it does NOT require any options. ``` ### 传入预解析对象 `commandos.parse()` 也可以接受 *options* 对象,并依据 *settings* 对其进行校验和规范化。例如: ```javascript const options = { v: '1.0', name: 'JACK' }; const settings = { explicit: true, options: [ '--version -v', '--name -n' ] }; commandos.parse(options, settings); // RETURN { version, name } ``` ## API ### commandos.parse() * Object __commandos.parse__() * Object __commandos.parse__(string | string[] *cmdline*) * Object __commandos.parse__(Object *options*) * Object __commandos.parse__(*cmdline* | *options*, Array *optionDefinitions*) * Object __commandos.parse__(*cmdline* | *options*, Object *settings*) 参数 *settings* 通过以下属性设定 __commandos.parse__ 的行为模式: * __overwrite__ *boolean* DEFAULT `true` OPTIONAL * __caseSensitive__ *boolean* DEFAULT `true` OPTIONAL * __explicit__ *boolean* DEFAULT `false` OPTIONAL * __ignoreInvalidArgument__ *boolean* DEFAULT `false` OPTIONAL * __options__ *Array* OPTIONAL * __groups__ *Array* OPTIONAL 一个标准的 *选项定义*(数组 *optionDefinitions**settings.options* 的元素)可以是一个对象或字符串。当它是一个对象时,可以包含以下属性: * __name__ *string* 选项的正式名称,将作为相应选项在 `commandos.parse()` 函数返回对象中相应的属性名。 * __alias__ *string | string[]* OPTIONAL 选项在 *cmdline* 中可能使用的别名。 * __assignable__ *boolean* DEFAULT `true` OPTIONAL 若选项被声明为 __assignable__,*cmdline* 中紧随选项名之后的片断将视为该选项的值。 * __caseSensitive__ *boolean* DEFAULT INHERIT OPTIONAL 若选项被声明为 __caseSensitive__,则 `version` 和 `Version` 将被视为不同选项。 * __multiple__ *boolean* DEFAULT `false` OPTIONAL 若选项被声明为 __multiple__,将选项的解析值将是一个数组。 * __nullable__ *boolean* DEFAULT `true` OPTIONAL 若选项的 __nullable__ 属性非真,则该选项__不应当__在 *cmdline* 中单独出现,若出现则必须附带选项值. * __overwrite__ *boolean* DEFAULT INHERIT OPTIONAL 若选项的 __overwrite__ 属性非真,该选项(包括其别)__不应当__在 *cmdline* 中出现多次。 * __required__ *boolean* DEFAULT `false` OPTIONAL 若选项被声明为 __required__,该选项__应当__在 *cmdline* 中至少出现一次。 __注意:以上属性之间可能是互斥的。__ 例如,如果选项声明为 __multiple__,则它__不应当__同时是一个开关量。也就是说,该选项是可赋值的且不能为空,因此选项声明中的 __nullable__ / __assignable__ / __overwrite__ 属性将被忽略。 选项声明也可以是一个字符串,遵从类似 [column definition in MySQL](https://dev.mysql.com/doc/refman/8.0/en/create-table.html) 的私有语法: ```javascript // * The option is named "version", or "v" in short. The first name is formal. // * The option SHOULD be appended with some value. // * The option SHOULD exist. // * The name is case-insensitive, that means "Version" and "V" are also // acceptable. '--version -v NOT NULL REQUIRED NOT CASE_SENSITIVE' // * The first word is regarded as formal name of the option. // * Alias "v" and "edition" are also acceptable. 'version alias(v, edition)' ``` ## 进阶 ### ODL 选项定义语言 ODL 是用于定义选项的微语言,它是选项定义对象的简易替代品。例如: ```javascript // * The option is named "version", or "v" in short. The first name is formal. // * The option SHOULD be appended with some value. // * The option SHOULD exist. // * The name is case-insensitive, that means "Version" and "V" are also // acceptable. '--version -v NOT NULL REQUIRED NOT CASE_SENSITIVE' // * If named option not offered, the first non-argument will be used as value of option "action". '--action [0:~* (start|stop|restart)]' // * The first word is regarded as formal name of the option. // * Alias "v" and "edition" are also acceptable. 'version alias(v, edition)' ``` ODL 中的关键字大小写不敏感: * [] * ALIAS * ASSIGNABLE * CASE_SENSITIVE * CASE_INSENSITIVE * COMMENT * DEFAULT * MULTIPLE * NULLALBE * OVERWRITE * REQUIRED ### 非选项参数替代选项值 为了让命令行更灵活,__commandos.parse__ 支持通过在 *选项定义* 添加 __nonOption__ 属性,在命令行中未找到命名选项时,取非选项参数作为选项值。属性 __nonOption__ 支持以下类型的重载: * __nonOption__ *number* * __nonOption__ *string* * __nonOption__ *RegExp* * __nonOption__ *Function*(value, index) 而在 ODL 中则使用定界符 `[]` 来定义 nonOption 属性: ```javascript // * Fixed position of non-option argument. // * Fixed value. '--help [0:=* help] NOT ASSIGNABLE' // * Any position. // * Use regular expression (case-insensitive) to validate the arguments. '--action [*:~* (start|stop|restart)]' // * Position range. '--name [>1]' ``` ## 示例 阅读测试用例代码以获取更多示例: * [commandos.parse: basic usage](./test/parse.basic-usage.js) * [commandos.parse: global settings](./test/parse.global-settings.js) * [commandos.parse: option settings](./test/parse.option-settings.js) * [commandos.parse: take non-option argument as option value](./test/parse.option-nonoption.js) * [commandos.parse: option groups](./test/parse.option-groups.js) ## 起源 在众多使用 Node.js 编写的命令行解析工具中,[minimist](https://www.npmjs.com/package/minimist) 和 [commander](https://www.npmjs.com/package/commander) 较为知名。但是,有时候 __minimist__ 功能太过单薄,而 __commander__ 又太重,这就是我为什么设计 __commandos__ 的原因。 ## 关于 *commandos* = *command* + *DOS* ## 参考 如果 __commandos__ 不合你的胃口, 有很多类似功能的包可供选择(按字母顺序排列): * [commander](https://www.npmjs.com/package/commander) * [getopts](https://www.npmjs.com/package/getopts) * [minimist](https://www.npmjs.com/package/minimist) * [nomnom](https://www.npmjs.com/package/nomnom) * [optimist](https://www.npmjs.com/package/optimist) * [yargs](https://www.npmjs.com/package/yargs)