-
Notifications
You must be signed in to change notification settings - Fork 995
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added ability to count boolean options and rolled minimist library ba…
…ck into project. I know that substack was interested in splitting off the main option parsing algorithm into the minimist module but I personally think that is getting to pedantic. I'm also going to roll shellQuote into yargs at some point so that yargs will understand string input as well as array input.
- Loading branch information
Alex Ford
committed
Nov 22, 2013
1 parent
49f0dce
commit 623dc26
Showing
5 changed files
with
300 additions
and
2 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#!/usr/bin/env node | ||
var argv = require('optimist') | ||
.count('verbose') | ||
.alias('v', 'verbose') | ||
.argv; | ||
|
||
VERBOSE_LEVEL = argv.verbose; | ||
|
||
function WARN() { VERBOSE_LEVEL >= 0 && console.log.apply(console, arguments); } | ||
function INFO() { VERBOSE_LEVEL >= 1 && console.log.apply(console, arguments); } | ||
function DEBUG() { VERBOSE_LEVEL >= 2 && console.log.apply(console, arguments); } | ||
|
||
WARN("Showing only important stuff"); | ||
INFO("Showing semi-important stuff too"); | ||
DEBUG("Extra chatty mode"); |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
module.exports = function (args, opts) { | ||
if (!opts) opts = {}; | ||
|
||
var flags = { bools : {}, strings : {}, counts: {} }; | ||
|
||
[].concat(opts['boolean']).filter(Boolean).forEach(function (key) { | ||
flags.bools[key] = true; | ||
}); | ||
|
||
[].concat(opts.string).filter(Boolean).forEach(function (key) { | ||
flags.strings[key] = true; | ||
}); | ||
|
||
[].concat(opts.count).filter(Boolean).forEach(function (key) { | ||
flags.counts[key] = true; | ||
}); | ||
|
||
var aliases = {}; | ||
Object.keys(opts.alias || {}).forEach(function (key) { | ||
aliases[key] = [].concat(opts.alias[key]); | ||
aliases[key].forEach(function (x) { | ||
aliases[x] = [key].concat(aliases[key].filter(function (y) { | ||
return x !== y; | ||
})); | ||
}); | ||
}); | ||
|
||
var defaults = opts['default'] || {}; | ||
|
||
var argv = { _ : [] }; | ||
Object.keys(flags.bools).forEach(function (key) { | ||
setArg(key, defaults[key] === undefined ? false : defaults[key]); | ||
}); | ||
|
||
var notFlags = []; | ||
|
||
if (args.indexOf('--') !== -1) { | ||
notFlags = args.slice(args.indexOf('--')+1); | ||
args = args.slice(0, args.indexOf('--')); | ||
} | ||
|
||
function setArg (key, val) { | ||
var value = !flags.strings[key] && isNumber(val) ? Number(val) : val; | ||
|
||
if (flags.counts[key] || flags.counts[aliases[key]]) { | ||
value = function(orig) { return orig !== undefined ? orig + 1 : 0; }; | ||
} | ||
|
||
setKey(argv, key.split('.'), value); | ||
|
||
(aliases[key] || []).forEach(function (x) { | ||
setKey(argv, x.split('.'), value); | ||
}); | ||
} | ||
|
||
for (var i = 0; i < args.length; i++) { | ||
var arg = args[i]; | ||
|
||
if (arg.match(/^--.+=/)) { | ||
// Using [\s\S] instead of . because js doesn't support the | ||
// 'dotall' regex modifier. See: | ||
// http://stackoverflow.com/a/1068308/13216 | ||
var m = arg.match(/^--([^=]+)=([\s\S]*)$/); | ||
setArg(m[1], m[2]); | ||
} | ||
else if (arg.match(/^--no-.+/)) { | ||
var key = arg.match(/^--no-(.+)/)[1]; | ||
setArg(key, false); | ||
} | ||
else if (arg.match(/^--.+/)) { | ||
var key = arg.match(/^--(.+)/)[1]; | ||
var next = args[i + 1]; | ||
if (next !== undefined && !next.match(/^-/) | ||
&& !flags.bools[key] | ||
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) { | ||
setArg(key, next); | ||
i++; | ||
} | ||
else if (/^(true|false)$/.test(next)) { | ||
setArg(key, next === 'true'); | ||
i++; | ||
} | ||
else { | ||
setArg(key, true); | ||
} | ||
} | ||
else if (arg.match(/^-[^-]+/)) { | ||
var letters = arg.slice(1,-1).split(''); | ||
|
||
var broken = false; | ||
for (var j = 0; j < letters.length; j++) { | ||
var next = arg.slice(j+2); | ||
|
||
if (letters[j+1] && letters[j+1] === '=') { | ||
setArg(letters[j], arg.slice(j+3)); | ||
broken = true; | ||
break; | ||
} | ||
|
||
if (next === '-') { | ||
setArg(letters[j], next) | ||
continue; | ||
} | ||
|
||
if (/[A-Za-z]/.test(letters[j]) | ||
&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { | ||
setArg(letters[j], next); | ||
broken = true; | ||
break; | ||
} | ||
|
||
if (letters[j+1] && letters[j+1].match(/\W/)) { | ||
setArg(letters[j], arg.slice(j+2)); | ||
broken = true; | ||
break; | ||
} | ||
else { | ||
setArg(letters[j], true); | ||
} | ||
} | ||
|
||
var key = arg.slice(-1)[0]; | ||
if (!broken && key !== '-') { | ||
if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1]) | ||
&& !flags.bools[key] | ||
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) { | ||
setArg(key, args[i+1]); | ||
i++; | ||
} | ||
else if (args[i+1] && /true|false/.test(args[i+1])) { | ||
setArg(key, args[i+1] === 'true'); | ||
i++; | ||
} | ||
else { | ||
setArg(key, true); | ||
} | ||
} | ||
} | ||
else { | ||
argv._.push( | ||
flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) | ||
); | ||
} | ||
} | ||
|
||
Object.keys(defaults).forEach(function (key) { | ||
if (!hasKey(argv, key.split('.'))) { | ||
setKey(argv, key.split('.'), defaults[key]); | ||
|
||
(aliases[key] || []).forEach(function (x) { | ||
setKey(argv, x.split('.'), defaults[key]); | ||
}); | ||
} | ||
}); | ||
|
||
Object.keys(flags.counts).forEach(function (key) { | ||
setArg(key, defaults[key]); | ||
}); | ||
|
||
notFlags.forEach(function(key) { | ||
argv._.push(key); | ||
}); | ||
|
||
return argv; | ||
}; | ||
|
||
function hasKey (obj, keys) { | ||
var o = obj; | ||
keys.slice(0,-1).forEach(function (key) { | ||
o = (o[key] || {}); | ||
}); | ||
|
||
var key = keys[keys.length - 1]; | ||
return key in o; | ||
} | ||
|
||
function setKey (obj, keys, value) { | ||
var o = obj; | ||
keys.slice(0,-1).forEach(function (key) { | ||
if (o[key] === undefined) o[key] = {}; | ||
o = o[key]; | ||
}); | ||
|
||
|
||
var key = keys[keys.length - 1]; | ||
if (typeof value === 'function') { | ||
o[key] = value(o[key]); | ||
} | ||
else if (o[key] === undefined || typeof o[key] === 'boolean') { | ||
o[key] = value; | ||
} | ||
else if (Array.isArray(o[key])) { | ||
o[key].push(value); | ||
} | ||
else { | ||
o[key] = [ o[key], value ]; | ||
} | ||
} | ||
|
||
function isNumber (x) { | ||
if (typeof x === 'number') return true; | ||
if (/^0x[0-9a-f]+$/i.test(x)) return true; | ||
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); | ||
} | ||
|
||
function longest (xs) { | ||
return Math.max.apply(null, xs.map(function (x) { return x.length })); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
var optimist = require('../index'); | ||
var path = require('path'); | ||
var test = require('tap').test; | ||
|
||
var $0 = 'node ./' + path.relative(process.cwd(), __filename); | ||
|
||
test('count', function(t) { | ||
var parsed; | ||
|
||
parsed = optimist(['-x']).count('verbose').argv; | ||
console.error(parsed); | ||
t.same(parsed.verbose, 0); | ||
|
||
parsed = optimist(['--verbose']).count('verbose').argv; | ||
t.same(parsed.verbose, 1); | ||
|
||
parsed = optimist(['--verbose', '--verbose']).count('verbose').argv; | ||
t.same(parsed.verbose, 2); | ||
|
||
// w/alias | ||
parsed = optimist(['--verbose', '--verbose', '-v', '--verbose']).count('verbose').alias('v', 'verbose').argv; | ||
t.same(parsed.verbose, 4); | ||
|
||
t.end(); | ||
}); |