问题
最近在使用commander
制作命令行工具时遇到了这样一个问题:在调用单个子命令的时候,该命令行工具下的所有子命令都被触发了!如下,我在app.js
里定义了两个子命令config
和add
,然后调用config
子命令时,可以看到add
子命令也被触发了。
app.js 文件
const program = require('commander')
// config 子命令
program
.command('config', '设置本程序')
.action(() => {
console.log('config 执行!')
})
// add 子命令
program
.command('add', '添加设置')
.action(() => {
console.log('add 执行!')
})
program.parse(process.argv)
调用
> node app.js config
config 执行!
add 执行!
解决
出现这个问题个根本原因在于 子命令介绍的设置问题,应使用description()
方法来设置介绍内容,而不是command()
的第二个参数。将问题代码改成如下形式即可解决问题(所有的子命令都要改成这样):
// 错误写法
program
.command('config', '设置本程序')
.action(() => {
console.log('config 执行!')
})
// 正确写法
program
.command('config')
.description('设置本程序')
.action(() => {
console.log('config 执行!')
})
原因
出现这个问题的原因是因为command
方法在接受不同数量的参数时会返回不同的对象导致的,如果它只接受一个参数子命令名
的话返回的是 子命令本身,而如果加上第二个参数子命令介绍
的话,返回值就变成了整个命令行的原型!
command()
不添加第二个参数
console.log(program.command('config'))
// 返回子命令对象
{
...
_name: 'config',
_noHelp: false,
parent: // 这里可以看到父节点,证明返回值是子命令本身
Command {
...
}
}
command()
添加第二个参数
console.log(program.command('add', '添加设置'))
// 返回整个命令行原型
{
commands: [ // 所有的子命令
Command { ... }, // 子命令1
Command { ... } // 子命令2
],
options: [ ... ], // 命令行工具全局的参数
...
}
这么设计的原因是command(key, describe)
这种写法是为了方便使用 子命令模式 的链式调用的,所以才会返回整个原型,如下,如果不使用子命令模式的话就不要用这种方式来设置子命令的介绍:
const program = require('commander')
program
.version('1.0.0')
.description('这是一个命令行工具')
.command('add', '第一个命令')
.command('config', '第二个命令')
.command('list', '第三个命令')
.parse(process.argv)
这样一来就清楚了,如果使用了给command()
添加第二个参数的形式来创建子命令的话,它就会返回整个命令行的原型,再加上后面还链式调用了action
方法,这就导致了action()
是基于整个命令行原型进行挂载的。从而导致了 调用某一子命令时会异常触发其他子命令 问题的产生。
网友评论