Comparing version 2020.8.6 to 2020.8.7
@@ -7,2 +7,9 @@ ### change type: f / x / m / p | ||
### 2020.8.7 | ||
* **f** Optional alias to options and arguments | ||
* **f** Save first tagged argument in arg property | ||
* **f** Save all key value arguments in args property | ||
* **f** Save all untagged arguments in plain property | ||
### 2020.8.6 | ||
@@ -9,0 +16,0 @@ |
105
index.js
@@ -1,2 +0,1 @@ | ||
// a argument, o option, kv key-value | ||
const parse_arg = (arg) => { | ||
@@ -10,21 +9,18 @@ if (arg.includes('__proto__')) | ||
const flag = arg.slice(2) | ||
const option = arg.slice(2) | ||
if (flag.includes('=')) { | ||
// key-value | ||
const [option, value] = flag.split('=') | ||
if (option === '' || value === '') | ||
throw Error(`Option key or value has length of 0 (${arg}). Expected at least one, eg: --pet=cat`) | ||
if (option.includes('=')) { | ||
const [key, value] = option.split('=') | ||
if (key === '' || value === '') | ||
throw Error(`key-value has empty key or value (${arg}). Expected at least one, eg: --pet=cat`) | ||
else { | ||
return ['kv', [option, value]] | ||
return ['kv', [key, value]] | ||
} | ||
} | ||
else return ['o', [flag]] //single option | ||
else return ['o', [option]] | ||
} | ||
else if (arg.startsWith('-') && arg.length > 1) { | ||
// options | ||
const options = arg.slice(1).split('') | ||
return ['o', options] | ||
} else { | ||
// argument | ||
return ['a', arg] | ||
@@ -34,10 +30,5 @@ } | ||
const add_args = (obj, key, val) => { | ||
if (!obj.args[key]) | ||
obj.args[key] = [val] | ||
else obj.args[key].push(val) | ||
} | ||
const combine_options = (opts) => | ||
opts.reduce((acc, next) => { | ||
const [kind, parsed] = acc.skip ? ['a', next] : parse_arg(next) | ||
@@ -47,51 +38,27 @@ | ||
const options = parsed.map(o => ({ [o]: true })).reduce((acc, next) => ({ ...acc, ...next }), {}) | ||
acc.opt = { ...acc.opt, ...options } | ||
return { | ||
opts: { ...acc.opts, ...options }, | ||
tag: parsed.length == 1 && parsed.find(_ => true) || acc.tag, | ||
opt: acc.opt, | ||
opt: { ...acc.opt, ...options }, | ||
args: acc.args, | ||
plain: acc.plain | ||
} | ||
} | ||
} else if (kind === 'a') { | ||
if (kind === 'a') { | ||
if (parsed === '--' && !acc.skip) { | ||
acc.skip = true | ||
} else { | ||
acc.opts.$$.push(parsed) | ||
if (acc.tag) { | ||
const prop = '$' + acc.tag | ||
if (!acc.opts[prop]) | ||
acc.opts[prop] = [parsed] | ||
else acc.opts[prop].push(parsed) | ||
} | ||
if (acc.tag) { | ||
add_args(acc, acc.tag, parsed) | ||
} else acc.plain.push(parsed) | ||
} else if (acc.tag) { | ||
acc.args[acc.tag] = [...acc.args[acc.tag] || [], parsed] | ||
} | ||
else acc.plain.push(parsed) | ||
return acc | ||
} | ||
} else if (kind === 'kv') { | ||
if (kind === 'kv') { | ||
const [k, v] = parsed | ||
const obj = {} | ||
obj[`$${k}`] = v | ||
add_args(acc, k, v) | ||
return { | ||
opts: { ...acc.opts, ...obj }, | ||
tag: acc.tag, | ||
opt: acc.opt, | ||
args: acc.args, | ||
plain: acc.plain | ||
} | ||
} else throw Error('kind mismatch') | ||
acc.args[k] = [...acc.args[k] || [], v] | ||
return acc | ||
} | ||
else throw Error(`Unhandled combine option ${kind}`) | ||
}, { | ||
opts: { $$: [] }, | ||
tag: undefined, | ||
@@ -104,8 +71,32 @@ skip: false, | ||
module.exports = (args = []) => { | ||
const wip = combine_options(args) | ||
const first_arg = (args) => Object.keys(args).reduce((acc, key) => { | ||
const [val] = args[key] | ||
const o = { [key]: val } | ||
return { ...o, ...acc } | ||
}, {}) | ||
// add arg proxy to .clia.args | ||
const copy_alias_values = (result, names) => { | ||
names.forEach(name => { | ||
const [letter] = name | ||
const arg_val = result.args[name] || result.args[letter] | ||
const opt_val = result.opt[name] || result.opt[letter] | ||
if (arg_val) | ||
result.args[name] = arg_val | ||
if (opt_val) | ||
result.opt[name] = opt_val | ||
}); | ||
} | ||
return wip.opts | ||
module.exports = (args = [], alias = []) => { | ||
const parsed = combine_options(args) | ||
copy_alias_values(parsed, alias) | ||
return { | ||
arg: first_arg(parsed.args), | ||
args: parsed.args, | ||
opt: parsed.opt, | ||
plain: parsed.plain | ||
} | ||
} |
{ | ||
"name": "clia", | ||
"version": "2020.8.6", | ||
"version": "2020.8.7", | ||
"description": "Command line parser and t3st example project", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -17,3 +17,3 @@ # clia | ||
```bash | ||
node your-node-app -a -ab -cd hello | ||
node your-node-app hello -a -ab -d world | ||
``` | ||
@@ -23,8 +23,7 @@ | ||
```js | ||
opts === { | ||
a: true, | ||
b: true, | ||
c: true, | ||
d: true | ||
$$: ['hello'] | ||
{ | ||
arg: { d: 'world' }, | ||
args: { d: [ 'world' ] }, | ||
opt: { a: true, b: true, d: true }, | ||
plain: [ 'hello' ] | ||
} | ||
@@ -67,7 +66,12 @@ ``` | ||
* When a key-value option is stated more than once, the last value is used assigned | ||
* If a `--` is encountered, it is ignored. All subsequent inputs are treated as arguments. | ||
* If a `--` is encountered, it is ignored. All subsequent inputs are treated as arguments. | ||
## errors are thrown for: | ||
## output | ||
* When a key-value option is stated more than once, all values are saved under `args`. | ||
* The `arg` object returns the first `args` if there are any | ||
## edge cases | ||
* `__proto__` to prevent prototype pollution | ||
@@ -74,0 +78,0 @@ * key-value pair with missing value, eg: `--store=` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7533
111
84