Comparing version 1.1.1 to 1.1.2
178
lib/index.js
@@ -1,69 +0,35 @@ | ||
'use strict'; | ||
const EQQ = /\s|=/; | ||
const FLAG = /^-{1,2}/; | ||
const PREFIX = /^--no-/i; | ||
function isBool(any) { | ||
return typeof any === 'boolean'; | ||
} | ||
function toArr(any) { | ||
return Array.isArray(any) ? any : any == null ? [] : [any]; | ||
return any == null ? [] : Array.isArray(any) ? any : [any]; | ||
} | ||
function toString(any) { | ||
return any == null || any === true ? '' : String(any); | ||
function toVal(out, key, val, opts) { | ||
var x, old=out[key], nxt=( | ||
!!~opts.string.indexOf(key) ? (val == null || val === true ? '' : String(val)) | ||
: !!~opts.boolean.indexOf(key) ? (val === 'false' ? false : val === 'true' || (out._.push((x = +val,x * 0 === 0) ? x : val),!!val)) | ||
: typeof val === 'boolean' ? val | ||
: (x = +val,x * 0 === 0) ? x : val | ||
); | ||
out[key] = old == null ? nxt : (Array.isArray(old) ? old.concat(nxt) : [old, nxt]); | ||
} | ||
function toBool(any) { | ||
return any === 'false' ? false : Boolean(any); | ||
} | ||
module.exports = function (args, opts) { | ||
args = args || []; | ||
opts = opts || {}; | ||
function toNum(any) { | ||
let x = Number(any); | ||
return !isBool(any) && (x * 0 === 0) ? x : any; | ||
} | ||
var k, arr, arg, name, val, out={ _:[] }; | ||
var i=0, j=0, idx=0, len=args.length; | ||
function getAlibi(names, arr) { | ||
if (arr.length === 0) return arr; | ||
let k, i = 0, len = arr.length, vals = []; | ||
for (; i < len; i++) { | ||
k = arr[i]; | ||
vals.push(k); | ||
if (names[k] !== void 0) { | ||
vals = vals.concat(names[k]); | ||
} | ||
} | ||
return vals; | ||
} | ||
const alibi = opts.alias !== void 0; | ||
const strict = opts.unknown !== void 0; | ||
const defaults = opts.default !== void 0; | ||
function typecast(key, val, strings, booleans) { | ||
if (strings.indexOf(key) !== -1) return toString(val); | ||
if (booleans.indexOf(key) !== -1) return toBool(val); | ||
return toNum(val); | ||
} | ||
module.exports = function(args, opts) { | ||
args = args || []; | ||
opts = opts || {}; | ||
opts.alias = opts.alias || {}; | ||
opts.string = toArr(opts.string); | ||
opts.boolean = toArr(opts.boolean); | ||
const aliases = {}; | ||
let k, i, j, x, y, len, type; | ||
if (opts.alias !== void 0) { | ||
if (alibi) { | ||
for (k in opts.alias) { | ||
aliases[k] = toArr(opts.alias[k]); | ||
len = aliases[k].length; // save length | ||
for (i = 0; i < len; i++) { | ||
x = aliases[k][i]; // alias's key name | ||
aliases[x] = [k]; // set initial array | ||
for (j = 0; j < len; j++) { | ||
if (x !== aliases[k][j]) { | ||
aliases[x].push(aliases[k][j]); | ||
} | ||
} | ||
arr = opts.alias[k] = toArr(opts.alias[k]); | ||
for (i=0; i < arr.length; i++) { | ||
(opts.alias[arr[i]] = arr.concat(k)).splice(i, 1); | ||
} | ||
@@ -73,67 +39,57 @@ } | ||
if (opts.default !== void 0) { | ||
opts.boolean.forEach(key => { | ||
opts.boolean = opts.boolean.concat(opts.alias[key] = opts.alias[key] || []); | ||
}); | ||
opts.string.forEach(key => { | ||
opts.string = opts.string.concat(opts.alias[key] = opts.alias[key] || []); | ||
}); | ||
if (defaults) { | ||
for (k in opts.default) { | ||
type = typeof opts.default[k]; | ||
opts[type] = (opts[type] || []).concat(k); | ||
opts.alias[k] = opts.alias[k] || []; | ||
opts[typeof opts.default[k]].push(k); | ||
} | ||
} | ||
// apply to all aliases | ||
opts.string = getAlibi(aliases, opts.string); | ||
opts.boolean = getAlibi(aliases, opts.boolean); | ||
const keys = strict ? Object.keys(opts.alias) : []; | ||
let idx = 0; | ||
const out = { _: [] }; | ||
for (i=0; i < len; i++) { | ||
arg = args[i]; | ||
while (args[idx] !== void 0) { | ||
let incr = 1; | ||
const val = args[idx]; | ||
if (val === '--') { | ||
out._ = out._.concat(args.slice(idx + 1)); | ||
if (arg === '--') { | ||
out._ = out._.concat(args.slice(++i)); | ||
break; | ||
} else if (!FLAG.test(val)) { | ||
out._.push(val); | ||
} else if (PREFIX.test(val)) { | ||
out[val.replace(PREFIX, '')] = false; | ||
} else { | ||
let tmp; | ||
const segs = val.split(EQQ); | ||
const isGroup = segs[0].charCodeAt(1) !== 45; // '-' | ||
} | ||
const flag = segs[0].substr(isGroup ? 1 : 2); | ||
len = flag.length; | ||
const key = isGroup ? flag[len - 1] : flag; | ||
for (j=0; j < arg.length; j++) { | ||
if (arg.charCodeAt(j) !== 45) break; // "-" | ||
} | ||
if (opts.unknown !== void 0 && aliases[key] === void 0) { | ||
return opts.unknown(segs[0]); | ||
if (j === 0) { | ||
out._.push(arg); | ||
} else if (arg.substring(j, j + 3) === 'no-') { | ||
name = arg.substring(j + 3); | ||
if (strict && !~keys.indexOf(name)) { | ||
return opts.unknown(arg); | ||
} | ||
if (segs.length > 1) { | ||
tmp = segs[1]; | ||
} else { | ||
tmp = args[idx + 1] || true; | ||
FLAG.test(tmp) ? (tmp = true) : (incr = 2); | ||
out[name] = false; | ||
} else { | ||
for (idx=j+1; idx < arg.length; idx++) { | ||
if (arg.charCodeAt(idx) === 61) break; // "=" | ||
} | ||
if (isGroup && len > 1) { | ||
for (i = len - 1; i--; ) { | ||
k = flag[i]; // all but last key | ||
out[k] = typecast(k, true, opts.string, opts.boolean); | ||
} | ||
} | ||
name = arg.substring(j, idx); | ||
val = arg.substring(++idx) || (i+1 === len || (''+args[i+1]).charCodeAt(0) === 45 || args[++i]); | ||
arr = (j === 2 ? [name] : name); | ||
const value = typecast(key, tmp, opts.string, opts.boolean); | ||
out[key] = out[key] !== void 0 ? toArr(out[key]).concat(value) : value; | ||
// handle discarded args when dealing with booleans | ||
if (isBool(value) && !isBool(tmp) && tmp !== 'true' && tmp !== 'false') { | ||
out._.push(tmp); | ||
for (idx=0; idx < arr.length; idx++) { | ||
name = arr[idx]; | ||
if (strict && !~keys.indexOf(name)) return opts.unknown('-'.repeat(j) + name); | ||
toVal(out, name, (idx + 1 < arr.length) || val, opts); | ||
} | ||
} | ||
idx += incr; | ||
} | ||
if (opts.default !== void 0) { | ||
if (defaults) { | ||
for (k in opts.default) { | ||
@@ -146,8 +102,8 @@ if (out[k] === void 0) { | ||
for (k in out) { | ||
if (aliases[k] === void 0) continue; | ||
y = out[k]; | ||
len = aliases[k].length; | ||
for (i = 0; i < len; i++) { | ||
out[aliases[k][i]] = y; // assign value | ||
if (alibi) { | ||
for (k in out) { | ||
arr = opts.alias[k] || []; | ||
while (arr.length > 0) { | ||
out[arr.shift()] = out[k]; | ||
} | ||
} | ||
@@ -157,2 +113,2 @@ } | ||
return out; | ||
}; | ||
} |
{ | ||
"name": "mri", | ||
"version": "1.1.1", | ||
"version": "1.1.2", | ||
"description": "Quickly scan for CLI flags and arguments", | ||
"license": "MIT", | ||
"repository": "lukeed/mri", | ||
"main": "lib/index.js", | ||
"license": "MIT", | ||
"files": [ | ||
@@ -9,0 +9,0 @@ "lib" |
@@ -11,11 +11,9 @@ # mri [![Build Status](https://travis-ci.org/lukeed/mri.svg?branch=master)](https://travis-ci.org/lukeed/mri) | ||
## Usage | ||
## Install | ||
Firstly, install the package: | ||
```sh | ||
$ npm install --save mri | ||
``` | ||
npm install --save mri | ||
``` | ||
Then start using it: | ||
## Usage | ||
@@ -29,11 +27,11 @@ ```sh | ||
const args = process.argv.slice(2); | ||
const argv = process.argv.slice(2); | ||
mri(args); | ||
mri(argv); | ||
//=> { _: ['hello', 'world'], foo:true, bar:'baz', m:true, t:true, v:true } | ||
mri(args, { boolean:['bar'] }); | ||
mri(argv, { boolean:['bar'] }); | ||
//=> { _: ['baz', 'hello', 'world'], foo:true, bar:true, m:true, t:true, v:true } | ||
mri(args, { | ||
mri(argv, { | ||
alias: { | ||
@@ -50,6 +48,6 @@ b: 'bar', | ||
### mri(args, options) | ||
Return: `Object` | ||
#### args | ||
Type: `array`<br> | ||
Type: `Array`<br> | ||
Default: `[]` | ||
@@ -60,11 +58,9 @@ | ||
#### options.alias | ||
Type: `object`<br> | ||
Type: `Object`<br> | ||
Default: `{}` | ||
An object of keys whose values are a `string` or `array` of aliases. These will be added to the parsed output with matching values. | ||
An object of keys whose values are `String`s or `Array<String>` of aliases. These will be added to the parsed output with matching values. | ||
#### options.boolean | ||
Type: `array|string`<br> | ||
Type: `Array|String`<br> | ||
Default: `[]` | ||
@@ -75,4 +71,3 @@ | ||
#### options.default | ||
Type: `object`<br> | ||
Type: `Object`<br> | ||
Default: `{}` | ||
@@ -87,3 +82,3 @@ | ||
mri(['--foo', 'bar'], { | ||
default:{ foo:true, baz:'hello', bat:42 } | ||
default: { foo:true, baz:'hello', bat:42 } | ||
}); | ||
@@ -93,7 +88,6 @@ //=> { _:['bar'], foo:true, baz:'hello', bat:42 } | ||
> **Note:** Because `--foo` has a default of `true`, its output is cast to a boolean. This means that `foo:true`, which makes `'bar'` an extra argument (`_` key). | ||
> **Note:** Because `--foo` has a default of `true`, its output is cast to a Boolean. This means that `foo=true`, making `'bar'` an extra argument (`_` key). | ||
#### options.string | ||
Type: `array|string`<br> | ||
Type: `Array|String`<br> | ||
Default: `[]` | ||
@@ -104,4 +98,3 @@ | ||
#### options.unknown | ||
Type: `function`<br> | ||
Type: `Function`<br> | ||
Default: `undefined` | ||
@@ -120,3 +113,3 @@ | ||
- `mri` is 2.5x faster (see [benchmarks](#benchmarks)) | ||
- `mri` is 5x faster (see [benchmarks](#benchmarks)) | ||
- Numerical values are cast as `Number`s when possible | ||
@@ -143,3 +136,3 @@ - A key (and its aliases) will always honor `opts.boolean` or `opts.string` | ||
- `mri` is 20x faster (see [benchmarks](#benchmarks)) | ||
- `mri` is 40x faster (see [benchmarks](#benchmarks)) | ||
- Numerical values are cast as `Number`s when possible | ||
@@ -160,13 +153,14 @@ - A key (and its aliases) will always honor `opts.boolean` or `opts.string` | ||
- No [additional configuration](https://github.com/yargs/yargs-parser#configuration) object | ||
- Added [`options.unknown`](##optionsunknown) feature | ||
- Added [`options.unknown`](#optionsunknown) feature | ||
## Benchmarks | ||
``` | ||
mri | ||
--> 329,310 ops/sec ±0.27% (88 runs sampled) | ||
yargs | ||
--> 16,100 ops/sec ±0.57% (91 runs sampled) | ||
minimist | ||
--> 129,670 ops/sec ±0.72% (93 runs sampled) | ||
# Node v10.13.0 | ||
minimist x 324,469 ops/sec ±1.20% (96 runs sampled) | ||
mri x 1,611,167 ops/sec ±0.22% (96 runs sampled) | ||
nopt x 920,029 ops/sec ±1.13% (97 runs sampled) | ||
yargs-parser x 39,542 ops/sec ±1.14% (95 runs sampled) | ||
``` | ||
@@ -173,0 +167,0 @@ |
9380
92
160