yargs

引子

仲尼曰:君子中庸;小人反中庸

君子中庸也,君子而士中。小人之反中庸也,小人而无忌惮也。

–《中庸》

yargs api 探索

1
2
var argv = require("yargs").argv; //等价于以下方法
var argv = require("yargs").parse(); //此二者用于拿到命令行参数

.alias(key, alias)

此接口用于使用短符号等价比较长的 key
例如:

1
.alias('i', 'ingredient')

.argv

取得输入参数,用 object 表示

.array(key)

指定 key 为数组,例:.array(‘foo’)设置之后,–foo foo bar 将会变成[‘foo’,’bar’]

.boolean(key)

指定 key 为 bool 值,例:.boolean(‘foo’)设置之后, –foo foo 将会变成 true

.check(fn, [global=true])

函数 fn 接受两个参数,argv,options

1
2
{ _: [], help: false, version: false, foo: 'test', '$0': 'app.js' } // argv
{ help: [], version: [] } // options

这个函数用于检测参数传的是不是合法,return 不为 true 的时候会显示抛出的错误,使用说明,然后退出。
global = true 的时候意思是这个应该放到顶层(检查嘛,应该在最开始检查)

.choices(key, choices)

给 key 预定义一些列可取的值,如果这个方法调用了多次,那么列举的值会被 merge 到一起。选项是一般的字符串或者数字,并且对大小写敏感。例:

1
2
3
4
var argv = require("yargs")
.choices("i", ["peanut-butter", "jelly", "banana", "pickles"])
.choices("i", ["apple"])
.parse();

另外,.choices()可以使用一个对象携带多个 key-choices。例:

1
2
3
4
5
6
var argv = require("yargs")
.choices({
j: ["butter", "ly", "ana", "kles"],
i: ["peanut-butter", "jelly", "banana", "pickles"]
})
.parse();

而且,choices 可以设置为 option()方法的一个 key

1
2
3
4
5
var argv = require("yargs").option("size", {
alias: "s",
describe: "choose a size",
choices: ["xs", "s", "m", "l", "xl"]
}).argv;

.coerce(key, fn)

这个接口是用来强制转换 key 的 value 值的。这个强转函数接受一个参数,也就是命令行中的 key 值。此函数必须返回一个新的值,或者抛出错误。返回的新值将会作为 key 的 value(或者 key 的 alias 的 value)。

抛出的错误,可以在fail()方法中捕获并打印。

强制转换可以在所有其他修改方法之后应用,比如在.normalize()方法之后应用。

例如:

1
2
3
4
5
var argv = require("yargs")
.alias("f", "file")
.coerce("file", function(arg) {
throw new Error("test");
}).argv;

当然,此方法也可以接受对象参数:

1
2
3
4
var argv = require("yargs").coerce({
date: Date.parse,
json: JSON.parse
}).argv;

还有,你可以使用一个函数对应好几个 key:

1
2
var path = require("path");
var argv = require("yargs").coerce(["src", "dest"], path.resolve).argv;

如果使用点操作或者数组,强制转换会应用到最终的 object 上:

1
2
3
4
5
6
7
8
9
// --user.name Batman --user.password 123
// gives us: {name: 'batman', password: '[SECRET]'}
var argv = require("yargs")
.option("user")
.coerce("user", opt => {
opt.name = opt.name.toLowerCase();
opt.password = "[SECRET]";
return opt;
}).argv;

.command(cmd, desc, [builder], [handler]);.command(cmd, desc, [module]);.command(module)

此用法用于定义应用暴露出来的的命令(默认我们程序命名为 app.js)

cmd用于定义命令(注意这里要和参数 key 区分开),可以为字符串或者字符串数组,当然也可以使用 alias,下面有专门叙述。

desc用于描述应用提供的所有命令(逐条对应)。定义为 false 可以生成一个隐藏命令,隐藏命令不会在帮助信息中展示,同时不能在.completion中使用

另外,也可以提供一个构建者 object 提供一些命令接受的选项信息

1
2
3
4
5
6
7
8
yargs
.command("get", "make a get HTTP request", {
url: {
alias: "u",
default: "http://yargs.js.org/"
}
})
.help().argv;

构建者 还可以是一个函数。函数携带一个 yargs 实例, 可以用来提供更详细的命令描述。

1
2
3
4
5
6
7
8
yargs
.command("get", "make a get HTTP request", function(yargs) {
return yargs.option("url", {
alias: "u",
default: "http://yargs.js.org/"
});
})
.help().argv;

而且,还可以加上一个处理函数,参数为转化后的argv对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
yargs
.command(
"get",
"make a get HTTP request",
function(yargs) {
return yargs.option("u", {
alias: "url",
describe: "the URL to make an HTTP request to"
});
},
function(argv) {
console.log(argv.url);
}
)
.help().argv;

想要进一步了解 command api 更详尽的特性,请点击这里

.completion([cmd], [description], [fn])

此命令用户命令行补全(切记执行 chmod u+x 文件 改为可执行文件再进行补全尝试)

cmd 定义参与命令补全的命令。第一次使用会有提示,如果用的 zsh,那么将提示中.bashrc改成.zshrc,然后按照提示操作(切记将你的 js 文件设置为可执行文件,然后再操作)

description 描述命令的使用方法

fn: 提供待补全的参数

如果实现的时候没有携带参数,那么.completion()会让补全命令输出补全脚本

1
2
3
4
5
6
var argv = require("yargs").completion("completion", function(current, argv) {
// 'current' is the current command being completed.
// 'argv' is the parsed arguments so far.
// simply return an array of completions.
return ["foo", "bar"];
}).argv;

还可以提供异步补全

1
2
3
4
5
6
7
8
9
var argv = require("yargs").completion("completion", function(
current,
argv,
done
) {
setTimeout(function() {
done(["apple", "banana"]);
}, 500);
}).argv;

还可以使用异步的 promise

1
2
3
4
5
6
7
8
9
10
11
var argv = require("yargs").completion("completion", function(
current,
argv,
done
) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(["apple", "banana"]);
}, 10);
});
}).argv;

.config([key], [description], [parseFn]) .config(object)

此方法使得传入 key 的值被认为是一个 JSON 配置文件的路径。文件中的 JSON 属性被设置为对应的 key 和 value(挂在 argv 上)。文件使用 nodejs 的 require api 加载的,文件名最好为.js, .json。

如果此方法没有携带任何参数,.config()将会使用--config选项传入 JSON 配置文件(此时只能传入以.json 结尾文件)

description同其他方法,用于描述命令

可选项 parseFn 可以用来定制转换器。转换函数必须是同步的,并且应当返回一个带有 key,value 键值对的对象或者一个 error。

1
2
3
var argv = require("yargs").config("settings", function(configPath) {
return JSON.parse(fs.readFileSync(configPath, "utf-8"));
}).argv;

你还可以传一个明确的 object,同样的,它的键值对会转化为argv的键值对。

1
var argv = require("yargs").config({ foo: 1, bar: 2 }).argv;

configpkgConf可以提供extends关键词,用来表明配置应该从别处继承。

extends参数可以是绝对路径也可以是相对路径

1
2
3
4
yargs.config({
extends: "./configs/a.json",
logLevel: "verbose"
}).argv;

或者,还可以是一个模块

1
2
# my-library.js
yargs.pkgConf('nyc')
1
2
3
4
5
6
# package.json
{
"nyc": {
"extends": "nyc-babel-config"
}
}

nyc-babel-config 是一个提供配置的包

.conflicts(x, y)

如果 x 被设置了,那么 y 一定不能被设置。y 可以是字符串也可以是数组

当然,此方法也可以接受 Object 对象

.count(key)

此命令用来对命令计数,并转化为命令的参数。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/env node
var argv = require("yargs")
.count("verbose")
.alias("v", "verbose").argv;

VERBOSE_LEVEL = argv.verbose;

function WARN() {
VERBOSE_LEVEL >= 0 && console.log.apply(console, arguments);
}
function INFO() {
VERBOSE_LEVEL >= 1 && console.log.apply(console, arguments);
}
function DEBUG() {
VERBOSE_LEVEL >= 2 && console.log.apply(console, arguments);
}

WARN("Showing only important stuff");
INFO("Showing semi-important stuff too");
DEBUG("Extra chatty mode");

.default(key, value, [description]) .defaults(key, value, [description])

注意:这个命令已经弃用。将在将来的主版本中移除

如果没有选项传入的话,为 key 设置默认值

当然,同样此命令可以接受一个 object 为参数,设置 key 的默认值

而且,默认值还可以是一个函数,函数名会被写到 help 里面的用法说明中

1
2
3
var argv = require("yargs").default("random", function randomValue() {
return Math.random() * 256;
}).argv;

而且,description参数可以优先提供用法说明

.demandOption(key, [msg | boolean]) .demandOption(key, msg)

此命令用来强制用户输入某些参数

如果 key 是一个字符串,且 key 没有出现在命令行参数中,展示使用说明并退出。

如果 key 是数组,限制每一个数组中的参数

如果提供了 msg,而且没有相应参数,那么 msg 将会展示,替代原有的标准错误信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// demand an array of keys to be provided
require("yargs")
.option("run", {
alias: "r",
describe: "run your program"
})
.option("path", {
alias: "p",
describe: "provide a path to file"
})
.option("spec", {
alias: "s",
describe: "program specifications"
})
.demandOption(
["run", "path"],
"Please provide both run and path arguments to work with this tool"
)
.help().argv;

当第二个参数为布尔值的时候,布尔值决定了这个选项是不是必须的。当使用 options 方法的时候,这个选项很有用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// demand individual options within the option constructor
require("yargs")
.options({
run: {
alias: "r",
describe: "run your program",
demandOption: true
},
path: {
alias: "p",
describe: "provide a path to file",
demandOption: true
},
spec: {
alias: "s",
describe: "program specifications"
}
})
.help().argv;

.demandCommand([min=1], [minMsg]) .demandCommand([min=1], [max], [minMsg], [maxMsg])

此命令用于限定用户在程序中使用的命令次数。如果命令没有传进来,使用 msg 提供标准的错误提示

1
2
3
4
5
6
7
8
9
10
11
12
13
require("yargs")
.command({
command: "configure <key> [value]",
aliases: ["config", "cfg"],
desc: "Set a config variable",
builder: yargs => yargs.default("value", "true"),
handler: argv => {
console.log(`setting ${argv.key} to ${argv.value}`);
}
})
// provide a minimum demand and a minimum demand message
.demandCommand(1, "You need at least one command before moving on")
.help().argv;

.describe(key, desc)

描述 key 的使用方法,可以使用 object

.detectLocale(boolean)

yargs 是否检查系统的所在地,默认是 true

.env([prefix])

定义环境变量的值,使用”_“来表明嵌套的选项(nested__foo => nested.foo)

程序参数定义优先的次序:

  1. 命令行参数
  2. env 参数
  3. 配置文件或者 object
  4. 默认选项
1
2
3
4
5
6
7
var argv = require("yargs")
.env("MY_PROGRAM")
.option("f", {
alias: "fruit-thing",
default: "apple"
}).argv;
console.log(argv);
1
2
3
4
5
6
$ node fruity.js
{ _: [],
f: 'apple',
'fruit-thing': 'apple',
fruitThing: 'apple',
'$0': 'fruity.js' }
1
2
3
4
5
6
$ MY_PROGRAM_FRUIT_THING=banana node fruity.js
{ _: [],
fruitThing: 'banana',
f: 'banana',
'fruit-thing': 'banana',
'$0': 'fruity.js' }
1
2
3
4
5
6
$ MY_PROGRAM_FRUIT_THING=banana node fruity.js -f cat
{ _: [],
f: 'cat',
'fruit-thing': 'cat',
fruitThing: 'cat',
'$0': 'fruity.js' }

默认情况下不读取 env 参数(没有传啊!!!),但是可以用.env(false)让环境变量失效。

.epilog(str) .epilogue(str)

使用说明之后的收场白

1
2
3
var argv = require("yargs").epilogue(
"for more information, find our manual at http://example.com"
);

.example(cmd, desc)

增加示例,第一个参数cmd中,$0代表命令行中的第一个参数。例子会随着帮助信息打印出来。

.exitProcess(enable)

暂时没发现有什么卵用

.fail(fn)

当失败发生的时候,此函数调用,而不是打印错误信息。

fn 参数有三个,msg: ‘本来要打印的信息’;err:最开始抛出来的Error实例;’yargs’,参数对象

1
2
3
4
5
6
7
var argv = require("yargs").fail(function(msg, err, yargs) {
if (err) throw err; // preserve stack
console.error("You broke it!");
console.error(msg);
console.error("You should be doing", yargs.help());
process.exit(1);
}).argv;

.getCompletion(args, done);

原文是可以程序地补全任何行的选项

args: 命令行要补全的参数

done: 回调函数,参数为补全的结果

示例:

1
2
3
4
5
6
7
require("yargs")
.option("foobar")
.option("foobaz")
.completion()
.getCompletion(["./test.js", "--foo"], function(completions) {
console.log(completions);
});

输入的补全选项:./test.js --foo (按 tab 键):–foobar 和 –foobaz

此方法我没有实际测试通过,特此备注

.global(globals, [global=true])

默认 option 都是全局的,但是此命令可以恢复设置为 false 的选项重新为全局的。

全局的 option 在定义的命令执行之后不会清除,非全局的会被清除。默认所有选项都是全局的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var argv = require("yargs")
.option("a", {
alias: "all",
default: true,
global: false
})
.option("n", {
alias: "none",
default: true,
global: false
})
.command("foo", "foo command", function(yargs) {
return yargs.option("b", {
alias: "bar"
});
})
.help("help")
.global("a").argv;

.group(key(s), groupName)

 这个就是在显示使用说明的时候,为同一组 option 增加一个头标题

1
2
3
4
5
var yargs = require("yargs")(["--help"])
.help()
.group("batman", "Heroes:")
.describe("batman", "world's greatest detective")
.wrap(null).argv;

.help() .help([option | boolean]) .help([option, [description]])

展示和配置帮助信息,yargs 默认支持--help选项

option 参数代表可以使用其他选项或命令调出帮助信息。

description 可以修改默认帮助信息的文案

1
2
3
var yargs = require("yargs")(["--info"])
.usage("$0 -operand1 number -operand2 number -operation [add|subtract]")
.help("info").argv;

.implies(x, y)

此命令意味着 y 对 x 有依赖,y 可以是数组,可以是参数名,甚至可以是数字(参数位置)

同样地,这个方法可以接受一个对象参数

1
var yargs = require("yargs").implies("a", "b").argv;

.locale()

开启本地模式,默认 yargs 会自动检测系统位置,然后使用当地的语言

实用一个静态的 locale 可以覆盖掉默认的行为,如下所示

.locale(locale)

覆盖默认检测到的 locale

1
2
3
4
5
6
7
8
9
10
11
12
var argv = require("yargs")
.usage("./$0 - follow ye instructions true")
.option("option", {
alias: "o",
describe: "'tis a mighty fine option",
demandOption: true
})
.command("run", "Arrr, ya best be knowin' what yer doin'")
.example("$0 run foo", "shiver me timbers, here's an example for ye")
.help("help")
.wrap(70)
.locale("pirate").argv;

1
2
3
4
5
6
7
8
9
10
11
12
13
./test.js - follow ye instructions true

Choose yer command:
run Arrr, ya best be knowin' what yer doin'

Options for me hearties!
--option, -o 'tis a mighty fine option [requi-yar-ed]
--help Parlay this here code of conduct [boolean]

Ex. marks the spot:
test.js run foo shiver me timbers, here's an example for ye

Ye be havin' to set the followin' argument land lubber: option

一般用不到这个东东

.nargs(key, count)

此方法用于限制 key 后面跟的参数长度

1
var argv = require("yargs").nargs("token", 1).argv;

当然,也可以传 object 参数

.normalize(key)

据说是为了传入 path 的时候,便于调用 path.normalize()

number(key)

告诉 parser,一直将这个key当作数字转换

参数可以是数组

选项如果并没有值,默认为undefined

不能转化为数字,会被转换为NaN

小数,16 进制数,科学计数法都是合法的

1
2
3
var argv = require("yargs")
.number("n")
.number(["width", "height"]).argv;

.option(key, [opt]) .options(key, [opt])

key配置各种选项的命令

1
2
3
4
5
6
7
var argv = require("yargs").option("f", {
alias: "file",
demandOption: true,
default: "/etc/passwd",
describe: "x marks the spot",
type: "string"
}).argv;

1
2
3
4
5
6
var argv = require("yargs")
.alias("f", "file")
.demandOption("f")
.default("f", "/etc/passwd")
.describe("f", "x marks the spot")
.string("f").argv;

还可以这样

1
2
3
4
5
6
7
8
9
var argv = require("yargs").options({
f: {
alias: "file",
demandOption: true,
default: "/etc/passwd",
describe: "x marks the spot",
type: "string"
}
}).argv;

可用的 key 有以下这些

  • alias
  • array
  • boolean
  • choices
  • coerce
  • config
  • configParser
  • conflicts
  • count
  • default
  • defaultDescription
  • demandOption
  • desc/describe/description
  • global
  • group
  • hidden
  • implies
  • nargs
  • normalize
  • number
  • requiresArg
  • skipValidation
  • string
  • type: ‘array’,’boolean’,’count’,’number’,’string’

.parse([args], [context], [parseCallback])

可以替代从process.argv传参,返回 argv 对象。args 可以是数组或者原生参数字符串。

context:可以同时携带的一个对象参数,可以为命令提供状态信息,是很实用的技术。

1
2
3
4
5
6
7
8
9
10
const parser = yargs
.command(
"lunch-train <restaurant>",
"start lunch train",
function() {},
function(argv) {
console.log(argv.restaurant, argv.time);
}
)
.parse("lunch-train rudy's", { time: "12:15" });

parseCallback: 此方法的回调函数,会携带三个参数

  1. err: 转化中出现的验证错误
  2. argv: 转化的 argv 对象
  3. output: 将要在终端输出的文本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// providing the `fn` argument to `parse()` runs yargs in headless mode, this
// makes it easy to use yargs in contexts other than the CLI, e.g., writing
// a chat-bot.
const parser = yargs
.command(
"lunch-train <restaurant> <time>",
"start lunch train",
function() {},
function(argv) {
api.scheduleLunch(argv.restaurant, moment(argv.time));
}
)
.help();

parser.parse(bot.userText, function(err, argv, output) {
if (output) bot.respond(output);
});

提醒: 给 parse 函数回调参数会导致 exitProcess 设置失效,直至回调调用

.pkgConf(key, [cwd])

类似于 .config(),这表明 yargs 从 package.json 中寻找特定的配置对象

cwd可以选择性地提供,package.json 将从这里读取

.positional(key, opt)

这个我尝试了,但是没泡通

对命令的参数进行配置,类似于 .option(),但是不能作用于顶层 yargs 实例

1
2
3
4
5
6
7
8
9
10
11
const argv = require("yargs")("run --help").command(
"run <port> <guid>",
"run the server",
yargs => {
yargs.positional("guid", {
describe: "a unique identifier for the server",
type: "string"
});
}
).argv;
console.log(argv);

可选的参数有:

  • alias
  • choices
  • coerce
  • confilicts
  • default
  • desc/describe/description
  • implies
  • normalize
  • type: ‘boolean’,’number’,’string’

.recommendCommands()

决定 yargs 是否在没有匹配命令的时候,提示相关的类似命令

.require(key, [msg | boolean]) .required(key, [msg | boolean])

.demand()

.requiresArg(key)

可以接收数组或者字符串

规定所有的 key 后面必须要跟 value,否则,现实用法信心并退出

默认如果 key 后面不跟 value,key 赋值为 true

.reset() [已废弃]

重置所有已经构建的参数。对于嵌套命令行接口特别有用。使用 global 避免不想要重置的 keys 被重置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var yargs = require("yargs")
.usage("$0 command")
.command("hello", "hello command")
.command("world", "world command")
.demandCommand(1, "must provide a valid command"),
argv = yargs.argv,
command = argv._[0];

if (command === "hello") {
yargs
.reset()
.usage("$0 hello")
.help("h")
.example("$0 hello", "print the hello message!").argv;

console.log("hello!");
} else if (command === "world") {
yargs
.reset()
.usage("$0 world")
.help("h")
.example("$0 world", "print the world message!").argv;

console.log("world!");
} else {
yargs.showHelp();
}

.showCompletionScript()

生成一个补全脚本。应用的使用者可以在他们的.bashrc中安装,yargs 会提供命令和参数补全的快捷方式

.showHelp(consoleLevel=’error’)

实用 console 的consoleLevel打印使用数据

Example:

1
2
3
4
var yargs = require("yargs").usage(
"$0 -operand1 number -operand2 number -operation [add|subtract]"
);
yargs.showHelp(); //prints to stderr using console.error()

或者,使用标准输出打印使用信息,可以选择console.log:

1
yargs.showHelp("log"); //prints to stdout using console.log()

.showHelpOnFail(enable, [message])

默认,yargs 检测到错误会输出使用信息。我们可以使用这个方法定制行为。enable 为 false 的时候,使用信息不输出。如果 message 参数存在,这个信息会在错误信息之后输出。

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env node
var argv = require("yargs")
.usage("Count the lines in a file.\nUsage: $0 -f <file>")
.demandOption("f")
.alias("f", "file")
.describe("f", "Load a file")
.string("f")
.showHelpOnFail(false, "Specify --help for available options")
.help("help").argv;

// etc.
1
2
3
4
$ node line_count.js
Missing argument value: f

Specify --help for available options

.skipValidation(key)

指定一些选项,跳过验证

.strict([enabled=true])

如果所有的参数都没有被demand, 或者都没有一个正确的描述,这将会被当成错误报告出来

不被认可的命令依然会被当作错误报告出来

.string(key)

告诉 parser 不要将 key 当成数字或布尔值来转换

.updateLocale(obj) .updateStrings(obj)

没有测试通过

覆盖默认的字符串

1
2
3
4
5
6
7
var argv = require("yargs")
.command("run", "the run command")
.help("help")
.updateStrings({
"Commands:": "My Commands -->\n"
})
.wrap(null).argv;

1
2
3
4
5
6
My Commands -->

run the run command

Options:
--help Show help [boolean]

如果特定了一个locale(), 应该在updateStrings()之前调用

.usage(<message|command>, [desc], [builder], [handler])

设置显示哪一条命令的使用信息。在 message 中,$0会被转译成脚本名字,node 命令等。

如果 desc/builder/handler 等参数提供了,此方法相当于 .command

1
2
3
4
5
6
7
8
9
10
const argv = require("yargs").usage(
"$0 <port>",
"start the application server",
yargs => {
yargs.positional("port", {
describe: "the port that your application should bind to",
type: "number"
});
}
).argv;

.version() .version([version|boolean]) .version([option], [description], [version])

设置显示的版本号并退出程序。默认支持 –version。

如果没有参数传入,yargs 会从 package.json 中寻找 version 值

如果传入布尔值 false, 将会禁掉 –version

.wrap(columns)

格式化使用信息的展示 – 多少列

默认的 wrap 是Math.min(80, windowWidth), 使用.wrap(null)去掉列限制。使用.wrap(yargs.terminalWidth())控制显示信息为最大宽度。