commander 9.0.0-0 → 9.0.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Readme.md CHANGED
@@ -11,6 +11,7 @@ Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
11
11
 
12
12
  - [Commander.js](#commanderjs)
13
13
  - [Installation](#installation)
14
+ - [Quick Start](#quick-start)
14
15
  - [Declaring _program_ variable](#declaring-program-variable)
15
16
  - [Options](#options)
16
17
  - [Common option types, boolean and value](#common-option-types-boolean-and-value)
@@ -46,9 +47,9 @@ Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
46
47
  - [createCommand()](#createcommand)
47
48
  - [Node options such as `--harmony`](#node-options-such-as---harmony)
48
49
  - [Debugging stand-alone executable subcommands](#debugging-stand-alone-executable-subcommands)
50
+ - [Display error](#display-error)
49
51
  - [Override exit and output handling](#override-exit-and-output-handling)
50
52
  - [Additional documentation](#additional-documentation)
51
- - [Examples](#examples)
52
53
  - [Support](#support)
53
54
  - [Commander for enterprise](#commander-for-enterprise)
54
55
 
@@ -60,6 +61,85 @@ For information about terms used in this document see: [terminology](./docs/term
60
61
  npm install commander
61
62
  ```
62
63
 
64
+ ## Quick Start
65
+
66
+ You write code to describe your command line interface.
67
+ Commander looks after parsing the arguments into options and command-arguments,
68
+ displays usage errors for problems, and implements a help system.
69
+
70
+ Commander is strict and displays an error for unrecognised options.
71
+ The two most used option types are a boolean option, and an option which takes its value from the following argument.
72
+
73
+ Example file: [split.js](./examples/split.js)
74
+
75
+ ```js
76
+ const { program } = require('commander');
77
+
78
+ program
79
+ .option('--first')
80
+ .option('-s, --separator <char>');
81
+
82
+ program.parse();
83
+
84
+ const options = program.opts();
85
+ const limit = options.first ? 1 : undefined;
86
+ console.log(program.args[0].split(options.separator, limit));
87
+ ```
88
+
89
+ ```sh
90
+ $ node split.js -s / --fits a/b/c
91
+ error: unknown option '--fits'
92
+ (Did you mean --first?)
93
+ $ node split.js -s / --first a/b/c
94
+ [ 'a' ]
95
+ ```
96
+
97
+ Here is a more complete program using a subcommand and with descriptions for the help. In a multi-command program, you have an action handler for each command (or stand-alone executables for the commands).
98
+
99
+ Example file: [string-util.js](./examples/string-util.js)
100
+
101
+ ```js
102
+ const { Command } = require('commander');
103
+ const program = new Command();
104
+
105
+ program
106
+ .name('string-util')
107
+ .description('CLI to some JavaScript string utilities')
108
+ .version('0.8.0');
109
+
110
+ program.command('split')
111
+ .description('Split a string into substrings and display as an array')
112
+ .argument('<string>', 'string to split')
113
+ .option('--first', 'display just the first substring')
114
+ .option('-s, --separator <char>', 'separator character', ',')
115
+ .action((str, options) => {
116
+ const limit = options.first ? 1 : undefined;
117
+ console.log(str.split(options.separator, limit));
118
+ });
119
+
120
+ program.parse();
121
+ ```
122
+
123
+ ```sh
124
+ $ node string-util.js help split
125
+ Usage: string-util split [options] <string>
126
+
127
+ Split a string into substrings and display as an array.
128
+
129
+ Arguments:
130
+ string string to split
131
+
132
+ Options:
133
+ --first display just the first substring
134
+ -s, --separator <char> separator character (default: ",")
135
+ -h, --help display help for command
136
+
137
+ $ node string-util.js split --separator=/ a/b/c
138
+ [ 'a', 'b', 'c' ]
139
+ ```
140
+
141
+ More samples can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
142
+
63
143
  ## Declaring _program_ variable
64
144
 
65
145
  Commander exports a global object which is convenient for quick programs.
@@ -95,8 +175,6 @@ const program = new Command();
95
175
  Options are defined with the `.option()` method, also serving as documentation for the options. Each option can have a short flag (single character) and a long name, separated by a comma or space or vertical bar ('|').
96
176
 
97
177
  The parsed options can be accessed by calling `.opts()` on a `Command` object, and are passed to the action handler.
98
- (You can also use `.getOptionValue()` and `.setOptionValue()` to work with a single option value,
99
- and `.getOptionValueSource()` and `.setOptionValueWithSource()` when it matters where the option value came from.)
100
178
 
101
179
  Multi-word options such as "--template-engine" are camel-cased, becoming `program.opts().templateEngine` etc.
102
180
 
@@ -107,6 +185,12 @@ You can use `--` to indicate the end of the options, and any remaining arguments
107
185
 
108
186
  By default options on the command line are not positional, and can be specified before or after other arguments.
109
187
 
188
+ There are additional related routines for when `.opts()` is not enough:
189
+
190
+ - `.optsWithGlobals()` returns merged local and global option values
191
+ - `.getOptionValue()` and `.setOptionValue()` work with a single option value
192
+ - `.getOptionValueSource()` and `.setOptionValueWithSource()` include where the option value came from
193
+
110
194
  ### Common option types, boolean and value
111
195
 
112
196
  The two most used option types are a boolean option, and an option which takes its value
@@ -535,6 +619,20 @@ program
535
619
  });
536
620
  ```
537
621
 
622
+ If you prefer, you can work with the command directly and skip declaring the parameters for the action handler. The `this` keyword is set to the running command and can be used from a function expression (but not from an arrow function).
623
+
624
+ Example file: [action-this.js](./examples/action-this.js)
625
+
626
+ ```js
627
+ program
628
+ .command('serve')
629
+ .argument('<script>')
630
+ .option('-p, --port <number>', 'port number', 80)
631
+ .action(function() {
632
+ console.error('Run script %s on port %s', this.args[0], this.opts().port);
633
+ });
634
+ ```
635
+
538
636
  You may supply an `async` action handler, in which case you call `.parseAsync` rather than `.parse`.
539
637
 
540
638
  ```js
@@ -906,6 +1004,18 @@ the inspector port is incremented by 1 for the spawned subcommand.
906
1004
 
907
1005
  If you are using VSCode to debug executable subcommands you need to set the `"autoAttachChildProcesses": true` flag in your launch.json configuration.
908
1006
 
1007
+ ### Display error
1008
+
1009
+ This routine is available to invoke the Commander error handling for your own error conditions. (See also the next section about exit handling.)
1010
+
1011
+ As well as the error message, you can optionally specify the `exitCode` (used with `process.exit`)
1012
+ and `code` (used with `CommanderError`).
1013
+
1014
+ ```js
1015
+ program.exit('Password must be longer than four characters');
1016
+ program.exit('Custom processing has failed', { exitCode: 2, code: 'my.custom.error' });
1017
+ ```
1018
+
909
1019
  ### Override exit and output handling
910
1020
 
911
1021
  By default Commander calls `process.exit` when it detects errors, or after displaying the help or version. You can override
@@ -952,72 +1062,6 @@ There is more information available about:
952
1062
  - [deprecated](./docs/deprecated.md) features still supported for backwards compatibility
953
1063
  - [options taking varying arguments](./docs/options-taking-varying-arguments.md)
954
1064
 
955
- ## Examples
956
-
957
- In a single command program, you might not need an action handler.
958
-
959
- Example file: [pizza](./examples/pizza)
960
-
961
- ```js
962
- const { program } = require('commander');
963
-
964
- program
965
- .description('An application for pizza ordering')
966
- .option('-p, --peppers', 'Add peppers')
967
- .option('-c, --cheese <type>', 'Add the specified type of cheese', 'marble')
968
- .option('-C, --no-cheese', 'You do not want any cheese');
969
-
970
- program.parse();
971
-
972
- const options = program.opts();
973
- console.log('you ordered a pizza with:');
974
- if (options.peppers) console.log(' - peppers');
975
- const cheese = !options.cheese ? 'no' : options.cheese;
976
- console.log(' - %s cheese', cheese);
977
- ```
978
-
979
- In a multi-command program, you will have action handlers for each command (or stand-alone executables for the commands).
980
-
981
- Example file: [deploy](./examples/deploy)
982
-
983
- ```js
984
- const { Command } = require('commander');
985
- const program = new Command();
986
-
987
- program
988
- .name('deploy')
989
- .version('0.0.1')
990
- .option('-c, --config <path>', 'set config path', './deploy.conf');
991
-
992
- program
993
- .command('setup [env]')
994
- .description('run setup commands for all envs')
995
- .option('-s, --setup_mode <mode>', 'Which setup mode to use', 'normal')
996
- .action((env, options) => {
997
- env = env || 'all';
998
- console.log('read config from %s', program.opts().config);
999
- console.log('setup for %s env(s) with %s mode', env, options.setup_mode);
1000
- });
1001
-
1002
- program
1003
- .command('exec <script>')
1004
- .alias('ex')
1005
- .description('execute the given remote cmd')
1006
- .option('-e, --exec_mode <mode>', 'Which exec mode to use', 'fast')
1007
- .action((script, options) => {
1008
- console.log('read config from %s', program.opts().config);
1009
- console.log('exec "%s" using %s mode and config %s', script, options.exec_mode, program.opts().config);
1010
- }).addHelpText('after', `
1011
- Examples:
1012
- $ deploy exec sequential
1013
- $ deploy exec async`
1014
- );
1015
-
1016
- program.parse(process.argv);
1017
- ```
1018
-
1019
- More samples can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
1020
-
1021
1065
  ## Support
1022
1066
 
1023
1067
  The current version of Commander is fully supported on Long Term Support versions of Node.js, and requires at least v12.20.0.
package/lib/argument.js CHANGED
@@ -49,7 +49,7 @@ class Argument {
49
49
 
50
50
  name() {
51
51
  return this._name;
52
- };
52
+ }
53
53
 
54
54
  /**
55
55
  * @api private
@@ -75,7 +75,7 @@ class Argument {
75
75
  this.defaultValue = value;
76
76
  this.defaultValueDescription = description;
77
77
  return this;
78
- };
78
+ }
79
79
 
80
80
  /**
81
81
  * Set the custom handler for processing CLI command arguments into argument values.
@@ -87,7 +87,7 @@ class Argument {
87
87
  argParser(fn) {
88
88
  this.parseArg = fn;
89
89
  return this;
90
- };
90
+ }
91
91
 
92
92
  /**
93
93
  * Only allow argument value to be one of choices.
@@ -97,10 +97,10 @@ class Argument {
97
97
  */
98
98
 
99
99
  choices(values) {
100
- this.argChoices = values;
100
+ this.argChoices = values.slice();
101
101
  this.parseArg = (arg, previous) => {
102
- if (!values.includes(arg)) {
103
- throw new InvalidArgumentError(`Allowed choices are ${values.join(', ')}.`);
102
+ if (!this.argChoices.includes(arg)) {
103
+ throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(', ')}.`);
104
104
  }
105
105
  if (this.variadic) {
106
106
  return this._concatValue(arg, previous);
@@ -108,7 +108,7 @@ class Argument {
108
108
  return arg;
109
109
  };
110
110
  return this;
111
- };
111
+ }
112
112
 
113
113
  /**
114
114
  * Make argument required.
package/lib/command.js CHANGED
@@ -83,7 +83,7 @@ class Command extends EventEmitter {
83
83
  * (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)
84
84
  *
85
85
  * @param {Command} sourceCommand
86
- * @return {Command} returns `this` for executable command
86
+ * @return {Command} `this` command for chaining
87
87
  */
88
88
  copyInheritedSettings(sourceCommand) {
89
89
  this._outputConfiguration = sourceCommand._outputConfiguration;
@@ -157,7 +157,7 @@ class Command extends EventEmitter {
157
157
 
158
158
  if (desc) return this;
159
159
  return cmd;
160
- };
160
+ }
161
161
 
162
162
  /**
163
163
  * Factory routine to create a new unattached command.
@@ -171,7 +171,7 @@ class Command extends EventEmitter {
171
171
 
172
172
  createCommand(name) {
173
173
  return new Command(name);
174
- };
174
+ }
175
175
 
176
176
  /**
177
177
  * You can customise the help with a subclass of Help by overriding createHelp,
@@ -182,7 +182,7 @@ class Command extends EventEmitter {
182
182
 
183
183
  createHelp() {
184
184
  return Object.assign(new Help(), this.configureHelp());
185
- };
185
+ }
186
186
 
187
187
  /**
188
188
  * You can customise the help by overriding Help properties using configureHelp(),
@@ -271,7 +271,7 @@ class Command extends EventEmitter {
271
271
  this.commands.push(cmd);
272
272
  cmd.parent = this;
273
273
  return this;
274
- };
274
+ }
275
275
 
276
276
  /**
277
277
  * Factory routine to create a new unattached argument.
@@ -286,7 +286,7 @@ class Command extends EventEmitter {
286
286
 
287
287
  createArgument(name, description) {
288
288
  return new Argument(name, description);
289
- };
289
+ }
290
290
 
291
291
  /**
292
292
  * Define argument syntax for command.
@@ -332,7 +332,7 @@ class Command extends EventEmitter {
332
332
  this.argument(detail);
333
333
  });
334
334
  return this;
335
- };
335
+ }
336
336
 
337
337
  /**
338
338
  * Define argument syntax for command, adding a prepared argument.
@@ -374,7 +374,7 @@ class Command extends EventEmitter {
374
374
  this._helpCommandDescription = description || this._helpCommandDescription;
375
375
  }
376
376
  return this;
377
- };
377
+ }
378
378
 
379
379
  /**
380
380
  * @return {boolean}
@@ -386,7 +386,7 @@ class Command extends EventEmitter {
386
386
  return this.commands.length && !this._actionHandler && !this._findCommand('help');
387
387
  }
388
388
  return this._addImplicitHelpCommand;
389
- };
389
+ }
390
390
 
391
391
  /**
392
392
  * Add hook for life cycle event.
@@ -430,7 +430,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
430
430
  };
431
431
  }
432
432
  return this;
433
- };
433
+ }
434
434
 
435
435
  /**
436
436
  * Call process.exit, and _exitCallback if defined.
@@ -448,7 +448,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
448
448
  // Expecting this line is not reached.
449
449
  }
450
450
  process.exit(exitCode);
451
- };
451
+ }
452
452
 
453
453
  /**
454
454
  * Register callback `fn` for the command.
@@ -481,7 +481,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
481
481
  };
482
482
  this._actionHandler = listener;
483
483
  return this;
484
- };
484
+ }
485
485
 
486
486
  /**
487
487
  * Factory routine to create a new unattached option.
@@ -496,7 +496,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
496
496
 
497
497
  createOption(flags, description) {
498
498
  return new Option(flags, description);
499
- };
499
+ }
500
500
 
501
501
  /**
502
502
  * Add an option.
@@ -538,7 +538,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
538
538
  } catch (err) {
539
539
  if (err.code === 'commander.invalidArgument') {
540
540
  const message = `${invalidValueMessage} ${err.message}`;
541
- this._displayError(err.exitCode, err.code, message);
541
+ this.error(message, { exitCode: err.exitCode, code: err.code });
542
542
  }
543
543
  throw err;
544
544
  }
@@ -654,7 +654,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
654
654
 
655
655
  option(flags, description, fn, defaultValue) {
656
656
  return this._optionEx({}, flags, description, fn, defaultValue);
657
- };
657
+ }
658
658
 
659
659
  /**
660
660
  * Add a required option which must have a value after parsing. This usually means
@@ -671,7 +671,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
671
671
 
672
672
  requiredOption(flags, description, fn, defaultValue) {
673
673
  return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue);
674
- };
674
+ }
675
675
 
676
676
  /**
677
677
  * Alter parsing of short flags with optional values.
@@ -686,7 +686,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
686
686
  combineFlagAndOptionalValue(combine = true) {
687
687
  this._combineFlagAndOptionalValue = !!combine;
688
688
  return this;
689
- };
689
+ }
690
690
 
691
691
  /**
692
692
  * Allow unknown options on the command line.
@@ -697,7 +697,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
697
697
  allowUnknownOption(allowUnknown = true) {
698
698
  this._allowUnknownOption = !!allowUnknown;
699
699
  return this;
700
- };
700
+ }
701
701
 
702
702
  /**
703
703
  * Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
@@ -708,7 +708,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
708
708
  allowExcessArguments(allowExcess = true) {
709
709
  this._allowExcessArguments = !!allowExcess;
710
710
  return this;
711
- };
711
+ }
712
712
 
713
713
  /**
714
714
  * Enable positional options. Positional means global options are specified before subcommands which lets
@@ -720,7 +720,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
720
720
  enablePositionalOptions(positional = true) {
721
721
  this._enablePositionalOptions = !!positional;
722
722
  return this;
723
- };
723
+ }
724
724
 
725
725
  /**
726
726
  * Pass through options that come after command-arguments rather than treat them as command-options,
@@ -737,7 +737,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
737
737
  throw new Error('passThroughOptions can not be used without turning on enablePositionalOptions for parent command(s)');
738
738
  }
739
739
  return this;
740
- };
740
+ }
741
741
 
742
742
  /**
743
743
  * Whether to store option values as properties on command object,
@@ -753,7 +753,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
753
753
  throw new Error('call .storeOptionsAsProperties() before adding options');
754
754
  }
755
755
  return this;
756
- };
756
+ }
757
757
 
758
758
  /**
759
759
  * Retrieve option value.
@@ -767,7 +767,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
767
767
  return this[key];
768
768
  }
769
769
  return this._optionValues[key];
770
- };
770
+ }
771
771
 
772
772
  /**
773
773
  * Store option value.
@@ -784,7 +784,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
784
784
  this._optionValues[key] = value;
785
785
  }
786
786
  return this;
787
- };
787
+ }
788
788
 
789
789
  /**
790
790
  * Store option value and where the value came from.
@@ -811,7 +811,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
811
811
 
812
812
  getOptionValueSource(key) {
813
813
  return this._optionValueSources[key];
814
- };
814
+ }
815
815
 
816
816
  /**
817
817
  * Get user arguments from implied or explicit arguments.
@@ -889,7 +889,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
889
889
  this._parseCommand([], userArgs);
890
890
 
891
891
  return this;
892
- };
892
+ }
893
893
 
894
894
  /**
895
895
  * Parse `argv`, setting options and invoking commands when defined.
@@ -915,7 +915,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
915
915
  await this._parseCommand([], userArgs);
916
916
 
917
917
  return this;
918
- };
918
+ }
919
919
 
920
920
  /**
921
921
  * Execute a sub-command executable.
@@ -1041,7 +1041,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1041
1041
 
1042
1042
  // Store the reference to the child process
1043
1043
  this.runningCommand = proc;
1044
- };
1044
+ }
1045
1045
 
1046
1046
  /**
1047
1047
  * @api private
@@ -1056,7 +1056,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1056
1056
  } else {
1057
1057
  return subCommand._parseCommand(operands, unknown);
1058
1058
  }
1059
- };
1059
+ }
1060
1060
 
1061
1061
  /**
1062
1062
  * Check this.args against expected this._args.
@@ -1078,7 +1078,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1078
1078
  if (this.args.length > this._args.length) {
1079
1079
  this._excessArguments(this.args);
1080
1080
  }
1081
- };
1081
+ }
1082
1082
 
1083
1083
  /**
1084
1084
  * Process this.args using this._args and save as this.processedArgs!
@@ -1096,7 +1096,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1096
1096
  } catch (err) {
1097
1097
  if (err.code === 'commander.invalidArgument') {
1098
1098
  const message = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'. ${err.message}`;
1099
- this._displayError(err.exitCode, err.code, message);
1099
+ this.error(message, { exitCode: err.exitCode, code: err.code });
1100
1100
  }
1101
1101
  throw err;
1102
1102
  }
@@ -1266,7 +1266,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1266
1266
  this._processArguments();
1267
1267
  // fall through for caller to handle after calling .parse()
1268
1268
  }
1269
- };
1269
+ }
1270
1270
 
1271
1271
  /**
1272
1272
  * Find matching command.
@@ -1276,7 +1276,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1276
1276
  _findCommand(name) {
1277
1277
  if (!name) return undefined;
1278
1278
  return this.commands.find(cmd => cmd._name === name || cmd._aliases.includes(name));
1279
- };
1279
+ }
1280
1280
 
1281
1281
  /**
1282
1282
  * Return an option matching `arg` if any.
@@ -1288,7 +1288,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1288
1288
 
1289
1289
  _findOption(arg) {
1290
1290
  return this.options.find(option => option.is(arg));
1291
- };
1291
+ }
1292
1292
 
1293
1293
  /**
1294
1294
  * Display an error message if a mandatory option does not have a value.
@@ -1306,7 +1306,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1306
1306
  }
1307
1307
  });
1308
1308
  }
1309
- };
1309
+ }
1310
1310
 
1311
1311
  /**
1312
1312
  * Parse options from `argv` removing known options,
@@ -1438,10 +1438,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1438
1438
  }
1439
1439
 
1440
1440
  return { operands, unknown };
1441
- };
1441
+ }
1442
1442
 
1443
1443
  /**
1444
- * Return an object containing options as key-value pairs
1444
+ * Return an object containing local option values as key-value pairs.
1445
1445
  *
1446
1446
  * @return {Object}
1447
1447
  */
@@ -1459,14 +1459,31 @@ Expecting one of '${allowedValues.join("', '")}'`);
1459
1459
  }
1460
1460
 
1461
1461
  return this._optionValues;
1462
- };
1462
+ }
1463
1463
 
1464
1464
  /**
1465
- * Internal bottleneck for handling of parsing errors.
1465
+ * Return an object containing merged local and global option values as key-value pairs.
1466
1466
  *
1467
- * @api private
1467
+ * @return {Object}
1468
1468
  */
1469
- _displayError(exitCode, code, message) {
1469
+ optsWithGlobals() {
1470
+ // globals overwrite locals
1471
+ return getCommandAndParents(this).reduce(
1472
+ (combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()),
1473
+ {}
1474
+ );
1475
+ }
1476
+
1477
+ /**
1478
+ * Display error message and exit (or call exitOverride).
1479
+ *
1480
+ * @param {string} message
1481
+ * @param {Object} [errorOptions]
1482
+ * @param {string} [errorOptions.code] - an id string representing the error
1483
+ * @param {number} [errorOptions.exitCode] - used with process.exit
1484
+ */
1485
+ error(message, errorOptions) {
1486
+ // output handling
1470
1487
  this._outputConfiguration.outputError(`${message}\n`, this._outputConfiguration.writeErr);
1471
1488
  if (typeof this._showHelpAfterError === 'string') {
1472
1489
  this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`);
@@ -1474,6 +1491,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1474
1491
  this._outputConfiguration.writeErr('\n');
1475
1492
  this.outputHelp({ error: true });
1476
1493
  }
1494
+
1495
+ // exit handling
1496
+ const config = errorOptions || {};
1497
+ const exitCode = config.exitCode || 1;
1498
+ const code = config.code || 'commander.error';
1477
1499
  this._exit(exitCode, code, message);
1478
1500
  }
1479
1501
 
@@ -1510,8 +1532,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
1510
1532
 
1511
1533
  missingArgument(name) {
1512
1534
  const message = `error: missing required argument '${name}'`;
1513
- this._displayError(1, 'commander.missingArgument', message);
1514
- };
1535
+ this.error(message, { code: 'commander.missingArgument' });
1536
+ }
1515
1537
 
1516
1538
  /**
1517
1539
  * `Option` is missing an argument.
@@ -1522,8 +1544,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
1522
1544
 
1523
1545
  optionMissingArgument(option) {
1524
1546
  const message = `error: option '${option.flags}' argument missing`;
1525
- this._displayError(1, 'commander.optionMissingArgument', message);
1526
- };
1547
+ this.error(message, { code: 'commander.optionMissingArgument' });
1548
+ }
1527
1549
 
1528
1550
  /**
1529
1551
  * `Option` does not have a value, and is a mandatory option.
@@ -1534,8 +1556,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
1534
1556
 
1535
1557
  missingMandatoryOptionValue(option) {
1536
1558
  const message = `error: required option '${option.flags}' not specified`;
1537
- this._displayError(1, 'commander.missingMandatoryOptionValue', message);
1538
- };
1559
+ this.error(message, { code: 'commander.missingMandatoryOptionValue' });
1560
+ }
1539
1561
 
1540
1562
  /**
1541
1563
  * Unknown option `flag`.
@@ -1563,8 +1585,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
1563
1585
  }
1564
1586
 
1565
1587
  const message = `error: unknown option '${flag}'${suggestion}`;
1566
- this._displayError(1, 'commander.unknownOption', message);
1567
- };
1588
+ this.error(message, { code: 'commander.unknownOption' });
1589
+ }
1568
1590
 
1569
1591
  /**
1570
1592
  * Excess arguments, more than expected.
@@ -1580,8 +1602,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
1580
1602
  const s = (expected === 1) ? '' : 's';
1581
1603
  const forSubcommand = this.parent ? ` for '${this.name()}'` : '';
1582
1604
  const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
1583
- this._displayError(1, 'commander.excessArguments', message);
1584
- };
1605
+ this.error(message, { code: 'commander.excessArguments' });
1606
+ }
1585
1607
 
1586
1608
  /**
1587
1609
  * Unknown command.
@@ -1604,8 +1626,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
1604
1626
  }
1605
1627
 
1606
1628
  const message = `error: unknown command '${unknownName}'${suggestion}`;
1607
- this._displayError(1, 'commander.unknownCommand', message);
1608
- };
1629
+ this.error(message, { code: 'commander.unknownCommand' });
1630
+ }
1609
1631
 
1610
1632
  /**
1611
1633
  * Set the program version to `str`.
@@ -1634,7 +1656,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1634
1656
  this._exit(0, 'commander.version', str);
1635
1657
  });
1636
1658
  return this;
1637
- };
1659
+ }
1638
1660
 
1639
1661
  /**
1640
1662
  * Set the description to `str`.
@@ -1650,7 +1672,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1650
1672
  this._argsDescription = argsDescription;
1651
1673
  }
1652
1674
  return this;
1653
- };
1675
+ }
1654
1676
 
1655
1677
  /**
1656
1678
  * Set an alias for the command.
@@ -1675,7 +1697,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1675
1697
 
1676
1698
  command._aliases.push(alias);
1677
1699
  return this;
1678
- };
1700
+ }
1679
1701
 
1680
1702
  /**
1681
1703
  * Set aliases for the command.
@@ -1692,7 +1714,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1692
1714
 
1693
1715
  aliases.forEach((alias) => this.alias(alias));
1694
1716
  return this;
1695
- };
1717
+ }
1696
1718
 
1697
1719
  /**
1698
1720
  * Set / get the command usage `str`.
@@ -1717,7 +1739,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1717
1739
 
1718
1740
  this._usage = str;
1719
1741
  return this;
1720
- };
1742
+ }
1721
1743
 
1722
1744
  /**
1723
1745
  * Get or set the name of the command.
@@ -1730,7 +1752,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1730
1752
  if (str === undefined) return this._name;
1731
1753
  this._name = str;
1732
1754
  return this;
1733
- };
1755
+ }
1734
1756
 
1735
1757
  /**
1736
1758
  * Set the name of the command from script filename, such as process.argv[1],
@@ -1767,7 +1789,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1767
1789
  if (path === undefined) return this._executableDir;
1768
1790
  this._executableDir = path;
1769
1791
  return this;
1770
- };
1792
+ }
1771
1793
 
1772
1794
  /**
1773
1795
  * Return program help documentation.
@@ -1782,7 +1804,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1782
1804
  helper.helpWidth = (contextOptions && contextOptions.error) ? this._outputConfiguration.getErrHelpWidth() : this._outputConfiguration.getOutHelpWidth();
1783
1805
  }
1784
1806
  return helper.formatHelp(this, helper);
1785
- };
1807
+ }
1786
1808
 
1787
1809
  /**
1788
1810
  * @api private
@@ -1833,7 +1855,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1833
1855
  this.emit(this._helpLongFlag); // deprecated
1834
1856
  this.emit('afterHelp', context);
1835
1857
  getCommandAndParents(this).forEach(command => command.emit('afterAllHelp', context));
1836
- };
1858
+ }
1837
1859
 
1838
1860
  /**
1839
1861
  * You can pass in flags and a description to override the help
@@ -1858,7 +1880,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1858
1880
  this._helpLongFlag = helpFlags.longFlag;
1859
1881
 
1860
1882
  return this;
1861
- };
1883
+ }
1862
1884
 
1863
1885
  /**
1864
1886
  * Output help information and exit.
@@ -1876,7 +1898,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1876
1898
  }
1877
1899
  // message: do not have all displayed text available so only passing placeholder.
1878
1900
  this._exit(exitCode, 'commander.help', '(outputHelp)');
1879
- };
1901
+ }
1880
1902
 
1881
1903
  /**
1882
1904
  * Add additional text to be displayed with the built-in help.
@@ -1909,7 +1931,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1909
1931
  });
1910
1932
  return this;
1911
1933
  }
1912
- };
1934
+ }
1913
1935
 
1914
1936
  /**
1915
1937
  * Output help information if help flags specified
package/lib/help.js CHANGED
@@ -98,7 +98,7 @@ class Help {
98
98
  // If there are any arguments with a description then return all the arguments.
99
99
  if (cmd._args.find(argument => argument.description)) {
100
100
  return cmd._args;
101
- };
101
+ }
102
102
  return [];
103
103
  }
104
104
 
@@ -152,7 +152,7 @@ class Help {
152
152
  return helper.visibleCommands(cmd).reduce((max, command) => {
153
153
  return Math.max(max, helper.subcommandTerm(command).length);
154
154
  }, 0);
155
- };
155
+ }
156
156
 
157
157
  /**
158
158
  * Get the longest option term length.
@@ -166,7 +166,7 @@ class Help {
166
166
  return helper.visibleOptions(cmd).reduce((max, option) => {
167
167
  return Math.max(max, helper.optionTerm(option).length);
168
168
  }, 0);
169
- };
169
+ }
170
170
 
171
171
  /**
172
172
  * Get the longest argument term length.
@@ -180,7 +180,7 @@ class Help {
180
180
  return helper.visibleArguments(cmd).reduce((max, argument) => {
181
181
  return Math.max(max, helper.argumentTerm(argument).length);
182
182
  }, 0);
183
- };
183
+ }
184
184
 
185
185
  /**
186
186
  * Get the command usage to be displayed at the top of the built-in help.
@@ -262,7 +262,7 @@ class Help {
262
262
  }
263
263
 
264
264
  return option.description;
265
- };
265
+ }
266
266
 
267
267
  /**
268
268
  * Get the argument description to show in the list of arguments.
@@ -310,7 +310,7 @@ class Help {
310
310
  return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
311
311
  }
312
312
  return term;
313
- };
313
+ }
314
314
  function formatList(textArray) {
315
315
  return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
316
316
  }
@@ -365,7 +365,7 @@ class Help {
365
365
  helper.longestSubcommandTermLength(cmd, helper),
366
366
  helper.longestArgumentTermLength(cmd, helper)
367
367
  );
368
- };
368
+ }
369
369
 
370
370
  /**
371
371
  * Wrap the given string to width characters per line, with lines after the first indented.
package/lib/option.js CHANGED
@@ -47,7 +47,7 @@ class Option {
47
47
  this.defaultValue = value;
48
48
  this.defaultValueDescription = description;
49
49
  return this;
50
- };
50
+ }
51
51
 
52
52
  /**
53
53
  * Preset to use when option used without option-argument, especially optional but also boolean and negated.
@@ -64,7 +64,7 @@ class Option {
64
64
  preset(arg) {
65
65
  this.presetArg = arg;
66
66
  return this;
67
- };
67
+ }
68
68
 
69
69
  /**
70
70
  * Set environment variable to check for option value.
@@ -77,7 +77,7 @@ class Option {
77
77
  env(name) {
78
78
  this.envVar = name;
79
79
  return this;
80
- };
80
+ }
81
81
 
82
82
  /**
83
83
  * Set the custom handler for processing CLI option arguments into option values.
@@ -89,7 +89,7 @@ class Option {
89
89
  argParser(fn) {
90
90
  this.parseArg = fn;
91
91
  return this;
92
- };
92
+ }
93
93
 
94
94
  /**
95
95
  * Whether the option is mandatory and must have a value after parsing.
@@ -101,7 +101,7 @@ class Option {
101
101
  makeOptionMandatory(mandatory = true) {
102
102
  this.mandatory = !!mandatory;
103
103
  return this;
104
- };
104
+ }
105
105
 
106
106
  /**
107
107
  * Hide option in help.
@@ -113,7 +113,7 @@ class Option {
113
113
  hideHelp(hide = true) {
114
114
  this.hidden = !!hide;
115
115
  return this;
116
- };
116
+ }
117
117
 
118
118
  /**
119
119
  * @api private
@@ -135,10 +135,10 @@ class Option {
135
135
  */
136
136
 
137
137
  choices(values) {
138
- this.argChoices = values;
138
+ this.argChoices = values.slice();
139
139
  this.parseArg = (arg, previous) => {
140
- if (!values.includes(arg)) {
141
- throw new InvalidArgumentError(`Allowed choices are ${values.join(', ')}.`);
140
+ if (!this.argChoices.includes(arg)) {
141
+ throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(', ')}.`);
142
142
  }
143
143
  if (this.variadic) {
144
144
  return this._concatValue(arg, previous);
@@ -146,7 +146,7 @@ class Option {
146
146
  return arg;
147
147
  };
148
148
  return this;
149
- };
149
+ }
150
150
 
151
151
  /**
152
152
  * Return option name.
@@ -159,7 +159,7 @@ class Option {
159
159
  return this.long.replace(/^--/, '');
160
160
  }
161
161
  return this.short.replace(/^-/, '');
162
- };
162
+ }
163
163
 
164
164
  /**
165
165
  * Return option name, in a camelcase format that can be used
@@ -171,7 +171,7 @@ class Option {
171
171
 
172
172
  attributeName() {
173
173
  return camelcase(this.name().replace(/^no-/, ''));
174
- };
174
+ }
175
175
 
176
176
  /**
177
177
  * Check if `arg` matches the short or long flag.
@@ -183,7 +183,7 @@ class Option {
183
183
 
184
184
  is(arg) {
185
185
  return this.short === arg || this.long === arg;
186
- };
186
+ }
187
187
 
188
188
  /**
189
189
  * Return whether a boolean option.
@@ -196,7 +196,7 @@ class Option {
196
196
 
197
197
  isBoolean() {
198
198
  return !this.required && !this.optional && !this.negate;
199
- };
199
+ }
200
200
  }
201
201
 
202
202
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commander",
3
- "version": "9.0.0-0",
3
+ "version": "9.0.0-1",
4
4
  "description": "the complete solution for node.js command-line programs",
5
5
  "keywords": [
6
6
  "commander",
@@ -19,13 +19,14 @@
19
19
  "url": "https://github.com/tj/commander.js.git"
20
20
  },
21
21
  "scripts": {
22
- "lint": "eslint index.js esm.mjs \"lib/*.js\" \"tests/**/*.js\"",
23
- "typescript-lint": "eslint typings/*.ts tests/*.ts",
22
+ "lint": "npm run lint:javascript && npm run lint:typescript",
23
+ "lint:javascript": "eslint index.js esm.mjs \"lib/*.js\" \"tests/**/*.js\"",
24
+ "lint:typescript": "eslint typings/*.ts tests/*.ts",
24
25
  "test": "jest && npm run test-typings",
25
26
  "test-esm": "node --experimental-modules ./tests/esm-imports-test.mjs",
26
27
  "test-typings": "tsd",
27
28
  "typescript-checkJS": "tsc --allowJS --checkJS index.js lib/*.js --noEmit",
28
- "test-all": "npm run test && npm run lint && npm run typescript-lint && npm run typescript-checkJS && npm run test-esm"
29
+ "test-all": "npm run test && npm run lint && npm run typescript-checkJS && npm run test-esm"
29
30
  },
30
31
  "files": [
31
32
  "index.js",
@@ -46,13 +47,16 @@
46
47
  "devDependencies": {
47
48
  "@types/jest": "^27.0.3",
48
49
  "@types/node": "^16.11.15",
49
- "@typescript-eslint/eslint-plugin": "^4.27.0",
50
+ "@typescript-eslint/eslint-plugin": "^4.33.0",
50
51
  "@typescript-eslint/parser": "^4.27.0",
51
52
  "eslint": "^7.29.0",
52
53
  "eslint-config-standard": "^16.0.3",
54
+ "eslint-config-standard-with-typescript": "^21.0.1",
55
+ "eslint-plugin-import": "^2.25.3",
53
56
  "eslint-plugin-jest": "^24.3.6",
57
+ "eslint-plugin-node": "^11.1.0",
58
+ "eslint-plugin-promise": "^5.2.0",
54
59
  "jest": "^27.0.4",
55
- "standard": "^16.0.3",
56
60
  "ts-jest": "^27.0.3",
57
61
  "tsd": "^0.17.0",
58
62
  "typescript": "^4.3.4"
@@ -31,6 +31,13 @@ export class InvalidArgumentError extends CommanderError {
31
31
  }
32
32
  export { InvalidArgumentError as InvalidOptionArgumentError }; // deprecated old name
33
33
 
34
+ export interface ErrorOptions { // optional parameter for error()
35
+ /** an id string representing the error */
36
+ code?: string;
37
+ /** suggested exit code which could be used with process.exit */
38
+ exitCode?: number;
39
+ }
40
+
34
41
  export class Argument {
35
42
  description: string;
36
43
  required: boolean;
@@ -61,7 +68,7 @@ export class Argument {
61
68
  /**
62
69
  * Only allow argument value to be one of choices.
63
70
  */
64
- choices(values: string[]): this;
71
+ choices(values: readonly string[]): this;
65
72
 
66
73
  /**
67
74
  * Make argument required.
@@ -72,7 +79,7 @@ export class Argument {
72
79
  * Make argument optional.
73
80
  */
74
81
  argOptional(): this;
75
- }
82
+ }
76
83
 
77
84
  export class Option {
78
85
  flags: string;
@@ -109,7 +116,7 @@ export class Option {
109
116
  * new Option('--donate [amount]').preset('20').argParser(parseFloat);
110
117
  * ```
111
118
  */
112
- preset(arg: unknown): this;
119
+ preset(arg: unknown): this;
113
120
 
114
121
  /**
115
122
  * Set environment variable to check for option value.
@@ -140,7 +147,7 @@ export class Option {
140
147
  /**
141
148
  * Only allow option value to be one of choices.
142
149
  */
143
- choices(values: string[]): this;
150
+ choices(values: readonly string[]): this;
144
151
 
145
152
  /**
146
153
  * Return option name.
@@ -158,8 +165,7 @@ export class Option {
158
165
  *
159
166
  * Options are one of boolean, negated, required argument, or optional argument.
160
167
  */
161
- isBoolean(): boolean;
162
-
168
+ isBoolean(): boolean;
163
169
  }
164
170
 
165
171
  export class Help {
@@ -340,8 +346,8 @@ export class Command {
340
346
  *
341
347
  * @returns `this` command for chaining
342
348
  */
343
- argument<T>(flags: string, description: string, fn: (value: string, previous: T) => T, defaultValue?: T): this;
344
- argument(name: string, description?: string, defaultValue?: unknown): this;
349
+ argument<T>(flags: string, description: string, fn: (value: string, previous: T) => T, defaultValue?: T): this;
350
+ argument(name: string, description?: string, defaultValue?: unknown): this;
345
351
 
346
352
  /**
347
353
  * Define argument syntax for command, adding a prepared argument.
@@ -388,6 +394,11 @@ export class Command {
388
394
  */
389
395
  exitOverride(callback?: (err: CommanderError) => never|void): this;
390
396
 
397
+ /**
398
+ * Display error message and exit (or call exitOverride).
399
+ */
400
+ error(message: string, errorOptions?: ErrorOptions): never;
401
+
391
402
  /**
392
403
  * You can customise the help with a subclass of Help by overriding createHelp,
393
404
  * or by overriding Help properties using configureHelp().
@@ -439,7 +450,7 @@ export class Command {
439
450
  */
440
451
  showSuggestionAfterError(displaySuggestion?: boolean): this;
441
452
 
442
- /**
453
+ /**
443
454
  * Register callback `fn` for the command.
444
455
  *
445
456
  * @example
@@ -562,7 +573,7 @@ export class Command {
562
573
  */
563
574
  getOptionValueSource(key: string): OptionValueSource;
564
575
 
565
- /**
576
+ /**
566
577
  * Alter parsing of short flags with optional values.
567
578
  *
568
579
  * @example
@@ -626,7 +637,7 @@ export class Command {
626
637
  *
627
638
  * @returns `this` command for chaining
628
639
  */
629
- parse(argv?: string[], options?: ParseOptions): this;
640
+ parse(argv?: readonly string[], options?: ParseOptions): this;
630
641
 
631
642
  /**
632
643
  * Parse `argv`, setting options and invoking commands when defined.
@@ -645,7 +656,7 @@ export class Command {
645
656
  *
646
657
  * @returns Promise
647
658
  */
648
- parseAsync(argv?: string[], options?: ParseOptions): Promise<this>;
659
+ parseAsync(argv?: readonly string[], options?: ParseOptions): Promise<this>;
649
660
 
650
661
  /**
651
662
  * Parse options from `argv` removing known options,
@@ -660,10 +671,15 @@ export class Command {
660
671
  parseOptions(argv: string[]): ParseOptionsResult;
661
672
 
662
673
  /**
663
- * Return an object containing options as key-value pairs
674
+ * Return an object containing local option values as key-value pairs
664
675
  */
665
676
  opts<T extends OptionValues>(): T;
666
677
 
678
+ /**
679
+ * Return an object containing merged local and global option values as key-value pairs.
680
+ */
681
+ optsWithGlobals<T extends OptionValues>(): T;
682
+
667
683
  /**
668
684
  * Set the description.
669
685
  *
@@ -698,7 +714,7 @@ export class Command {
698
714
  *
699
715
  * @returns `this` command for chaining
700
716
  */
701
- aliases(aliases: string[]): this;
717
+ aliases(aliases: readonly string[]): this;
702
718
  /**
703
719
  * Get aliases for the command.
704
720
  */
@@ -759,7 +775,7 @@ export class Command {
759
775
  */
760
776
  executableDir(): string;
761
777
 
762
- /**
778
+ /**
763
779
  * Output help information for this command.
764
780
  *
765
781
  * Outputs built-in help, and custom text added using `.addHelpText()`.