diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-10-10 03:43:44 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-10-10 03:43:44 +0200 |
commit | abd94a7f5a50f43c797a11b53549ae48fff667c3 (patch) | |
tree | ab8ed457f65cdd72e13e0571d2975729428f1551 /node_modules/nomnom/nomnom.js | |
parent | a0247c6a3fd6a09a41a7e35a3441324c4dcb58be (diff) | |
download | wallet-core-abd94a7f5a50f43c797a11b53549ae48fff667c3.tar.xz |
add node_modules to address #4364
Diffstat (limited to 'node_modules/nomnom/nomnom.js')
-rw-r--r-- | node_modules/nomnom/nomnom.js | 584 |
1 files changed, 584 insertions, 0 deletions
diff --git a/node_modules/nomnom/nomnom.js b/node_modules/nomnom/nomnom.js new file mode 100644 index 000000000..315597414 --- /dev/null +++ b/node_modules/nomnom/nomnom.js @@ -0,0 +1,584 @@ +var _ = require("underscore"), chalk = require('chalk'); + + +function ArgParser() { + this.commands = {}; // expected commands + this.specs = {}; // option specifications +} + +ArgParser.prototype = { + /* Add a command to the expected commands */ + command : function(name) { + var command; + if (name) { + command = this.commands[name] = { + name: name, + specs: {} + }; + } + else { + command = this.fallback = { + specs: {} + }; + } + + // facilitates command('name').options().cb().help() + var chain = { + options : function(specs) { + command.specs = specs; + return chain; + }, + opts : function(specs) { + // old API + return this.options(specs); + }, + option : function(name, spec) { + command.specs[name] = spec; + return chain; + }, + callback : function(cb) { + command.cb = cb; + return chain; + }, + help : function(help) { + command.help = help; + return chain; + }, + usage : function(usage) { + command._usage = usage; + return chain; + } + }; + return chain; + }, + + nocommand : function() { + return this.command(); + }, + + options : function(specs) { + this.specs = specs; + return this; + }, + + opts : function(specs) { + // old API + return this.options(specs); + }, + + globalOpts : function(specs) { + // old API + return this.options(specs); + }, + + option : function(name, spec) { + this.specs[name] = spec; + return this; + }, + + usage : function(usage) { + this._usage = usage; + return this; + }, + + printer : function(print) { + this.print = print; + return this; + }, + + script : function(script) { + this._script = script; + return this; + }, + + scriptName : function(script) { + // old API + return this.script(script); + }, + + help : function(help) { + this._help = help; + return this; + }, + + colors: function() { + // deprecated - colors are on by default now + return this; + }, + + nocolors : function() { + this._nocolors = true; + return this; + }, + + parseArgs : function(argv) { + // old API + return this.parse(argv); + }, + + nom : function(argv) { + return this.parse(argv); + }, + + parse : function(argv) { + this.print = this.print || function(str, code) { + console.log(str); + process.exit(code || 0); + }; + this._help = this._help || ""; + this._script = this._script || process.argv[0] + " " + + require('path').basename(process.argv[1]); + this.specs = this.specs || {}; + + var argv = argv || process.argv.slice(2); + + var arg = Arg(argv[0]).isValue && argv[0], + command = arg && this.commands[arg], + commandExpected = !_(this.commands).isEmpty(); + + if (commandExpected) { + if (command) { + _(this.specs).extend(command.specs); + this._script += " " + command.name; + if (command.help) { + this._help = command.help; + } + this.command = command; + } + else if (arg) { + return this.print(this._script + ": no such command '" + arg + "'", 1); + } + else { + // no command but command expected e.g. 'git -v' + var helpStringBuilder = { + list : function() { + return 'one of: ' + _(this.commands).keys().join(", "); + }, + twoColumn : function() { + // find the longest command name to ensure horizontal alignment + var maxLength = _(this.commands).max(function (cmd) { + return cmd.name.length; + }).name.length; + + // create the two column text strings + var cmdHelp = _.map(this.commands, function(cmd, name) { + var diff = maxLength - name.length; + var pad = new Array(diff + 4).join(" "); + return " " + [ name, pad, cmd.help ].join(" "); + }); + return "\n" + cmdHelp.join("\n"); + } + }; + + // if there are a small number of commands and all have help strings, + // display them in a two column table; otherwise use the brief version. + // The arbitrary choice of "20" comes from the number commands git + // displays as "common commands" + var helpType = 'list'; + if (_(this.commands).size() <= 20) { + if (_(this.commands).every(function (cmd) { return cmd.help; })) { + helpType = 'twoColumn'; + } + } + + this.specs.command = { + position: 0, + help: helpStringBuilder[helpType].call(this) + } + + if (this.fallback) { + _(this.specs).extend(this.fallback.specs); + this._help = this.fallback.help; + } else { + this.specs.command.required = true; + } + } + } + + if (this.specs.length === undefined) { + // specs is a hash not an array + this.specs = _(this.specs).map(function(opt, name) { + opt.name = name; + return opt; + }); + } + this.specs = this.specs.map(function(opt) { + return Opt(opt); + }); + + if (argv.indexOf("--help") >= 0 || argv.indexOf("-h") >= 0) { + return this.print(this.getUsage()); + } + + var options = {}; + var args = argv.map(function(arg) { + return Arg(arg); + }) + .concat(Arg()); + + var positionals = []; + + /* parse the args */ + var that = this; + args.reduce(function(arg, val) { + /* positional */ + if (arg.isValue) { + positionals.push(arg.value); + } + else if (arg.chars) { + var last = arg.chars.pop(); + + /* -cfv */ + (arg.chars).forEach(function(ch) { + that.setOption(options, ch, true); + }); + + /* -v key */ + if (!that.opt(last).flag) { + if (val.isValue) { + that.setOption(options, last, val.value); + return Arg(); // skip next turn - swallow arg + } + else { + that.print("'-" + (that.opt(last).name || last) + "'" + + " expects a value\n\n" + that.getUsage(), 1); + } + } + else { + /* -v */ + that.setOption(options, last, true); + } + + } + else if (arg.full) { + var value = arg.value; + + /* --key */ + if (value === undefined) { + /* --key value */ + if (!that.opt(arg.full).flag) { + if (val.isValue) { + that.setOption(options, arg.full, val.value); + return Arg(); + } + else { + that.print("'--" + (that.opt(arg.full).name || arg.full) + "'" + + " expects a value\n\n" + that.getUsage(), 1); + } + } + else { + /* --flag */ + value = true; + } + } + that.setOption(options, arg.full, value); + } + return val; + }); + + positionals.forEach(function(pos, index) { + this.setOption(options, index, pos); + }, this); + + options._ = positionals; + + this.specs.forEach(function(opt) { + if (opt.default !== undefined && options[opt.name] === undefined) { + options[opt.name] = opt.default; + } + }, this); + + // exit if required arg isn't present + this.specs.forEach(function(opt) { + if (opt.required && options[opt.name] === undefined) { + var msg = opt.name + " argument is required"; + msg = this._nocolors ? msg : chalk.red(msg); + + this.print("\n" + msg + "\n" + this.getUsage(), 1); + } + }, this); + + if (command && command.cb) { + command.cb(options); + } + else if (this.fallback && this.fallback.cb) { + this.fallback.cb(options); + } + + return options; + }, + + getUsage : function() { + if (this.command && this.command._usage) { + return this.command._usage; + } + else if (this.fallback && this.fallback._usage) { + return this.fallback._usage; + } + if (this._usage) { + return this._usage; + } + + // todo: use a template + var str = "\n" + if (!this._nocolors) { + str += chalk.bold("Usage:"); + } + else { + str += "Usage:"; + } + str += " " + this._script; + + var positionals = _(this.specs).select(function(opt) { + return opt.position != undefined; + }) + positionals = _(positionals).sortBy(function(opt) { + return opt.position; + }); + var options = _(this.specs).select(function(opt) { + return opt.position === undefined; + }); + + // assume there are no gaps in the specified pos. args + positionals.forEach(function(pos) { + str += " "; + var posStr = pos.string; + if (!posStr) { + posStr = pos.name || "arg" + pos.position; + if (pos.required) { + posStr = "<" + posStr + ">"; + } else { + posStr = "[" + posStr + "]"; + } + if (pos.list) { + posStr += "..."; + } + } + str += posStr; + }); + + if (options.length) { + if (!this._nocolors) { + // must be a better way to do this + str += chalk.blue(" [options]"); + } + else { + str += " [options]"; + } + } + + if (options.length || positionals.length) { + str += "\n\n"; + } + + function spaces(length) { + var spaces = ""; + for (var i = 0; i < length; i++) { + spaces += " "; + } + return spaces; + } + var longest = positionals.reduce(function(max, pos) { + return pos.name.length > max ? pos.name.length : max; + }, 0); + + positionals.forEach(function(pos) { + var posStr = pos.string || pos.name; + str += posStr + spaces(longest - posStr.length) + " "; + if (!this._nocolors) { + str += chalk.grey(pos.help || "") + } + else { + str += (pos.help || "") + } + str += "\n"; + }, this); + if (positionals.length && options.length) { + str += "\n"; + } + + if (options.length) { + if (!this._nocolors) { + str += chalk.blue("Options:"); + } + else { + str += "Options:"; + } + str += "\n" + + var longest = options.reduce(function(max, opt) { + return opt.string.length > max && !opt.hidden ? opt.string.length : max; + }, 0); + + options.forEach(function(opt) { + if (!opt.hidden) { + str += " " + opt.string + spaces(longest - opt.string.length) + " "; + + var defaults = (opt.default != null ? " [" + opt.default + "]" : ""); + var help = opt.help ? opt.help + defaults : ""; + str += this._nocolors ? help: chalk.grey(help); + + str += "\n"; + } + }, this); + } + + if (this._help) { + str += "\n" + this._help; + } + return str; + } +}; + +ArgParser.prototype.opt = function(arg) { + // get the specified opt for this parsed arg + var match = Opt({}); + this.specs.forEach(function(opt) { + if (opt.matches(arg)) { + match = opt; + } + }); + return match; +}; + +ArgParser.prototype.setOption = function(options, arg, value) { + var option = this.opt(arg); + if (option.callback) { + var message = option.callback(value); + + if (typeof message == "string") { + this.print(message, 1); + } + } + + if (option.type != "string") { + try { + // infer type by JSON parsing the string + value = JSON.parse(value) + } + catch(e) {} + } + + if (option.transform) { + value = option.transform(value); + } + + var name = option.name || arg; + if (option.choices && option.choices.indexOf(value) == -1) { + this.print(name + " must be one of: " + option.choices.join(", "), 1); + } + + if (option.list) { + if (!options[name]) { + options[name] = [value]; + } + else { + options[name].push(value); + } + } + else { + options[name] = value; + } +}; + + +/* an arg is an item that's actually parsed from the command line + e.g. "-l", "log.txt", or "--logfile=log.txt" */ +var Arg = function(str) { + var abbrRegex = /^\-(\w+?)$/, + fullRegex = /^\-\-(no\-)?(.+?)(?:=(.+))?$/, + valRegex = /^[^\-].*/; + + var charMatch = abbrRegex.exec(str), + chars = charMatch && charMatch[1].split(""); + + var fullMatch = fullRegex.exec(str), + full = fullMatch && fullMatch[2]; + + var isValue = str !== undefined && (str === "" || valRegex.test(str)); + var value; + if (isValue) { + value = str; + } + else if (full) { + value = fullMatch[1] ? false : fullMatch[3]; + } + + return { + str: str, + chars: chars, + full: full, + value: value, + isValue: isValue + } +} + + +/* an opt is what's specified by the user in opts hash */ +var Opt = function(opt) { + var strings = (opt.string || "").split(","), + abbr, full, metavar; + for (var i = 0; i < strings.length; i++) { + var string = strings[i].trim(), + matches; + if (matches = string.match(/^\-([^-])(?:\s+(.*))?$/)) { + abbr = matches[1]; + metavar = matches[2]; + } + else if (matches = string.match(/^\-\-(.+?)(?:[=\s]+(.+))?$/)) { + full = matches[1]; + metavar = metavar || matches[2]; + } + } + + matches = matches || []; + var abbr = opt.abbr || abbr, // e.g. v from -v + full = opt.full || full, // e.g. verbose from --verbose + metavar = opt.metavar || metavar; // e.g. PATH from '--config=PATH' + + var string; + if (opt.string) { + string = opt.string; + } + else if (opt.position === undefined) { + string = ""; + if (abbr) { + string += "-" + abbr; + if (metavar) + string += " " + metavar + string += ", "; + } + string += "--" + (full || opt.name); + if (metavar) { + string += " " + metavar; + } + } + + opt = _(opt).extend({ + name: opt.name || full || abbr, + string: string, + abbr: abbr, + full: full, + metavar: metavar, + matches: function(arg) { + return opt.full == arg || opt.abbr == arg || opt.position == arg + || opt.name == arg || (opt.list && arg >= opt.position); + } + }); + return opt; +} + + +var createParser = function() { + return new ArgParser(); +} + +var nomnom = createParser(); + +for (var i in nomnom) { + if (typeof nomnom[i] == "function") { + createParser[i] = _(nomnom[i]).bind(nomnom); + } +} + +module.exports = createParser; |