Umama-at-Bluchip/Quick-UI
0
1/**2 * Module dependencies.3 */4 5var EventEmitter = require('events').EventEmitter;6var spawn = require('child_process').spawn;7var path = require('path');8var dirname = path.dirname;9var basename = path.basename;10var fs = require('fs');11 12/**13 * Inherit `Command` from `EventEmitter.prototype`.14 */15 16require('util').inherits(Command, EventEmitter);17 18/**19 * Expose the root command.20 */21 22exports = module.exports = new Command();23 24/**25 * Expose `Command`.26 */27 28exports.Command = Command;29 30/**31 * Expose `Option`.32 */33 34exports.Option = Option;35 36/**37 * Initialize a new `Option` with the given `flags` and `description`.38 *39 * @param {String} flags40 * @param {String} description41 * @api public42 */43 44function Option(flags, description) {45 this.flags = flags;46 this.required = flags.indexOf('<') >= 0; // A value must be supplied when the option is specified.47 this.optional = flags.indexOf('[') >= 0; // A value is optional when the option is specified.48 this.mandatory = false; // The option must have a value after parsing, which usually means it must be specified on command line.49 this.negate = flags.indexOf('-no-') !== -1;50 flags = flags.split(/[ ,|]+/);51 if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();52 this.long = flags.shift();53 this.description = description || '';54}55 56/**57 * Return option name.58 *59 * @return {String}60 * @api private61 */62 63Option.prototype.name = function() {64 return this.long.replace(/^--/, '');65};66 67/**68 * Return option name, in a camelcase format that can be used69 * as a object attribute key.70 *71 * @return {String}72 * @api private73 */74 75Option.prototype.attributeName = function() {76 return camelcase(this.name().replace(/^no-/, ''));77};78 79/**80 * Check if `arg` matches the short or long flag.81 *82 * @param {String} arg83 * @return {Boolean}84 * @api private85 */86 87Option.prototype.is = function(arg) {88 return this.short === arg || this.long === arg;89};90 91/**92 * CommanderError class93 * @class94 */95class CommanderError extends Error {96 /**97 * Constructs the CommanderError class98 * @param {Number} exitCode suggested exit code which could be used with process.exit99 * @param {String} code an id string representing the error100 * @param {String} message human-readable description of the error101 * @constructor102 */103 constructor(exitCode, code, message) {104 super(message);105 // properly capture stack trace in Node.js106 Error.captureStackTrace(this, this.constructor);107 this.name = this.constructor.name;108 this.code = code;109 this.exitCode = exitCode;110 }111}112 113exports.CommanderError = CommanderError;114 115/**116 * Initialize a new `Command`.117 *118 * @param {String} [name]119 * @api public120 */121 122function Command(name) {123 this.commands = [];124 this.options = [];125 this._execs = new Set();126 this._allowUnknownOption = false;127 this._args = [];128 this._name = name || '';129 this._optionValues = {};130 this._storeOptionsAsProperties = true; // backwards compatible by default131 this._passCommandToAction = true; // backwards compatible by default132 this._actionResults = [];133 134 this._helpFlags = '-h, --help';135 this._helpDescription = 'output usage information';136 this._helpShortFlag = '-h';137 this._helpLongFlag = '--help';138}139 140/**141 * Define a command.142 *143 * There are two styles of command: pay attention to where to put the description.144 *145 * Examples:146 *147 * // Command implemented using action handler (description is supplied separately to `.command`)148 * program149 * .command('clone <source> [destination]')150 * .description('clone a repository into a newly created directory')151 * .action((source, destination) => {152 * console.log('clone command called');153 * });154 *155 * // Command implemented using separate executable file (description is second parameter to `.command`)156 * program157 * .command('start <service>', 'start named service')158 * .command('stop [service]', 'stop named service, or all if no name supplied');159 *160 * @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`161 * @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)162 * @param {Object} [execOpts] - configuration options (for executable)163 * @return {Command} returns new command for action handler, or top-level command for executable command164 * @api public165 */166 167Command.prototype.command = function(nameAndArgs, actionOptsOrExecDesc, execOpts) {168 var desc = actionOptsOrExecDesc;169 var opts = execOpts;170 if (typeof desc === 'object' && desc !== null) {171 opts = desc;172 desc = null;173 }174 opts = opts || {};175 var args = nameAndArgs.split(/ +/);176 var cmd = new Command(args.shift());177 178 if (desc) {179 cmd.description(desc);180 this.executables = true;181 this._execs.add(cmd._name);182 if (opts.isDefault) this.defaultExecutable = cmd._name;183 }184 cmd._noHelp = !!opts.noHelp;185 cmd._helpFlags = this._helpFlags;186 cmd._helpDescription = this._helpDescription;187 cmd._helpShortFlag = this._helpShortFlag;188 cmd._helpLongFlag = this._helpLongFlag;189 cmd._exitCallback = this._exitCallback;190 cmd._storeOptionsAsProperties = this._storeOptionsAsProperties;191 cmd._passCommandToAction = this._passCommandToAction;192 193 cmd._executableFile = opts.executableFile; // Custom name for executable file194 this.commands.push(cmd);195 cmd.parseExpectedArgs(args);196 cmd.parent = this;197 198 if (desc) return this;199 return cmd;200};201 202/**203 * Define argument syntax for the top-level command.204 *205 * @api public206 */207 208Command.prototype.arguments = function(desc) {209 return this.parseExpectedArgs(desc.split(/ +/));210};211 212/**213 * Add an implicit `help [cmd]` subcommand214 * which invokes `--help` for the given command.215 *216 * @api private217 */218 219Command.prototype.addImplicitHelpCommand = function() {220 this.command('help [cmd]', 'display help for [cmd]');221};222 223/**224 * Parse expected `args`.225 *226 * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.227 *228 * @param {Array} args229 * @return {Command} for chaining230 * @api public231 */232 233Command.prototype.parseExpectedArgs = function(args) {234 if (!args.length) return;235 var self = this;236 args.forEach(function(arg) {237 var argDetails = {238 required: false,239 name: '',240 variadic: false241 };242 243 switch (arg[0]) {244 case '<':245 argDetails.required = true;246 argDetails.name = arg.slice(1, -1);247 break;248 case '[':249 argDetails.name = arg.slice(1, -1);250 break;251 }252 253 if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {254 argDetails.variadic = true;255 argDetails.name = argDetails.name.slice(0, -3);256 }257 if (argDetails.name) {258 self._args.push(argDetails);259 }260 });261 return this;262};263 264/**265 * Register callback to use as replacement for calling process.exit.266 *267 * @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing268 * @return {Command} for chaining269 * @api public270 */271 272Command.prototype.exitOverride = function(fn) {273 if (fn) {274 this._exitCallback = fn;275 } else {276 this._exitCallback = function(err) {277 if (err.code !== 'commander.executeSubCommandAsync') {278 throw err;279 } else {280 // Async callback from spawn events, not useful to throw.281 }282 };283 }284 return this;285};286 287/**288 * Call process.exit, and _exitCallback if defined.289 *290 * @param {Number} exitCode exit code for using with process.exit291 * @param {String} code an id string representing the error292 * @param {String} message human-readable description of the error293 * @return never294 * @api private295 */296 297Command.prototype._exit = function(exitCode, code, message) {298 if (this._exitCallback) {299 this._exitCallback(new CommanderError(exitCode, code, message));300 // Expecting this line is not reached.301 }302 process.exit(exitCode);303};304 305/**306 * Register callback `fn` for the command.307 *308 * Examples:309 *310 * program311 * .command('help')312 * .description('display verbose help')313 * .action(function() {314 * // output help here315 * });316 *317 * @param {Function} fn318 * @return {Command} for chaining319 * @api public320 */321 322Command.prototype.action = function(fn) {323 var self = this;324 var listener = function(args, unknown) {325 // Parse any so-far unknown options326 args = args || [];327 unknown = unknown || [];328 329 var parsed = self.parseOptions(unknown);330 331 // Output help if necessary332 outputHelpIfRequested(self, parsed.unknown);333 self._checkForMissingMandatoryOptions();334 335 // If there are still any unknown options, then we simply336 // die, unless someone asked for help, in which case we give it337 // to them, and then we die.338 if (parsed.unknown.length > 0) {339 self.unknownOption(parsed.unknown[0]);340 }341 342 // Leftover arguments need to be pushed back. Fixes issue #56343 if (parsed.args.length) args = parsed.args.concat(args);344 345 self._args.forEach(function(arg, i) {346 if (arg.required && args[i] == null) {347 self.missingArgument(arg.name);348 } else if (arg.variadic) {349 if (i !== self._args.length - 1) {350 self.variadicArgNotLast(arg.name);351 }352 353 args[i] = args.splice(i);354 }355 });356 357 // The .action callback takes an extra parameter which is the command itself.358 var expectedArgsCount = self._args.length;359 var actionArgs = args.slice(0, expectedArgsCount);360 if (self._passCommandToAction) {361 actionArgs[expectedArgsCount] = self;362 } else {363 actionArgs[expectedArgsCount] = self.opts();364 }365 // Add the extra arguments so available too.366 if (args.length > expectedArgsCount) {367 actionArgs.push(args.slice(expectedArgsCount));368 }369 370 const actionResult = fn.apply(self, actionArgs);371 // Remember result in case it is async. Assume parseAsync getting called on root.372 let rootCommand = self;373 while (rootCommand.parent) {374 rootCommand = rootCommand.parent;375 }376 rootCommand._actionResults.push(actionResult);377 };378 var parent = this.parent || this;379 var name = parent === this ? '*' : this._name;380 parent.on('command:' + name, listener);381 if (this._alias) parent.on('command:' + this._alias, listener);382 return this;383};384 385/**386 * Internal implementation shared by .option() and .requiredOption()387 *388 * @param {Object} config389 * @param {String} flags390 * @param {String} description391 * @param {Function|*} [fn] - custom option processing function or default vaue392 * @param {*} [defaultValue]393 * @return {Command} for chaining394 * @api private395 */396 397Command.prototype._optionEx = function(config, flags, description, fn, defaultValue) {398 var self = this,399 option = new Option(flags, description),400 oname = option.name(),401 name = option.attributeName();402 option.mandatory = !!config.mandatory;403 404 // default as 3rd arg405 if (typeof fn !== 'function') {406 if (fn instanceof RegExp) {407 // This is a bit simplistic (especially no error messages), and probably better handled by caller using custom option processing.408 // No longer documented in README, but still present for backwards compatibility.409 var regex = fn;410 fn = function(val, def) {411 var m = regex.exec(val);412 return m ? m[0] : def;413 };414 } else {415 defaultValue = fn;416 fn = null;417 }418 }419 420 // preassign default value for --no-*, [optional], <required>, or plain flag if boolean value421 if (option.negate || option.optional || option.required || typeof defaultValue === 'boolean') {422 // when --no-foo we make sure default is true, unless a --foo option is already defined423 if (option.negate) {424 const positiveLongFlag = option.long.replace(/^--no-/, '--');425 defaultValue = self.optionFor(positiveLongFlag) ? self._getOptionValue(name) : true;426 }427 // preassign only if we have a default428 if (defaultValue !== undefined) {429 self._setOptionValue(name, defaultValue);430 option.defaultValue = defaultValue;431 }432 }433 434 // register the option435 this.options.push(option);436 437 // when it's passed assign the value438 // and conditionally invoke the callback439 this.on('option:' + oname, function(val) {440 // coercion441 if (val !== null && fn) {442 val = fn(val, self._getOptionValue(name) === undefined ? defaultValue : self._getOptionValue(name));443 }444 445 // unassigned or boolean value446 if (typeof self._getOptionValue(name) === 'boolean' || typeof self._getOptionValue(name) === 'undefined') {447 // if no value, negate false, and we have a default, then use it!448 if (val == null) {449 self._setOptionValue(name, option.negate450 ? false451 : defaultValue || true);452 } else {453 self._setOptionValue(name, val);454 }455 } else if (val !== null) {456 // reassign457 self._setOptionValue(name, option.negate ? false : val);458 }459 });460 461 return this;462};463 464/**465 * Define option with `flags`, `description` and optional466 * coercion `fn`.467 *468 * The `flags` string should contain both the short and long flags,469 * separated by comma, a pipe or space. The following are all valid470 * all will output this way when `--help` is used.471 *472 * "-p, --pepper"473 * "-p|--pepper"474 * "-p --pepper"475 *476 * Examples:477 *478 * // simple boolean defaulting to undefined479 * program.option('-p, --pepper', 'add pepper');480 *481 * program.pepper482 * // => undefined483 *484 * --pepper485 * program.pepper486 * // => true487 *488 * // simple boolean defaulting to true (unless non-negated option is also defined)489 * program.option('-C, --no-cheese', 'remove cheese');490 *491 * program.cheese492 * // => true493 *494 * --no-cheese495 * program.cheese496 * // => false497 *498 * // required argument499 * program.option('-C, --chdir <path>', 'change the working directory');500 *501 * --chdir /tmp502 * program.chdir503 * // => "/tmp"504 *505 * // optional argument506 * program.option('-c, --cheese [type]', 'add cheese [marble]');507 *508 * @param {String} flags509 * @param {String} description510 * @param {Function|*} [fn] - custom option processing function or default vaue511 * @param {*} [defaultValue]512 * @return {Command} for chaining513 * @api public514 */515 516Command.prototype.option = function(flags, description, fn, defaultValue) {517 return this._optionEx({}, flags, description, fn, defaultValue);518};519 520/*521 * Add a required option which must have a value after parsing. This usually means522 * the option must be specified on the command line. (Otherwise the same as .option().)523 *524 * The `flags` string should contain both the short and long flags, separated by comma, a pipe or space.525 *526 * @param {String} flags527 * @param {String} description528 * @param {Function|*} [fn] - custom option processing function or default vaue529 * @param {*} [defaultValue]530 * @return {Command} for chaining531 * @api public532 */533 534Command.prototype.requiredOption = function(flags, description, fn, defaultValue) {535 return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue);536};537 538/**539 * Allow unknown options on the command line.540 *541 * @param {Boolean} arg if `true` or omitted, no error will be thrown542 * for unknown options.543 * @api public544 */545Command.prototype.allowUnknownOption = function(arg) {546 this._allowUnknownOption = arguments.length === 0 || arg;547 return this;548};549 550/**551 * Whether to store option values as properties on command object,552 * or store separately (specify false). In both cases the option values can be accessed using .opts().553 *554 * @param {boolean} value555 * @return {Command} Command for chaining556 * @api public557 */558 559Command.prototype.storeOptionsAsProperties = function(value) {560 this._storeOptionsAsProperties = (value === undefined) || value;561 if (this.options.length) {562 // This is for programmer, not end user.563 console.error('Commander usage error: call storeOptionsAsProperties before adding options');564 }565 return this;566};567 568/**569 * Whether to pass command to action handler,570 * or just the options (specify false).571 *572 * @param {boolean} value573 * @return {Command} Command for chaining574 * @api public575 */576 577Command.prototype.passCommandToAction = function(value) {578 this._passCommandToAction = (value === undefined) || value;579 return this;580};581 582/**583 * Store option value584 *585 * @param {String} key586 * @param {Object} value587 * @api private588 */589 590Command.prototype._setOptionValue = function(key, value) {591 if (this._storeOptionsAsProperties) {592 this[key] = value;593 } else {594 this._optionValues[key] = value;595 }596};597 598/**599 * Retrieve option value600 *601 * @param {String} key602 * @return {Object} value603 * @api private604 */605 606Command.prototype._getOptionValue = function(key) {607 if (this._storeOptionsAsProperties) {608 return this[key];609 }610 return this._optionValues[key];611};612 613/**614 * Parse `argv`, setting options and invoking commands when defined.615 *616 * @param {Array} argv617 * @return {Command} for chaining618 * @api public619 */620 621Command.prototype.parse = function(argv) {622 // implicit help623 if (this.executables) this.addImplicitHelpCommand();624 625 // store raw args626 this.rawArgs = argv;627 628 // guess name629 this._name = this._name || basename(argv[1], '.js');630 631 // github-style sub-commands with no sub-command632 if (this.executables && argv.length < 3 && !this.defaultExecutable) {633 // this user needs help634 argv.push(this._helpLongFlag);635 }636 637 // process argv638 var normalized = this.normalize(argv.slice(2));639 var parsed = this.parseOptions(normalized);640 var args = this.args = parsed.args;641 642 var result = this.parseArgs(this.args, parsed.unknown);643 644 if (args[0] === 'help' && args.length === 1) this.help();645 646 // Note for future: we could return early if we found an action handler in parseArgs, as none of following code needed?647 648 // <cmd> --help649 if (args[0] === 'help') {650 args[0] = args[1];651 args[1] = this._helpLongFlag;652 } else {653 // If calling through to executable subcommand we could check for help flags before failing,654 // but a somewhat unlikely case since program options not passed to executable subcommands.655 // Wait for reports to see if check needed and what usage pattern is.656 this._checkForMissingMandatoryOptions();657 }658 659 // executable sub-commands660 // (Debugging note for future: args[0] is not right if an action has been called)661 var name = result.args[0];662 var subCommand = null;663 664 // Look for subcommand665 if (name) {666 subCommand = this.commands.find(function(command) {667 return command._name === name;668 });669 }670 671 // Look for alias672 if (!subCommand && name) {673 subCommand = this.commands.find(function(command) {674 return command.alias() === name;675 });676 if (subCommand) {677 name = subCommand._name;678 args[0] = name;679 }680 }681 682 // Look for default subcommand683 if (!subCommand && this.defaultExecutable) {684 name = this.defaultExecutable;685 args.unshift(name);686 subCommand = this.commands.find(function(command) {687 return command._name === name;688 });689 }690 691 if (this._execs.has(name)) {692 return this.executeSubCommand(argv, args, parsed.unknown, subCommand ? subCommand._executableFile : undefined);693 }694 695 return result;696};697 698/**699 * Parse `argv`, setting options and invoking commands when defined.700 *701 * Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.702 *703 * @param {Array} argv704 * @return {Promise}705 * @api public706 */707Command.prototype.parseAsync = function(argv) {708 this.parse(argv);709 return Promise.all(this._actionResults);710};711 712/**713 * Execute a sub-command executable.714 *715 * @param {Array} argv716 * @param {Array} args717 * @param {Array} unknown718 * @param {String} executableFile719 * @api private720 */721 722Command.prototype.executeSubCommand = function(argv, args, unknown, executableFile) {723 args = args.concat(unknown);724 725 if (!args.length) this.help();726 727 var isExplicitJS = false; // Whether to use node to launch "executable"728 729 // executable730 var pm = argv[1];731 // name of the subcommand, like `pm-install`732 var bin = basename(pm, path.extname(pm)) + '-' + args[0];733 if (executableFile != null) {734 bin = executableFile;735 // Check for same extensions as we scan for below so get consistent launch behaviour.736 var executableExt = path.extname(executableFile);737 isExplicitJS = executableExt === '.js' || executableExt === '.ts' || executableExt === '.mjs';738 }739 740 // In case of globally installed, get the base dir where executable741 // subcommand file should be located at742 var baseDir;743 744 var resolvedLink = fs.realpathSync(pm);745 746 baseDir = dirname(resolvedLink);747 748 // prefer local `./<bin>` to bin in the $PATH749 var localBin = path.join(baseDir, bin);750 751 // whether bin file is a js script with explicit `.js` or `.ts` extension752 if (exists(localBin + '.js')) {753 bin = localBin + '.js';754 isExplicitJS = true;755 } else if (exists(localBin + '.ts')) {756 bin = localBin + '.ts';757 isExplicitJS = true;758 } else if (exists(localBin + '.mjs')) {759 bin = localBin + '.mjs';760 isExplicitJS = true;761 } else if (exists(localBin)) {762 bin = localBin;763 }764 765 args = args.slice(1);766 767 var proc;768 if (process.platform !== 'win32') {769 if (isExplicitJS) {770 args.unshift(bin);771 // add executable arguments to spawn772 args = incrementNodeInspectorPort(process.execArgv).concat(args);773 774 proc = spawn(process.argv[0], args, { stdio: 'inherit' });775 } else {776 proc = spawn(bin, args, { stdio: 'inherit' });777 }778 } else {779 args.unshift(bin);780 // add executable arguments to spawn781 args = incrementNodeInspectorPort(process.execArgv).concat(args);782 proc = spawn(process.execPath, args, { stdio: 'inherit' });783 }784 785 var signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];786 signals.forEach(function(signal) {787 process.on(signal, function() {788 if (proc.killed === false && proc.exitCode === null) {789 proc.kill(signal);790 }791 });792 });793 794 // By default terminate process when spawned process terminates.795 // Suppressing the exit if exitCallback defined is a bit messy and of limited use, but does allow process to stay running!796 const exitCallback = this._exitCallback;797 if (!exitCallback) {798 proc.on('close', process.exit.bind(process));799 } else {800 proc.on('close', () => {801 exitCallback(new CommanderError(process.exitCode || 0, 'commander.executeSubCommandAsync', '(close)'));802 });803 }804 proc.on('error', function(err) {805 if (err.code === 'ENOENT') {806 console.error('error: %s(1) does not exist, try --help', bin);807 } else if (err.code === 'EACCES') {808 console.error('error: %s(1) not executable. try chmod or run with root', bin);809 }810 if (!exitCallback) {811 process.exit(1);812 } else {813 const wrappedError = new CommanderError(1, 'commander.executeSubCommandAsync', '(error)');814 wrappedError.nestedError = err;815 exitCallback(wrappedError);816 }817 });818 819 // Store the reference to the child process820 this.runningCommand = proc;821};822 823/**824 * Normalize `args`, splitting joined short flags. For example825 * the arg "-abc" is equivalent to "-a -b -c".826 * This also normalizes equal sign and splits "--abc=def" into "--abc def".827 *828 * @param {Array} args829 * @return {Array}830 * @api private831 */832 833Command.prototype.normalize = function(args) {834 var ret = [],835 arg,836 lastOpt,837 index,838 short,839 opt;840 841 for (var i = 0, len = args.length; i < len; ++i) {842 arg = args[i];843 if (i > 0) {844 lastOpt = this.optionFor(args[i - 1]);845 }846 847 if (arg === '--') {848 // Honor option terminator849 ret = ret.concat(args.slice(i));850 break;851 } else if (lastOpt && lastOpt.required) {852 ret.push(arg);853 } else if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {854 short = arg.slice(0, 2);855 opt = this.optionFor(short);856 if (opt && (opt.required || opt.optional)) {857 ret.push(short);858 ret.push(arg.slice(2));859 } else {860 arg.slice(1).split('').forEach(function(c) {861 ret.push('-' + c);862 });863 }864 } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {865 ret.push(arg.slice(0, index), arg.slice(index + 1));866 } else {867 ret.push(arg);868 }869 }870 871 return ret;872};873 874/**875 * Parse command `args`.876 *877 * When listener(s) are available those878 * callbacks are invoked, otherwise the "*"879 * event is emitted and those actions are invoked.880 *881 * @param {Array} args882 * @return {Command} for chaining883 * @api private884 */885 886Command.prototype.parseArgs = function(args, unknown) {887 var name;888 889 if (args.length) {890 name = args[0];891 if (this.listeners('command:' + name).length) {892 this.emit('command:' + args.shift(), args, unknown);893 } else {894 this.emit('command:*', args, unknown);895 }896 } else {897 outputHelpIfRequested(this, unknown);898 899 // If there were no args and we have unknown options,900 // then they are extraneous and we need to error.901 if (unknown.length > 0 && !this.defaultExecutable) {902 this.unknownOption(unknown[0]);903 }904 if (this.commands.length === 0 &&905 this._args.filter(function(a) { return a.required; }).length === 0) {906 this.emit('command:*');907 }908 }909 910 return this;911};912 913/**914 * Return an option matching `arg` if any.915 *916 * @param {String} arg917 * @return {Option}918 * @api private919 */920 921Command.prototype.optionFor = function(arg) {922 for (var i = 0, len = this.options.length; i < len; ++i) {923 if (this.options[i].is(arg)) {924 return this.options[i];925 }926 }927};928 929/**930 * Display an error message if a mandatory option does not have a value.931 *932 * @api private933 */934 935Command.prototype._checkForMissingMandatoryOptions = function() {936 // Walk up hierarchy so can call from action handler after checking for displaying help.937 for (var cmd = this; cmd; cmd = cmd.parent) {938 cmd.options.forEach((anOption) => {939 if (anOption.mandatory && (cmd._getOptionValue(anOption.attributeName()) === undefined)) {940 cmd.missingMandatoryOptionValue(anOption);941 }942 });943 }944};945 946/**947 * Parse options from `argv` returning `argv`948 * void of these options.949 *950 * @param {Array} argv951 * @return {{args: Array, unknown: Array}}952 * @api public953 */954 955Command.prototype.parseOptions = function(argv) {956 var args = [],957 len = argv.length,958 literal,959 option,960 arg;961 962 var unknownOptions = [];963 964 // parse options965 for (var i = 0; i < len; ++i) {966 arg = argv[i];967 968 // literal args after --969 if (literal) {970 args.push(arg);971 continue;972 }973 974 if (arg === '--') {975 literal = true;976 continue;977 }978 979 // find matching Option980 option = this.optionFor(arg);981 982 // option is defined983 if (option) {984 // requires arg985 if (option.required) {986 arg = argv[++i];987 if (arg == null) return this.optionMissingArgument(option);988 this.emit('option:' + option.name(), arg);989 // optional arg990 } else if (option.optional) {991 arg = argv[i + 1];992 if (arg == null || (arg[0] === '-' && arg !== '-')) {993 arg = null;994 } else {995 ++i;996 }997 this.emit('option:' + option.name(), arg);998 // flag999 } else {1000 this.emit('option:' + option.name());1001 }1002 continue;1003 }1004 1005 // looks like an option1006 if (arg.length > 1 && arg[0] === '-') {1007 unknownOptions.push(arg);1008 1009 // If the next argument looks like it might be1010 // an argument for this option, we pass it on.1011 // If it isn't, then it'll simply be ignored1012 if ((i + 1) < argv.length && (argv[i + 1][0] !== '-' || argv[i + 1] === '-')) {1013 unknownOptions.push(argv[++i]);1014 }1015 continue;1016 }1017 1018 // arg1019 args.push(arg);1020 }1021 1022 return { args: args, unknown: unknownOptions };1023};1024 1025/**1026 * Return an object containing options as key-value pairs1027 *1028 * @return {Object}1029 * @api public1030 */1031Command.prototype.opts = function() {1032 if (this._storeOptionsAsProperties) {1033 // Preserve original behaviour so backwards compatible when still using properties1034 var result = {},1035 len = this.options.length;1036 1037 for (var i = 0; i < len; i++) {1038 var key = this.options[i].attributeName();1039 result[key] = key === this._versionOptionName ? this._version : this[key];1040 }1041 return result;1042 }1043 1044 return this._optionValues;1045};1046 1047/**1048 * Argument `name` is missing.1049 *1050 * @param {String} name1051 * @api private1052 */1053 1054Command.prototype.missingArgument = function(name) {1055 const message = `error: missing required argument '${name}'`;1056 console.error(message);1057 this._exit(1, 'commander.missingArgument', message);1058};1059 1060/**1061 * `Option` is missing an argument, but received `flag` or nothing.1062 *1063 * @param {Option} option1064 * @param {String} [flag]1065 * @api private1066 */1067 1068Command.prototype.optionMissingArgument = function(option, flag) {1069 let message;1070 if (flag) {1071 message = `error: option '${option.flags}' argument missing, got '${flag}'`;1072 } else {1073 message = `error: option '${option.flags}' argument missing`;1074 }1075 console.error(message);1076 this._exit(1, 'commander.optionMissingArgument', message);1077};1078 1079/**1080 * `Option` does not have a value, and is a mandatory option.1081 *1082 * @param {Option} option1083 * @api private1084 */1085 1086Command.prototype.missingMandatoryOptionValue = function(option) {1087 const message = `error: required option '${option.flags}' not specified`;1088 console.error(message);1089 this._exit(1, 'commander.missingMandatoryOptionValue', message);1090};1091 1092/**1093 * Unknown option `flag`.1094 *1095 * @param {String} flag1096 * @api private1097 */1098 1099Command.prototype.unknownOption = function(flag) {1100 if (this._allowUnknownOption) return;1101 const message = `error: unknown option '${flag}'`;1102 console.error(message);1103 this._exit(1, 'commander.unknownOption', message);1104};1105 1106/**1107 * Variadic argument with `name` is not the last argument as required.1108 *1109 * @param {String} name1110 * @api private1111 */1112 1113Command.prototype.variadicArgNotLast = function(name) {1114 const message = `error: variadic arguments must be last '${name}'`;1115 console.error(message);1116 this._exit(1, 'commander.variadicArgNotLast', message);1117};1118 1119/**1120 * Set the program version to `str`.1121 *1122 * This method auto-registers the "-V, --version" flag1123 * which will print the version number when passed.1124 *1125 * You can optionally supply the flags and description to override the defaults.1126 *1127 * @param {String} str1128 * @param {String} [flags]1129 * @param {String} [description]1130 * @return {Command} for chaining1131 * @api public1132 */1133 1134Command.prototype.version = function(str, flags, description) {1135 if (arguments.length === 0) return this._version;1136 this._version = str;1137 flags = flags || '-V, --version';1138 description = description || 'output the version number';1139 var versionOption = new Option(flags, description);1140 this._versionOptionName = versionOption.long.substr(2) || 'version';1141 this.options.push(versionOption);1142 var self = this;1143 this.on('option:' + this._versionOptionName, function() {1144 process.stdout.write(str + '\n');1145 self._exit(0, 'commander.version', str);1146 });1147 return this;1148};1149 1150/**1151 * Set the description to `str`.1152 *1153 * @param {String} str1154 * @param {Object} [argsDescription]1155 * @return {String|Command}1156 * @api public1157 */1158 1159Command.prototype.description = function(str, argsDescription) {1160 if (arguments.length === 0) return this._description;1161 this._description = str;1162 this._argsDescription = argsDescription;1163 return this;1164};1165 1166/**1167 * Set an alias for the command1168 *1169 * @param {String} alias1170 * @return {String|Command}1171 * @api public1172 */1173 1174Command.prototype.alias = function(alias) {1175 var command = this;1176 if (this.commands.length !== 0) {1177 command = this.commands[this.commands.length - 1];1178 }1179 1180 if (arguments.length === 0) return command._alias;1181 1182 if (alias === command._name) throw new Error('Command alias can\'t be the same as its name');1183 1184 command._alias = alias;1185 return this;1186};1187 1188/**1189 * Set / get the command usage `str`.1190 *1191 * @param {String} [str]1192 * @return {String|Command}1193 * @api public1194 */1195 1196Command.prototype.usage = function(str) {1197 var args = this._args.map(function(arg) {1198 return humanReadableArgName(arg);1199 });1200 