1/**
2 * Module dependencies.
3 */
4
5const EventEmitter = require('events').EventEmitter;
6const spawn = require('child_process').spawn;
7const path = require('path');
8const fs = require('fs');
9
10// @ts-check
11
12class Option {
13  /**
14   * Initialize a new `Option` with the given `flags` and `description`.
15   *
16   * @param {string} flags
17   * @param {string} description
18   * @api public
19   */
20
21  constructor(flags, description) {
22    this.flags = flags;
23    this.required = flags.indexOf('<') >= 0; // A value must be supplied when the option is specified.
24    this.optional = flags.indexOf('[') >= 0; // A value is optional when the option is specified.
25    this.mandatory = false; // The option must have a value after parsing, which usually means it must be specified on command line.
26    this.negate = flags.indexOf('-no-') !== -1;
27    const flagParts = flags.split(/[ ,|]+/);
28    if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1])) this.short = flagParts.shift();
29    this.long = flagParts.shift();
30    this.description = description || '';
31    this.defaultValue = undefined;
32  }
33
34  /**
35   * Return option name.
36   *
37   * @return {string}
38   * @api private
39   */
40
41  name() {
42    return this.long.replace(/^--/, '');
43  };
44
45  /**
46   * Return option name, in a camelcase format that can be used
47   * as a object attribute key.
48   *
49   * @return {string}
50   * @api private
51   */
52
53  attributeName() {
54    return camelcase(this.name().replace(/^no-/, ''));
55  };
56
57  /**
58   * Check if `arg` matches the short or long flag.
59   *
60   * @param {string} arg
61   * @return {boolean}
62   * @api private
63   */
64
65  is(arg) {
66    return this.short === arg || this.long === arg;
67  };
68}
69
70/**
71 * CommanderError class
72 * @class
73 */
74class CommanderError extends Error {
75  /**
76   * Constructs the CommanderError class
77   * @param {number} exitCode suggested exit code which could be used with process.exit
78   * @param {string} code an id string representing the error
79   * @param {string} message human-readable description of the error
80   * @constructor
81   */
82  constructor(exitCode, code, message) {
83    super(message);
84    // properly capture stack trace in Node.js
85    Error.captureStackTrace(this, this.constructor);
86    this.name = this.constructor.name;
87    this.code = code;
88    this.exitCode = exitCode;
89    this.nestedError = undefined;
90  }
91}
92
93class Command extends EventEmitter {
94  /**
95   * Initialize a new `Command`.
96   *
97   * @param {string} [name]
98   * @api public
99   */
100
101  constructor(name) {
102    super();
103    this.commands = [];
104    this.options = [];
105    this.parent = null;
106    this._allowUnknownOption = false;
107    this._args = [];
108    this.rawArgs = null;
109    this._scriptPath = null;
110    this._name = name || '';
111    this._optionValues = {};
112    this._storeOptionsAsProperties = true; // backwards compatible by default
113    this._passCommandToAction = true; // backwards compatible by default
114    this._actionResults = [];
115    this._actionHandler = null;
116    this._executableHandler = false;
117    this._executableFile = null; // custom name for executable
118    this._defaultCommandName = null;
119    this._exitCallback = null;
120    this._aliases = [];
121
122    this._hidden = false;
123    this._helpFlags = '-h, --help';
124    this._helpDescription = 'display help for command';
125    this._helpShortFlag = '-h';
126    this._helpLongFlag = '--help';
127    this._hasImplicitHelpCommand = undefined; // Deliberately undefined, not decided whether true or false
128    this._helpCommandName = 'help';
129    this._helpCommandnameAndArgs = 'help [command]';
130    this._helpCommandDescription = 'display help for command';
131  }
132
133  /**
134   * Define a command.
135   *
136   * There are two styles of command: pay attention to where to put the description.
137   *
138   * Examples:
139   *
140   *      // Command implemented using action handler (description is supplied separately to `.command`)
141   *      program
142   *        .command('clone <source> [destination]')
143   *        .description('clone a repository into a newly created directory')
144   *        .action((source, destination) => {
145   *          console.log('clone command called');
146   *        });
147   *
148   *      // Command implemented using separate executable file (description is second parameter to `.command`)
149   *      program
150   *        .command('start <service>', 'start named service')
151   *        .command('stop [service]', 'stop named service, or all if no name supplied');
152   *
153   * @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
154   * @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
155   * @param {Object} [execOpts] - configuration options (for executable)
156   * @return {Command} returns new command for action handler, or `this` for executable command
157   * @api public
158   */
159
160  command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
161    let desc = actionOptsOrExecDesc;
162    let opts = execOpts;
163    if (typeof desc === 'object' && desc !== null) {
164      opts = desc;
165      desc = null;
166    }
167    opts = opts || {};
168    const args = nameAndArgs.split(/ +/);
169    const cmd = this.createCommand(args.shift());
170
171    if (desc) {
172      cmd.description(desc);
173      cmd._executableHandler = true;
174    }
175    if (opts.isDefault) this._defaultCommandName = cmd._name;
176
177    cmd._hidden = !!(opts.noHelp || opts.hidden);
178    cmd._helpFlags = this._helpFlags;
179    cmd._helpDescription = this._helpDescription;
180    cmd._helpShortFlag = this._helpShortFlag;
181    cmd._helpLongFlag = this._helpLongFlag;
182    cmd._helpCommandName = this._helpCommandName;
183    cmd._helpCommandnameAndArgs = this._helpCommandnameAndArgs;
184    cmd._helpCommandDescription = this._helpCommandDescription;
185    cmd._exitCallback = this._exitCallback;
186    cmd._storeOptionsAsProperties = this._storeOptionsAsProperties;
187    cmd._passCommandToAction = this._passCommandToAction;
188
189    cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor
190    this.commands.push(cmd);
191    cmd._parseExpectedArgs(args);
192    cmd.parent = this;
193
194    if (desc) return this;
195    return cmd;
196  };
197
198  /**
199   * Factory routine to create a new unattached command.
200   *
201   * See .command() for creating an attached subcommand, which uses this routine to
202   * create the command. You can override createCommand to customise subcommands.
203   *
204   * @param {string} [name]
205   * @return {Command} new command
206   * @api public
207   */
208
209  createCommand(name) {
210    return new Command(name);
211  };
212
213  /**
214   * Add a prepared subcommand.
215   *
216   * See .command() for creating an attached subcommand which inherits settings from its parent.
217   *
218   * @param {Command} cmd - new subcommand
219   * @param {Object} [opts] - configuration options
220   * @return {Command} `this` command for chaining
221   * @api public
222   */
223
224  addCommand(cmd, opts) {
225    if (!cmd._name) throw new Error('Command passed to .addCommand() must have a name');
226
227    // To keep things simple, block automatic name generation for deeply nested executables.
228    // Fail fast and detect when adding rather than later when parsing.
229    function checkExplicitNames(commandArray) {
230      commandArray.forEach((cmd) => {
231        if (cmd._executableHandler && !cmd._executableFile) {
232          throw new Error(`Must specify executableFile for deeply nested executable: ${cmd.name()}`);
233        }
234        checkExplicitNames(cmd.commands);
235      });
236    }
237    checkExplicitNames(cmd.commands);
238
239    opts = opts || {};
240    if (opts.isDefault) this._defaultCommandName = cmd._name;
241    if (opts.noHelp || opts.hidden) cmd._hidden = true; // modifying passed command due to existing implementation
242
243    this.commands.push(cmd);
244    cmd.parent = this;
245    return this;
246  };
247
248  /**
249   * Define argument syntax for the command.
250   *
251   * @api public
252   */
253
254  arguments(desc) {
255    return this._parseExpectedArgs(desc.split(/ +/));
256  };
257
258  /**
259   * Override default decision whether to add implicit help command.
260   *
261   *    addHelpCommand() // force on
262   *    addHelpCommand(false); // force off
263   *    addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom detais
264   *
265   * @return {Command} `this` command for chaining
266   * @api public
267   */
268
269  addHelpCommand(enableOrNameAndArgs, description) {
270    if (enableOrNameAndArgs === false) {
271      this._hasImplicitHelpCommand = false;
272    } else {
273      this._hasImplicitHelpCommand = true;
274      if (typeof enableOrNameAndArgs === 'string') {
275        this._helpCommandName = enableOrNameAndArgs.split(' ')[0];
276        this._helpCommandnameAndArgs = enableOrNameAndArgs;
277      }
278      this._helpCommandDescription = description || this._helpCommandDescription;
279    }
280    return this;
281  };
282
283  /**
284   * @return {boolean}
285   * @api private
286   */
287
288  _lazyHasImplicitHelpCommand() {
289    if (this._hasImplicitHelpCommand === undefined) {
290      this._hasImplicitHelpCommand = this.commands.length && !this._actionHandler && !this._findCommand('help');
291    }
292    return this._hasImplicitHelpCommand;
293  };
294
295  /**
296   * Parse expected `args`.
297   *
298   * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
299   *
300   * @param {Array} args
301   * @return {Command} `this` command for chaining
302   * @api private
303   */
304
305  _parseExpectedArgs(args) {
306    if (!args.length) return;
307    args.forEach((arg) => {
308      const argDetails = {
309        required: false,
310        name: '',
311        variadic: false
312      };
313
314      switch (arg[0]) {
315        case '<':
316          argDetails.required = true;
317          argDetails.name = arg.slice(1, -1);
318          break;
319        case '[':
320          argDetails.name = arg.slice(1, -1);
321          break;
322      }
323
324      if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {
325        argDetails.variadic = true;
326        argDetails.name = argDetails.name.slice(0, -3);
327      }
328      if (argDetails.name) {
329        this._args.push(argDetails);
330      }
331    });
332    this._args.forEach((arg, i) => {
333      if (arg.variadic && i < this._args.length - 1) {
334        throw new Error(`only the last argument can be variadic '${arg.name}'`);
335      }
336    });
337    return this;
338  };
339
340  /**
341   * Register callback to use as replacement for calling process.exit.
342   *
343   * @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing
344   * @return {Command} `this` command for chaining
345   * @api public
346   */
347
348  exitOverride(fn) {
349    if (fn) {
350      this._exitCallback = fn;
351    } else {
352      this._exitCallback = (err) => {
353        if (err.code !== 'commander.executeSubCommandAsync') {
354          throw err;
355        } else {
356          // Async callback from spawn events, not useful to throw.
357        }
358      };
359    }
360    return this;
361  };
362
363  /**
364   * Call process.exit, and _exitCallback if defined.
365   *
366   * @param {number} exitCode exit code for using with process.exit
367   * @param {string} code an id string representing the error
368   * @param {string} message human-readable description of the error
369   * @return never
370   * @api private
371   */
372
373  _exit(exitCode, code, message) {
374    if (this._exitCallback) {
375      this._exitCallback(new CommanderError(exitCode, code, message));
376      // Expecting this line is not reached.
377    }
378    process.exit(exitCode);
379  };
380
381  /**
382   * Register callback `fn` for the command.
383   *
384   * Examples:
385   *
386   *      program
387   *        .command('help')
388   *        .description('display verbose help')
389   *        .action(function() {
390   *           // output help here
391   *        });
392   *
393   * @param {Function} fn
394   * @return {Command} `this` command for chaining
395   * @api public
396   */
397
398  action(fn) {
399    const listener = (args) => {
400      // The .action callback takes an extra parameter which is the command or options.
401      const expectedArgsCount = this._args.length;
402      const actionArgs = args.slice(0, expectedArgsCount);
403      if (this._passCommandToAction) {
404        actionArgs[expectedArgsCount] = this;
405      } else {
406        actionArgs[expectedArgsCount] = this.opts();
407      }
408      // Add the extra arguments so available too.
409      if (args.length > expectedArgsCount) {
410        actionArgs.push(args.slice(expectedArgsCount));
411      }
412
413      const actionResult = fn.apply(this, actionArgs);
414      // Remember result in case it is async. Assume parseAsync getting called on root.
415      let rootCommand = this;
416      while (rootCommand.parent) {
417        rootCommand = rootCommand.parent;
418      }
419      rootCommand._actionResults.push(actionResult);
420    };
421    this._actionHandler = listener;
422    return this;
423  };
424
425  /**
426   * Internal implementation shared by .option() and .requiredOption()
427   *
428   * @param {Object} config
429   * @param {string} flags
430   * @param {string} description
431   * @param {Function|*} [fn] - custom option processing function or default vaue
432   * @param {*} [defaultValue]
433   * @return {Command} `this` command for chaining
434   * @api private
435   */
436
437  _optionEx(config, flags, description, fn, defaultValue) {
438    const option = new Option(flags, description);
439    const oname = option.name();
440    const name = option.attributeName();
441    option.mandatory = !!config.mandatory;
442
443    // default as 3rd arg
444    if (typeof fn !== 'function') {
445      if (fn instanceof RegExp) {
446        // This is a bit simplistic (especially no error messages), and probably better handled by caller using custom option processing.
447        // No longer documented in README, but still present for backwards compatibility.
448        const regex = fn;
449        fn = (val, def) => {
450          const m = regex.exec(val);
451          return m ? m[0] : def;
452        };
453      } else {
454        defaultValue = fn;
455        fn = null;
456      }
457    }
458
459    // preassign default value for --no-*, [optional], <required>, or plain flag if boolean value
460    if (option.negate || option.optional || option.required || typeof defaultValue === 'boolean') {
461      // when --no-foo we make sure default is true, unless a --foo option is already defined
462      if (option.negate) {
463        const positiveLongFlag = option.long.replace(/^--no-/, '--');
464        defaultValue = this._findOption(positiveLongFlag) ? this._getOptionValue(name) : true;
465      }
466      // preassign only if we have a default
467      if (defaultValue !== undefined) {
468        this._setOptionValue(name, defaultValue);
469        option.defaultValue = defaultValue;
470      }
471    }
472
473    // register the option
474    this.options.push(option);
475
476    // when it's passed assign the value
477    // and conditionally invoke the callback
478    this.on('option:' + oname, (val) => {
479      // coercion
480      if (val !== null && fn) {
481        val = fn(val, this._getOptionValue(name) === undefined ? defaultValue : this._getOptionValue(name));
482      }
483
484      // unassigned or boolean value
485      if (typeof this._getOptionValue(name) === 'boolean' || typeof this._getOptionValue(name) === 'undefined') {
486        // if no value, negate false, and we have a default, then use it!
487        if (val == null) {
488          this._setOptionValue(name, option.negate
489            ? false
490            : defaultValue || true);
491        } else {
492          this._setOptionValue(name, val);
493        }
494      } else if (val !== null) {
495        // reassign
496        this._setOptionValue(name, option.negate ? false : val);
497      }
498    });
499
500    return this;
501  };
502
503  /**
504   * Define option with `flags`, `description` and optional
505   * coercion `fn`.
506   *
507   * The `flags` string should contain both the short and long flags,
508   * separated by comma, a pipe or space. The following are all valid
509   * all will output this way when `--help` is used.
510   *
511   *    "-p, --pepper"
512   *    "-p|--pepper"
513   *    "-p --pepper"
514   *
515   * Examples:
516   *
517   *     // simple boolean defaulting to undefined
518   *     program.option('-p, --pepper', 'add pepper');
519   *
520   *     program.pepper
521   *     // => undefined
522   *
523   *     --pepper
524   *     program.pepper
525   *     // => true
526   *
527   *     // simple boolean defaulting to true (unless non-negated option is also defined)
528   *     program.option('-C, --no-cheese', 'remove cheese');
529   *
530   *     program.cheese
531   *     // => true
532   *
533   *     --no-cheese
534   *     program.cheese
535   *     // => false
536   *
537   *     // required argument
538   *     program.option('-C, --chdir <path>', 'change the working directory');
539   *
540   *     --chdir /tmp
541   *     program.chdir
542   *     // => "/tmp"
543   *
544   *     // optional argument
545   *     program.option('-c, --cheese [type]', 'add cheese [marble]');
546   *
547   * @param {string} flags
548   * @param {string} description
549   * @param {Function|*} [fn] - custom option processing function or default vaue
550   * @param {*} [defaultValue]
551   * @return {Command} `this` command for chaining
552   * @api public
553   */
554
555  option(flags, description, fn, defaultValue) {
556    return this._optionEx({}, flags, description, fn, defaultValue);
557  };
558
559  /*
560  * Add a required option which must have a value after parsing. This usually means
561  * the option must be specified on the command line. (Otherwise the same as .option().)
562  *
563  * The `flags` string should contain both the short and long flags, separated by comma, a pipe or space.
564  *
565  * @param {string} flags
566  * @param {string} description
567  * @param {Function|*} [fn] - custom option processing function or default vaue
568  * @param {*} [defaultValue]
569  * @return {Command} `this` command for chaining
570  * @api public
571  */
572
573  requiredOption(flags, description, fn, defaultValue) {
574    return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue);
575  };
576
577  /**
578   * Allow unknown options on the command line.
579   *
580   * @param {Boolean} [arg] - if `true` or omitted, no error will be thrown
581   * for unknown options.
582   * @api public
583   */
584  allowUnknownOption(arg) {
585    this._allowUnknownOption = (arg === undefined) || arg;
586    return this;
587  };
588
589  /**
590    * Whether to store option values as properties on command object,
591    * or store separately (specify false). In both cases the option values can be accessed using .opts().
592    *
593    * @param {boolean} value
594    * @return {Command} `this` command for chaining
595    * @api public
596    */
597
598  storeOptionsAsProperties(value) {
599    this._storeOptionsAsProperties = (value === undefined) || value;
600    if (this.options.length) {
601      throw new Error('call .storeOptionsAsProperties() before adding options');
602    }
603    return this;
604  };
605
606  /**
607    * Whether to pass command to action handler,
608    * or just the options (specify false).
609    *
610    * @param {boolean} value
611    * @return {Command} `this` command for chaining
612    * @api public
613    */
614
615  passCommandToAction(value) {
616    this._passCommandToAction = (value === undefined) || value;
617    return this;
618  };
619
620  /**
621   * Store option value
622   *
623   * @param {string} key
624   * @param {Object} value
625   * @api private
626   */
627
628  _setOptionValue(key, value) {
629    if (this._storeOptionsAsProperties) {
630      this[key] = value;
631    } else {
632      this._optionValues[key] = value;
633    }
634  };
635
636  /**
637   * Retrieve option value
638   *
639   * @param {string} key
640   * @return {Object} value
641   * @api private
642   */
643
644  _getOptionValue(key) {
645    if (this._storeOptionsAsProperties) {
646      return this[key];
647    }
648    return this._optionValues[key];
649  };
650
651  /**
652   * Parse `argv`, setting options and invoking commands when defined.
653   *
654   * The default expectation is that the arguments are from node and have the application as argv[0]
655   * and the script being run in argv[1], with user parameters after that.
656   *
657   * Examples:
658   *
659   *      program.parse(process.argv);
660   *      program.parse(); // implicitly use process.argv and auto-detect node vs electron conventions
661   *      program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
662   *
663   * @param {string[]} [argv] - optional, defaults to process.argv
664   * @param {Object} [parseOptions] - optionally specify style of options with from: node/user/electron
665   * @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
666   * @return {Command} `this` command for chaining
667   * @api public
668   */
669
670  parse(argv, parseOptions) {
671    if (argv !== undefined && !Array.isArray(argv)) {
672      throw new Error('first parameter to parse must be array or undefined');
673    }
674    parseOptions = parseOptions || {};
675
676    // Default to using process.argv
677    if (argv === undefined) {
678      argv = process.argv;
679      // @ts-ignore
680      if (process.versions && process.versions.electron) {
681        parseOptions.from = 'electron';
682      }
683    }
684    this.rawArgs = argv.slice();
685
686    // make it a little easier for callers by supporting various argv conventions
687    let userArgs;
688    switch (parseOptions.from) {
689      case undefined:
690      case 'node':
691        this._scriptPath = argv[1];
692        userArgs = argv.slice(2);
693        break;
694      case 'electron':
695        // @ts-ignore
696        if (process.defaultApp) {
697          this._scriptPath = argv[1];
698          userArgs = argv.slice(2);
699        } else {
700          userArgs = argv.slice(1);
701        }
702        break;
703      case 'user':
704        userArgs = argv.slice(0);
705        break;
706      default:
707        throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`);
708    }
709    if (!this._scriptPath && process.mainModule) {
710      this._scriptPath = process.mainModule.filename;
711    }
712
713    // Guess name, used in usage in help.
714    this._name = this._name || (this._scriptPath && path.basename(this._scriptPath, path.extname(this._scriptPath)));
715
716    // Let's go!
717    this._parseCommand([], userArgs);
718
719    return this;
720  };
721
722  /**
723   * Parse `argv`, setting options and invoking commands when defined.
724   *
725   * Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.
726   *
727   * The default expectation is that the arguments are from node and have the application as argv[0]
728   * and the script being run in argv[1], with user parameters after that.
729   *
730   * Examples:
731   *
732   *      program.parseAsync(process.argv);
733   *      program.parseAsync(); // implicitly use process.argv and auto-detect node vs electron conventions
734   *      program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
735   *
736   * @param {string[]} [argv]
737   * @param {Object} [parseOptions]
738   * @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
739   * @return {Promise}
740   * @api public
741   */
742
743  parseAsync(argv, parseOptions) {
744    this.parse(argv, parseOptions);
745    return Promise.all(this._actionResults).then(() => this);
746  };
747
748  /**
749   * Execute a sub-command executable.
750   *
751   * @api private
752   */
753
754  _executeSubCommand(subcommand, args) {
755    args = args.slice();
756    let launchWithNode = false; // Use node for source targets so do not need to get permissions correct, and on Windows.
757    const sourceExt = ['.js', '.ts', '.mjs'];
758
759    // Not checking for help first. Unlikely to have mandatory and executable, and can't robustly test for help flags in external command.
760    this._checkForMissingMandatoryOptions();
761
762    // Want the entry script as the reference for command name and directory for searching for other files.
763    const scriptPath = this._scriptPath;
764
765    let baseDir;
766    try {
767      const resolvedLink = fs.realpathSync(scriptPath);
768      baseDir = path.dirname(resolvedLink);
769    } catch (e) {
770      baseDir = '.'; // dummy, probably not going to find executable!
771    }
772
773    // name of the subcommand, like `pm-install`
774    let bin = path.basename(scriptPath, path.extname(scriptPath)) + '-' + subcommand._name;
775    if (subcommand._executableFile) {
776      bin = subcommand._executableFile;
777    }
778
779    const localBin = path.join(baseDir, bin);
780    if (fs.existsSync(localBin)) {
781      // prefer local `./<bin>` to bin in the $PATH
782      bin = localBin;
783    } else {
784      // Look for source files.
785      sourceExt.forEach((ext) => {
786        if (fs.existsSync(`${localBin}${ext}`)) {
787          bin = `${localBin}${ext}`;
788        }
789      });
790    }
791    launchWithNode = sourceExt.includes(path.extname(bin));
792
793    let proc;
794    if (process.platform !== 'win32') {
795      if (launchWithNode) {
796        args.unshift(bin);
797        // add executable arguments to spawn
798        args = incrementNodeInspectorPort(process.execArgv).concat(args);
799
800        proc = spawn(process.argv[0], args, { stdio: 'inherit' });
801      } else {
802        proc = spawn(bin, args, { stdio: 'inherit' });
803      }
804    } else {
805      args.unshift(bin);
806      // add executable arguments to spawn
807      args = incrementNodeInspectorPort(process.execArgv).concat(args);
808      proc = spawn(process.execPath, args, { stdio: 'inherit' });
809    }
810
811    const signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
812    signals.forEach((signal) => {
813      // @ts-ignore
814      process.on(signal, () => {
815        if (proc.killed === false && proc.exitCode === null) {
816          proc.kill(signal);
817        }
818      });
819    });
820
821    // By default terminate process when spawned process terminates.
822    // Suppressing the exit if exitCallback defined is a bit messy and of limited use, but does allow process to stay running!
823    const exitCallback = this._exitCallback;
824    if (!exitCallback) {
825      proc.on('close', process.exit.bind(process));
826    } else {
827      proc.on('close', () => {
828        exitCallback(new CommanderError(process.exitCode || 0, 'commander.executeSubCommandAsync', '(close)'));
829      });
830    }
831    proc.on('error', (err) => {
832      // @ts-ignore
833      if (err.code === 'ENOENT') {
834        const executableMissing = `'${bin}' does not exist
835 - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
836 - if the default executable name is not suitable, use the executableFile option to supply a custom name`;
837        throw new Error(executableMissing);
838      // @ts-ignore
839      } else if (err.code === 'EACCES') {
840        throw new Error(`'${bin}' not executable`);
841      }
842      if (!exitCallback) {
843        process.exit(1);
844      } else {
845        const wrappedError = new CommanderError(1, 'commander.executeSubCommandAsync', '(error)');
846        wrappedError.nestedError = err;
847        exitCallback(wrappedError);
848      }
849    });
850
851    // Store the reference to the child process
852    this.runningCommand = proc;
853  };
854
855  /**
856   * @api private
857   */
858  _dispatchSubcommand(commandName, operands, unknown) {
859    const subCommand = this._findCommand(commandName);
860    if (!subCommand) this._helpAndError();
861
862    if (subCommand._executableHandler) {
863      this._executeSubCommand(subCommand, operands.concat(unknown));
864    } else {
865      subCommand._parseCommand(operands, unknown);
866    }
867  };
868
869  /**
870   * Process arguments in context of this command.
871   *
872   * @api private
873   */
874
875  _parseCommand(operands, unknown) {
876    const parsed = this.parseOptions(unknown);
877    operands = operands.concat(parsed.operands);
878    unknown = parsed.unknown;
879    this.args = operands.concat(unknown);
880
881    if (operands && this._findCommand(operands[0])) {
882      this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
883    } else if (this._lazyHasImplicitHelpCommand() && operands[0] === this._helpCommandName) {
884      if (operands.length === 1) {
885        this.help();
886      } else {
887        this._dispatchSubcommand(operands[1], [], [this._helpLongFlag]);
888      }
889    } else if (this._defaultCommandName) {
890      outputHelpIfRequested(this, unknown); // Run the help for default command from parent rather than passing to default command
891      this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
892    } else {
893      if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
894        // probaby missing subcommand and no handler, user needs help
895        this._helpAndError();
896      }
897
898      outputHelpIfRequested(this, parsed.unknown);
899      this._checkForMissingMandatoryOptions();
900      if (parsed.unknown.length > 0) {
901        this.unknownOption(parsed.unknown[0]);
902      }
903
904      if (this._actionHandler) {
905        const args = this.args.slice();
906        this._args.forEach((arg, i) => {
907          if (arg.required && args[i] == null) {
908            this.missingArgument(arg.name);
909          } else if (arg.variadic) {
910            args[i] = args.splice(i);
911          }
912        });
913
914        this._actionHandler(args);
915        this.emit('command:' + this.name(), operands, unknown);
916      } else if (operands.length) {
917        if (this._findCommand('*')) {
918          this._dispatchSubcommand('*', operands, unknown);
919        } else if (this.listenerCount('command:*')) {
920          this.emit('command:*', operands, unknown);
921        } else if (this.commands.length) {
922          this.unknownCommand();
923        }
924      } else if (this.commands.length) {
925        // This command has subcommands and nothing hooked up at this level, so display help.
926        this._helpAndError();
927      } else {
928        // fall through for caller to handle after calling .parse()
929      }
930    }
931  };
932
933  /**
934   * Find matching command.
935   *
936   * @api private
937   */
938  _findCommand(name) {
939    if (!name) return undefined;
940    return this.commands.find(cmd => cmd._name === name || cmd._aliases.includes(name));
941  };
942
943  /**
944   * Return an option matching `arg` if any.
945   *
946   * @param {string} arg
947   * @return {Option}
948   * @api private
949   */
950
951  _findOption(arg) {
952    return this.options.find(option => option.is(arg));
953  };
954
955  /**
956   * Display an error message if a mandatory option does not have a value.
957   * Lazy calling after checking for help flags from leaf subcommand.
958   *
959   * @api private
960   */
961
962  _checkForMissingMandatoryOptions() {
963    // Walk up hierarchy so can call in subcommand after checking for displaying help.
964    for (let cmd = this; cmd; cmd = cmd.parent) {
965      cmd.options.forEach((anOption) => {
966        if (anOption.mandatory && (cmd._getOptionValue(anOption.attributeName()) === undefined)) {
967          cmd.missingMandatoryOptionValue(anOption);
968        }
969      });
970    }
971  };
972
973  /**
974   * Parse options from `argv` removing known options,
975   * and return argv split into operands and unknown arguments.
976   *
977   * Examples:
978   *
979   *    argv => operands, unknown
980   *    --known kkk op => [op], []
981   *    op --known kkk => [op], []
982   *    sub --unknown uuu op => [sub], [--unknown uuu op]
983   *    sub -- --unknown uuu op => [sub --unknown uuu op], []
984   *
985   * @param {String[]} argv
986   * @return {{operands: String[], unknown: String[]}}
987   * @api public
988   */
989
990  parseOptions(argv) {
991    const operands = []; // operands, not options or values
992    const unknown = []; // first unknown option and remaining unknown args
993    let dest = operands;
994    const args = argv.slice();
995
996    function maybeOption(arg) {
997      return arg.length > 1 && arg[0] === '-';
998    }
999
1000    // parse options
1001    while (args.length) {
1002      const arg = args.shift();
1003
1004      // literal
1005      if (arg === '--') {
1006        if (dest === unknown) dest.push(arg);
1007        dest.push(...args);
1008        break;
1009      }
1010
1011      if (maybeOption(arg)) {
1012        const option = this._findOption(arg);
1013        // recognised option, call listener to assign value with possible custom processing
1014        if (option) {
1015          if (option.required) {
1016            const value = args.shift();
1017            if (value === undefined) this.optionMissingArgument(option);
1018            this.emit(`option:${option.name()}`, value);
1019          } else if (option.optional) {
1020            let value = null;
1021            // historical behaviour is optional value is following arg unless an option
1022            if (args.length > 0 && !maybeOption(args[0])) {
1023              value = args.shift();
1024            }
1025            this.emit(`option:${option.name()}`, value);
1026          } else { // boolean flag
1027            this.emit(`option:${option.name()}`);
1028          }
1029          continue;
1030        }
1031      }
1032
1033      // Look for combo options following single dash, eat first one if known.
1034      if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
1035        const option = this._findOption(`-${arg[1]}`);
1036        if (option) {
1037          if (option.required || option.optional) {
1038            // option with value following in same argument
1039            this.emit(`option:${option.name()}`, arg.slice(2));
1040          } else {
1041            // boolean option, emit and put back remainder of arg for further processing
1042            this.emit(`option:${option.name()}`);
1043            args.unshift(`-${arg.slice(2)}`);
1044          }
1045          continue;
1046        }
1047      }
1048
1049      // Look for known long flag with value, like --foo=bar
1050      if (/^--[^=]+=/.test(arg)) {
1051        const index = arg.indexOf('=');
1052        const option = this._findOption(arg.slice(0, index));
1053        if (option && (option.required || option.optional)) {
1054          this.emit(`option:${option.name()}`, arg.slice(index + 1));
1055          continue;
1056        }
1057      }
1058
1059      // looks like an option but unknown, unknowns from here
1060      if (arg.length > 1 && arg[0] === '-') {
1061        dest = unknown;
1062      }
1063
1064      // add arg
1065      dest.push(arg);
1066    }
1067
1068    return { operands, unknown };
1069  };
1070
1071  /**
1072   * Return an object containing options as key-value pairs
1073   *
1074   * @return {Object}
1075   * @api public
1076   */
1077  opts() {
1078    if (this._storeOptionsAsProperties) {
1079      // Preserve original behaviour so backwards compatible when still using properties
1080      const result = {};
1081      const len = this.options.length;
1082
1083      for (let i = 0; i < len; i++) {
1084        const key = this.options[i].attributeName();
1085        result[key] = key === this._versionOptionName ? this._version : this[key];
1086      }
1087      return result;
1088    }
1089
1090    return this._optionValues;
1091  };
1092
1093  /**
1094   * Argument `name` is missing.
1095   *
1096   * @param {string} name
1097   * @api private
1098   */
1099
1100  missingArgument(name) {
1101    const message = `error: missing required argument '${name}'`;
1102    console.error(message);
1103    this._exit(1, 'commander.missingArgument', message);
1104  };
1105
1106  /**
1107   * `Option` is missing an argument, but received `flag` or nothing.
1108   *
1109   * @param {Option} option
1110   * @param {string} [flag]
1111   * @api private
1112   */
1113
1114  optionMissingArgument(option, flag) {
1115    let message;
1116    if (flag) {
1117      message = `error: option '${option.flags}' argument missing, got '${flag}'`;
1118    } else {
1119      message = `error: option '${option.flags}' argument missing`;
1120    }
1121    console.error(message);
1122    this._exit(1, 'commander.optionMissingArgument', message);
1123  };
1124
1125  /**
1126   * `Option` does not have a value, and is a mandatory option.
1127   *
1128   * @param {Option} option
1129   * @api private
1130   */
1131
1132  missingMandatoryOptionValue(option) {
1133    const message = `error: required option '${option.flags}' not specified`;
1134    console.error(message);
1135    this._exit(1, 'commander.missingMandatoryOptionValue', message);
1136  };
1137
1138  /**
1139   * Unknown option `flag`.
1140   *
1141   * @param {string} flag
1142   * @api private
1143   */
1144
1145  unknownOption(flag) {
1146    if (this._allowUnknownOption) return;
1147    const message = `error: unknown option '${flag}'`;
1148    console.error(message);
1149    this._exit(1, 'commander.unknownOption', message);
1150  };
1151
1152  /**
1153   * Unknown command.
1154   *
1155   * @api private
1156   */
1157
1158  unknownCommand() {
1159    const partCommands = [this.name()];
1160    for (let parentCmd = this.parent; parentCmd; parentCmd = parentCmd.parent) {
1161      partCommands.unshift(parentCmd.name());
1162    }
1163    const fullCommand = partCommands.join(' ');
1164    const message = `error: unknown command '${this.args[0]}'. See '${fullCommand} ${this._helpLongFlag}'.`;
1165    console.error(message);
1166    this._exit(1, 'commander.unknownCommand', message);
1167  };
1168
1169  /**
1170   * Set the program version to `str`.
1171   *
1172   * This method auto-registers the "-V, --version" flag
1173   * which will print the version number when passed.
1174   *
1175   * You can optionally supply the  flags and description to override the defaults.
1176   *
1177   * @param {string} str
1178   * @param {string} [flags]
1179   * @param {string} [description]
1180   * @return {this | string} `this` command for chaining, or version string if no arguments
1181   * @api public
1182   */
1183
1184  version(str, flags, description) {
1185    if (str === undefined) return this._version;
1186    this._version = str;
1187    flags = flags || '-V, --version';
1188    description = description || 'output the version number';
1189    const versionOption = new Option(flags, description);
1190    this._versionOptionName = versionOption.long.substr(2) || 'version';
1191    this.options.push(versionOption);
1192    this.on('option:' + this._versionOptionName, () => {
1193      process.stdout.write(str + '\n');
1194      this._exit(0, 'commander.version', str);
1195    });
1196    return this;
1197  };
1198
1199  /**
1200   * Set the description to `str`.
1201   *
1202   * @param {string} str
1203   * @param {Object} [argsDescription]
1204   * @return {string|Command}
1205   * @api public
1206   */
1207
1208  description(str, argsDescription) {
1209    if (str === undefined && argsDescription === undefined) return this._description;
1210    this._description = str;
1211    this._argsDescription = argsDescription;
1212    return this;
1213  };
1214
1215  /**
1216   * Set an alias for the command.
1217   *
1218   * You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
1219   *
1220   * @param {string} [alias]
1221   * @return {string|Command}
1222   * @api public
1223   */
1224
1225  alias(alias) {
1226    if (alias === undefined) return this._aliases[0]; // just return first, for backwards compatibility
1227
1228    let command = this;
1229    if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
1230      // assume adding alias for last added executable subcommand, rather than this
1231      command = this.commands[this.commands.length - 1];
1232    }
1233
1234    if (alias === command._name) throw new Error('Command alias can\'t be the same as its name');
1235
1236    command._aliases.push(alias);
1237    return this;
1238  };
1239
1240  /**
1241   * Set aliases for the command.
1242   *
1243   * Only the first alias is shown in the auto-generated help.
1244   *
1245   * @param {string[]} [aliases]
1246   * @return {string[]|Command}
1247   * @api public
1248   */
1249
1250  aliases(aliases) {
1251    // Getter for the array of aliases is the main reason for having aliases() in addition to alias().
1252    if (aliases === undefined) return this._aliases;
1253
1254    aliases.forEach((alias) => this.alias(alias));
1255    return this;
1256  };
1257
1258  /**
1259   * Set / get the command usage `str`.
1260   *
1261   * @param {string} [str]
1262   * @return {String|Command}
1263   * @api public
1264   */
1265
1266  usage(str) {
1267    if (str === undefined) {
1268      if (this._usage) return this._usage;
1269
1270      const args = this._args.map((arg) => {
1271        return humanReadableArgName(arg);
1272      });
1273      return '[options]' +
1274        (this.commands.length ? ' [command]' : '') +
1275        (this._args.length ? ' ' + args.join(' ') : '');
1276    }
1277
1278    this._usage = str;
1279    return this;
1280  };
1281
1282  /**
1283   * Get or set the name of the command
1284   *
1285   * @param {string} [str]
1286   * @return {String|Command}
1287   * @api public
1288   */
1289
1290  name(str) {
1291    if (str === undefined) return this._name;
1292    this._name = str;
1293    return this;
1294  };
1295
1296  /**
1297   * Return prepared commands.
1298   *
1299   * @return {Array}
1300   * @api private
1301   */
1302
1303  prepareCommands() {
1304    const commandDetails = this.commands.filter((cmd) => {
1305      return !cmd._hidden;
1306    }).map((cmd) => {
1307      const args = cmd._args.map((arg) => {
1308        return humanReadableArgName(arg);
1309      }).join(' ');
1310
1311      return [
1312        cmd._name +
1313          (cmd._aliases[0] ? '|' + cmd._aliases[0] : '') +
1314          (cmd.options.length ? ' [options]' : '') +
1315          (args ? ' ' + args : ''),
1316        cmd._description
1317      ];
1318    });
1319
1320    if (this._lazyHasImplicitHelpCommand()) {
1321      commandDetails.push([this._helpCommandnameAndArgs, this._helpCommandDescription]);
1322    }
1323    return commandDetails;
1324  };
1325
1326  /**
1327   * Return the largest command length.
1328   *
1329   * @return {number}
1330   * @api private
1331   */
1332
1333  largestCommandLength() {
1334    const commands = this.prepareCommands();
1335    return commands.reduce((max, command) => {
1336      return Math.max(max, command[0].length);
1337    }, 0);
1338  };
1339
1340  /**
1341   * Return the largest option length.
1342   *
1343   * @return {number}
1344   * @api private
1345   */
1346
1347  largestOptionLength() {
1348    const options = [].slice.call(this.options);
1349    options.push({
1350      flags: this._helpFlags
1351    });
1352
1353    return options.reduce((max, option) => {
1354      return Math.max(max, option.flags.length);
1355    }, 0);
1356  };
1357
1358  /**
1359   * Return the largest arg length.
1360   *
1361   * @return {number}
1362   * @api private
1363   */
1364
1365  largestArgLength() {
1366    return this._args.reduce((max, arg) => {
1367      return Math.max(max, arg.name.length);
1368    }, 0);
1369  };
1370
1371  /**
1372   * Return the pad width.
1373   *
1374   * @return {number}
1375   * @api private
1376   */
1377
1378  padWidth() {
1379    let width = this.largestOptionLength();
1380    if (this._argsDescription && this._args.length) {
1381      if (this.largestArgLength() > width) {
1382        width = this.largestArgLength();
1383      }
1384    }
1385
1386    if (this.commands && this.commands.length) {
1387      if (this.largestCommandLength() > width) {
1388        width = this.largestCommandLength();
1389      }
1390    }
1391
1392    return width;
1393  };
1394
1395  /**
1396   * Return help for options.
1397   *
1398   * @return {string}
1399   * @api private
1400   */
1401
1402  optionHelp() {
1403    const width = this.padWidth();
1404    const columns = process.stdout.columns || 80;
1405    const descriptionWidth = columns - width - 4;
1406    function padOptionDetails(flags, description) {
1407      return pad(flags, width) + '  ' + optionalWrap(description, descriptionWidth, width + 2);
1408    };
1409
1410    // Explicit options (including version)
1411    const help = this.options.map((option) => {
1412      const fullDesc = option.description +
1413        ((!option.negate && option.defaultValue !== undefined) ? ' (default: ' + JSON.stringify(option.defaultValue) + ')' : '');
1414      return padOptionDetails(option.flags, fullDesc);
1415    });
1416
1417    // Implicit help
1418    const showShortHelpFlag = this._helpShortFlag && !this._findOption(this._helpShortFlag);
1419    const showLongHelpFlag = !this._findOption(this._helpLongFlag);
1420    if (showShortHelpFlag || showLongHelpFlag) {
1421      let helpFlags = this._helpFlags;
1422      if (!showShortHelpFlag) {
1423        helpFlags = this._helpLongFlag;
1424      } else if (!showLongHelpFlag) {
1425        helpFlags = this._helpShortFlag;
1426      }
1427      help.push(padOptionDetails(helpFlags, this._helpDescription));
1428    }
1429
1430    return help.join('\n');
1431  };
1432
1433  /**
1434   * Return command help documentation.
1435   *
1436   * @return {string}
1437   * @api private
1438   */
1439
1440  commandHelp() {
1441    if (!this.commands.length && !this._lazyHasImplicitHelpCommand()) return '';
1442
1443    const commands = this.prepareCommands();
1444    const width = this.padWidth();
1445
1446    const columns = process.stdout.columns || 80;
1447    const descriptionWidth = columns - width - 4;
1448
1449    return [
1450      'Commands:',
1451      commands.map((cmd) => {
1452        const desc = cmd[1] ? '  ' + cmd[1] : '';
1453        return (desc ? pad(cmd[0], width) : cmd[0]) + optionalWrap(desc, descriptionWidth, width + 2);
1454      }).join('\n').replace(/^/gm, '  '),
1455      ''
1456    ].join('\n');
1457  };
1458
1459  /**
1460   * Return program help documentation.
1461   *
1462   * @return {string}
1463   * @api public
1464   */
1465
1466  helpInformation() {
1467    let desc = [];
1468    if (this._description) {
1469      desc = [
1470        this._description,
1471        ''
1472      ];
1473
1474      const argsDescription = this._argsDescription;
1475      if (argsDescription && this._args.length) {
1476        const width = this.padWidth();
1477        const columns = process.stdout.columns || 80;
1478        const descriptionWidth = columns - width - 5;
1479        desc.push('Arguments:');
1480        desc.push('');
1481        this._args.forEach((arg) => {
1482          desc.push('  ' + pad(arg.name, width) + '  ' + wrap(argsDescription[arg.name], descriptionWidth, width + 4));
1483        });
1484        desc.push('');
1485      }
1486    }
1487
1488    let cmdName = this._name;
1489    if (this._aliases[0]) {
1490      cmdName = cmdName + '|' + this._aliases[0];
1491    }
1492    let parentCmdNames = '';
1493    for (let parentCmd = this.parent; parentCmd; parentCmd = parentCmd.parent) {
1494      parentCmdNames = parentCmd.name() + ' ' + parentCmdNames;
1495    }
1496    const usage = [
1497      'Usage: ' + parentCmdNames + cmdName + ' ' + this.usage(),
1498      ''
1499    ];
1500
1501    let cmds = [];
1502    const commandHelp = this.commandHelp();
1503    if (commandHelp) cmds = [commandHelp];
1504
1505    const options = [
1506      'Options:',
1507      '' + this.optionHelp().replace(/^/gm, '  '),
1508      ''
1509    ];
1510
1511    return usage
1512      .concat(desc)
1513      .concat(options)
1514      .concat(cmds)
1515      .join('\n');
1516  };
1517
1518  /**
1519   * Output help information for this command.
1520   *
1521   * When listener(s) are available for the helpLongFlag
1522   * those callbacks are invoked.
1523   *
1524   * @api public
1525   */
1526
1527  outputHelp(cb) {
1528    if (!cb) {
1529      cb = (passthru) => {
1530        return passthru;
1531      };
1532    }
1533    const cbOutput = cb(this.helpInformation());
1534    if (typeof cbOutput !== 'string' && !Buffer.isBuffer(cbOutput)) {
1535      throw new Error('outputHelp callback must return a string or a Buffer');
1536    }
1537    process.stdout.write(cbOutput);
1538    this.emit(this._helpLongFlag);
1539  };
1540
1541  /**
1542   * You can pass in flags and a description to override the help
1543   * flags and help description for your command.
1544   *
1545   * @param {string} [flags]
1546   * @param {string} [description]
1547   * @return {Command} `this` command for chaining
1548   * @api public
1549   */
1550
1551  helpOption(flags, description) {
1552    this._helpFlags = flags || this._helpFlags;
1553    this._helpDescription = description || this._helpDescription;
1554
1555    const splitFlags = this._helpFlags.split(/[ ,|]+/);
1556
1557    this._helpShortFlag = undefined;
1558    if (splitFlags.length > 1) this._helpShortFlag = splitFlags.shift();
1559
1560    this._helpLongFlag = splitFlags.shift();
1561
1562    return this;
1563  };
1564
1565  /**
1566   * Output help information and exit.
1567   *
1568   * @param {Function} [cb]
1569   * @api public
1570   */
1571
1572  help(cb) {
1573    this.outputHelp(cb);
1574    // exitCode: preserving original behaviour which was calling process.exit()
1575    // message: do not have all displayed text available so only passing placeholder.
1576    this._exit(process.exitCode || 0, 'commander.help', '(outputHelp)');
1577  };
1578
1579  /**
1580   * Output help information and exit. Display for error situations.
1581   *
1582   * @api private
1583   */
1584
1585  _helpAndError() {
1586    this.outputHelp();
1587    // message: do not have all displayed text available so only passing placeholder.
1588    this._exit(1, 'commander.help', '(outputHelp)');
1589  };
1590};
1591
1592/**
1593 * Expose the root command.
1594 */
1595
1596exports = module.exports = new Command();
1597exports.program = exports; // More explicit access to global command.
1598
1599/**
1600 * Expose classes
1601 */
1602
1603exports.Command = Command;
1604exports.Option = Option;
1605exports.CommanderError = CommanderError;
1606
1607/**
1608 * Camel-case the given `flag`
1609 *
1610 * @param {string} flag
1611 * @return {string}
1612 * @api private
1613 */
1614
1615function camelcase(flag) {
1616  return flag.split('-').reduce((str, word) => {
1617    return str + word[0].toUpperCase() + word.slice(1);
1618  });
1619}
1620
1621/**
1622 * Pad `str` to `width`.
1623 *
1624 * @param {string} str
1625 * @param {number} width
1626 * @return {string}
1627 * @api private
1628 */
1629
1630function pad(str, width) {
1631  const len = Math.max(0, width - str.length);
1632  return str + Array(len + 1).join(' ');
1633}
1634
1635/**
1636 * Wraps the given string with line breaks at the specified width while breaking
1637 * words and indenting every but the first line on the left.
1638 *
1639 * @param {string} str
1640 * @param {number} width
1641 * @param {number} indent
1642 * @return {string}
1643 * @api private
1644 */
1645function wrap(str, width, indent) {
1646  const regex = new RegExp('.{1,' + (width - 1) + '}([\\s\u200B]|$)|[^\\s\u200B]+?([\\s\u200B]|$)', 'g');
1647  const lines = str.match(regex) || [];
1648  return lines.map((line, i) => {
1649    if (line.slice(-1) === '\n') {
1650      line = line.slice(0, line.length - 1);
1651    }
1652    return ((i > 0 && indent) ? Array(indent + 1).join(' ') : '') + line.trimRight();
1653  }).join('\n');
1654}
1655
1656/**
1657 * Optionally wrap the given str to a max width of width characters per line
1658 * while indenting with indent spaces. Do not wrap if insufficient width or
1659 * string is manually formatted.
1660 *
1661 * @param {string} str
1662 * @param {number} width
1663 * @param {number} indent
1664 * @return {string}
1665 * @api private
1666 */
1667function optionalWrap(str, width, indent) {
1668  // Detect manually wrapped and indented strings by searching for line breaks
1669  // followed by multiple spaces/tabs.
1670  if (str.match(/[\n]\s+/)) return str;
1671  // Do not wrap to narrow columns (or can end up with a word per line).
1672  const minWidth = 40;
1673  if (width < minWidth) return str;
1674
1675  return wrap(str, width, indent);
1676}
1677
1678/**
1679 * Output help information if help flags specified
1680 *
1681 * @param {Command} cmd - command to output help for
1682 * @param {Array} args - array of options to search for help flags
1683 * @api private
1684 */
1685
1686function outputHelpIfRequested(cmd, args) {
1687  const helpOption = args.find(arg => arg === cmd._helpLongFlag || arg === cmd._helpShortFlag);
1688  if (helpOption) {
1689    cmd.outputHelp();
1690    // (Do not have all displayed text available so only passing placeholder.)
1691    cmd._exit(0, 'commander.helpDisplayed', '(outputHelp)');
1692  }
1693}
1694
1695/**
1696 * Takes an argument and returns its human readable equivalent for help usage.
1697 *
1698 * @param {Object} arg
1699 * @return {string}
1700 * @api private
1701 */
1702
1703function humanReadableArgName(arg) {
1704  const nameOutput = arg.name + (arg.variadic === true ? '...' : '');
1705
1706  return arg.required
1707    ? '<' + nameOutput + '>'
1708    : '[' + nameOutput + ']';
1709}
1710
1711/**
1712 * Scan arguments and increment port number for inspect calls (to avoid conflicts when spawning new command).
1713 *
1714 * @param {string[]} args - array of arguments from node.execArgv
1715 * @returns {string[]}
1716 * @api private
1717 */
1718
1719function incrementNodeInspectorPort(args) {
1720  // Testing for these options:
1721  //  --inspect[=[host:]port]
1722  //  --inspect-brk[=[host:]port]
1723  //  --inspect-port=[host:]port
1724  return args.map((arg) => {
1725    let result = arg;
1726    if (arg.indexOf('--inspect') === 0) {
1727      let debugOption;
1728      let debugHost = '127.0.0.1';
1729      let debugPort = '9229';
1730      let match;
1731      if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
1732        // e.g. --inspect
1733        debugOption = match[1];
1734      } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
1735        debugOption = match[1];
1736        if (/^\d+$/.test(match[3])) {
1737          // e.g. --inspect=1234
1738          debugPort = match[3];
1739        } else {
1740          // e.g. --inspect=localhost
1741          debugHost = match[3];
1742        }
1743      } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
1744        // e.g. --inspect=localhost:1234
1745        debugOption = match[1];
1746        debugHost = match[3];
1747        debugPort = match[4];
1748      }
1749
1750      if (debugOption && debugPort !== '0') {
1751        result = `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
1752      }
1753    }
1754    return result;
1755  });
1756}
1757