接着处理 alias,代码里面有我的注释,假设 alias 一项是help : [h,he,hp],没加引号,不要在意,把 alias 里的每一项都变成 key
PS : 本来我想可以最后处理 alias 的,但是自己实现的时候有个问题,在 parse 的时候,需要知道是否是 boolean 的,最后做 alias 工作的话,达不到这个要求,作罢!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
var aliases = {}; Object.keys(opts.alias || {}).forEach(function(key) { //help : [h,he,hp] //help : h //key : help aliases[key] = [].concat(opts.alias[key]); //wrap single value to array aliases[key].forEach(function(x) { aliases[x] = [key].concat( aliases[key].filter(function(y) { return x !== y; }) ); //aliases[h] = [help, he,hp] //aliases[hp] = [help,h,he] }); });
接着是 option string,处理默认值,处理option['--']选项,把--的 index 找出,划分前后 再就是主 for 循环了…for args setArg 函数内部做了 alias 操作,简单看为设置 argv[key]=value 吧
--abcd=xxx 的情况,正则匹配出来
1 2 3 4 5 6 7
if (/^--.+=/.test(arg)) { // Using [\s\S] instead of . because js doesn't support the // 'dotall' regex modifier. See: // http://stackoverflow.com/a/1068308/13216 var m = arg.match(/^--([^=]+)=([\s\S]*)$/); setArg(m[1], m[2]); }
--no-abcd的情况,设置abcd=false
1 2 3 4
elseif (/^--no-.+/.test(arg)) { var key = arg.match(/^--no-(.+)/)[1]; setArg(key, false); }
再就是--process这种 取后面一个值,存在 and 不是以-开头 and 当前 flag 不是 boolean 的 and boolean 没有被设置成 true,即代码里面的 allTrue and 它的 alias 不是 boolean 的,就采用后面这个值
functionisNumber(x) { if (typeof x === "number") returntrue; if (/^0x[0-9a-f]+$/i.test(x)) returntrue; return/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); }
commander.js 使用及源码解析 ## 使用
官方例子 1 : 解析命令行参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
var program = require("commander");
program .version("0.0.1") .option("-p, --peppers", "Add peppers") .option("-P, --pineapple", "Add pineapple") .option("-b, --bbq", "Add bbq sauce") .option( "-c, --cheese [type]", "Add the specified type of cheese [marble]", "marble" ) .parse(process.argv);
console.log("you ordered a pizza with:"); if (program.peppers) console.log(" - peppers"); if (program.pineapple) console.log(" - pineapple"); if (program.bbq) console.log(" - bbq"); console.log(" - %s cheese", program.cheese);
就是将-s , --long这种解析到 program 上,放到 program.long 上,我写的-s表示 short,简短形式
// default as 3rd arg if ("function" != typeof fn) (defaultValue = fn), (fn = null);
// preassign default value only for --no-*, [optional], or <required> if (false == option.bool || option.optional || option.required) { //程序猿真是操心太多,明明required,管他作甚 // when --no-* we make sure default is true if (false == option.bool) defaultValue = true; // preassign only if we have a default if (undefined !== defaultValue) self[name] = defaultValue; }
// register the option this.options.push(option);
// when it's passed assign the value // and conditionally invoke the callback //cmd.on('option-name',)通过事件为option赋值 this.on(oname, function(val) { // coercion if (null !== val && fn) val = fn(val, undefined === self[name] ? defaultValue : self[name]);
// unassigned or bool if ("boolean" == typeof self[name] || "undefined" == typeof self[name]) { // if no value, bool true, and we have a default, then use it! if (null == val) { self[name] = option.bool ? defaultValue || true : false; } else { self[name] = val; } } elseif (null !== val) { // reassign self[name] = val; } });
// Output help if necessary outputHelpIfNecessary(self, parsed.unknown);
// If there are still any unknown options, then we simply // die, unless someone asked for help, in which case we give it // to them, and then we die. if (parsed.unknown.length > 0) { self.unknownOption(parsed.unknown[0]); }
// Leftover arguments need to be pushed back. Fixes issue #56 if (parsed.args.length) args = parsed.args.concat(args);
// Always append ourselves to the end of the arguments, // to make sure we match the number of arguments the user // expects if (self._args.length) { args[self._args.length] = self; } else { args.push(self); }