Skip to content

Instantly share code, notes, and snippets.

@oncomouse
Last active May 30, 2020 20:15
Show Gist options
  • Save oncomouse/23d85d46fa713c8d251472ca59d165d4 to your computer and use it in GitHub Desktop.
Save oncomouse/23d85d46fa713c8d251472ca59d165d4 to your computer and use it in GitHub Desktop.
Tiny ARGV Parser in Node
/**
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