optimist
Advanced tools
Comparing version 0.1.9 to 0.2.0
366
index.js
@@ -1,12 +0,5 @@ | ||
module.exports = Argv; | ||
var path = require('path'); | ||
// Hack to work when loaded with CoffeeScript | ||
if (process.argv.length < 2 | ||
|| !process.argv[0].match(/(?:^|\/)node(?:[^A-Za-z]|$)/)) { | ||
process.argv = ['coffee', ''].concat(process.argv); | ||
} | ||
/* Hack an instance of Argv with process.argv into Argv | ||
so people an do | ||
so people can do | ||
require('optimist')(['--beeble=1','-z','zizzle']).argv | ||
@@ -17,2 +10,3 @@ to parse a list of args and | ||
*/ | ||
var inst = Argv(process.argv.slice(2)); | ||
@@ -25,2 +19,3 @@ Object.keys(inst).forEach(function (key) { | ||
var exports = module.exports = Argv; | ||
function Argv (args, cwd) { | ||
@@ -46,18 +41,2 @@ var self = {}; | ||
function set (key, val) { | ||
var num = Number(val); | ||
var value = typeof val !== 'string' || isNaN(num) ? val : num; | ||
if (flags.strings[key]) value = val; | ||
if (key in self.argv) { | ||
if (!Array.isArray(self.argv[key])) { | ||
self.argv[key] = [ self.argv[key] ]; | ||
} | ||
self.argv[key].push(value); | ||
} | ||
else { | ||
self.argv[key] = value; | ||
} | ||
} | ||
var flags = { bools : {}, strings : {} }; | ||
@@ -74,10 +53,2 @@ | ||
rescan(); | ||
bools.forEach(function (name) { | ||
if (!self.argv[name]) { | ||
self.argv[name] = false; | ||
} | ||
}); | ||
return self; | ||
@@ -95,3 +66,22 @@ }; | ||
rescan(); | ||
return self; | ||
}; | ||
var aliases = {}; | ||
self.alias = function (x, y) { | ||
if (typeof x === 'object') { | ||
Object.keys(x).forEach(function (key) { | ||
aliases[key] = x[key]; | ||
aliases[x[key]] = key; | ||
}); | ||
} | ||
else if (Array.isArray(y)) { | ||
y.forEach(function (yy) { | ||
self.alias(x, y); | ||
}); | ||
} | ||
else { | ||
aliases[x] = y; | ||
aliases[y] = x; | ||
} | ||
@@ -101,10 +91,193 @@ return self; | ||
function rescan () { | ||
self.argv = { _ : [], $0 : self.$0 }; | ||
var demanded = {}; | ||
self.demand = function (keys, cb) { | ||
if (typeof keys == 'number') { | ||
if (!demanded._) demanded._ = 0; | ||
demanded._ += keys; | ||
} | ||
else if (Array.isArray(keys)) { | ||
keys.forEach(function (key) { | ||
self.demand(key); | ||
}); | ||
} | ||
else { | ||
demanded[keys] = true; | ||
} | ||
return self; | ||
}; | ||
var usage; | ||
self.usage = function (msg, opts) { | ||
if (!opts && typeof msg === 'object') { | ||
opts = msg; | ||
msg = null; | ||
} | ||
usage = msg; | ||
if (opts) self.options(opts); | ||
return self; | ||
}; | ||
function fail (msg) { | ||
self.showHelp(); | ||
if (msg) console.error(msg); | ||
process.exit(1); | ||
} | ||
var checks = []; | ||
self.check = function (f) { | ||
checks.push(f); | ||
return self; | ||
}; | ||
var defaults = {}; | ||
self.default = function (key, value) { | ||
if (typeof key === 'object') { | ||
Object.keys(key).forEach(function (k) { | ||
self.default(k, key[k]); | ||
}); | ||
} | ||
else { | ||
defaults[key] = value; | ||
} | ||
return self; | ||
}; | ||
var descriptions = {}; | ||
self.describe = function (key, desc) { | ||
if (typeof key === 'object') { | ||
Object.keys(key).forEach(function (k) { | ||
self.describe(k, key[k]); | ||
}); | ||
} | ||
else { | ||
descriptions[key] = desc; | ||
} | ||
return self; | ||
}; | ||
self.parse = function (args) { | ||
return Argv(args).argv; | ||
}; | ||
self.options = function (key, opt) { | ||
if (typeof key === 'object') { | ||
Object.keys(key).forEach(function (k) { | ||
self.options(k, key[k]); | ||
}); | ||
} | ||
else { | ||
if (opt.alias) self.alias(key, opt.alias); | ||
if (opt.demand) self.demand(key); | ||
if (opt.default) self.default(key, opt.default); | ||
if (opt.boolean || opt.type === 'boolean') { | ||
self.boolean(key); | ||
} | ||
if (opt.string || opt.type === 'string') { | ||
self.string(key); | ||
} | ||
var desc = opt.describe || opt.description || opt.desc; | ||
if (desc) { | ||
self.describe(key, desc); | ||
} | ||
} | ||
return self; | ||
}; | ||
self.showHelp = function (fn) { | ||
if (!fn) fn = console.error; | ||
fn(self.help()); | ||
}; | ||
self.help = function () { | ||
var help = []; | ||
if (usage) { | ||
help.push(usage.replace(/\$0/g, self.$0), ''); | ||
} | ||
var keys = Object.keys( | ||
Object.keys(descriptions) | ||
.concat(Object.keys(demanded)) | ||
.concat(Object.keys(defaults)) | ||
.reduce(function (acc, key) { | ||
if (key !== '_') acc[key] = true; | ||
return acc; | ||
}, {}) | ||
); | ||
keys.forEach(function (key) { | ||
var switches = [ key ].concat(aliases[key] || []) | ||
.map(function (sw) { | ||
return (sw.length > 1 ? '--' : '-') + sw | ||
}) | ||
.join(', ') | ||
; | ||
var type = null; | ||
if (flags.bools[key]) type = '[boolean]'; | ||
if (flags.strings[key]) type = '[string]'; | ||
help.push(' ' + switches + ' ' + [ | ||
type, | ||
demanded[key] | ||
? '[required]' | ||
: null | ||
, | ||
defaults[key] | ||
? '[default: ' + JSON.stringify(defaults[key]) + ']' | ||
: null | ||
, | ||
].filter(Boolean).join(' ')); | ||
var desc = descriptions[key]; | ||
if (desc) help.push(' ' + desc); | ||
help.push(''); | ||
}); | ||
return help.join('\n'); | ||
}; | ||
Object.defineProperty(self, 'argv', { | ||
get : parseArgs, | ||
enumerable : true, | ||
}); | ||
function parseArgs () { | ||
var argv = { _ : [], $0 : self.$0 }; | ||
Object.keys(flags.bools).forEach(function (key) { | ||
setArg(key, false); | ||
}); | ||
function setArg (key, val) { | ||
var num = Number(val); | ||
var value = typeof val !== 'string' || isNaN(num) ? val : num; | ||
if (flags.strings[key]) value = val; | ||
if (key in argv && !flags.bools[key]) { | ||
if (!Array.isArray(argv[key])) { | ||
argv[key] = [ argv[key] ]; | ||
} | ||
argv[key].push(value); | ||
} | ||
else { | ||
argv[key] = value; | ||
} | ||
if (aliases[key]) { | ||
argv[aliases[key]] = argv[key]; | ||
} | ||
} | ||
for (var i = 0; i < args.length; i++) { | ||
var arg = args[i]; | ||
if (arg == '--') { | ||
self.argv._.push.apply(self.argv._, args.slice(i + 1)); | ||
if (arg === '--') { | ||
argv._.push.apply(argv._, args.slice(i + 1)); | ||
break; | ||
@@ -114,7 +287,7 @@ } | ||
var m = arg.match(/^--([^=]+)=(.*)/); | ||
set(m[1], m[2]); | ||
setArg(m[1], m[2]); | ||
} | ||
else if (arg.match(/^--no-.+/)) { | ||
var key = arg.match(/^--no-(.+)/)[1]; | ||
set(key, false); | ||
setArg(key, false); | ||
} | ||
@@ -126,7 +299,7 @@ else if (arg.match(/^--.+/)) { | ||
&& !flags.bools[key]) { | ||
set(key, next); | ||
setArg(key, next); | ||
i++; | ||
} | ||
else { | ||
set(key, true); | ||
setArg(key, true); | ||
} | ||
@@ -140,3 +313,3 @@ } | ||
if (letters[j+1] && letters[j+1].match(/\W/)) { | ||
set(letters[j], arg.slice(j+2)); | ||
setArg(letters[j], arg.slice(j+2)); | ||
broken = true; | ||
@@ -146,3 +319,3 @@ break; | ||
else { | ||
set(letters[j], true); | ||
setArg(letters[j], true); | ||
} | ||
@@ -156,7 +329,7 @@ } | ||
&& !flags.bools[key]) { | ||
set(key, args[i+1]); | ||
setArg(key, args[i+1]); | ||
i++; | ||
} | ||
else { | ||
set(key, true); | ||
setArg(key, true); | ||
} | ||
@@ -167,87 +340,40 @@ } | ||
var n = Number(arg); | ||
self.argv._.push(isNaN(n) ? arg : n); | ||
argv._.push(isNaN(n) ? arg : n); | ||
} | ||
} | ||
} | ||
rescan(); | ||
var usage; | ||
self.usage = function (msg) { | ||
usage = msg; | ||
return self; | ||
}; | ||
function fail (msg) { | ||
if (usage) console.error(usage.replace(/\$0/g, self.$0)) | ||
console.error(msg); | ||
process.exit(); | ||
} | ||
self.check = function (f) { | ||
try { | ||
if (f(self.argv) === false) fail( | ||
'Argument check failed: ' + f.toString() | ||
Object.keys(defaults).forEach(function (key) { | ||
if (!(key in argv)) { | ||
argv[key] = defaults[key]; | ||
} | ||
}); | ||
if (demanded._ && argv._.length < demanded._) { | ||
fail('Not enough non-option arguments: got ' | ||
+ argv._.length + ', need at least ' + demanded._ | ||
); | ||
} | ||
catch (err) { fail(err) } | ||
return self; | ||
}; | ||
self.demand = function (keys, cb) { | ||
if (typeof keys == 'number') { | ||
return self.demandCount(keys, cb); | ||
} | ||
var missing = []; | ||
keys.forEach(function (key) { | ||
if (!(key in self.argv)) missing.push(key); | ||
Object.keys(demanded).forEach(function (key) { | ||
if (!argv[key]) missing.push(key); | ||
}); | ||
if (missing.length > 0) { | ||
if (cb) cb(missing); | ||
else fail('Missing arguments: ' + missing.join(' ')); | ||
if (missing.length) { | ||
fail('Missing required arguments: ' + missing.join(', ')); | ||
} | ||
return self; | ||
}; | ||
self.demandCount = function (count, cb) { | ||
if (self.argv._.length < count) { | ||
if (cb) cb(self.argv._.length); | ||
else fail('Not enough arguments, expected ' | ||
+ count + ', but only found ' + self.argv._.length); | ||
} | ||
return self; | ||
}; | ||
self.default = function (key, value) { | ||
if (typeof key === 'object') { | ||
Object.keys(key).forEach(function (k) { | ||
self.default(k, key[k]); | ||
}); | ||
} | ||
else { | ||
if (self.argv[key] === undefined) { | ||
self.argv[key] = value; | ||
checks.forEach(function (f) { | ||
try { | ||
if (f(argv) === false) { | ||
fail('Argument check failed: ' + f.toString()); | ||
} | ||
} | ||
} | ||
return self; | ||
}; | ||
self.parse = function (args) { | ||
return Argv(args).argv; | ||
}; | ||
self.camelCase = function () { | ||
for (var key in self.argv) { | ||
var camelCasedKey = key.replace(/-([a-z])/g, function ($0, firstLetter) { | ||
return firstLetter.toUpperCase(); | ||
}); | ||
if (camelCasedKey !== key) { | ||
self.argv[camelCasedKey] = self.argv[key]; | ||
delete self.argv[key]; | ||
catch (err) { | ||
fail(err) | ||
} | ||
} | ||
return self; | ||
}; | ||
}); | ||
return argv; | ||
} | ||
@@ -259,3 +385,3 @@ return self; | ||
// exported for tests | ||
module.exports.rebase = rebase; | ||
exports.rebase = rebase; | ||
function rebase (base, dir) { | ||
@@ -262,0 +388,0 @@ var ds = path.normalize(dir).split('/').slice(1); |
{ | ||
"name" : "optimist", | ||
"version" : "0.1.9", | ||
"version" : "0.2.0", | ||
"description" : "Light-weight option parsing with an argv hash. No optstrings attached.", | ||
@@ -25,3 +25,5 @@ "main" : "./index.js", | ||
"license" : "MIT/X11", | ||
"engine" : ["node >=0.1.100"] | ||
"engine" : { | ||
"node" : ">=0.4" | ||
} | ||
} |
@@ -210,1 +210,11 @@ var optimist = require('optimist'); | ||
}; | ||
exports.alias = function () { | ||
var argv = optimist([ '-f', '11', '--zoom', '55' ]) | ||
.alias('z', 'zoom') | ||
.argv | ||
; | ||
assert.equal(argv.zoom, 55); | ||
assert.equal(argv.z, argv.zoom); | ||
assert.equal(argv.f, 11); | ||
}; |
var Hash = require('hashish'); | ||
var optimist = require('optimist'); | ||
var assert = require('assert'); | ||
exports.usageFail = function (assert) { | ||
exports.usageFail = function () { | ||
var r = checkUsage(function () { | ||
@@ -11,11 +12,21 @@ return optimist('-x 10 -z 20'.split(' ')) | ||
}); | ||
assert.deepEqual(r, { | ||
result : { x : 10, z : 20, _ : [], $0 : './usage' }, | ||
errors : [ 'Usage: ./usage -x NUM -y NUM', 'Missing arguments: y' ], | ||
logs : [], | ||
exit: true, | ||
}); | ||
assert.deepEqual( | ||
r.result, | ||
{ x : 10, z : 20, _ : [], $0 : './usage' } | ||
); | ||
assert.deepEqual( | ||
r.errors.join('\n').split(/\n+/), | ||
[ | ||
'Usage: ./usage -x NUM -y NUM', | ||
' -x [required]', | ||
' -y [required]', | ||
'Missing required arguments: y', | ||
] | ||
); | ||
assert.deepEqual(r.logs, []); | ||
assert.ok(r.exit); | ||
}; | ||
exports.usagePass = function (assert) { | ||
exports.usagePass = function () { | ||
var r = checkUsage(function () { | ||
@@ -35,3 +46,3 @@ return optimist('-x 10 -y 20'.split(' ')) | ||
exports.checkPass = function (assert) { | ||
exports.checkPass = function () { | ||
var r = checkUsage(function () { | ||
@@ -54,3 +65,3 @@ return optimist('-x 10 -y 20'.split(' ')) | ||
exports.checkFail = function (assert) { | ||
exports.checkFail = function () { | ||
var r = checkUsage(function () { | ||
@@ -65,11 +76,21 @@ return optimist('-x 10 -z 20'.split(' ')) | ||
}); | ||
assert.deepEqual(r, { | ||
result : { x : 10, z : 20, _ : [], $0 : './usage' }, | ||
errors : [ 'Usage: ./usage -x NUM -y NUM', 'You forgot about -y' ], | ||
logs : [], | ||
exit: true, | ||
}); | ||
assert.deepEqual( | ||
r.result, | ||
{ x : 10, z : 20, _ : [], $0 : './usage' } | ||
); | ||
assert.deepEqual( | ||
r.errors.join('\n').split(/\n+/), | ||
[ | ||
'Usage: ./usage -x NUM -y NUM', | ||
'You forgot about -y' | ||
] | ||
); | ||
assert.deepEqual(r.logs, []); | ||
assert.ok(r.exit); | ||
}; | ||
exports.checkCondPass = function (assert) { | ||
exports.checkCondPass = function () { | ||
function checker (argv) { | ||
@@ -93,3 +114,3 @@ return 'x' in argv && 'y' in argv; | ||
exports.checkCondFail = function (assert) { | ||
exports.checkCondFail = function () { | ||
function checker (argv) { | ||
@@ -105,14 +126,19 @@ return 'x' in argv && 'y' in argv; | ||
}); | ||
assert.deepEqual(r, { | ||
result : { x : 10, z : 20, _ : [], $0 : './usage' }, | ||
errors : [ | ||
'Usage: ./usage -x NUM -y NUM', | ||
'Argument check failed: ' + checker.toString() | ||
], | ||
logs : [], | ||
exit: true, | ||
}); | ||
assert.deepEqual( | ||
r.result, | ||
{ x : 10, z : 20, _ : [], $0 : './usage' } | ||
); | ||
assert.deepEqual( | ||
r.errors.join('\n').split(/\n+/).join('\n'), | ||
'Usage: ./usage -x NUM -y NUM\n' | ||
+ 'Argument check failed: ' + checker.toString() | ||
); | ||
assert.deepEqual(r.logs, []); | ||
assert.ok(r.exit); | ||
}; | ||
exports.countPass = function (assert) { | ||
exports.countPass = function () { | ||
var r = checkUsage(function () { | ||
@@ -132,3 +158,3 @@ return optimist('1 2 3 --moo'.split(' ')) | ||
exports.countFail = function (assert) { | ||
exports.countFail = function () { | ||
var r = checkUsage(function () { | ||
@@ -140,14 +166,20 @@ return optimist('1 2 --moo'.split(' ')) | ||
}); | ||
assert.deepEqual(r, { | ||
result : { _ : [ '1', '2' ], moo : true, $0 : './usage' }, | ||
errors : [ | ||
assert.deepEqual( | ||
r.result, | ||
{ _ : [ '1', '2' ], moo : true, $0 : './usage' } | ||
); | ||
assert.deepEqual( | ||
r.errors.join('\n').split(/\n+/), | ||
[ | ||
'Usage: ./usage [x] [y] [z] {OPTIONS}', | ||
'Not enough arguments, expected 3, but only found 2' | ||
], | ||
logs : [], | ||
exit: true, | ||
}); | ||
'Not enough non-option arguments: got 2, need at least 3', | ||
] | ||
); | ||
assert.deepEqual(r.logs, []); | ||
assert.ok(r.exit); | ||
}; | ||
exports.defaultSingles = function (assert) { | ||
exports.defaultSingles = function () { | ||
var r = checkUsage(function () { | ||
@@ -171,3 +203,3 @@ return optimist('--foo 50 --baz 70 --powsy'.split(' ')) | ||
exports.defaultHash = function (assert) { | ||
exports.defaultHash = function () { | ||
var r = checkUsage(function () { | ||
@@ -189,3 +221,3 @@ return optimist('--foo 50 --baz 70'.split(' ')) | ||
exports.rebase = function (assert) { | ||
exports.rebase = function () { | ||
assert.equal( | ||
@@ -192,0 +224,0 @@ optimist.rebase('/home/substack', '/home/substack/foo/bar/baz'), |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
34904
24
930
261