Last active
May 30, 2020 20:15
-
-
Save oncomouse/23d85d46fa713c8d251472ca59d165d4 to your computer and use it in GitHub Desktop.
Tiny ARGV Parser in Node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Usage: | |
const arguments = argv() | |
.value({key: 'foo', defaultValue: 'bar', alias: 'f'}) | |
.flag({key: 'flag'}) | |
console.log(arguments.foo, arguments.flag) | |
> node script.js --flag -f TinyArgv | |
TinyArgv true | |
> node script.js -f "Tiny Argv" | |
Tiny Argv false | |
> node script.js --foo="Tiny Argv" | |
Tiny Argv false | |
Other arguments are collected on _: | |
const arguments = argv() | |
.flag({key: 'flag'}) | |
console.log(arguments.flag, arguments._) | |
> node script.js --flag file1 file2 | |
true [ 'file1', 'file2' ] | |
*/ | |
class TinyArgv { | |
constructor(argv) { | |
this.__argv = argv | |
this.__cleared = [] | |
this._ = [] | |
} | |
/** | |
* Rebuild remainder based on indices that have been read. | |
*/ | |
__rebuildUnderscore() { | |
if (this.__cleared.length === 0) return | |
this._ = this.__argv.filter((_arg, i) => this.__cleared.indexOf(i) < 0) | |
} | |
/** | |
* Mark an index as processed. | |
*/ | |
__clear(index) { | |
if (index >= 0 && index < this.__argv.length) { | |
this.__cleared.push(index) | |
this.__rebuildUnderscore() | |
} | |
} | |
/** | |
* Figure out the location of an argument in ARGV based on a key and an alias. | |
* Returns -1 if neither is found. | |
*/ | |
__argIndex(key, alias) { | |
const keyTest = new RegExp(`^--${key}`) | |
const aliasTest = alias ? new RegExp(`^-${alias}`) : undefined | |
return this.__argv.reduce((acc, cur, index) => { | |
if (acc >= 0) return acc | |
if (keyTest.test(cur)) return index | |
if (alias && aliasTest.test(cur)) return index | |
}, -1) | |
} | |
/** | |
* Extracts the value of a switch, which may be more than one word. | |
*/ | |
__extractValue(index) { | |
if (this.__argv[index].indexOf('=') >= 0) { | |
const [, value] = this.__argv[index].split('=') | |
return value; | |
} | |
this.__clear(index + 1) | |
return this.__argv[index + 1] | |
} | |
/** | |
* Extract a flag (boolean) argument. | |
* Can have a single-character alias and a default value (so can be true instead | |
* of false). | |
*/ | |
flag({key, defaultValue = false, alias = false}) { | |
const indexOf = this.__argIndex(key, alias) | |
this.__clear(indexOf) | |
this[key] = indexOf >= 0 ? !defaultValue : defaultValue | |
return this; | |
} | |
/* | |
* Extract a string-based argument. | |
* Can have a single-character alias or a default value. | |
*/ | |
value({key, defaultValue = null, alias = false}) { | |
const indexOf = this.__argIndex(key, alias) | |
this.__clear(indexOf) | |
this[key] = indexOf >= 0 ? this.__extractValue(indexOf) : defaultValue | |
return this; | |
} | |
} | |
/** | |
* Convenient chain-initiating function. Call this to start the processing. | |
* Optional argument: can process a different array than process.argv | |
*/ | |
const argv = function (argv) { | |
return new TinyArgv(argv ? argv : process.argv.slice(2)) | |
} | |
module.exports = argv |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment