4

前言

应公司要求准备弄一个cli,那就暂定为win-cli吧~
然而发现有很多不了解的东西,学习的东西也挺多的,那就慢慢啃吧(慢慢吭是不阔能的...)~哈哈
首先就是commander了。

什么是commander

关于github上的介绍,这是一个node命令行接口的解决方案,那肯定是和node相关的东东啦。
我们就按照github上的英文文档来吧!!(英文菜鸡一个...然后发现有中文的README,哈哈),还是手敲一遍加强记忆吧。

安装

npm install commander

声明program变量

Commander为了方便快捷编程导出一个全局对象。

const program = require('commander')
program.version('0.0.1')

对于可能以多种方式使用commander的大型程序,包括单元测试,最好创建一个本地commander对象来使用。

const commander = require('commander')
const program = new commander.Command()
program.version('0.0.1')

选项

.option()方法用来定义带有选项的commander,同时也用于这些选项的文档。每个选项可以有一个短标识(单个字符)和一个长名字,它们之间用逗号或者空格分开。

选项(第二个参数)会被放到commander对象的属性上,多词选项如“--template-engine”会被转为驼峰法"program.templateEngine"。多个短标识可以组合为一个参数,如“-a -b -c”等价于“-abc”。

program.option('选项命令','描述', '选项处理函数', '默认值')

常用选项类型,boolean和值

最常用的两个选项类型是boolean(选项后面不跟值)和选项跟一个值(用尖括号声明)。除非在命令行中指定,否者两者都是undefined

const program = require('commander')
program
    .option('-d, --debug', 'output extra debugging')
    .option('-s --small', 'small pizza size')
    .option('-p, --pizza-type <type>', 'flavour of pizza')
program.parse(process.argv)

if(program.debug) console.log(program.opts())
console.log('pizza details:');
if (program.small) console.log('- small pizza size');
if (program.pizzaType) console.log(`- ${program.pizzaType}`);

默认选项值

可以为选项设置一个默认值。

const program = require('commander')

program
    .option('-c, --cheese<type>', 'add the specified type of cheese', 'blue')
    
program.parse(process.argv)
console.log(`cheese:${program.cheese}`)

program.parse(arguments)会处理参数,没有被使用的选项会被存放在program.args数组中。

$ pizza-options
cheese: blue
$ pizza-options --cheese stilton
cheese: stilton

其他选项类型,可忽略的布尔值和标志值

选项的值伟boolean类型时,可以在其加长名字前加no-规定这个选项值伟false。单独定义同样使选项默认为真。
如果你先定义了--foo,再加上--no--foo并不会改变它本来的默认值。你可以为Boolean类型的标识指定一个默认的布尔值,从命令行里可以重写它的值。

const program = require('commander');

program
  .option('--no-sauce', 'Remove sauce')
  .option('--cheese <flavour>', 'cheese flavour', 'mozzarella')
  .option('--no-cheese', 'plain with no cheese')
  .parse(process.argv);

const sauceStr = program.sauce ? 'sauce' : 'no sauce';
const cheeseStr = (program.cheese === false) ? 'no cheese' : `${program.cheese} cheese`;
console.log(`You ordered a pizza with ${sauceStr} and ${cheeseStr}`);

你可以指定一个用作标志的选项,它可以接受值(使用方括号声明,即传值不是必须的)

const program = require('commander')

program
    .option('-c, --cheese [type]', 'ADD CHEESE WITH OPTIONAL TYPE')
program.parse(process.argv)

if(program.cheese === undefined) console.log('NO CHEESE');
else if(program.cheese === true) conosle.log('ADD CHEESE');
else console.log(`ADD CHEESE TYPE ${program.cheese}`)

自定义选项处理

你可以指定一个函数来处理选项的值,接受两个参数:用户传的值,上一个值(previous value),它会返回新的选项值。

版本选项

version方法会处理现实版本命令,默认选项标识为-V--version,当存在时会打印版本号并退出。

program.version('0.0.1')

你可以自定义标识,通过给version方法再传递一个参数,语法与option方法一致。版本标识名字可以是任意的,但是必须要有长名字。

program.version('0.0.1', '-v, --version', 'output the current version')

Commands

你可以使用.command为你的最高层命令指定子命令。这里我们有两种方法可以实现:

  • 为命令绑定一个操作处理程序(action handler)
  • 将命令单独写成一个可执行文件。

.command的第一个参数你可以指定命令的名字以任何参数。参数可以是<required>必须或者[optional]可选,并且最后一个参数也可以是variadic...可变

//通过绑定操作处理程序实现,这里description的定义和.command是分开的
//返回新生成的命令,即该子命令,以供继续配置
program
    .command('clone <source> [destination]')
    .description('clone a repository into a newly created directory')
    .action((source, detination) => {
        console.log('cloen command called')
    })
    
//通过单独分离的可执行文件实现命令(注意这里description是作为.command的第二个参数)
//返回最顶层的命令以供继续添加子命令
program
    .command('start <service>', 'start named service')
    .command('stop [service]', 'stop named service, or all if no name supplied')

指定参数语法

你可以通过.arguments来为最顶级命令指定参数,对于子命令来说参数都包括在.command调用之中的。尖括号(e.g.<required>)意味着必须的输入,而方括号(e.g.[optional])则代表了可选的输入。

var program = require('command')

program
    .version('0.0.1')
    .arguments('<cmd> [env]')
    .action(fucntion(cmd, env) {
        cmdValue = cmd
        envValue = env
    })
program.parse(process.argv)

//使用
win 'cmd' 'env'

一个命令有且仅有最后一个参数是可变的,你需要在参数名后加上...来使他可变,例如:

var program = require('commander')

program
    .version('0.1.0')
    .command('rmdir <dir> [otherDirs...]')
    .action(function(dirm otherDirs){
        if(otherDirs) {
            otherDirs.forEach(function(oDir){
                console.log('rmdir %s', oDir)
            })
        }
    })
program.parse(process.argv)

操作处理程序(Action handler)(子)命令

你可以使用操作处理程序为一个命令增加选项options。操作处理程序会接收每一个你声明的参数的变量,和一个额外的参数--这个命令对象自己。这个命令的参数包括添加的命令特定选项的值。

var program = require('commander')

program
    .command('rm <dir>')
    .option('-r, --recursive', 'REMOVE RECURSIVELY')
    .action(function(dir, cmdObj) {
        console.log('remove ' + dir + (cmdObj.recursive ? ' recursively' : ''))
    })
program.parse(process.argv)

当一个命令在命令行上被使用时,它的选项必须是合法的。使用任何未知的选项会报错。然而如果一个基于操作的命令没有定义任何操作,那么这些选项是不合法的。

定义配置选项可以随着调用 .command() 传递。 为 opts.noHelp 指定 true 则该命令不会出现生成的帮助输出里。

Git风格的子命令

.command()带有描述参数时,不能采用.action(callback)来处理子命令,否则会出错。这告诉commander,你将采用单独的可执行文件作为子命令,就像git(1)和其他流行的工具一样。Commander将会尝试在入口脚本(例如:./examples/pm)的目录搜索program-command形式的可执行文件,例如pm-install, pm-search。你可以是用配置选项executableFile来指定一个自定义的名字。

你可以在可执行文件里处理可执行子命令的选项,而不必在顶层声明他们

// file: ./examples/pm
var program = require('commander');

program
  .version('0.1.0')
  .command('install [name]', 'install one or more packages')
  .command('search [query]', 'search with optional query')
  .command('update', 'update installed packages', {executableFile: 'myUpdateSubCommand'})
  .command('list', 'list packages installed', {isDefault: true})
  .parse(process.argv)

自动化帮助信息 --help

帮助信息是 commander 基于你的程序自动生成的,下面是 --help 生成的帮助信息:

Options:
  -V, --version        output the version number
  -p, --peppers        Add peppers
  -P, --pineapple      Add pineapple
  -b, --bbq            Add bbq sauce
  -c, --cheese <type>  Add the specified type of cheese (default: "marble")
  -C, --no-cheese      You do not want any cheese
  -h, --help           output usage information

自定义帮助

你可以通过监听 --help来控制-h, --help显示任何信息。一旦调用完成,Commander将自动退出,你的程序的其余部分不会展示。
例如在下面的 “stuff” 将不会在执行 --help 时输出。

var program = require('commander');

program
  .version('0.0.1')
  .option('-f, --foo', 'enable some foo')
  .option('-b, --bar', 'enable some bar')
  .option('-B, --baz', 'enable some baz');

// must be before .parse() since
// node's emit() is immediate

program.on('--help', function(){
  console.log('');
  console.log('Examples:');
  console.log('  $ custom-help --help');
  console.log('  $ custom-help -h');
});

program.parse(process.argv);

console.log('stuff');

.outputHelp(cb)

输出帮助信息的同时不退出。可选的回调可在显示帮助文本后处理。如果你想显示默认的帮助。你可以使用类似的东西。

var program = require('commander');
var colors = require('colors');

program
  .version('0.1.0')
  .command('getstream [url]', 'get stream URL')
  .parse(process.argv);

if (!process.argv.slice(2).length) {
  program.outputHelp(make_red);
}

function make_red(txt) {
  return colors.red(txt); //display the help text in red on the console
}

.helpOption(flag, description)

重写覆盖默认的帮助标识和描述

program
  .helpOption('-e, --HELP', 'read more information');

.help(cb)

输出帮助信息并立即退出。 可选的回调可在显示帮助文本后处理。

自定义事件监听

你可以通过监听命令和选项来执行自定义函数。

// 当有选项verbose时会执行函数
program.on('option:verbose', function () {
  process.env.VERBOSE = this.verbose;
});

// 未知命令会报错
program.on('command:*', function () {
  console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' '));
  process.exit(1);
});

fsrookie
2.9k 声望256 粉丝

目前很多文章都是摘抄记录其他教程。见谅。


引用和评论

0 条评论