subparsers.js (3590B)
1 /** internal 2 * class ActionSubparsers 3 * 4 * Support the creation of such sub-commands with the addSubparsers() 5 * 6 * This class inherited from [[Action]] 7 **/ 8 'use strict'; 9 10 var util = require('util'); 11 var format = require('util').format; 12 13 14 var Action = require('../action'); 15 16 // Constants 17 var c = require('../const'); 18 19 // Errors 20 var argumentErrorHelper = require('../argument/error'); 21 22 23 /*:nodoc:* 24 * new ChoicesPseudoAction(name, help) 25 * 26 * Create pseudo action for correct help text 27 * 28 **/ 29 function ChoicesPseudoAction(name, help) { 30 var options = { 31 optionStrings: [], 32 dest: name, 33 help: help 34 }; 35 36 Action.call(this, options); 37 } 38 39 util.inherits(ChoicesPseudoAction, Action); 40 41 /** 42 * new ActionSubparsers(options) 43 * - options (object): options hash see [[Action.new]] 44 * 45 **/ 46 function ActionSubparsers(options) { 47 options = options || {}; 48 options.dest = options.dest || c.SUPPRESS; 49 options.nargs = c.PARSER; 50 51 this.debug = (options.debug === true); 52 53 this._progPrefix = options.prog; 54 this._parserClass = options.parserClass; 55 this._nameParserMap = {}; 56 this._choicesActions = []; 57 58 options.choices = this._nameParserMap; 59 Action.call(this, options); 60 } 61 62 util.inherits(ActionSubparsers, Action); 63 64 /*:nodoc:* 65 * ActionSubparsers#addParser(name, options) -> ArgumentParser 66 * - name (string): sub-command name 67 * - options (object): see [[ArgumentParser.new]] 68 * 69 * Note: 70 * addParser supports an additional aliases option, 71 * which allows multiple strings to refer to the same subparser. 72 * This example, like svn, aliases co as a shorthand for checkout 73 * 74 **/ 75 ActionSubparsers.prototype.addParser = function (name, options) { 76 var parser; 77 78 var self = this; 79 80 options = options || {}; 81 82 options.debug = (this.debug === true); 83 84 // set program from the existing prefix 85 if (!options.prog) { 86 options.prog = this._progPrefix + ' ' + name; 87 } 88 89 var aliases = options.aliases || []; 90 91 // create a pseudo-action to hold the choice help 92 if (!!options.help || typeof options.help === 'string') { 93 var help = options.help; 94 delete options.help; 95 96 var choiceAction = new ChoicesPseudoAction(name, help); 97 this._choicesActions.push(choiceAction); 98 } 99 100 // create the parser and add it to the map 101 parser = new this._parserClass(options); 102 this._nameParserMap[name] = parser; 103 104 // make parser available under aliases also 105 aliases.forEach(function (alias) { 106 self._nameParserMap[alias] = parser; 107 }); 108 109 return parser; 110 }; 111 112 ActionSubparsers.prototype._getSubactions = function () { 113 return this._choicesActions; 114 }; 115 116 /*:nodoc:* 117 * ActionSubparsers#call(parser, namespace, values, optionString) -> Void 118 * - parser (ArgumentParser): current parser 119 * - namespace (Namespace): namespace for output data 120 * - values (Array): parsed values 121 * - optionString (Array): input option string(not parsed) 122 * 123 * Call the action. Parse input aguments 124 **/ 125 ActionSubparsers.prototype.call = function (parser, namespace, values) { 126 var parserName = values[0]; 127 var argStrings = values.slice(1); 128 129 // set the parser name if requested 130 if (this.dest !== c.SUPPRESS) { 131 namespace[this.dest] = parserName; 132 } 133 134 // select the parser 135 if (this._nameParserMap[parserName]) { 136 parser = this._nameParserMap[parserName]; 137 } else { 138 throw argumentErrorHelper(format( 139 'Unknown parser "%s" (choices: [%s]).', 140 parserName, 141 Object.keys(this._nameParserMap).join(', ') 142 )); 143 } 144 145 // parse all the remaining options into the namespace 146 parser.parseArgs(argStrings, namespace); 147 }; 148 149 module.exports = ActionSubparsers;