Comparing version 1.0.9 to 1.1.0
@@ -13,3 +13,3 @@ #!/usr/bin/env node | ||
}) | ||
.option('-t', { type: 'switch' }) | ||
.option('-t', 'switch') | ||
.command('start', function (cmd, t) { | ||
@@ -16,0 +16,0 @@ console.log('cmd:', t); |
const Class = require('cify').Class; | ||
const fs = require('fs'); | ||
const os = require('os'); | ||
const utils = require('ntils'); | ||
@@ -36,21 +38,21 @@ const types = require('./types'); | ||
if (!names) return this; | ||
this._commands = this._commands || {}; | ||
if (utils.isFunction(pattern)) { | ||
fn = [pattern, pattern = fn][0]; | ||
} | ||
if (!utils.isFunction(fn)) { | ||
fn = NOOP_FUNCTION; | ||
}; | ||
this._commands = this._commands || {}; | ||
fn = utils.isFunction(fn) ? fn : NOOP_FUNCTION; | ||
pattern = (pattern === true ? { arguments: true } : pattern) || {}; | ||
names = utils.isArray(names) ? names : [names]; | ||
names.forEach(function (name) { | ||
//name 有可能是正则表达式,所以显式转换一下 | ||
this._commands[String(name)] = { | ||
names: names, | ||
names: names,//声明关联的 commands | ||
regexp: name instanceof RegExp ? name : new RegExp(name) | ||
}; | ||
if (pattern === true) { | ||
pattern = { arguments: true }; | ||
} | ||
pattern = (utils.isObject(pattern) ? pattern : {}) || {}; | ||
pattern.command = name; | ||
this.handle(pattern, fn); | ||
//防止多个 command 之间影响「拷贝」pattern | ||
var _pattern = utils.copy(pattern); | ||
//为每个 command 指定 'command 匹配' 的 handle | ||
//但如果 pattern 还有其它规则,并 and 的关系生效 | ||
_pattern.command = name; | ||
this.handle(_pattern, fn); | ||
}, this); | ||
@@ -67,3 +69,5 @@ return this; | ||
} | ||
if (!utils.isFunction(fn)) return this; | ||
if (!utils.isFunction(fn) || fn == NOOP_FUNCTION) { | ||
return this; | ||
} | ||
pattern = pattern || {}; | ||
@@ -83,30 +87,27 @@ if (utils.isString(pattern.command)) { | ||
**/ | ||
option: function (names, settings, fn) { | ||
option: function (names, setting, fn) { | ||
if (!names) return this; | ||
if (utils.isFunction(settings)) { | ||
fn = [settings, settings = fn][0]; | ||
this._options = this._options || {}; | ||
if (utils.isFunction(setting)) { | ||
fn = [setting, setting = fn][0]; | ||
} | ||
if (!utils.isFunction(fn)) { | ||
fn = NOOP_FUNCTION; | ||
}; | ||
this._options = this._options || {}; | ||
settings = (utils.isArray(settings) ? settings : [settings]).map(function (setting) { | ||
setting = setting || {}; | ||
var typeDefine = this._types[setting.type]; | ||
if (!typeDefine) return setting; | ||
setting.regexp = setting.regexp || typeDefine.regexp; | ||
setting.default = setting.default || typeDefine.default; | ||
setting.convert = setting.convert || typeDefine.convert; | ||
return setting; | ||
}, this); | ||
fn = utils.isFunction(fn) ? fn : NOOP_FUNCTION; | ||
//处理 setting 开始 | ||
setting = (utils.isString(setting) ? { type: setting } : setting) || {}; | ||
var typeDefine = this._types[setting.type]; | ||
if (!typeDefine) return setting; | ||
utils.each(typeDefine, function (name, value) { | ||
setting[name] = setting[name] || value; | ||
}.bind(this)); | ||
//处理 setting 结束 | ||
names = utils.isArray(names) ? names : [names]; | ||
names.forEach(function (name) { | ||
if (this._options[name]) { | ||
throw new Error('Repeated Option: ' + name); | ||
} | ||
settings.names = names; | ||
this._options[name] = settings; | ||
this.handle({ | ||
options: [name] | ||
}, fn); | ||
if (this._options[name]) throw new Error('Repeated Option: ' + name); | ||
//防止多个 options 之间影响「拷贝」setting | ||
var _setting = utils.copy(setting); | ||
_setting.names = names; //声明关联的 options | ||
this._options[name] = _setting; | ||
//为每个 option 添加 handle | ||
//option 的 handle 不能自行配置,只要出现包含的选项,就会执行 | ||
this.handle({ options: [name] }, fn); | ||
}, this); | ||
@@ -149,9 +150,23 @@ return this; | ||
/** | ||
* 字符串或文件内容 | ||
**/ | ||
_strOrFile: function (str) { | ||
if (utils.isNull(str)) return str; | ||
if (str[0] != '@') return str; | ||
try { | ||
return fs.readFileSync(str.substr(1), 'utf8'); | ||
} catch (err) { | ||
return str; | ||
} | ||
}, | ||
/** | ||
* 添加「版本」选项 | ||
**/ | ||
version: function (version) { | ||
this._version = this._strOrFile(version); | ||
this.option(['-v', '--version'], { | ||
type: 'switch' | ||
}, function ($self) { | ||
$self._console.log(version || 'unknow'); | ||
$self._console.log($self._version || 'unknow'); | ||
return false; | ||
@@ -166,6 +181,7 @@ }); | ||
help: function (help) { | ||
this._help = this._strOrFile(help); | ||
this.option(['-h', '--help'], { | ||
type: 'switch' | ||
}, function ($self) { | ||
$self._console.log(help || 'unknow'); | ||
$self._console.log($self._help || 'unknow'); | ||
return false; | ||
@@ -250,3 +266,2 @@ }); | ||
_parseTokensForComboOptions: function () { | ||
var invalidOptions = []; | ||
this._tokens.forEach(function (token, index) { | ||
@@ -256,5 +271,3 @@ if (!OPTION_REGEXP.test(token)) return; //如果不是 option | ||
var trimedName = this._trimOptionName(token); | ||
if (trimedName.length < 2 || this._hasRepeatChar(trimedName)) { | ||
return invalidOptions.push(token); | ||
} | ||
if (trimedName.length < 2 || this._hasRepeatChar(trimedName)) return; | ||
var shortOptions = trimedName.split('').map(function (char) { | ||
@@ -266,10 +279,6 @@ return '-' + char; | ||
}, this); | ||
if (!allExsits) { | ||
return invalidOptions.push(token); | ||
} | ||
if (!allExsits) return; | ||
//将分解后的短参插入 | ||
[].splice.apply(this._tokens, [index, 1].concat(shortOptions)); | ||
}, this); | ||
return invalidOptions.length > 0 ? | ||
new Error('Invalid option: ' + invalidOptions.join(' ')) : null; | ||
}, | ||
@@ -303,27 +312,37 @@ | ||
this.options = {}; | ||
var index = 0, length = this._tokens.length; | ||
while (index < length) { | ||
var invalidOptions = [], index = -1, len = this._tokens.length; | ||
while ((++index) < len) { | ||
var token = this._tokens[index]; | ||
if (OPTION_REGEXP.test(token)) { | ||
var settings = this._options[token]; | ||
var values = settings.map(function (setting) { | ||
index++; | ||
var nextToken = this._tokens[index]; | ||
if (!OPTION_REGEXP.test(nextToken) && | ||
(!setting.regexp || setting.regexp.test(nextToken))) { | ||
var value = utils.isNull(nextToken) ? | ||
setting.default : nextToken.toString(); | ||
return setting.convert ? setting.convert(value) : value; | ||
} else { | ||
index--; | ||
return setting.default; | ||
} | ||
}, this); | ||
this.options[token] = values; | ||
if (OPTION_REGEXP.test(token)) { //如果是一个 options | ||
index++; | ||
var setting = this._options[token]; | ||
//如果「选项」不存在,添加到 invalidOptions | ||
if (utils.isNull(setting)) { | ||
invalidOptions.push(token); | ||
continue; | ||
} | ||
//如果存在,则检查后边紧临的 token 是否符合「正则」这义的规则 | ||
var nextToken = this._tokens[index]; | ||
if ((!OPTION_REGEXP.test(nextToken) || setting.greed) && | ||
(!setting.regexp || setting.regexp.test(nextToken))) { | ||
var value = utils.isNull(nextToken) ? | ||
setting.default : nextToken.toString(); | ||
this.options[token] = setting.convert ? setting.convert(value) : value; | ||
} else { | ||
//如果后边紧临的 token 不符合「正则」这义的规则,则回退 index | ||
//并将「默认」值赋值给当前选项 | ||
index--; | ||
this.options[token] = setting.default; | ||
} | ||
} else if (token.type != TOKEN_TYPE_OPTION_VALUE) { | ||
//如果不是 option,也不是「=」号后的「只能作为选项值」的 token | ||
//则放到 argv 数组中 | ||
this.argv.push(token); | ||
} | ||
index++; | ||
} | ||
//得到参数个数 argc | ||
this.argc = this.argv.length; | ||
//检果是否有无效的 option 并返回 | ||
return invalidOptions.length > 0 ? | ||
new Error('Invalid option: ' + invalidOptions.join(',')) : null; | ||
}, | ||
@@ -405,2 +424,10 @@ | ||
/** | ||
* 在没有找到 handlers 时执行 | ||
**/ | ||
noHandle: function () { | ||
if (this._help) return this._console.log(this._help); | ||
this._emitError(new Error('No processing')); | ||
}, | ||
/** | ||
* 启动处理 | ||
@@ -420,9 +447,6 @@ **/ | ||
//检查预处理并执行下一步 | ||
if (firstError) { | ||
return this._emitError(firstError); | ||
} | ||
if (firstError) return this._emitError(firstError); | ||
//查找 handles 并执行 | ||
var handlers = this._findHandlers(); | ||
if (handlers.length < 1) { | ||
return this._emitError(new Error('No processing')); | ||
} | ||
if (handlers.length < 1) return this.noHandle(); | ||
utils.each(handlers, function (i, handler) { | ||
@@ -429,0 +453,0 @@ return this._callHandler(handler) === false || null; |
module.exports = { | ||
string: { | ||
"string": { | ||
regexp: /[\S\s]*/i, | ||
default: '', | ||
}, | ||
number: { | ||
"string*": { | ||
regexp: /[\S\s]*/i, | ||
default: '', | ||
greed: true | ||
}, | ||
"number": { | ||
regexp: /^[0-9]*$/i, | ||
@@ -11,10 +16,10 @@ default: 0, | ||
}, | ||
boolean: { | ||
"boolean": { | ||
regexp: /^(1|0|true|false|yes|no){1}$/i, | ||
default: true, | ||
convert: function (str) { | ||
return ["1", "true", "yes"].indexOf(str) > -1; | ||
return ['1', 'true', 'yes'].indexOf(str) > -1; | ||
} | ||
}, | ||
switch: { | ||
"switch": { | ||
regexp: /^$/i, | ||
@@ -21,0 +26,0 @@ default: true |
{ | ||
"name": "cmdline", | ||
"rawName": "cmdline", | ||
"version": "1.0.9", | ||
"version": "1.1.0", | ||
"description": "cmdline is a process.argv parser", | ||
@@ -6,0 +6,0 @@ "main": "./lib/index.js", |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
15430
486
1