react / wstein / node_modules / jest-cli / node_modules / istanbul / node_modules / js-yaml / node_modules / argparse / lib / argument_parser.js
80713 views/**1* class ArgumentParser2*3* Object for parsing command line strings into js objects.4*5* Inherited from [[ActionContainer]]6**/7'use strict';89var util = require('util');10var format = require('util').format;11var Path = require('path');1213var _ = require('lodash');14var sprintf = require('sprintf-js').sprintf;1516// Constants17var $$ = require('./const');1819var ActionContainer = require('./action_container');2021// Errors22var argumentErrorHelper = require('./argument/error');2324var HelpFormatter = require('./help/formatter');2526var Namespace = require('./namespace');272829/**30* new ArgumentParser(options)31*32* Create a new ArgumentParser object.33*34* ##### Options:35* - `prog` The name of the program (default: Path.basename(process.argv[1]))36* - `usage` A usage message (default: auto-generated from arguments)37* - `description` A description of what the program does38* - `epilog` Text following the argument descriptions39* - `parents` Parsers whose arguments should be copied into this one40* - `formatterClass` HelpFormatter class for printing help messages41* - `prefixChars` Characters that prefix optional arguments42* - `fromfilePrefixChars` Characters that prefix files containing additional arguments43* - `argumentDefault` The default value for all arguments44* - `addHelp` Add a -h/-help option45* - `conflictHandler` Specifies how to handle conflicting argument names46* - `debug` Enable debug mode. Argument errors throw exception in47* debug mode and process.exit in normal. Used for development and48* testing (default: false)49*50* See also [original guide][1]51*52* [1]:http://docs.python.org/dev/library/argparse.html#argumentparser-objects53**/54var ArgumentParser = module.exports = function ArgumentParser(options) {55var self = this;56options = options || {};5758options.description = (options.description || null);59options.argumentDefault = (options.argumentDefault || null);60options.prefixChars = (options.prefixChars || '-');61options.conflictHandler = (options.conflictHandler || 'error');62ActionContainer.call(this, options);6364options.addHelp = (options.addHelp === undefined || !!options.addHelp);65options.parents = (options.parents || []);66// default program name67options.prog = (options.prog || Path.basename(process.argv[1]));68this.prog = options.prog;69this.usage = options.usage;70this.epilog = options.epilog;71this.version = options.version;7273this.debug = (options.debug === true);7475this.formatterClass = (options.formatterClass || HelpFormatter);76this.fromfilePrefixChars = options.fromfilePrefixChars || null;77this._positionals = this.addArgumentGroup({title: 'Positional arguments'});78this._optionals = this.addArgumentGroup({title: 'Optional arguments'});79this._subparsers = null;8081// register types82var FUNCTION_IDENTITY = function (o) {83return o;84};85this.register('type', 'auto', FUNCTION_IDENTITY);86this.register('type', null, FUNCTION_IDENTITY);87this.register('type', 'int', function (x) {88var result = parseInt(x, 10);89if (isNaN(result)) {90throw new Error(x + ' is not a valid integer.');91}92return result;93});94this.register('type', 'float', function (x) {95var result = parseFloat(x);96if (isNaN(result)) {97throw new Error(x + ' is not a valid float.');98}99return result;100});101this.register('type', 'string', function (x) {102return '' + x;103});104105// add help and version arguments if necessary106var defaultPrefix = (this.prefixChars.indexOf('-') > -1) ? '-' : this.prefixChars[0];107if (options.addHelp) {108this.addArgument(109[defaultPrefix + 'h', defaultPrefix + defaultPrefix + 'help'],110{111action: 'help',112defaultValue: $$.SUPPRESS,113help: 'Show this help message and exit.'114}115);116}117if (this.version !== undefined) {118this.addArgument(119[defaultPrefix + 'v', defaultPrefix + defaultPrefix + 'version'],120{121action: 'version',122version: this.version,123defaultValue: $$.SUPPRESS,124help: "Show program's version number and exit."125}126);127}128129// add parent arguments and defaults130options.parents.forEach(function (parent) {131self._addContainerActions(parent);132if (parent._defaults !== undefined) {133for (var defaultKey in parent._defaults) {134if (parent._defaults.hasOwnProperty(defaultKey)) {135self._defaults[defaultKey] = parent._defaults[defaultKey];136}137}138}139});140141};142util.inherits(ArgumentParser, ActionContainer);143144/**145* ArgumentParser#addSubparsers(options) -> [[ActionSubparsers]]146* - options (object): hash of options see [[ActionSubparsers.new]]147*148* See also [subcommands][1]149*150* [1]:http://docs.python.org/dev/library/argparse.html#sub-commands151**/152ArgumentParser.prototype.addSubparsers = function (options) {153if (!!this._subparsers) {154this.error('Cannot have multiple subparser arguments.');155}156157options = options || {};158options.debug = (this.debug === true);159options.optionStrings = [];160options.parserClass = (options.parserClass || ArgumentParser);161162163if (!!options.title || !!options.description) {164165this._subparsers = this.addArgumentGroup({166title: (options.title || 'subcommands'),167description: options.description168});169delete options.title;170delete options.description;171172} else {173this._subparsers = this._positionals;174}175176// prog defaults to the usage message of this parser, skipping177// optional arguments and with no "usage:" prefix178if (!options.prog) {179var formatter = this._getFormatter();180var positionals = this._getPositionalActions();181var groups = this._mutuallyExclusiveGroups;182formatter.addUsage(this.usage, positionals, groups, '');183options.prog = _.trim(formatter.formatHelp());184}185186// create the parsers action and add it to the positionals list187var ParsersClass = this._popActionClass(options, 'parsers');188var action = new ParsersClass(options);189this._subparsers._addAction(action);190191// return the created parsers action192return action;193};194195ArgumentParser.prototype._addAction = function (action) {196if (action.isOptional()) {197this._optionals._addAction(action);198} else {199this._positionals._addAction(action);200}201return action;202};203204ArgumentParser.prototype._getOptionalActions = function () {205return this._actions.filter(function (action) {206return action.isOptional();207});208};209210ArgumentParser.prototype._getPositionalActions = function () {211return this._actions.filter(function (action) {212return action.isPositional();213});214};215216217/**218* ArgumentParser#parseArgs(args, namespace) -> Namespace|Object219* - args (array): input elements220* - namespace (Namespace|Object): result object221*222* Parsed args and throws error if some arguments are not recognized223*224* See also [original guide][1]225*226* [1]:http://docs.python.org/dev/library/argparse.html#the-parse-args-method227**/228ArgumentParser.prototype.parseArgs = function (args, namespace) {229var argv;230var result = this.parseKnownArgs(args, namespace);231232args = result[0];233argv = result[1];234if (argv && argv.length > 0) {235this.error(236format('Unrecognized arguments: %s.', argv.join(' '))237);238}239return args;240};241242/**243* ArgumentParser#parseKnownArgs(args, namespace) -> array244* - args (array): input options245* - namespace (Namespace|Object): result object246*247* Parse known arguments and return tuple of result object248* and unknown args249*250* See also [original guide][1]251*252* [1]:http://docs.python.org/dev/library/argparse.html#partial-parsing253**/254ArgumentParser.prototype.parseKnownArgs = function (args, namespace) {255var self = this;256257// args default to the system args258args = args || process.argv.slice(2);259260// default Namespace built from parser defaults261namespace = namespace || new Namespace();262263self._actions.forEach(function (action) {264if (action.dest !== $$.SUPPRESS) {265if (!_.has(namespace, action.dest)) {266if (action.defaultValue !== $$.SUPPRESS) {267var defaultValue = action.defaultValue;268if (_.isString(action.defaultValue)) {269defaultValue = self._getValue(action, defaultValue);270}271namespace[action.dest] = defaultValue;272}273}274}275});276277_.keys(self._defaults).forEach(function (dest) {278namespace[dest] = self._defaults[dest];279});280281// parse the arguments and exit if there are any errors282try {283var res = this._parseKnownArgs(args, namespace);284285namespace = res[0];286args = res[1];287if (_.has(namespace, $$._UNRECOGNIZED_ARGS_ATTR)) {288args = _.union(args, namespace[$$._UNRECOGNIZED_ARGS_ATTR]);289delete namespace[$$._UNRECOGNIZED_ARGS_ATTR];290}291return [namespace, args];292} catch (e) {293this.error(e);294}295};296297ArgumentParser.prototype._parseKnownArgs = function (argStrings, namespace) {298var self = this;299300var extras = [];301302// replace arg strings that are file references303if (this.fromfilePrefixChars !== null) {304argStrings = this._readArgsFromFiles(argStrings);305}306// map all mutually exclusive arguments to the other arguments307// they can't occur with308// Python has 'conflicts = action_conflicts.setdefault(mutex_action, [])'309// though I can't conceive of a way in which an action could be a member310// of two different mutually exclusive groups.311312function actionHash(action) {313// some sort of hashable key for this action314// action itself cannot be a key in actionConflicts315// I think getName() (join of optionStrings) is unique enough316return action.getName();317}318319var conflicts, key;320var actionConflicts = {};321322this._mutuallyExclusiveGroups.forEach(function (mutexGroup) {323mutexGroup._groupActions.forEach(function (mutexAction, i, groupActions) {324key = actionHash(mutexAction);325if (!_.has(actionConflicts, key)) {326actionConflicts[key] = [];327}328conflicts = actionConflicts[key];329conflicts.push.apply(conflicts, groupActions.slice(0, i));330conflicts.push.apply(conflicts, groupActions.slice(i + 1));331});332});333334// find all option indices, and determine the arg_string_pattern335// which has an 'O' if there is an option at an index,336// an 'A' if there is an argument, or a '-' if there is a '--'337var optionStringIndices = {};338339var argStringPatternParts = [];340341argStrings.forEach(function (argString, argStringIndex) {342if (argString === '--') {343argStringPatternParts.push('-');344while (argStringIndex < argStrings.length) {345argStringPatternParts.push('A');346argStringIndex++;347}348}349// otherwise, add the arg to the arg strings350// and note the index if it was an option351else {352var pattern;353var optionTuple = self._parseOptional(argString);354if (!optionTuple) {355pattern = 'A';356}357else {358optionStringIndices[argStringIndex] = optionTuple;359pattern = 'O';360}361argStringPatternParts.push(pattern);362}363});364var argStringsPattern = argStringPatternParts.join('');365366var seenActions = [];367var seenNonDefaultActions = [];368369370function takeAction(action, argumentStrings, optionString) {371seenActions.push(action);372var argumentValues = self._getValues(action, argumentStrings);373374// error if this argument is not allowed with other previously375// seen arguments, assuming that actions that use the default376// value don't really count as "present"377if (argumentValues !== action.defaultValue) {378seenNonDefaultActions.push(action);379if (!!actionConflicts[actionHash(action)]) {380actionConflicts[actionHash(action)].forEach(function (actionConflict) {381if (seenNonDefaultActions.indexOf(actionConflict) >= 0) {382throw argumentErrorHelper(383action,384format('Not allowed with argument "%s".', actionConflict.getName())385);386}387});388}389}390391if (argumentValues !== $$.SUPPRESS) {392action.call(self, namespace, argumentValues, optionString);393}394}395396function consumeOptional(startIndex) {397// get the optional identified at this index398var optionTuple = optionStringIndices[startIndex];399var action = optionTuple[0];400var optionString = optionTuple[1];401var explicitArg = optionTuple[2];402403// identify additional optionals in the same arg string404// (e.g. -xyz is the same as -x -y -z if no args are required)405var actionTuples = [];406407var args, argCount, start, stop;408409while (true) {410if (!action) {411extras.push(argStrings[startIndex]);412return startIndex + 1;413}414if (!!explicitArg) {415argCount = self._matchArgument(action, 'A');416417// if the action is a single-dash option and takes no418// arguments, try to parse more single-dash options out419// of the tail of the option string420var chars = self.prefixChars;421if (argCount === 0 && chars.indexOf(optionString[1]) < 0) {422actionTuples.push([action, [], optionString]);423optionString = optionString[0] + explicitArg[0];424var newExplicitArg = explicitArg.slice(1) || null;425var optionalsMap = self._optionStringActions;426427if (_.keys(optionalsMap).indexOf(optionString) >= 0) {428action = optionalsMap[optionString];429explicitArg = newExplicitArg;430}431else {432var msg = 'ignored explicit argument %r';433throw argumentErrorHelper(action, msg);434}435}436// if the action expect exactly one argument, we've437// successfully matched the option; exit the loop438else if (argCount === 1) {439stop = startIndex + 1;440args = [explicitArg];441actionTuples.push([action, args, optionString]);442break;443}444// error if a double-dash option did not use the445// explicit argument446else {447var message = 'ignored explicit argument %r';448throw argumentErrorHelper(action, sprintf(message, explicitArg));449}450}451// if there is no explicit argument, try to match the452// optional's string arguments with the following strings453// if successful, exit the loop454else {455456start = startIndex + 1;457var selectedPatterns = argStringsPattern.substr(start);458459argCount = self._matchArgument(action, selectedPatterns);460stop = start + argCount;461462463args = argStrings.slice(start, stop);464465actionTuples.push([action, args, optionString]);466break;467}468469}470471// add the Optional to the list and return the index at which472// the Optional's string args stopped473if (actionTuples.length < 1) {474throw new Error('length should be > 0');475}476for (var i = 0; i < actionTuples.length; i++) {477takeAction.apply(self, actionTuples[i]);478}479return stop;480}481482// the list of Positionals left to be parsed; this is modified483// by consume_positionals()484var positionals = self._getPositionalActions();485486function consumePositionals(startIndex) {487// match as many Positionals as possible488var selectedPattern = argStringsPattern.substr(startIndex);489var argCounts = self._matchArgumentsPartial(positionals, selectedPattern);490491// slice off the appropriate arg strings for each Positional492// and add the Positional and its args to the list493_.zip(positionals, argCounts).forEach(function (item) {494var action = item[0];495var argCount = item[1];496if (argCount === undefined) {497return;498}499var args = argStrings.slice(startIndex, startIndex + argCount);500501startIndex += argCount;502takeAction(action, args);503});504505// slice off the Positionals that we just parsed and return the506// index at which the Positionals' string args stopped507positionals = positionals.slice(argCounts.length);508return startIndex;509}510511// consume Positionals and Optionals alternately, until we have512// passed the last option string513var startIndex = 0;514var position;515516var maxOptionStringIndex = -1;517518Object.keys(optionStringIndices).forEach(function (position) {519maxOptionStringIndex = Math.max(maxOptionStringIndex, parseInt(position, 10));520});521522var positionalsEndIndex, nextOptionStringIndex;523524while (startIndex <= maxOptionStringIndex) {525// consume any Positionals preceding the next option526nextOptionStringIndex = null;527for (position in optionStringIndices) {528if (!optionStringIndices.hasOwnProperty(position)) { continue; }529530position = parseInt(position, 10);531if (position >= startIndex) {532if (nextOptionStringIndex !== null) {533nextOptionStringIndex = Math.min(nextOptionStringIndex, position);534}535else {536nextOptionStringIndex = position;537}538}539}540541if (startIndex !== nextOptionStringIndex) {542positionalsEndIndex = consumePositionals(startIndex);543// only try to parse the next optional if we didn't consume544// the option string during the positionals parsing545if (positionalsEndIndex > startIndex) {546startIndex = positionalsEndIndex;547continue;548}549else {550startIndex = positionalsEndIndex;551}552}553554// if we consumed all the positionals we could and we're not555// at the index of an option string, there were extra arguments556if (!optionStringIndices[startIndex]) {557var strings = argStrings.slice(startIndex, nextOptionStringIndex);558extras = extras.concat(strings);559startIndex = nextOptionStringIndex;560}561// consume the next optional and any arguments for it562startIndex = consumeOptional(startIndex);563}564565// consume any positionals following the last Optional566var stopIndex = consumePositionals(startIndex);567568// if we didn't consume all the argument strings, there were extras569extras = extras.concat(argStrings.slice(stopIndex));570571// if we didn't use all the Positional objects, there were too few572// arg strings supplied.573if (positionals.length > 0) {574self.error('too few arguments');575}576577// make sure all required actions were present578self._actions.forEach(function (action) {579if (action.required) {580if (_.indexOf(seenActions, action) < 0) {581self.error(format('Argument "%s" is required', action.getName()));582}583}584});585586// make sure all required groups have one option present587var actionUsed = false;588self._mutuallyExclusiveGroups.forEach(function (group) {589if (group.required) {590actionUsed = _.any(group._groupActions, function (action) {591return _.contains(seenNonDefaultActions, action);592});593594// if no actions were used, report the error595if (!actionUsed) {596var names = [];597group._groupActions.forEach(function (action) {598if (action.help !== $$.SUPPRESS) {599names.push(action.getName());600}601});602names = names.join(' ');603var msg = 'one of the arguments ' + names + ' is required';604self.error(msg);605}606}607});608609// return the updated namespace and the extra arguments610return [namespace, extras];611};612613ArgumentParser.prototype._readArgsFromFiles = function (argStrings) {614// expand arguments referencing files615var _this = this;616var fs = require('fs');617var newArgStrings = [];618argStrings.forEach(function (argString) {619if (_this.fromfilePrefixChars.indexOf(argString[0]) < 0) {620// for regular arguments, just add them back into the list621newArgStrings.push(argString);622} else {623// replace arguments referencing files with the file content624try {625var argstrs = [];626var filename = argString.slice(1);627var content = fs.readFileSync(filename, 'utf8');628content = content.trim().split('\n');629content.forEach(function (argLine) {630_this.convertArgLineToArgs(argLine).forEach(function (arg) {631argstrs.push(arg);632});633argstrs = _this._readArgsFromFiles(argstrs);634});635newArgStrings.push.apply(newArgStrings, argstrs);636} catch (error) {637return _this.error(error.message);638}639}640});641return newArgStrings;642};643644ArgumentParser.prototype.convertArgLineToArgs = function (argLine) {645return [argLine];646};647648ArgumentParser.prototype._matchArgument = function (action, regexpArgStrings) {649650// match the pattern for this action to the arg strings651var regexpNargs = new RegExp('^' + this._getNargsPattern(action));652var matches = regexpArgStrings.match(regexpNargs);653var message;654655// throw an exception if we weren't able to find a match656if (!matches) {657switch (action.nargs) {658case undefined:659case null:660message = 'Expected one argument.';661break;662case $$.OPTIONAL:663message = 'Expected at most one argument.';664break;665case $$.ONE_OR_MORE:666message = 'Expected at least one argument.';667break;668default:669message = 'Expected %s argument(s)';670}671672throw argumentErrorHelper(673action,674format(message, action.nargs)675);676}677// return the number of arguments matched678return matches[1].length;679};680681ArgumentParser.prototype._matchArgumentsPartial = function (actions, regexpArgStrings) {682// progressively shorten the actions list by slicing off the683// final actions until we find a match684var self = this;685var result = [];686var actionSlice, pattern, matches;687var i, j;688689var getLength = function (string) {690return string.length;691};692693for (i = actions.length; i > 0; i--) {694pattern = '';695actionSlice = actions.slice(0, i);696for (j = 0; j < actionSlice.length; j++) {697pattern += self._getNargsPattern(actionSlice[j]);698}699700pattern = new RegExp('^' + pattern);701matches = regexpArgStrings.match(pattern);702703if (matches && matches.length > 0) {704// need only groups705matches = matches.splice(1);706result = result.concat(matches.map(getLength));707break;708}709}710711// return the list of arg string counts712return result;713};714715ArgumentParser.prototype._parseOptional = function (argString) {716var action, optionString, argExplicit, optionTuples;717718// if it's an empty string, it was meant to be a positional719if (!argString) {720return null;721}722723// if it doesn't start with a prefix, it was meant to be positional724if (this.prefixChars.indexOf(argString[0]) < 0) {725return null;726}727728// if the option string is present in the parser, return the action729if (!!this._optionStringActions[argString]) {730return [this._optionStringActions[argString], argString, null];731}732733// if it's just a single character, it was meant to be positional734if (argString.length === 1) {735return null;736}737738// if the option string before the "=" is present, return the action739if (argString.indexOf('=') >= 0) {740var argStringSplit = argString.split('=');741optionString = argStringSplit[0];742argExplicit = argStringSplit[1];743744if (!!this._optionStringActions[optionString]) {745action = this._optionStringActions[optionString];746return [action, optionString, argExplicit];747}748}749750// search through all possible prefixes of the option string751// and all actions in the parser for possible interpretations752optionTuples = this._getOptionTuples(argString);753754// if multiple actions match, the option string was ambiguous755if (optionTuples.length > 1) {756var optionStrings = optionTuples.map(function (optionTuple) {757return optionTuple[1];758});759this.error(format(760'Ambiguous option: "%s" could match %s.',761argString, optionStrings.join(', ')762));763// if exactly one action matched, this segmentation is good,764// so return the parsed action765} else if (optionTuples.length === 1) {766return optionTuples[0];767}768769// if it was not found as an option, but it looks like a negative770// number, it was meant to be positional771// unless there are negative-number-like options772if (argString.match(this._regexpNegativeNumber)) {773if (!_.any(this._hasNegativeNumberOptionals)) {774return null;775}776}777// if it contains a space, it was meant to be a positional778if (argString.search(' ') >= 0) {779return null;780}781782// it was meant to be an optional but there is no such option783// in this parser (though it might be a valid option in a subparser)784return [null, argString, null];785};786787ArgumentParser.prototype._getOptionTuples = function (optionString) {788var result = [];789var chars = this.prefixChars;790var optionPrefix;791var argExplicit;792var action;793var actionOptionString;794795// option strings starting with two prefix characters are only split at796// the '='797if (chars.indexOf(optionString[0]) >= 0 && chars.indexOf(optionString[1]) >= 0) {798if (optionString.indexOf('=') >= 0) {799var optionStringSplit = optionString.split('=', 1);800801optionPrefix = optionStringSplit[0];802argExplicit = optionStringSplit[1];803} else {804optionPrefix = optionString;805argExplicit = null;806}807808for (actionOptionString in this._optionStringActions) {809if (actionOptionString.substr(0, optionPrefix.length) === optionPrefix) {810action = this._optionStringActions[actionOptionString];811result.push([action, actionOptionString, argExplicit]);812}813}814815// single character options can be concatenated with their arguments816// but multiple character options always have to have their argument817// separate818} else if (chars.indexOf(optionString[0]) >= 0 && chars.indexOf(optionString[1]) < 0) {819optionPrefix = optionString;820argExplicit = null;821var optionPrefixShort = optionString.substr(0, 2);822var argExplicitShort = optionString.substr(2);823824for (actionOptionString in this._optionStringActions) {825action = this._optionStringActions[actionOptionString];826if (actionOptionString === optionPrefixShort) {827result.push([action, actionOptionString, argExplicitShort]);828} else if (actionOptionString.substr(0, optionPrefix.length) === optionPrefix) {829result.push([action, actionOptionString, argExplicit]);830}831}832833// shouldn't ever get here834} else {835throw new Error(format('Unexpected option string: %s.', optionString));836}837// return the collected option tuples838return result;839};840841ArgumentParser.prototype._getNargsPattern = function (action) {842// in all examples below, we have to allow for '--' args843// which are represented as '-' in the pattern844var regexpNargs;845846switch (action.nargs) {847// the default (null) is assumed to be a single argument848case undefined:849case null:850regexpNargs = '(-*A-*)';851break;852// allow zero or more arguments853case $$.OPTIONAL:854regexpNargs = '(-*A?-*)';855break;856// allow zero or more arguments857case $$.ZERO_OR_MORE:858regexpNargs = '(-*[A-]*)';859break;860// allow one or more arguments861case $$.ONE_OR_MORE:862regexpNargs = '(-*A[A-]*)';863break;864// allow any number of options or arguments865case $$.REMAINDER:866regexpNargs = '([-AO]*)';867break;868// allow one argument followed by any number of options or arguments869case $$.PARSER:870regexpNargs = '(-*A[-AO]*)';871break;872// all others should be integers873default:874regexpNargs = '(-*' + _.repeat('-*A', action.nargs) + '-*)';875}876877// if this is an optional action, -- is not allowed878if (action.isOptional()) {879regexpNargs = regexpNargs.replace(/-\*/g, '');880regexpNargs = regexpNargs.replace(/-/g, '');881}882883// return the pattern884return regexpNargs;885};886887//888// Value conversion methods889//890891ArgumentParser.prototype._getValues = function (action, argStrings) {892var self = this;893894// for everything but PARSER args, strip out '--'895if (action.nargs !== $$.PARSER && action.nargs !== $$.REMAINDER) {896argStrings = argStrings.filter(function (arrayElement) {897return arrayElement !== '--';898});899}900901var value, argString;902903// optional argument produces a default when not present904if (argStrings.length === 0 && action.nargs === $$.OPTIONAL) {905906value = (action.isOptional()) ? action.constant: action.defaultValue;907908if (typeof(value) === 'string') {909value = this._getValue(action, value);910this._checkValue(action, value);911}912913// when nargs='*' on a positional, if there were no command-line914// args, use the default if it is anything other than None915} else if (argStrings.length === 0 && action.nargs === $$.ZERO_OR_MORE &&916action.optionStrings.length === 0) {917918value = (action.defaultValue || argStrings);919this._checkValue(action, value);920921// single argument or optional argument produces a single value922} else if (argStrings.length === 1 &&923(!action.nargs || action.nargs === $$.OPTIONAL)) {924925argString = argStrings[0];926value = this._getValue(action, argString);927this._checkValue(action, value);928929// REMAINDER arguments convert all values, checking none930} else if (action.nargs === $$.REMAINDER) {931value = argStrings.map(function (v) {932return self._getValue(action, v);933});934935// PARSER arguments convert all values, but check only the first936} else if (action.nargs === $$.PARSER) {937value = argStrings.map(function (v) {938return self._getValue(action, v);939});940this._checkValue(action, value[0]);941942// all other types of nargs produce a list943} else {944value = argStrings.map(function (v) {945return self._getValue(action, v);946});947value.forEach(function (v) {948self._checkValue(action, v);949});950}951952// return the converted value953return value;954};955956ArgumentParser.prototype._getValue = function (action, argString) {957var result;958959var typeFunction = this._registryGet('type', action.type, action.type);960if (!_.isFunction(typeFunction)) {961var message = format('%s is not callable', typeFunction);962throw argumentErrorHelper(action, message);963}964965// convert the value to the appropriate type966try {967result = typeFunction(argString);968969// ArgumentTypeErrors indicate errors970// If action.type is not a registered string, it is a function971// Try to deduce its name for inclusion in the error message972// Failing that, include the error message it raised.973} catch (e) {974var name = null;975if (_.isString(action.type)) {976name = action.type;977} else {978name = action.type.name || action.type.displayName || '<function>';979}980var msg = format('Invalid %s value: %s', name, argString);981if (name === '<function>') {msg += '\n' + e.message; }982throw argumentErrorHelper(action, msg);983}984// return the converted value985return result;986};987988ArgumentParser.prototype._checkValue = function (action, value) {989// converted value must be one of the choices (if specified)990var choices = action.choices;991if (!!choices) {992// choise for argument can by array or string993if ((_.isString(choices) || _.isArray(choices)) &&994choices.indexOf(value) !== -1) {995return;996}997// choise for subparsers can by only hash998if (_.isObject(choices) && !_.isArray(choices) && choices[value]) {999return;1000}10011002if (_.isString(choices)) {1003choices = choices.split('').join(', ');1004}1005else if (_.isArray(choices)) {1006choices = choices.join(', ');1007}1008else {1009choices = _.keys(choices).join(', ');1010}1011var message = format('Invalid choice: %s (choose from [%s])', value, choices);1012throw argumentErrorHelper(action, message);1013}1014};10151016//1017// Help formatting methods1018//10191020/**1021* ArgumentParser#formatUsage -> string1022*1023* Return usage string1024*1025* See also [original guide][1]1026*1027* [1]:http://docs.python.org/dev/library/argparse.html#printing-help1028**/1029ArgumentParser.prototype.formatUsage = function () {1030var formatter = this._getFormatter();1031formatter.addUsage(this.usage, this._actions, this._mutuallyExclusiveGroups);1032return formatter.formatHelp();1033};10341035/**1036* ArgumentParser#formatHelp -> string1037*1038* Return help1039*1040* See also [original guide][1]1041*1042* [1]:http://docs.python.org/dev/library/argparse.html#printing-help1043**/1044ArgumentParser.prototype.formatHelp = function () {1045var formatter = this._getFormatter();10461047// usage1048formatter.addUsage(this.usage, this._actions, this._mutuallyExclusiveGroups);10491050// description1051formatter.addText(this.description);10521053// positionals, optionals and user-defined groups1054this._actionGroups.forEach(function (actionGroup) {1055formatter.startSection(actionGroup.title);1056formatter.addText(actionGroup.description);1057formatter.addArguments(actionGroup._groupActions);1058formatter.endSection();1059});10601061// epilog1062formatter.addText(this.epilog);10631064// determine help from format above1065return formatter.formatHelp();1066};10671068ArgumentParser.prototype._getFormatter = function () {1069var FormatterClass = this.formatterClass;1070var formatter = new FormatterClass({prog: this.prog});1071return formatter;1072};10731074//1075// Print functions1076//10771078/**1079* ArgumentParser#printUsage() -> Void1080*1081* Print usage1082*1083* See also [original guide][1]1084*1085* [1]:http://docs.python.org/dev/library/argparse.html#printing-help1086**/1087ArgumentParser.prototype.printUsage = function () {1088this._printMessage(this.formatUsage());1089};10901091/**1092* ArgumentParser#printHelp() -> Void1093*1094* Print help1095*1096* See also [original guide][1]1097*1098* [1]:http://docs.python.org/dev/library/argparse.html#printing-help1099**/1100ArgumentParser.prototype.printHelp = function () {1101this._printMessage(this.formatHelp());1102};11031104ArgumentParser.prototype._printMessage = function (message, stream) {1105if (!stream) {1106stream = process.stdout;1107}1108if (message) {1109stream.write('' + message);1110}1111};11121113//1114// Exit functions1115//11161117/**1118* ArgumentParser#exit(status=0, message) -> Void1119* - status (int): exit status1120* - message (string): message1121*1122* Print message in stderr/stdout and exit program1123**/1124ArgumentParser.prototype.exit = function (status, message) {1125if (!!message) {1126if (status === 0) {1127this._printMessage(message);1128}1129else {1130this._printMessage(message, process.stderr);1131}1132}11331134process.exit(status);1135};11361137/**1138* ArgumentParser#error(message) -> Void1139* - err (Error|string): message1140*1141* Error method Prints a usage message incorporating the message to stderr and1142* exits. If you override this in a subclass,1143* it should not return -- it should1144* either exit or throw an exception.1145*1146**/1147ArgumentParser.prototype.error = function (err) {1148var message;1149if (err instanceof Error) {1150if (this.debug === true) {1151throw err;1152}1153message = err.message;1154}1155else {1156message = err;1157}1158var msg = format('%s: error: %s', this.prog, message) + $$.EOL;11591160if (this.debug === true) {1161throw new Error(msg);1162}11631164this.printUsage(process.stderr);11651166return this.exit(2, msg);1167};116811691170