-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
stripped down code and a passing test from optimist
- Loading branch information
James Halliday
committed
Jun 25, 2013
0 parents
commit 7cced88
Showing
2 changed files
with
186 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
module.exports = function (args, opts) { | ||
if (!opts) opts = {}; | ||
|
||
var flags = { bools : {}, strings : {} }; | ||
|
||
[].concat(opts['boolean']).filter(Boolean).forEach(function (key) { | ||
flags.bools[key] = true; | ||
}); | ||
|
||
[].concat(opts.string).filter(Boolean).forEach(function (key) { | ||
flags.strings[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] || false); | ||
}); | ||
|
||
function setArg (key, val) { | ||
var value = !flags.strings[key] && isNumber(val) | ||
? Number(val) : val | ||
; | ||
setKey(argv, key.split('.'), value); | ||
|
||
(aliases[key] || []).forEach(function (x) { | ||
argv[x] = argv[key]; | ||
}); | ||
} | ||
|
||
for (var i = 0; i < args.length; i++) { | ||
var arg = args[i]; | ||
|
||
if (arg === '--') { | ||
argv._.push.apply(argv._, args.slice(i + 1)); | ||
break; | ||
} | ||
else 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 (next === '-') { | ||
setArg(letters[j], next) | ||
continue; | ||
} | ||
|
||
if (/[A-Za-z]/.test(letters[j]) | ||
&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { | ||
setArg(letters[j], next); | ||
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 (!(key in argv)) { | ||
argv[key] = defaults[key]; | ||
if (key in aliases) { | ||
argv[aliases[key]] = defaults[key]; | ||
} | ||
} | ||
}); | ||
|
||
return argv; | ||
}; | ||
|
||
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 (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,17 @@ | ||
var parse = require('../'); | ||
var test = require('tape'); | ||
|
||
test('-', function (t) { | ||
t.plan(5); | ||
t.deepEqual(parse([ '-n', '-' ]), { n: '-', _: [] }); | ||
t.deepEqual(parse([ '-' ]), { _: [ '-' ] }); | ||
t.deepEqual(parse([ '-f-' ]), { f: '-', _: [] }); | ||
t.deepEqual( | ||
parse([ '-b', '-' ], { boolean: 'b' }), | ||
{ b: true, _: [ '-' ] } | ||
); | ||
t.deepEqual( | ||
parse([ '-s', '-' ], { string: 's' }), | ||
{ s: '-', _: [] } | ||
); | ||
}); |