BVB Source Codes

reactide Show argument_parser.js Source code

Return Download reactide: download argument_parser.js Source code - Download reactide Source code - Type:.js
  1. /**
  2.  * class ArgumentParser
  3.  *
  4.  * Object for parsing command line strings into js objects.
  5.  *
  6.  * Inherited from [[ActionContainer]]
  7.  **/
  8. 'use strict';
  9.  
  10. var util    = require('util');
  11. var format  = require('util').format;
  12. var Path    = require('path');
  13. var sprintf = require('sprintf-js').sprintf;
  14.  
  15. // Constants
  16. var c = require('./const');
  17.  
  18. var $$ = require('./utils');
  19.  
  20. var ActionContainer = require('./action_container');
  21.  
  22. // Errors
  23. var argumentErrorHelper = require('./argument/error');
  24.  
  25. var HelpFormatter = require('./help/formatter');
  26.  
  27. var Namespace = require('./namespace');
  28.  
  29.  
  30. /**
  31.  * new ArgumentParser(options)
  32.  *
  33.  * Create a new ArgumentParser object.
  34.  *
  35.  * ##### Options:
  36.  * - `prog`  The name of the program (default: Path.basename(process.argv[1]))
  37.  * - `usage`  A usage message (default: auto-generated from arguments)
  38.  * - `description`  A description of what the program does
  39.  * - `epilog`  Text following the argument descriptions
  40.  * - `parents`  Parsers whose arguments should be copied into this one
  41.  * - `formatterClass`  HelpFormatter class for printing help messages
  42.  * - `prefixChars`  Characters that prefix optional arguments
  43.  * - `fromfilePrefixChars` Characters that prefix files containing additional arguments
  44.  * - `argumentDefault`  The default value for all arguments
  45.  * - `addHelp`  Add a -h/-help option
  46.  * - `conflictHandler`  Specifies how to handle conflicting argument names
  47.  * - `debug`  Enable debug mode. Argument errors throw exception in
  48.  *   debug mode and process.exit in normal. Used for development and
  49.  *   testing (default: false)
  50.  *
  51.  * See also [original guide][1]
  52.  *
  53.  * [1]:http://docs.python.org/dev/library/argparse.html#argumentparser-objects
  54.  **/
  55. function ArgumentParser(options) {
  56.   if (!(this instanceof ArgumentParser)) {
  57.     return new ArgumentParser(options);
  58.   }
  59.   var self = this;
  60.   options = options || {};
  61.  
  62.   options.description = (options.description || null);
  63.   options.argumentDefault = (options.argumentDefault || null);
  64.   options.prefixChars = (options.prefixChars || '-');
  65.   options.conflictHandler = (options.conflictHandler || 'error');
  66.   ActionContainer.call(this, options);
  67.  
  68.   options.addHelp = typeof options.addHelp === 'undefined' || !!options.addHelp;
  69.   options.parents = options.parents || [];
  70.   // default program name
  71.   options.prog = (options.prog || Path.basename(process.argv[1]));
  72.   this.prog = options.prog;
  73.   this.usage = options.usage;
  74.   this.epilog = options.epilog;
  75.   this.version = options.version;
  76.  
  77.   this.debug = (options.debug === true);
  78.  
  79.   this.formatterClass = (options.formatterClass || HelpFormatter);
  80.   this.fromfilePrefixChars = options.fromfilePrefixChars || null;
  81.   this._positionals = this.addArgumentGroup({ title: 'Positional arguments' });
  82.   this._optionals = this.addArgumentGroup({ title: 'Optional arguments' });
  83.   this._subparsers = null;
  84.  
  85.   // register types
  86.   function FUNCTION_IDENTITY(o) {
  87.     return o;
  88.   }
  89.   this.register('type', 'auto', FUNCTION_IDENTITY);
  90.   this.register('type', null, FUNCTION_IDENTITY);
  91.   this.register('type', 'int', function (x) {
  92.     var result = parseInt(x, 10);
  93.     if (isNaN(result)) {
  94.       throw new Error(x + ' is not a valid integer.');
  95.     }
  96.     return result;
  97.   });
  98.   this.register('type', 'float', function (x) {
  99.     var result = parseFloat(x);
  100.     if (isNaN(result)) {
  101.       throw new Error(x + ' is not a valid float.');
  102.     }
  103.     return result;
  104.   });
  105.   this.register('type', 'string', function (x) {
  106.     return '' + x;
  107.   });
  108.  
  109.   // add help and version arguments if necessary
  110.   var defaultPrefix = (this.prefixChars.indexOf('-') > -1) ? '-' : this.prefixChars[0];
  111.   if (options.addHelp) {
  112.     this.addArgument(
  113.       [ defaultPrefix + 'h', defaultPrefix + defaultPrefix + 'help' ],
  114.       {
  115.         action: 'help',
  116.         defaultValue: c.SUPPRESS,
  117.         help: 'Show this help message and exit.'
  118.       }
  119.     );
  120.   }
  121.   if (typeof this.version !== 'undefined') {
  122.     this.addArgument(
  123.       [ defaultPrefix + 'v', defaultPrefix + defaultPrefix + 'version' ],
  124.       {
  125.         action: 'version',
  126.         version: this.version,
  127.         defaultValue: c.SUPPRESS,
  128.         help: "Show program's version number and exit."
  129.       }
  130.     );
  131.   }
  132.  
  133.   // add parent arguments and defaults
  134.   options.parents.forEach(function (parent) {
  135.     self._addContainerActions(parent);
  136.     if (typeof parent._defaults !== 'undefined') {
  137.       for (var defaultKey in parent._defaults) {
  138.         if (parent._defaults.hasOwnProperty(defaultKey)) {
  139.           self._defaults[defaultKey] = parent._defaults[defaultKey];
  140.         }
  141.       }
  142.     }
  143.   });
  144. }
  145.  
  146. util.inherits(ArgumentParser, ActionContainer);
  147.  
  148. /**
  149.  * ArgumentParser#addSubparsers(options) -> [[ActionSubparsers]]
  150.  * - options (object): hash of options see [[ActionSubparsers.new]]
  151.  *
  152.  * See also [subcommands][1]
  153.  *
  154.  * [1]:http://docs.python.org/dev/library/argparse.html#sub-commands
  155.  **/
  156. ArgumentParser.prototype.addSubparsers = function (options) {
  157.   if (this._subparsers) {
  158.     this.error('Cannot have multiple subparser arguments.');
  159.   }
  160.  
  161.   options = options || {};
  162.   options.debug = (this.debug === true);
  163.   options.optionStrings = [];
  164.   options.parserClass = (options.parserClass || ArgumentParser);
  165.  
  166.  
  167.   if (!!options.title || !!options.description) {
  168.  
  169.     this._subparsers = this.addArgumentGroup({
  170.       title: (options.title || 'subcommands'),
  171.       description: options.description
  172.     });
  173.     delete options.title;
  174.     delete options.description;
  175.  
  176.   } else {
  177.     this._subparsers = this._positionals;
  178.   }
  179.  
  180.   // prog defaults to the usage message of this parser, skipping
  181.   // optional arguments and with no "usage:" prefix
  182.   if (!options.prog) {
  183.     var formatter = this._getFormatter();
  184.     var positionals = this._getPositionalActions();
  185.     var groups = this._mutuallyExclusiveGroups;
  186.     formatter.addUsage(this.usage, positionals, groups, '');
  187.     options.prog = formatter.formatHelp().trim();
  188.   }
  189.  
  190.   // create the parsers action and add it to the positionals list
  191.   var ParsersClass = this._popActionClass(options, 'parsers');
  192.   var action = new ParsersClass(options);
  193.   this._subparsers._addAction(action);
  194.  
  195.   // return the created parsers action
  196.   return action;
  197. };
  198.  
  199. ArgumentParser.prototype._addAction = function (action) {
  200.   if (action.isOptional()) {
  201.     this._optionals._addAction(action);
  202.   } else {
  203.     this._positionals._addAction(action);
  204.   }
  205.   return action;
  206. };
  207.  
  208. ArgumentParser.prototype._getOptionalActions = function () {
  209.   return this._actions.filter(function (action) {
  210.     return action.isOptional();
  211.   });
  212. };
  213.  
  214. ArgumentParser.prototype._getPositionalActions = function () {
  215.   return this._actions.filter(function (action) {
  216.     return action.isPositional();
  217.   });
  218. };
  219.  
  220.  
  221. /**
  222.  * ArgumentParser#parseArgs(args, namespace) -> Namespace|Object
  223.  * - args (array): input elements
  224.  * - namespace (Namespace|Object): result object
  225.  *
  226.  * Parsed args and throws error if some arguments are not recognized
  227.  *
  228.  * See also [original guide][1]
  229.  *
  230.  * [1]:http://docs.python.org/dev/library/argparse.html#the-parse-args-method
  231.  **/
  232. ArgumentParser.prototype.parseArgs = function (args, namespace) {
  233.   var argv;
  234.   var result = this.parseKnownArgs(args, namespace);
  235.  
  236.   args = result[0];
  237.   argv = result[1];
  238.   if (argv && argv.length > 0) {
  239.     this.error(
  240.       format('Unrecognized arguments: %s.', argv.join(' '))
  241.     );
  242.   }
  243.   return args;
  244. };
  245.  
  246. /**
  247.  * ArgumentParser#parseKnownArgs(args, namespace) -> array
  248.  * - args (array): input options
  249.  * - namespace (Namespace|Object): result object
  250.  *
  251.  * Parse known arguments and return tuple of result object
  252.  * and unknown args
  253.  *
  254.  * See also [original guide][1]
  255.  *
  256.  * [1]:http://docs.python.org/dev/library/argparse.html#partial-parsing
  257.  **/
  258. ArgumentParser.prototype.parseKnownArgs = function (args, namespace) {
  259.   var self = this;
  260.  
  261.   // args default to the system args
  262.   args = args || process.argv.slice(2);
  263.  
  264.   // default Namespace built from parser defaults
  265.   namespace = namespace || new Namespace();
  266.  
  267.   self._actions.forEach(function (action) {
  268.     if (action.dest !== c.SUPPRESS) {
  269.       if (!$$.has(namespace, action.dest)) {
  270.         if (action.defaultValue !== c.SUPPRESS) {
  271.           var defaultValue = action.defaultValue;
  272.           if (typeof action.defaultValue === 'string') {
  273.             defaultValue = self._getValue(action, defaultValue);
  274.           }
  275.           namespace[action.dest] = defaultValue;
  276.         }
  277.       }
  278.     }
  279.   });
  280.  
  281.   Object.keys(self._defaults).forEach(function (dest) {
  282.     namespace[dest] = self._defaults[dest];
  283.   });
  284.  
  285.   // parse the arguments and exit if there are any errors
  286.   try {
  287.     var res = this._parseKnownArgs(args, namespace);
  288.  
  289.     namespace = res[0];
  290.     args = res[1];
  291.     if ($$.has(namespace, c._UNRECOGNIZED_ARGS_ATTR)) {
  292.       args = $$.arrayUnion(args, namespace[c._UNRECOGNIZED_ARGS_ATTR]);
  293.       delete namespace[c._UNRECOGNIZED_ARGS_ATTR];
  294.     }
  295.     return [ namespace, args ];
  296.   } catch (e) {
  297.     this.error(e);
  298.   }
  299. };
  300.  
  301. ArgumentParser.prototype._parseKnownArgs = function (argStrings, namespace) {
  302.   var self = this;
  303.  
  304.   var extras = [];
  305.  
  306.   // replace arg strings that are file references
  307.   if (this.fromfilePrefixChars !== null) {
  308.     argStrings = this._readArgsFromFiles(argStrings);
  309.   }
  310.   // map all mutually exclusive arguments to the other arguments
  311.   // they can't occur with
  312.   // Python has 'conflicts = action_conflicts.setdefault(mutex_action, [])'
  313.   // though I can't conceive of a way in which an action could be a member
  314.   // of two different mutually exclusive groups.
  315.  
  316.   function actionHash(action) {
  317.     // some sort of hashable key for this action
  318.     // action itself cannot be a key in actionConflicts
  319.     // I think getName() (join of optionStrings) is unique enough
  320.     return action.getName();
  321.   }
  322.  
  323.   var conflicts, key;
  324.   var actionConflicts = {};
  325.  
  326.   this._mutuallyExclusiveGroups.forEach(function (mutexGroup) {
  327.     mutexGroup._groupActions.forEach(function (mutexAction, i, groupActions) {
  328.       key = actionHash(mutexAction);
  329.       if (!$$.has(actionConflicts, key)) {
  330.         actionConflicts[key] = [];
  331.       }
  332.       conflicts = actionConflicts[key];
  333.       conflicts.push.apply(conflicts, groupActions.slice(0, i));
  334.       conflicts.push.apply(conflicts, groupActions.slice(i + 1));
  335.     });
  336.   });
  337.  
  338.   // find all option indices, and determine the arg_string_pattern
  339.   // which has an 'O' if there is an option at an index,
  340.   // an 'A' if there is an argument, or a '-' if there is a '--'
  341.   var optionStringIndices = {};
  342.  
  343.   var argStringPatternParts = [];
  344.  
  345.   argStrings.forEach(function (argString, argStringIndex) {
  346.     if (argString === '--') {
  347.       argStringPatternParts.push('-');
  348.       while (argStringIndex < argStrings.length) {
  349.         argStringPatternParts.push('A');
  350.         argStringIndex++;
  351.       }
  352.     } else {
  353.       // otherwise, add the arg to the arg strings
  354.       // and note the index if it was an option
  355.       var pattern;
  356.       var optionTuple = self._parseOptional(argString);
  357.       if (!optionTuple) {
  358.         pattern = 'A';
  359.       } else {
  360.         optionStringIndices[argStringIndex] = optionTuple;
  361.         pattern = 'O';
  362.       }
  363.       argStringPatternParts.push(pattern);
  364.     }
  365.   });
  366.   var argStringsPattern = argStringPatternParts.join('');
  367.  
  368.   var seenActions = [];
  369.   var seenNonDefaultActions = [];
  370.  
  371.  
  372.   function takeAction(action, argumentStrings, optionString) {
  373.     seenActions.push(action);
  374.     var argumentValues = self._getValues(action, argumentStrings);
  375.  
  376.     // error if this argument is not allowed with other previously
  377.     // seen arguments, assuming that actions that use the default
  378.     // value don't really count as "present"
  379.     if (argumentValues !== action.defaultValue) {
  380.       seenNonDefaultActions.push(action);
  381.       if (actionConflicts[actionHash(action)]) {
  382.         actionConflicts[actionHash(action)].forEach(function (actionConflict) {
  383.           if (seenNonDefaultActions.indexOf(actionConflict) >= 0) {
  384.             throw argumentErrorHelper(
  385.               action,
  386.               format('Not allowed with argument "%s".', actionConflict.getName())
  387.             );
  388.           }
  389.         });
  390.       }
  391.     }
  392.  
  393.     if (argumentValues !== c.SUPPRESS) {
  394.       action.call(self, namespace, argumentValues, optionString);
  395.     }
  396.   }
  397.  
  398.   function consumeOptional(startIndex) {
  399.     // get the optional identified at this index
  400.     var optionTuple = optionStringIndices[startIndex];
  401.     var action = optionTuple[0];
  402.     var optionString = optionTuple[1];
  403.     var explicitArg = optionTuple[2];
  404.  
  405.     // identify additional optionals in the same arg string
  406.     // (e.g. -xyz is the same as -x -y -z if no args are required)
  407.     var actionTuples = [];
  408.  
  409.     var args, argCount, start, stop;
  410.  
  411.     for (;;) {
  412.       if (!action) {
  413.         extras.push(argStrings[startIndex]);
  414.         return startIndex + 1;
  415.       }
  416.       if (explicitArg) {
  417.         argCount = self._matchArgument(action, 'A');
  418.  
  419.         // if the action is a single-dash option and takes no
  420.         // arguments, try to parse more single-dash options out
  421.         // of the tail of the option string
  422.         var chars = self.prefixChars;
  423.         if (argCount === 0 && chars.indexOf(optionString[1]) < 0) {
  424.           actionTuples.push([ action, [], optionString ]);
  425.           optionString = optionString[0] + explicitArg[0];
  426.           var newExplicitArg = explicitArg.slice(1) || null;
  427.           var optionalsMap = self._optionStringActions;
  428.  
  429.           if (Object.keys(optionalsMap).indexOf(optionString) >= 0) {
  430.             action = optionalsMap[optionString];
  431.             explicitArg = newExplicitArg;
  432.           } else {
  433.             throw argumentErrorHelper(action, sprintf('ignored explicit argument %r', explicitArg));
  434.           }
  435.         } else if (argCount === 1) {
  436.           // if the action expect exactly one argument, we've
  437.           // successfully matched the option; exit the loop
  438.           stop = startIndex + 1;
  439.           args = [ explicitArg ];
  440.           actionTuples.push([ action, args, optionString ]);
  441.           break;
  442.         } else {
  443.           // error if a double-dash option did not use the
  444.           // explicit argument
  445.           throw argumentErrorHelper(action, sprintf('ignored explicit argument %r', explicitArg));
  446.         }
  447.       } else {
  448.         // if there is no explicit argument, try to match the
  449.         // optional's string arguments with the following strings
  450.         // if successful, exit the loop
  451.  
  452.         start = startIndex + 1;
  453.         var selectedPatterns = argStringsPattern.substr(start);
  454.  
  455.         argCount = self._matchArgument(action, selectedPatterns);
  456.         stop = start + argCount;
  457.  
  458.  
  459.         args = argStrings.slice(start, stop);
  460.  
  461.         actionTuples.push([ action, args, optionString ]);
  462.         break;
  463.       }
  464.  
  465.     }
  466.  
  467.     // add the Optional to the list and return the index at which
  468.     // the Optional's string args stopped
  469.     if (actionTuples.length < 1) {
  470.       throw new Error('length should be > 0');
  471.     }
  472.     for (var i = 0; i < actionTuples.length; i++) {
  473.       takeAction.apply(self, actionTuples[i]);
  474.     }
  475.     return stop;
  476.   }
  477.  
  478.   // the list of Positionals left to be parsed; this is modified
  479.   // by consume_positionals()
  480.   var positionals = self._getPositionalActions();
  481.  
  482.   function consumePositionals(startIndex) {
  483.     // match as many Positionals as possible
  484.     var selectedPattern = argStringsPattern.substr(startIndex);
  485.     var argCounts = self._matchArgumentsPartial(positionals, selectedPattern);
  486.  
  487.     // slice off the appropriate arg strings for each Positional
  488.     // and add the Positional and its args to the list
  489.     for (var i = 0; i < positionals.length; i++) {
  490.       var action = positionals[i];
  491.       var argCount = argCounts[i];
  492.       if (typeof argCount === 'undefined') {
  493.         continue;
  494.       }
  495.       var args = argStrings.slice(startIndex, startIndex + argCount);
  496.  
  497.       startIndex += argCount;
  498.       takeAction(action, args);
  499.     }
  500.  
  501.     // slice off the Positionals that we just parsed and return the
  502.     // index at which the Positionals' string args stopped
  503.     positionals = positionals.slice(argCounts.length);
  504.     return startIndex;
  505.   }
  506.  
  507.   // consume Positionals and Optionals alternately, until we have
  508.   // passed the last option string
  509.   var startIndex = 0;
  510.   var position;
  511.  
  512.   var maxOptionStringIndex = -1;
  513.  
  514.   Object.keys(optionStringIndices).forEach(function (position) {
  515.     maxOptionStringIndex = Math.max(maxOptionStringIndex, parseInt(position, 10));
  516.   });
  517.  
  518.   var positionalsEndIndex, nextOptionStringIndex;
  519.  
  520.   while (startIndex <= maxOptionStringIndex) {
  521.     // consume any Positionals preceding the next option
  522.     nextOptionStringIndex = null;
  523.     for (position in optionStringIndices) {
  524.       if (!optionStringIndices.hasOwnProperty(position)) { continue; }
  525.  
  526.       position = parseInt(position, 10);
  527.       if (position >= startIndex) {
  528.         if (nextOptionStringIndex !== null) {
  529.           nextOptionStringIndex = Math.min(nextOptionStringIndex, position);
  530.         } else {
  531.           nextOptionStringIndex = position;
  532.         }
  533.       }
  534.     }
  535.  
  536.     if (startIndex !== nextOptionStringIndex) {
  537.       positionalsEndIndex = consumePositionals(startIndex);
  538.       // only try to parse the next optional if we didn't consume
  539.       // the option string during the positionals parsing
  540.       if (positionalsEndIndex > startIndex) {
  541.         startIndex = positionalsEndIndex;
  542.         continue;
  543.       } else {
  544.         startIndex = positionalsEndIndex;
  545.       }
  546.     }
  547.  
  548.     // if we consumed all the positionals we could and we're not
  549.     // at the index of an option string, there were extra arguments
  550.     if (!optionStringIndices[startIndex]) {
  551.       var strings = argStrings.slice(startIndex, nextOptionStringIndex);
  552.       extras = extras.concat(strings);
  553.       startIndex = nextOptionStringIndex;
  554.     }
  555.     // consume the next optional and any arguments for it
  556.     startIndex = consumeOptional(startIndex);
  557.   }
  558.  
  559.   // consume any positionals following the last Optional
  560.   var stopIndex = consumePositionals(startIndex);
  561.  
  562.   // if we didn't consume all the argument strings, there were extras
  563.   extras = extras.concat(argStrings.slice(stopIndex));
  564.  
  565.   // if we didn't use all the Positional objects, there were too few
  566.   // arg strings supplied.
  567.   if (positionals.length > 0) {
  568.     self.error('too few arguments');
  569.   }
  570.  
  571.   // make sure all required actions were present
  572.   self._actions.forEach(function (action) {
  573.     if (action.required) {
  574.       if (seenActions.indexOf(action) < 0) {
  575.         self.error(format('Argument "%s" is required', action.getName()));
  576.       }
  577.     }
  578.   });
  579.  
  580.   // make sure all required groups have one option present
  581.   var actionUsed = false;
  582.   self._mutuallyExclusiveGroups.forEach(function (group) {
  583.     if (group.required) {
  584.       actionUsed = group._groupActions.some(function (action) {
  585.         return seenNonDefaultActions.indexOf(action) !== -1;
  586.       });
  587.  
  588.       // if no actions were used, report the error
  589.       if (!actionUsed) {
  590.         var names = [];
  591.         group._groupActions.forEach(function (action) {
  592.           if (action.help !== c.SUPPRESS) {
  593.             names.push(action.getName());
  594.           }
  595.         });
  596.         names = names.join(' ');
  597.         var msg = 'one of the arguments ' + names + ' is required';
  598.         self.error(msg);
  599.       }
  600.     }
  601.   });
  602.  
  603.   // return the updated namespace and the extra arguments
  604.   return [ namespace, extras ];
  605. };
  606.  
  607. ArgumentParser.prototype._readArgsFromFiles = function (argStrings) {
  608.   // expand arguments referencing files
  609.   var self = this;
  610.   var fs = require('fs');
  611.   var newArgStrings = [];
  612.   argStrings.forEach(function (argString) {
  613.     if (self.fromfilePrefixChars.indexOf(argString[0]) < 0) {
  614.       // for regular arguments, just add them back into the list
  615.       newArgStrings.push(argString);
  616.     } else {
  617.       // replace arguments referencing files with the file content
  618.       try {
  619.         var argstrs = [];
  620.         var filename = argString.slice(1);
  621.         var content = fs.readFileSync(filename, 'utf8');
  622.         content = content.trim().split('\n');
  623.         content.forEach(function (argLine) {
  624.           self.convertArgLineToArgs(argLine).forEach(function (arg) {
  625.             argstrs.push(arg);
  626.           });
  627.           argstrs = self._readArgsFromFiles(argstrs);
  628.         });
  629.         newArgStrings.push.apply(newArgStrings, argstrs);
  630.       } catch (error) {
  631.         return self.error(error.message);
  632.       }
  633.     }
  634.   });
  635.   return newArgStrings;
  636. };
  637.  
  638. ArgumentParser.prototype.convertArgLineToArgs = function (argLine) {
  639.   return [ argLine ];
  640. };
  641.  
  642. ArgumentParser.prototype._matchArgument = function (action, regexpArgStrings) {
  643.  
  644.   // match the pattern for this action to the arg strings
  645.   var regexpNargs = new RegExp('^' + this._getNargsPattern(action));
  646.   var matches = regexpArgStrings.match(regexpNargs);
  647.   var message;
  648.  
  649.   // throw an exception if we weren't able to find a match
  650.   if (!matches) {
  651.     switch (action.nargs) {
  652.       /*eslint-disable no-undefined*/
  653.       case undefined:
  654.       case null:
  655.         message = 'Expected one argument.';
  656.         break;
  657.       case c.OPTIONAL:
  658.         message = 'Expected at most one argument.';
  659.         break;
  660.       case c.ONE_OR_MORE:
  661.         message = 'Expected at least one argument.';
  662.         break;
  663.       default:
  664.         message = 'Expected %s argument(s)';
  665.     }
  666.  
  667.     throw argumentErrorHelper(
  668.       action,
  669.       format(message, action.nargs)
  670.     );
  671.   }
  672.   // return the number of arguments matched
  673.   return matches[1].length;
  674. };
  675.  
  676. ArgumentParser.prototype._matchArgumentsPartial = function (actions, regexpArgStrings) {
  677.   // progressively shorten the actions list by slicing off the
  678.   // final actions until we find a match
  679.   var self = this;
  680.   var result = [];
  681.   var actionSlice, pattern, matches;
  682.   var i, j;
  683.  
  684.   function getLength(string) {
  685.     return string.length;
  686.   }
  687.  
  688.   for (i = actions.length; i > 0; i--) {
  689.     pattern = '';
  690.     actionSlice = actions.slice(0, i);
  691.     for (j = 0; j < actionSlice.length; j++) {
  692.       pattern += self._getNargsPattern(actionSlice[j]);
  693.     }
  694.  
  695.     pattern = new RegExp('^' + pattern);
  696.     matches = regexpArgStrings.match(pattern);
  697.  
  698.     if (matches && matches.length > 0) {
  699.       // need only groups
  700.       matches = matches.splice(1);
  701.       result = result.concat(matches.map(getLength));
  702.       break;
  703.     }
  704.   }
  705.  
  706.   // return the list of arg string counts
  707.   return result;
  708. };
  709.  
  710. ArgumentParser.prototype._parseOptional = function (argString) {
  711.   var action, optionString, argExplicit, optionTuples;
  712.  
  713.   // if it's an empty string, it was meant to be a positional
  714.   if (!argString) {
  715.     return null;
  716.   }
  717.  
  718.   // if it doesn't start with a prefix, it was meant to be positional
  719.   if (this.prefixChars.indexOf(argString[0]) < 0) {
  720.     return null;
  721.   }
  722.  
  723.   // if the option string is present in the parser, return the action
  724.   if (this._optionStringActions[argString]) {
  725.     return [ this._optionStringActions[argString], argString, null ];
  726.   }
  727.  
  728.   // if it's just a single character, it was meant to be positional
  729.   if (argString.length === 1) {
  730.     return null;
  731.   }
  732.  
  733.   // if the option string before the "=" is present, return the action
  734.   if (argString.indexOf('=') >= 0) {
  735.     optionString = argString.split('=', 1)[0];
  736.     argExplicit = argString.slice(optionString.length + 1);
  737.  
  738.     if (this._optionStringActions[optionString]) {
  739.       action = this._optionStringActions[optionString];
  740.       return [ action, optionString, argExplicit ];
  741.     }
  742.   }
  743.  
  744.   // search through all possible prefixes of the option string
  745.   // and all actions in the parser for possible interpretations
  746.   optionTuples = this._getOptionTuples(argString);
  747.  
  748.   // if multiple actions match, the option string was ambiguous
  749.   if (optionTuples.length > 1) {
  750.     var optionStrings = optionTuples.map(function (optionTuple) {
  751.       return optionTuple[1];
  752.     });
  753.     this.error(format(
  754.           'Ambiguous option: "%s" could match %s.',
  755.           argString, optionStrings.join(', ')
  756.     ));
  757.   // if exactly one action matched, this segmentation is good,
  758.   // so return the parsed action
  759.   } else if (optionTuples.length === 1) {
  760.     return optionTuples[0];
  761.   }
  762.  
  763.   // if it was not found as an option, but it looks like a negative
  764.   // number, it was meant to be positional
  765.   // unless there are negative-number-like options
  766.   if (argString.match(this._regexpNegativeNumber)) {
  767.     if (!this._hasNegativeNumberOptionals.some(Boolean)) {
  768.       return null;
  769.     }
  770.   }
  771.   // if it contains a space, it was meant to be a positional
  772.   if (argString.search(' ') >= 0) {
  773.     return null;
  774.   }
  775.  
  776.   // it was meant to be an optional but there is no such option
  777.   // in this parser (though it might be a valid option in a subparser)
  778.   return [ null, argString, null ];
  779. };
  780.  
  781. ArgumentParser.prototype._getOptionTuples = function (optionString) {
  782.   var result = [];
  783.   var chars = this.prefixChars;
  784.   var optionPrefix;
  785.   var argExplicit;
  786.   var action;
  787.   var actionOptionString;
  788.  
  789.   // option strings starting with two prefix characters are only split at
  790.   // the '='
  791.   if (chars.indexOf(optionString[0]) >= 0 && chars.indexOf(optionString[1]) >= 0) {
  792.     if (optionString.indexOf('=') >= 0) {
  793.       var optionStringSplit = optionString.split('=', 1);
  794.  
  795.       optionPrefix = optionStringSplit[0];
  796.       argExplicit = optionStringSplit[1];
  797.     } else {
  798.       optionPrefix = optionString;
  799.       argExplicit = null;
  800.     }
  801.  
  802.     for (actionOptionString in this._optionStringActions) {
  803.       if (actionOptionString.substr(0, optionPrefix.length) === optionPrefix) {
  804.         action = this._optionStringActions[actionOptionString];
  805.         result.push([ action, actionOptionString, argExplicit ]);
  806.       }
  807.     }
  808.  
  809.   // single character options can be concatenated with their arguments
  810.   // but multiple character options always have to have their argument
  811.   // separate
  812.   } else if (chars.indexOf(optionString[0]) >= 0 && chars.indexOf(optionString[1]) < 0) {
  813.     optionPrefix = optionString;
  814.     argExplicit = null;
  815.     var optionPrefixShort = optionString.substr(0, 2);
  816.     var argExplicitShort = optionString.substr(2);
  817.  
  818.     for (actionOptionString in this._optionStringActions) {
  819.       if (!$$.has(this._optionStringActions, actionOptionString)) continue;
  820.  
  821.       action = this._optionStringActions[actionOptionString];
  822.       if (actionOptionString === optionPrefixShort) {
  823.         result.push([ action, actionOptionString, argExplicitShort ]);
  824.       } else if (actionOptionString.substr(0, optionPrefix.length) === optionPrefix) {
  825.         result.push([ action, actionOptionString, argExplicit ]);
  826.       }
  827.     }
  828.  
  829.   // shouldn't ever get here
  830.   } else {
  831.     throw new Error(format('Unexpected option string: %s.', optionString));
  832.   }
  833.   // return the collected option tuples
  834.   return result;
  835. };
  836.  
  837. ArgumentParser.prototype._getNargsPattern = function (action) {
  838.   // in all examples below, we have to allow for '--' args
  839.   // which are represented as '-' in the pattern
  840.   var regexpNargs;
  841.  
  842.   switch (action.nargs) {
  843.     // the default (null) is assumed to be a single argument
  844.     case undefined:
  845.     case null:
  846.       regexpNargs = '(-*A-*)';
  847.       break;
  848.     // allow zero or more arguments
  849.     case c.OPTIONAL:
  850.       regexpNargs = '(-*A?-*)';
  851.       break;
  852.     // allow zero or more arguments
  853.     case c.ZERO_OR_MORE:
  854.       regexpNargs = '(-*[A-]*)';
  855.       break;
  856.     // allow one or more arguments
  857.     case c.ONE_OR_MORE:
  858.       regexpNargs = '(-*A[A-]*)';
  859.       break;
  860.     // allow any number of options or arguments
  861.     case c.REMAINDER:
  862.       regexpNargs = '([-AO]*)';
  863.       break;
  864.     // allow one argument followed by any number of options or arguments
  865.     case c.PARSER:
  866.       regexpNargs = '(-*A[-AO]*)';
  867.       break;
  868.     // all others should be integers
  869.     default:
  870.       regexpNargs = '(-*' + $$.repeat('-*A', action.nargs) + '-*)';
  871.   }
  872.  
  873.   // if this is an optional action, -- is not allowed
  874.   if (action.isOptional()) {
  875.     regexpNargs = regexpNargs.replace(/-\*/g, '');
  876.     regexpNargs = regexpNargs.replace(/-/g, '');
  877.   }
  878.  
  879.   // return the pattern
  880.   return regexpNargs;
  881. };
  882.  
  883. //
  884. // Value conversion methods
  885. //
  886.  
  887. ArgumentParser.prototype._getValues = function (action, argStrings) {
  888.   var self = this;
  889.  
  890.   // for everything but PARSER args, strip out '--'
  891.   if (action.nargs !== c.PARSER && action.nargs !== c.REMAINDER) {
  892.     argStrings = argStrings.filter(function (arrayElement) {
  893.       return arrayElement !== '--';
  894.     });
  895.   }
  896.  
  897.   var value, argString;
  898.  
  899.   // optional argument produces a default when not present
  900.   if (argStrings.length === 0 && action.nargs === c.OPTIONAL) {
  901.  
  902.     value = (action.isOptional()) ? action.constant : action.defaultValue;
  903.  
  904.     if (typeof (value) === 'string') {
  905.       value = this._getValue(action, value);
  906.       this._checkValue(action, value);
  907.     }
  908.  
  909.   // when nargs='*' on a positional, if there were no command-line
  910.   // args, use the default if it is anything other than None
  911.   } else if (argStrings.length === 0 && action.nargs === c.ZERO_OR_MORE &&
  912.     action.optionStrings.length === 0) {
  913.  
  914.     value = (action.defaultValue || argStrings);
  915.     this._checkValue(action, value);
  916.  
  917.   // single argument or optional argument produces a single value
  918.   } else if (argStrings.length === 1 &&
  919.         (!action.nargs || action.nargs === c.OPTIONAL)) {
  920.  
  921.     argString = argStrings[0];
  922.     value = this._getValue(action, argString);
  923.     this._checkValue(action, value);
  924.  
  925.   // REMAINDER arguments convert all values, checking none
  926.   } else if (action.nargs === c.REMAINDER) {
  927.     value = argStrings.map(function (v) {
  928.       return self._getValue(action, v);
  929.     });
  930.  
  931.   // PARSER arguments convert all values, but check only the first
  932.   } else if (action.nargs === c.PARSER) {
  933.     value = argStrings.map(function (v) {
  934.       return self._getValue(action, v);
  935.     });
  936.     this._checkValue(action, value[0]);
  937.  
  938.   // all other types of nargs produce a list
  939.   } else {
  940.     value = argStrings.map(function (v) {
  941.       return self._getValue(action, v);
  942.     });
  943.     value.forEach(function (v) {
  944.       self._checkValue(action, v);
  945.     });
  946.   }
  947.  
  948.   // return the converted value
  949.   return value;
  950. };
  951.  
  952. ArgumentParser.prototype._getValue = function (action, argString) {
  953.   var result;
  954.  
  955.   var typeFunction = this._registryGet('type', action.type, action.type);
  956.   if (typeof typeFunction !== 'function') {
  957.     var message = format('%s is not callable', typeFunction);
  958.     throw argumentErrorHelper(action, message);
  959.   }
  960.  
  961.   // convert the value to the appropriate type
  962.   try {
  963.     result = typeFunction(argString);
  964.  
  965.     // ArgumentTypeErrors indicate errors
  966.     // If action.type is not a registered string, it is a function
  967.     // Try to deduce its name for inclusion in the error message
  968.     // Failing that, include the error message it raised.
  969.   } catch (e) {
  970.     var name = null;
  971.     if (typeof action.type === 'string') {
  972.       name = action.type;
  973.     } else {
  974.       name = action.type.name || action.type.displayName || '<function>';
  975.     }
  976.     var msg = format('Invalid %s value: %s', name, argString);
  977.     if (name === '<function>') { msg += '\n' + e.message; }
  978.     throw argumentErrorHelper(action, msg);
  979.   }
  980.   // return the converted value
  981.   return result;
  982. };
  983.  
  984. ArgumentParser.prototype._checkValue = function (action, value) {
  985.   // converted value must be one of the choices (if specified)
  986.   var choices = action.choices;
  987.   if (choices) {
  988.     // choise for argument can by array or string
  989.     if ((typeof choices === 'string' || Array.isArray(choices)) &&
  990.         choices.indexOf(value) !== -1) {
  991.       return;
  992.     }
  993.     // choise for subparsers can by only hash
  994.     if (typeof choices === 'object' && !Array.isArray(choices) && choices[value]) {
  995.       return;
  996.     }
  997.  
  998.     if (typeof choices === 'string') {
  999.       choices = choices.split('').join(', ');
  1000.     } else if (Array.isArray(choices)) {
  1001.       choices =  choices.join(', ');
  1002.     } else {
  1003.       choices =  Object.keys(choices).join(', ');
  1004.     }
  1005.     var message = format('Invalid choice: %s (choose from [%s])', value, choices);
  1006.     throw argumentErrorHelper(action, message);
  1007.   }
  1008. };
  1009.  
  1010. //
  1011. // Help formatting methods
  1012. //
  1013.  
  1014. /**
  1015.  * ArgumentParser#formatUsage -> string
  1016.  *
  1017.  * Return usage string
  1018.  *
  1019.  * See also [original guide][1]
  1020.  *
  1021.  * [1]:http://docs.python.org/dev/library/argparse.html#printing-help
  1022.  **/
  1023. ArgumentParser.prototype.formatUsage = function () {
  1024.   var formatter = this._getFormatter();
  1025.   formatter.addUsage(this.usage, this._actions, this._mutuallyExclusiveGroups);
  1026.   return formatter.formatHelp();
  1027. };
  1028.  
  1029. /**
  1030.  * ArgumentParser#formatHelp -> string
  1031.  *
  1032.  * Return help
  1033.  *
  1034.  * See also [original guide][1]
  1035.  *
  1036.  * [1]:http://docs.python.org/dev/library/argparse.html#printing-help
  1037.  **/
  1038. ArgumentParser.prototype.formatHelp = function () {
  1039.   var formatter = this._getFormatter();
  1040.  
  1041.   // usage
  1042.   formatter.addUsage(this.usage, this._actions, this._mutuallyExclusiveGroups);
  1043.  
  1044.   // description
  1045.   formatter.addText(this.description);
  1046.  
  1047.   // positionals, optionals and user-defined groups
  1048.   this._actionGroups.forEach(function (actionGroup) {
  1049.     formatter.startSection(actionGroup.title);
  1050.     formatter.addText(actionGroup.description);
  1051.     formatter.addArguments(actionGroup._groupActions);
  1052.     formatter.endSection();
  1053.   });
  1054.  
  1055.   // epilog
  1056.   formatter.addText(this.epilog);
  1057.  
  1058.   // determine help from format above
  1059.   return formatter.formatHelp();
  1060. };
  1061.  
  1062. ArgumentParser.prototype._getFormatter = function () {
  1063.   var FormatterClass = this.formatterClass;
  1064.   var formatter = new FormatterClass({ prog: this.prog });
  1065.   return formatter;
  1066. };
  1067.  
  1068. //
  1069. //  Print functions
  1070. //
  1071.  
  1072. /**
  1073.  * ArgumentParser#printUsage() -> Void
  1074.  *
  1075.  * Print usage
  1076.  *
  1077.  * See also [original guide][1]
  1078.  *
  1079.  * [1]:http://docs.python.org/dev/library/argparse.html#printing-help
  1080.  **/
  1081. ArgumentParser.prototype.printUsage = function () {
  1082.   this._printMessage(this.formatUsage());
  1083. };
  1084.  
  1085. /**
  1086.  * ArgumentParser#printHelp() -> Void
  1087.  *
  1088.  * Print help
  1089.  *
  1090.  * See also [original guide][1]
  1091.  *
  1092.  * [1]:http://docs.python.org/dev/library/argparse.html#printing-help
  1093.  **/
  1094. ArgumentParser.prototype.printHelp = function () {
  1095.   this._printMessage(this.formatHelp());
  1096. };
  1097.  
  1098. ArgumentParser.prototype._printMessage = function (message, stream) {
  1099.   if (!stream) {
  1100.     stream = process.stdout;
  1101.   }
  1102.   if (message) {
  1103.     stream.write('' + message);
  1104.   }
  1105. };
  1106.  
  1107. //
  1108. //  Exit functions
  1109. //
  1110.  
  1111. /**
  1112.  * ArgumentParser#exit(status=0, message) -> Void
  1113.  * - status (int): exit status
  1114.  * - message (string): message
  1115.  *
  1116.  * Print message in stderr/stdout and exit program
  1117.  **/
  1118. ArgumentParser.prototype.exit = function (status, message) {
  1119.   if (message) {
  1120.     if (status === 0) {
  1121.       this._printMessage(message);
  1122.     } else {
  1123.       this._printMessage(message, process.stderr);
  1124.     }
  1125.   }
  1126.  
  1127.   process.exit(status);
  1128. };
  1129.  
  1130. /**
  1131.  * ArgumentParser#error(message) -> Void
  1132.  * - err (Error|string): message
  1133.  *
  1134.  * Error method Prints a usage message incorporating the message to stderr and
  1135.  * exits. If you override this in a subclass,
  1136.  * it should not return -- it should
  1137.  * either exit or throw an exception.
  1138.  *
  1139.  **/
  1140. ArgumentParser.prototype.error = function (err) {
  1141.   var message;
  1142.   if (err instanceof Error) {
  1143.     if (this.debug === true) {
  1144.       throw err;
  1145.     }
  1146.     message = err.message;
  1147.   } else {
  1148.     message = err;
  1149.   }
  1150.   var msg = format('%s: error: %s', this.prog, message) + c.EOL;
  1151.  
  1152.   if (this.debug === true) {
  1153.     throw new Error(msg);
  1154.   }
  1155.  
  1156.   this.printUsage(process.stderr);
  1157.  
  1158.   return this.exit(2, msg);
  1159. };
  1160.  
  1161. module.exports = ArgumentParser;
  1162.  
downloadargument_parser.js Source code - Download reactide Source code
Related Source Codes/Software:
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
postal - 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top