commander 5.1.0 → 6.2.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/CHANGELOG.md CHANGED
@@ -6,6 +6,65 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). (Format adopted after v3.0.0.)
7
7
 
8
8
  <!-- markdownlint-disable MD024 -->
9
+ <!-- markdownlint-disable MD004 -->
10
+
11
+ ## [6.2.1] (2020-12-13)
12
+
13
+ ### Fixed
14
+
15
+ - some tests failed if directory path included a space ([1390])
16
+
17
+ ## [6.2.0] (2020-10-25)
18
+
19
+ ### Added
20
+
21
+ - added 'tsx' file extension for stand-alone executable subcommands ([#1368])
22
+ - documented second parameter to `.description()` to describe command arguments ([#1353])
23
+ - documentation of special cases with options taking varying numbers of option-arguments ([#1332])
24
+ - documentation for terminology ([#1361])
25
+
26
+ ### Fixed
27
+
28
+ - add missing TypeScript definition for `.addHelpCommand()' ([#1375])
29
+ - removed blank line after "Arguments:" in help, to match "Options:" and "Commands:" ([#1360])
30
+
31
+ ### Changed
32
+
33
+ - update dependencies
34
+
35
+ ## [6.1.0] (2020-08-28)
36
+
37
+ ### Added
38
+
39
+ - include URL to relevant section of README for error for potential conflict between Command properties and option values ([#1306])
40
+ - `.combineFlagAndOptionalValue(false)` to ease upgrade path from older versions of Commander ([#1326])
41
+ - allow disabling the built-in help option using `.helpOption(false)` ([#1325])
42
+ - allow just some arguments in `argumentDescription` to `.description()` ([#1323])
43
+
44
+ ### Changed
45
+
46
+ - tidy async test and remove lint override ([#1312])
47
+
48
+ ### Fixed
49
+
50
+ - executable subcommand launching when script path not known ([#1322])
51
+
52
+ ## [6.0.0] (2020-07-21)
53
+
54
+ ### Added
55
+
56
+ - add support for variadic options ([#1250])
57
+ - allow options to be added with just a short flag ([#1256])
58
+ - *Breaking* the option property has same case as flag. e.g. flag `-n` accessed as `opts().n` (previously uppercase)
59
+ - *Breaking* throw an error if there might be a clash between option name and a Command property, with advice on how to resolve ([#1275])
60
+
61
+ ### Fixed
62
+
63
+ - Options which contain -no- in the middle of the option flag should not be treated as negatable. ([#1301])
64
+
65
+ ## [6.0.0-0] (2020-06-20)
66
+
67
+ (Released in 6.0.0)
9
68
 
10
69
  ## [5.1.0] (2020-04-25)
11
70
 
@@ -96,6 +155,9 @@ If you use `program.args` or more complicated tests to detect a missing subcomma
96
155
 
97
156
  If you use `.command('*')` to add a default command, you may be be able to switch to `isDefault:true` with a named command.
98
157
 
158
+ If you want to continue combining short options with optional values as though they were boolean flags, set `combineFlagAndOptionalValue(false)`
159
+ to expand `-fb` to `-f -b` rather than `-f b`.
160
+
99
161
  ## [5.0.0-4] (2020-03-03)
100
162
 
101
163
  (Released in 5.0.0)
@@ -198,95 +260,9 @@ if (program.rawArgs.length < 3) ...
198
260
 
199
261
  (Released in 4.0.0)
200
262
 
201
- ## [2.20.1] (2019-09-29)
202
-
203
- ### Fixed
204
-
205
- * Improve tracking of executable subcommands.
206
-
207
- ### Changed
208
-
209
- * update development dependencies
210
-
211
- ## [3.0.2] (2019-09-27)
212
-
213
- ### Fixed
214
-
215
- * Improve tracking of executable subcommands.
216
-
217
- ### Changed
218
-
219
- * update development dependencies
220
-
221
- ## [3.0.1] (2019-08-30)
222
-
223
- ### Added
224
-
225
- * .name and .usage to README ([#1010])
226
- * Table of Contents to README ([#1010])
227
- * TypeScript definition for `executableFile` in CommandOptions ([#1028])
228
-
229
- ### Changed
230
-
231
- * consistently use `const` rather than `var` in README ([#1026])
232
-
233
- ### Fixed
234
-
235
- * help for sub commands with custom executableFile ([#1018])
236
-
237
- ## [3.0.0] / 2019-08-08
238
-
239
- * Add option to specify executable file name ([#999])
240
- * e.g. `.command('clone', 'clone description', { executableFile: 'myClone' })`
241
- * Change docs for `.command` to contrast action handler vs git-style executable. ([#938] [#990])
242
- * **Breaking** Change TypeScript to use overloaded function for `.command`. ([#938] [#990])
243
- * Change to use straight quotes around strings in error messages (like 'this' instead of `this') ([#915])
244
- * Add TypeScript "reference types" for node ([#974])
245
- * Add support for hyphen as an option argument in subcommands ([#697])
246
- * Add support for a short option flag and its value to be concatenated for action handler subcommands ([#599])
247
- * e.g. `-p 80` can also be supplied as `-p80`
248
- * Add executable arguments to spawn in win32, for git-style executables ([#611])
249
- * e.g. `node --harmony myCommand.js clone`
250
- * Add parent command as prefix of subcommand in help ([#980])
251
- * Add optional custom description to `.version` ([#963])
252
- * e.g. `program.version('0.0.1', '-v, --vers', 'output the current version')`
253
- * Add `.helpOption(flags, description)` routine to customise help flags and description ([#963])
254
- * e.g. `.helpOption('-e, --HELP', 'read more information')`
255
- * Fix behavior of --no-* options ([#795])
256
- * can now define both `--foo` and `--no-foo`
257
- * **Breaking** custom event listeners: `--no-foo` on cli now emits `option:no-foo` (previously `option:foo`)
258
- * **Breaking** default value: defining `--no-foo` after defining `--foo` leaves the default value unchanged (previously set it to false)
259
- * allow boolean default value, such as from environment ([#987])
260
- * Increment inspector port for spawned subcommands ([#991])
261
- * e.g. `node --inspect myCommand.js clone`
262
-
263
- ### Migration Tips
264
-
265
- The custom event for a negated option like `--no-foo` is `option:no-foo` (previously `option:foo`).
266
-
267
- ```js
268
- program
269
- .option('--no-foo')
270
- .on('option:no-foo', () => {
271
- console.log('removing foo');
272
- });
273
- ```
274
-
275
- When using TypeScript, adding a command does not allow an explicit `undefined` for an unwanted executable description (e.g
276
- for a command with an action handler).
277
-
278
- ```js
279
- program
280
- .command('action1', undefined, { noHelp: true }) // No longer valid
281
- .command('action2', { noHelp: true }) // Correct
282
- ```
283
-
284
- ## 3.0.0-0 Prerelease / 2019-07-28
285
-
286
- (Released as 3.0.0)
287
-
288
263
  ## Older versions
289
264
 
265
+ * [3.x](./changelogs/CHANGELOG-3.md)
290
266
  * [2.x](./changelogs/CHANGELOG-2.md)
291
267
  * [1.x](./changelogs/CHANGELOG-1.md)
292
268
  * [0.x](./changelogs/CHANGELOG-0.md)
@@ -296,34 +272,16 @@ program
296
272
  [#508]: https://github.com/tj/commander.js/issues/508
297
273
  [#512]: https://github.com/tj/commander.js/issues/512
298
274
  [#531]: https://github.com/tj/commander.js/issues/531
299
- [#599]: https://github.com/tj/commander.js/issues/599
300
- [#611]: https://github.com/tj/commander.js/issues/611
301
275
  [#645]: https://github.com/tj/commander.js/issues/645
302
- [#697]: https://github.com/tj/commander.js/issues/697
303
276
  [#742]: https://github.com/tj/commander.js/issues/742
304
277
  [#764]: https://github.com/tj/commander.js/issues/764
305
- [#795]: https://github.com/tj/commander.js/issues/795
306
278
  [#802]: https://github.com/tj/commander.js/issues/802
307
279
  [#806]: https://github.com/tj/commander.js/issues/806
308
280
  [#809]: https://github.com/tj/commander.js/issues/809
309
- [#915]: https://github.com/tj/commander.js/issues/915
310
- [#938]: https://github.com/tj/commander.js/issues/938
311
281
  [#948]: https://github.com/tj/commander.js/issues/948
312
282
  [#962]: https://github.com/tj/commander.js/issues/962
313
- [#963]: https://github.com/tj/commander.js/issues/963
314
- [#974]: https://github.com/tj/commander.js/issues/974
315
- [#980]: https://github.com/tj/commander.js/issues/980
316
- [#987]: https://github.com/tj/commander.js/issues/987
317
- [#990]: https://github.com/tj/commander.js/issues/990
318
- [#991]: https://github.com/tj/commander.js/issues/991
319
- [#993]: https://github.com/tj/commander.js/issues/993
320
283
  [#995]: https://github.com/tj/commander.js/issues/995
321
- [#999]: https://github.com/tj/commander.js/issues/999
322
- [#1010]: https://github.com/tj/commander.js/pull/1010
323
- [#1018]: https://github.com/tj/commander.js/pull/1018
324
- [#1026]: https://github.com/tj/commander.js/pull/1026
325
284
  [#1027]: https://github.com/tj/commander.js/pull/1027
326
- [#1028]: https://github.com/tj/commander.js/pull/1028
327
285
  [#1032]: https://github.com/tj/commander.js/issues/1032
328
286
  [#1035]: https://github.com/tj/commander.js/pull/1035
329
287
  [#1040]: https://github.com/tj/commander.js/pull/1040
@@ -364,8 +322,30 @@ program
364
322
  [#1236]: https://github.com/tj/commander.js/pull/1236
365
323
  [#1247]: https://github.com/tj/commander.js/pull/1247
366
324
  [#1248]: https://github.com/tj/commander.js/pull/1248
325
+ [#1250]: https://github.com/tj/commander.js/pull/1250
326
+ [#1256]: https://github.com/tj/commander.js/pull/1256
327
+ [#1275]: https://github.com/tj/commander.js/pull/1275
328
+ [#1301]: https://github.com/tj/commander.js/issues/1301
329
+ [#1306]: https://github.com/tj/commander.js/pull/1306
330
+ [#1312]: https://github.com/tj/commander.js/pull/1312
331
+ [#1322]: https://github.com/tj/commander.js/pull/1322
332
+ [#1323]: https://github.com/tj/commander.js/pull/1323
333
+ [#1325]: https://github.com/tj/commander.js/pull/1325
334
+ [#1326]: https://github.com/tj/commander.js/pull/1326
335
+ [#1332]: https://github.com/tj/commander.js/pull/1332
336
+ [#1353]: https://github.com/tj/commander.js/pull/1353
337
+ [#1360]: https://github.com/tj/commander.js/pull/1360
338
+ [#1361]: https://github.com/tj/commander.js/pull/1361
339
+ [#1368]: https://github.com/tj/commander.js/pull/1368
340
+ [#1375]: https://github.com/tj/commander.js/pull/1375
341
+ [#1390]: https://github.com/tj/commander.js/pull/1390
367
342
 
368
343
  [Unreleased]: https://github.com/tj/commander.js/compare/master...develop
344
+ [6.2.1]: https://github.com/tj/commander.js/compare/v6.2.0..v6.2.1
345
+ [6.2.0]: https://github.com/tj/commander.js/compare/v6.1.0..v6.2.0
346
+ [6.1.0]: https://github.com/tj/commander.js/compare/v6.0.0..v6.1.0
347
+ [6.0.0]: https://github.com/tj/commander.js/compare/v5.1.0..v6.0.0
348
+ [6.0.0-0]: https://github.com/tj/commander.js/compare/v5.1.0..v6.0.0-0
369
349
  [5.1.0]: https://github.com/tj/commander.js/compare/v5.0.0..v5.1.0
370
350
  [5.0.0]: https://github.com/tj/commander.js/compare/v4.1.1..v5.0.0
371
351
  [5.0.0-4]: https://github.com/tj/commander.js/compare/v5.0.0-3..v5.0.0-4
@@ -379,7 +359,3 @@ program
379
359
  [4.0.0]: https://github.com/tj/commander.js/compare/v3.0.2..v4.0.0
380
360
  [4.0.0-1]: https://github.com/tj/commander.js/compare/v4.0.0-0..v4.0.0-1
381
361
  [4.0.0-0]: https://github.com/tj/commander.js/compare/v3.0.2...v4.0.0-0
382
- [3.0.2]: https://github.com/tj/commander.js/compare/v3.0.1...v3.0.2
383
- [3.0.1]: https://github.com/tj/commander.js/compare/v3.0.0...v3.0.1
384
- [3.0.0]: https://github.com/tj/commander.js/compare/v2.20.1...v3.0.0
385
- [2.20.1]: https://github.com/tj/commander.js/compare/v2.20.0...v2.20.1
package/Readme.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://npmcharts.com/compare/commander?minimal=true)
6
6
  [![Install Size](https://packagephobia.now.sh/badge?p=commander)](https://packagephobia.now.sh/result?p=commander)
7
7
 
8
- The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/commander-rb/commander).
8
+ The complete solution for [node.js](http://nodejs.org) command-line interfaces.
9
9
 
10
10
  Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
11
11
 
@@ -15,9 +15,10 @@ Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
15
15
  - [Options](#options)
16
16
  - [Common option types, boolean and value](#common-option-types-boolean-and-value)
17
17
  - [Default option value](#default-option-value)
18
- - [Other option types, negatable boolean and flag|value](#other-option-types-negatable-boolean-and-flagvalue)
18
+ - [Other option types, negatable boolean and boolean|value](#other-option-types-negatable-boolean-and-booleanvalue)
19
19
  - [Custom option processing](#custom-option-processing)
20
20
  - [Required option](#required-option)
21
+ - [Variadic option](#variadic-option)
21
22
  - [Version option](#version-option)
22
23
  - [Commands](#commands)
23
24
  - [Specify the argument syntax](#specify-the-argument-syntax)
@@ -37,14 +38,16 @@ Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
37
38
  - [Avoiding option name clashes](#avoiding-option-name-clashes)
38
39
  - [TypeScript](#typescript)
39
40
  - [createCommand()](#createcommand)
41
+ - [Import into ECMAScript Module](#import-into-ecmascript-module)
40
42
  - [Node options such as `--harmony`](#node-options-such-as---harmony)
41
43
  - [Debugging stand-alone executable subcommands](#debugging-stand-alone-executable-subcommands)
42
44
  - [Override exit handling](#override-exit-handling)
43
45
  - [Examples](#examples)
44
- - [License](#license)
45
46
  - [Support](#support)
46
47
  - [Commander for enterprise](#commander-for-enterprise)
47
48
 
49
+ For information about terms used in this document see: [terminology](./docs/terminology.md)
50
+
48
51
  ## Installation
49
52
 
50
53
  ```bash
@@ -63,11 +66,11 @@ program.version('0.0.1');
63
66
 
64
67
  For larger programs which may use commander in multiple ways, including unit testing, it is better to create a local Command object to use.
65
68
 
66
- ```js
67
- const { Command } = require('commander');
68
- const program = new Command();
69
- program.version('0.0.1');
70
- ```
69
+ ```js
70
+ const { Command } = require('commander');
71
+ const program = new Command();
72
+ program.version('0.0.1');
73
+ ```
71
74
 
72
75
  ## Options
73
76
 
@@ -75,22 +78,21 @@ Options are defined with the `.option()` method, also serving as documentation f
75
78
 
76
79
  The options can be accessed as properties on the Command object. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. See also optional new behaviour to [avoid name clashes](#avoiding-option-name-clashes).
77
80
 
78
- Multiple short flags may optionally be combined in a single argument following the dash: boolean flags, the last flag may take a value, and the value.
81
+ Multiple short flags may optionally be combined in a single argument following the dash: boolean flags, followed by a single option taking a value (possibly followed by the value).
79
82
  For example `-a -b -p 80` may be written as `-ab -p80` or even `-abp80`.
80
83
 
81
84
  You can use `--` to indicate the end of the options, and any remaining arguments will be used without being interpreted.
82
- This is particularly useful for passing options through to another
83
- command, like: `do -- git --version`.
84
85
 
85
- Options on the command line are not positional, and can be specified before or after other command arguments.
86
+ Options on the command line are not positional, and can be specified before or after other arguments.
86
87
 
87
88
  ### Common option types, boolean and value
88
89
 
89
- The two most used option types are a boolean flag, and an option which takes a value (declared using angle brackets). Both are `undefined` unless specified on command line.
90
+ The two most used option types are a boolean option, and an option which takes its value
91
+ from the following argument (declared with angle brackets like `--expect <value>`). Both are `undefined` unless specified on command line.
90
92
 
91
- ```js
92
- const { program } = require('commander');
93
+ Example file: [options-common.js](./examples/options-common.js)
93
94
 
95
+ ```js
94
96
  program
95
97
  .option('-d, --debug', 'output extra debugging')
96
98
  .option('-s, --small', 'small pizza size')
@@ -126,9 +128,9 @@ pizza details:
126
128
 
127
129
  You can specify a default value for an option which takes a value.
128
130
 
129
- ```js
130
- const { program } = require('commander');
131
+ Example file: [options-defaults.js](./examples/options-defaults.js)
131
132
 
133
+ ```js
132
134
  program
133
135
  .option('-c, --cheese <type>', 'add the specified type of cheese', 'blue');
134
136
 
@@ -144,17 +146,17 @@ $ pizza-options --cheese stilton
144
146
  cheese: stilton
145
147
  ```
146
148
 
147
- ### Other option types, negatable boolean and flag|value
149
+ ### Other option types, negatable boolean and boolean|value
148
150
 
149
- You can specify a boolean option long name with a leading `no-` to set the option value to false when used.
151
+ You can define a boolean option long name with a leading `no-` to set the option value to false when used.
150
152
  Defined alone this also makes the option true by default.
151
153
 
152
154
  If you define `--foo` first, adding `--no-foo` does not change the default value from what it would
153
- otherwise be. You can specify a default boolean value for a boolean flag and it can be overridden on command line.
155
+ otherwise be. You can specify a default boolean value for a boolean option and it can be overridden on command line.
154
156
 
155
- ```js
156
- const { program } = require('commander');
157
+ Example file: [options-negatable.js](./examples/options-negatable.js)
157
158
 
159
+ ```js
158
160
  program
159
161
  .option('--no-sauce', 'Remove sauce')
160
162
  .option('--cheese <flavour>', 'cheese flavour', 'mozzarella')
@@ -177,11 +179,12 @@ $ pizza-options --no-sauce --no-cheese
177
179
  You ordered a pizza with no sauce and no cheese
178
180
  ```
179
181
 
180
- You can specify an option which functions as a flag but may also take a value (declared using square brackets).
182
+ You can specify an option which may be used as a boolean option but may optionally take an option-argument
183
+ (declared with square brackets like `--optional [value]`).
181
184
 
182
- ```js
183
- const { program } = require('commander');
185
+ Example file: [options-boolean-or-value.js](./examples/options-boolean-or-value.js)
184
186
 
187
+ ```js
185
188
  program
186
189
  .option('-c, --cheese [type]', 'Add cheese with optional type');
187
190
 
@@ -201,18 +204,20 @@ $ pizza-options --cheese mozzarella
201
204
  add cheese type mozzarella
202
205
  ```
203
206
 
207
+ For information about possible ambiguous cases, see [options taking varying arguments](./docs/options-taking-varying-arguments.md).
208
+
204
209
  ### Custom option processing
205
210
 
206
- You may specify a function to do custom processing of option values. The callback function receives two parameters, the user specified value and the
207
- previous value for the option. It returns the new value for the option.
211
+ You may specify a function to do custom processing of option-arguments. The callback function receives two parameters,
212
+ the user specified option-argument and the previous value for the option. It returns the new value for the option.
208
213
 
209
- This allows you to coerce the option value to the desired type, or accumulate values, or do entirely custom processing.
214
+ This allows you to coerce the option-argument to the desired type, or accumulate values, or do entirely custom processing.
210
215
 
211
- You can optionally specify the default/starting value for the option after the function.
216
+ You can optionally specify the default/starting value for the option after the function parameter.
212
217
 
213
- ```js
214
- const { program } = require('commander');
218
+ Example file: [options-custom-processing.js](./examples/options-custom-processing.js)
215
219
 
220
+ ```js
216
221
  function myParseInt(value, dummyPrevious) {
217
222
  // parseInt takes a string and an optional radix
218
223
  return parseInt(value);
@@ -264,9 +269,9 @@ $ custom --list x,y,z
264
269
 
265
270
  You may specify a required (mandatory) option using `.requiredOption`. The option must have a value after parsing, usually specified on the command line, or perhaps from a default value (say from environment). The method is otherwise the same as `.option` in format, taking flags and description, and optional default value or custom processing.
266
271
 
267
- ```js
268
- const { program } = require('commander');
272
+ Example file: [options-required.js](./examples/options-required.js)
269
273
 
274
+ ```js
270
275
  program
271
276
  .requiredOption('-c, --cheese <type>', 'pizza must have cheese');
272
277
 
@@ -278,6 +283,40 @@ $ pizza
278
283
  error: required option '-c, --cheese <type>' not specified
279
284
  ```
280
285
 
286
+ ### Variadic option
287
+
288
+ You may make an option variadic by appending `...` to the value placeholder when declaring the option. On the command line you
289
+ can then specify multiple option-arguments, and the parsed option value will be an array. The extra arguments
290
+ are read until the first argument starting with a dash. The special argument `--` stops option processing entirely. If a value
291
+ is specified in the same argument as the option then no further values are read.
292
+
293
+ Example file: [options-variadic.js](./examples/options-variadic.js)
294
+
295
+ ```js
296
+ program
297
+ .option('-n, --number <numbers...>', 'specify numbers')
298
+ .option('-l, --letter [letters...]', 'specify letters');
299
+
300
+ program.parse();
301
+
302
+ console.log('Options: ', program.opts());
303
+ console.log('Remaining arguments: ', program.args);
304
+ ```
305
+
306
+ ```bash
307
+ $ collect -n 1 2 3 --letter a b c
308
+ Options: { number: [ '1', '2', '3' ], letter: [ 'a', 'b', 'c' ] }
309
+ Remaining arguments: []
310
+ $ collect --letter=A -n80 operand
311
+ Options: { number: [ '80' ], letter: [ 'A' ] }
312
+ Remaining arguments: [ 'operand' ]
313
+ $ collect --letter -n 1 -n 2 3 -- operand
314
+ Options: { number: [ '1', '2', '3' ], letter: true }
315
+ Remaining arguments: [ 'operand' ]
316
+ ```
317
+
318
+ For information about possible ambiguous cases, see [options taking varying arguments](./docs/options-taking-varying-arguments.md).
319
+
281
320
  ### Version option
282
321
 
283
322
  The optional `version` method adds handling for displaying the command version. The default option flags are `-V` and `--version`, and when present the command prints the version number and exits.
@@ -292,7 +331,7 @@ $ ./examples/pizza -V
292
331
  ```
293
332
 
294
333
  You may change the flags and description by passing additional parameters to the `version` method, using
295
- the same syntax for flags as the `option` method. The version flags can be named anything, but a long name is required.
334
+ the same syntax for flags as the `option` method.
296
335
 
297
336
  ```js
298
337
  program.version('0.0.1', '-v, --vers', 'output the current version');
@@ -302,7 +341,7 @@ program.version('0.0.1', '-v, --vers', 'output the current version');
302
341
 
303
342
  You can specify (sub)commands using `.command()` or `.addCommand()`. There are two ways these can be implemented: using an action handler attached to the command, or as a stand-alone executable file (described in more detail later). The subcommands may be nested ([example](./examples/nestedCommands.js)).
304
343
 
305
- In the first parameter to `.command()` you specify the command name and any command arguments. The arguments may be `<required>` or `[optional]`, and the last argument may also be `variadic...`.
344
+ In the first parameter to `.command()` you specify the command name and any command-arguments. The arguments may be `<required>` or `[optional]`, and the last argument may also be `variadic...`.
306
345
 
307
346
  You can use `.addCommand()` to add an already configured subcommand to the program.
308
347
 
@@ -330,31 +369,33 @@ program
330
369
  .addCommand(build.makeBuildCommand());
331
370
  ```
332
371
 
333
- Configuration options can be passed with the call to `.command()` and `.addCommand()`. Specifying `true` for `opts.hidden` will remove the command from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified ([example](./examples/defaultCommand.js)).
372
+ Configuration options can be passed with the call to `.command()` and `.addCommand()`. Specifying `hidden: true` will
373
+ remove the command from the generated help output. Specifying `isDefault: true` will run the subcommand if no other
374
+ subcommand is specified ([example](./examples/defaultCommand.js)).
334
375
 
335
376
  ### Specify the argument syntax
336
377
 
337
- You use `.arguments` to specify the arguments for the top-level command, and for subcommands they are usually included in the `.command` call. Angled brackets (e.g. `<required>`) indicate required input. Square brackets (e.g. `[optional]`) indicate optional input.
378
+ You use `.arguments` to specify the expected command-arguments for the top-level command, and for subcommands they are usually
379
+ included in the `.command` call. Angled brackets (e.g. `<required>`) indicate required command-arguments.
380
+ Square brackets (e.g. `[optional]`) indicate optional command-arguments.
381
+ You can optionally describe the arguments in the help by supplying a hash as second parameter to `.description()`.
338
382
 
339
- ```js
340
- const { program } = require('commander');
383
+ Example file: [env](./examples/env)
341
384
 
385
+ ```js
342
386
  program
343
387
  .version('0.1.0')
344
388
  .arguments('<cmd> [env]')
389
+ .description('test command', {
390
+ cmd: 'command to run',
391
+ env: 'environment to run test in'
392
+ })
345
393
  .action(function (cmd, env) {
346
- cmdValue = cmd;
347
- envValue = env;
394
+ console.log('command:', cmd);
395
+ console.log('environment:', env || 'no environment given');
348
396
  });
349
397
 
350
398
  program.parse(process.argv);
351
-
352
- if (typeof cmdValue === 'undefined') {
353
- console.error('no command given!');
354
- process.exit(1);
355
- }
356
- console.log('command:', cmdValue);
357
- console.log('environment:', envValue || "no environment given");
358
399
  ```
359
400
 
360
401
  The last argument of a command can be variadic, and only the last argument. To make an argument variadic you
@@ -422,17 +463,17 @@ You can specify a custom name with the `executableFile` configuration option.
422
463
 
423
464
  You handle the options for an executable (sub)command in the executable, and don't declare them at the top-level.
424
465
 
425
- ```js
426
- // file: ./examples/pm
427
- const { program } = require('commander');
466
+ Example file: [pm](./examples/pm)
428
467
 
468
+ ```js
429
469
  program
430
470
  .version('0.1.0')
431
471
  .command('install [name]', 'install one or more packages')
432
472
  .command('search [query]', 'search with optional query')
433
- .command('update', 'update installed packages', {executableFile: 'myUpdateSubCommand'})
434
- .command('list', 'list packages installed', {isDefault: true})
435
- .parse(process.argv);
473
+ .command('update', 'update installed packages', { executableFile: 'myUpdateSubCommand' })
474
+ .command('list', 'list packages installed', { isDefault: true });
475
+
476
+ program.parse(process.argv);
436
477
  ```
437
478
 
438
479
  If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
@@ -440,7 +481,9 @@ If the program is designed to be installed globally, make sure the executables h
440
481
  ## Automated help
441
482
 
442
483
  The help information is auto-generated based on the information commander already knows about your program. The default
443
- help option is `-h,--help`. ([example](./examples/pizza))
484
+ help option is `-h,--help`.
485
+
486
+ Example file: [pizza](./examples/pizza)
444
487
 
445
488
  ```bash
446
489
  $ node ./examples/pizza --help
@@ -469,7 +512,9 @@ shell spawn --help
469
512
 
470
513
  ### Custom help
471
514
 
472
- You can display extra information by listening for "--help". ([example](./examples/custom-help))
515
+ You can display extra information by listening for "--help".
516
+
517
+ Example file: [custom-help](./examples/custom-help)
473
518
 
474
519
  ```js
475
520
  program
@@ -529,7 +574,7 @@ from `--help` listeners.)
529
574
 
530
575
  ### .helpOption(flags, description)
531
576
 
532
- Override the default help flags and description.
577
+ Override the default help flags and description. Pass false to disable the built-in help option.
533
578
 
534
579
  ```js
535
580
  program
@@ -597,7 +642,7 @@ There are two new routines to change the behaviour, and the default behaviour ma
597
642
  - `passCommandToAction`: whether to pass command to action handler,
598
643
  or just the options (specify false)
599
644
 
600
- ([example](./examples/storeOptionsAsProperties-action.js))
645
+ Example file: [storeOptionsAsProperties-action.js](./examples/storeOptionsAsProperties-action.js)
601
646
 
602
647
  ```js
603
648
  program
@@ -644,6 +689,17 @@ const program = createCommand();
644
689
  when creating subcommands using `.command()`, and you may override it to
645
690
  customise the new subcommand (examples using [subclass](./examples/custom-command-class.js) and [function](./examples/custom-command-function.js)).
646
691
 
692
+ ### Import into ECMAScript Module
693
+
694
+ Commander is currently a CommonJS package, and the default export can be imported into an ES Module:
695
+
696
+ ```js
697
+ // index.mjs
698
+ import commander from 'commander';
699
+ const program = commander.program;
700
+ const newCommand = new commander.Command();
701
+ ```
702
+
647
703
  ### Node options such as `--harmony`
648
704
 
649
705
  You can enable `--harmony` option in two ways:
@@ -668,7 +724,7 @@ this behaviour and optionally supply a callback. The default override throws a `
668
724
  The override callback is passed a `CommanderError` with properties `exitCode` number, `code` string, and `message`. The default override behaviour is to throw the error, except for async handling of executable subcommand completion which carries on. The normal display of error messages or version or help
669
725
  is not affected by the override which is called after the display.
670
726
 
671
- ``` js
727
+ ```js
672
728
  program.exitOverride();
673
729
 
674
730
  try {
@@ -680,6 +736,8 @@ try {
680
736
 
681
737
  ## Examples
682
738
 
739
+ Example file: [deploy](./examples/deploy)
740
+
683
741
  ```js
684
742
  const { program } = require('commander');
685
743
 
@@ -719,13 +777,9 @@ program.parse(process.argv);
719
777
 
720
778
  More Demos can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
721
779
 
722
- ## License
723
-
724
- [MIT](https://github.com/tj/commander.js/blob/master/LICENSE)
725
-
726
780
  ## Support
727
781
 
728
- Commander 5.x is fully supported on Long Term Support versions of Node, and is likely to work with Node 6 but not tested.
782
+ The current version of Commander is fully supported on Long Term Support versions of Node, and is likely to work with Node 6 but not tested.
729
783
  (For versions of Node below Node 6, use Commander 3.x or 2.x.)
730
784
 
731
785
  The main forum for free and community support is the project [Issues](https://github.com/tj/commander.js/issues) on GitHub.
package/index.js CHANGED
@@ -20,13 +20,18 @@ class Option {
20
20
 
21
21
  constructor(flags, description) {
22
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.
23
+ this.required = flags.includes('<'); // A value must be supplied when the option is specified.
24
+ this.optional = flags.includes('['); // A value is optional when the option is specified.
25
+ // variadic test ignores <value,...> et al which might be used to describe custom splitting of single argument
26
+ this.variadic = /\w\.\.\.[>\]]$/.test(flags); // The option can take multiple values.
25
27
  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();
28
+ const optionFlags = _parseOptionFlags(flags);
29
+ this.short = optionFlags.shortFlag;
30
+ this.long = optionFlags.longFlag;
31
+ this.negate = false;
32
+ if (this.long) {
33
+ this.negate = this.long.startsWith('--no-');
34
+ }
30
35
  this.description = description || '';
31
36
  this.defaultValue = undefined;
32
37
  }
@@ -39,7 +44,10 @@ class Option {
39
44
  */
40
45
 
41
46
  name() {
42
- return this.long.replace(/^--/, '');
47
+ if (this.long) {
48
+ return this.long.replace(/^--/, '');
49
+ }
50
+ return this.short.replace(/^-/, '');
43
51
  };
44
52
 
45
53
  /**
@@ -110,6 +118,7 @@ class Command extends EventEmitter {
110
118
  this._name = name || '';
111
119
  this._optionValues = {};
112
120
  this._storeOptionsAsProperties = true; // backwards compatible by default
121
+ this._storeOptionsAsPropertiesCalled = false;
113
122
  this._passCommandToAction = true; // backwards compatible by default
114
123
  this._actionResults = [];
115
124
  this._actionHandler = null;
@@ -118,8 +127,10 @@ class Command extends EventEmitter {
118
127
  this._defaultCommandName = null;
119
128
  this._exitCallback = null;
120
129
  this._aliases = [];
130
+ this._combineFlagAndOptionalValue = true;
121
131
 
122
132
  this._hidden = false;
133
+ this._hasHelpOption = true;
123
134
  this._helpFlags = '-h, --help';
124
135
  this._helpDescription = 'display help for command';
125
136
  this._helpShortFlag = '-h';
@@ -175,6 +186,7 @@ class Command extends EventEmitter {
175
186
  if (opts.isDefault) this._defaultCommandName = cmd._name;
176
187
 
177
188
  cmd._hidden = !!(opts.noHelp || opts.hidden);
189
+ cmd._hasHelpOption = this._hasHelpOption;
178
190
  cmd._helpFlags = this._helpFlags;
179
191
  cmd._helpDescription = this._helpDescription;
180
192
  cmd._helpShortFlag = this._helpShortFlag;
@@ -185,6 +197,7 @@ class Command extends EventEmitter {
185
197
  cmd._exitCallback = this._exitCallback;
186
198
  cmd._storeOptionsAsProperties = this._storeOptionsAsProperties;
187
199
  cmd._passCommandToAction = this._passCommandToAction;
200
+ cmd._combineFlagAndOptionalValue = this._combineFlagAndOptionalValue;
188
201
 
189
202
  cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor
190
203
  this.commands.push(cmd);
@@ -260,7 +273,7 @@ class Command extends EventEmitter {
260
273
  *
261
274
  * addHelpCommand() // force on
262
275
  * addHelpCommand(false); // force off
263
- * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom detais
276
+ * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details
264
277
  *
265
278
  * @return {Command} `this` command for chaining
266
279
  * @api public
@@ -422,13 +435,56 @@ class Command extends EventEmitter {
422
435
  return this;
423
436
  };
424
437
 
438
+ /**
439
+ * Internal routine to check whether there is a clash storing option value with a Command property.
440
+ *
441
+ * @param {Option} option
442
+ * @api private
443
+ */
444
+
445
+ _checkForOptionNameClash(option) {
446
+ if (!this._storeOptionsAsProperties || this._storeOptionsAsPropertiesCalled) {
447
+ // Storing options safely, or user has been explicit and up to them.
448
+ return;
449
+ }
450
+ // User may override help, and hard to tell if worth warning.
451
+ if (option.name() === 'help') {
452
+ return;
453
+ }
454
+
455
+ const commandProperty = this._getOptionValue(option.attributeName());
456
+ if (commandProperty === undefined) {
457
+ // no clash
458
+ return;
459
+ }
460
+
461
+ let foundClash = true;
462
+ if (option.negate) {
463
+ // It is ok if define foo before --no-foo.
464
+ const positiveLongFlag = option.long.replace(/^--no-/, '--');
465
+ foundClash = !this._findOption(positiveLongFlag);
466
+ } else if (option.long) {
467
+ const negativeLongFlag = option.long.replace(/^--/, '--no-');
468
+ foundClash = !this._findOption(negativeLongFlag);
469
+ }
470
+
471
+ if (foundClash) {
472
+ throw new Error(`option '${option.name()}' clashes with existing property '${option.attributeName()}' on Command
473
+ - call storeOptionsAsProperties(false) to store option values safely,
474
+ - or call storeOptionsAsProperties(true) to suppress this check,
475
+ - or change option name
476
+
477
+ Read more on https://git.io/JJc0W`);
478
+ }
479
+ };
480
+
425
481
  /**
426
482
  * Internal implementation shared by .option() and .requiredOption()
427
483
  *
428
484
  * @param {Object} config
429
485
  * @param {string} flags
430
486
  * @param {string} description
431
- * @param {Function|*} [fn] - custom option processing function or default vaue
487
+ * @param {Function|*} [fn] - custom option processing function or default value
432
488
  * @param {*} [defaultValue]
433
489
  * @return {Command} `this` command for chaining
434
490
  * @api private
@@ -440,6 +496,8 @@ class Command extends EventEmitter {
440
496
  const name = option.attributeName();
441
497
  option.mandatory = !!config.mandatory;
442
498
 
499
+ this._checkForOptionNameClash(option);
500
+
443
501
  // default as 3rd arg
444
502
  if (typeof fn !== 'function') {
445
503
  if (fn instanceof RegExp) {
@@ -476,13 +534,21 @@ class Command extends EventEmitter {
476
534
  // when it's passed assign the value
477
535
  // and conditionally invoke the callback
478
536
  this.on('option:' + oname, (val) => {
479
- // coercion
537
+ const oldValue = this._getOptionValue(name);
538
+
539
+ // custom processing
480
540
  if (val !== null && fn) {
481
- val = fn(val, this._getOptionValue(name) === undefined ? defaultValue : this._getOptionValue(name));
541
+ val = fn(val, oldValue === undefined ? defaultValue : oldValue);
542
+ } else if (val !== null && option.variadic) {
543
+ if (oldValue === defaultValue || !Array.isArray(oldValue)) {
544
+ val = [val];
545
+ } else {
546
+ val = oldValue.concat(val);
547
+ }
482
548
  }
483
549
 
484
550
  // unassigned or boolean value
485
- if (typeof this._getOptionValue(name) === 'boolean' || typeof this._getOptionValue(name) === 'undefined') {
551
+ if (typeof oldValue === 'boolean' || typeof oldValue === 'undefined') {
486
552
  // if no value, negate false, and we have a default, then use it!
487
553
  if (val == null) {
488
554
  this._setOptionValue(name, option.negate
@@ -546,7 +612,7 @@ class Command extends EventEmitter {
546
612
  *
547
613
  * @param {string} flags
548
614
  * @param {string} description
549
- * @param {Function|*} [fn] - custom option processing function or default vaue
615
+ * @param {Function|*} [fn] - custom option processing function or default value
550
616
  * @param {*} [defaultValue]
551
617
  * @return {Command} `this` command for chaining
552
618
  * @api public
@@ -556,7 +622,7 @@ class Command extends EventEmitter {
556
622
  return this._optionEx({}, flags, description, fn, defaultValue);
557
623
  };
558
624
 
559
- /*
625
+ /**
560
626
  * Add a required option which must have a value after parsing. This usually means
561
627
  * the option must be specified on the command line. (Otherwise the same as .option().)
562
628
  *
@@ -564,7 +630,7 @@ class Command extends EventEmitter {
564
630
  *
565
631
  * @param {string} flags
566
632
  * @param {string} description
567
- * @param {Function|*} [fn] - custom option processing function or default vaue
633
+ * @param {Function|*} [fn] - custom option processing function or default value
568
634
  * @param {*} [defaultValue]
569
635
  * @return {Command} `this` command for chaining
570
636
  * @api public
@@ -574,6 +640,23 @@ class Command extends EventEmitter {
574
640
  return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue);
575
641
  };
576
642
 
643
+ /**
644
+ * Alter parsing of short flags with optional values.
645
+ *
646
+ * Examples:
647
+ *
648
+ * // for `.option('-f,--flag [value]'):
649
+ * .combineFlagAndOptionalValue(true) // `-f80` is treated like `--flag=80`, this is the default behaviour
650
+ * .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
651
+ *
652
+ * @param {Boolean} [arg] - if `true` or omitted, an optional value can be specified directly after the flag.
653
+ * @api public
654
+ */
655
+ combineFlagAndOptionalValue(arg) {
656
+ this._combineFlagAndOptionalValue = (arg === undefined) || arg;
657
+ return this;
658
+ };
659
+
577
660
  /**
578
661
  * Allow unknown options on the command line.
579
662
  *
@@ -596,6 +679,7 @@ class Command extends EventEmitter {
596
679
  */
597
680
 
598
681
  storeOptionsAsProperties(value) {
682
+ this._storeOptionsAsPropertiesCalled = true;
599
683
  this._storeOptionsAsProperties = (value === undefined) || value;
600
684
  if (this.options.length) {
601
685
  throw new Error('call .storeOptionsAsProperties() before adding options');
@@ -754,13 +838,17 @@ class Command extends EventEmitter {
754
838
  _executeSubCommand(subcommand, args) {
755
839
  args = args.slice();
756
840
  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'];
841
+ const sourceExt = ['.js', '.ts', '.tsx', '.mjs'];
758
842
 
759
843
  // Not checking for help first. Unlikely to have mandatory and executable, and can't robustly test for help flags in external command.
760
844
  this._checkForMissingMandatoryOptions();
761
845
 
762
846
  // Want the entry script as the reference for command name and directory for searching for other files.
763
- const scriptPath = this._scriptPath;
847
+ let scriptPath = this._scriptPath;
848
+ // Fallback in case not set, due to how Command created or called.
849
+ if (!scriptPath && process.mainModule) {
850
+ scriptPath = process.mainModule.filename;
851
+ }
764
852
 
765
853
  let baseDir;
766
854
  try {
@@ -891,7 +979,7 @@ class Command extends EventEmitter {
891
979
  this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
892
980
  } else {
893
981
  if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
894
- // probaby missing subcommand and no handler, user needs help
982
+ // probably missing subcommand and no handler, user needs help
895
983
  this._helpAndError();
896
984
  }
897
985
 
@@ -998,6 +1086,7 @@ class Command extends EventEmitter {
998
1086
  }
999
1087
 
1000
1088
  // parse options
1089
+ let activeVariadicOption = null;
1001
1090
  while (args.length) {
1002
1091
  const arg = args.shift();
1003
1092
 
@@ -1008,6 +1097,12 @@ class Command extends EventEmitter {
1008
1097
  break;
1009
1098
  }
1010
1099
 
1100
+ if (activeVariadicOption && !maybeOption(arg)) {
1101
+ this.emit(`option:${activeVariadicOption.name()}`, arg);
1102
+ continue;
1103
+ }
1104
+ activeVariadicOption = null;
1105
+
1011
1106
  if (maybeOption(arg)) {
1012
1107
  const option = this._findOption(arg);
1013
1108
  // recognised option, call listener to assign value with possible custom processing
@@ -1026,6 +1121,7 @@ class Command extends EventEmitter {
1026
1121
  } else { // boolean flag
1027
1122
  this.emit(`option:${option.name()}`);
1028
1123
  }
1124
+ activeVariadicOption = option.variadic ? option : null;
1029
1125
  continue;
1030
1126
  }
1031
1127
  }
@@ -1034,7 +1130,7 @@ class Command extends EventEmitter {
1034
1130
  if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
1035
1131
  const option = this._findOption(`-${arg[1]}`);
1036
1132
  if (option) {
1037
- if (option.required || option.optional) {
1133
+ if (option.required || (option.optional && this._combineFlagAndOptionalValue)) {
1038
1134
  // option with value following in same argument
1039
1135
  this.emit(`option:${option.name()}`, arg.slice(2));
1040
1136
  } else {
@@ -1161,7 +1257,8 @@ class Command extends EventEmitter {
1161
1257
  partCommands.unshift(parentCmd.name());
1162
1258
  }
1163
1259
  const fullCommand = partCommands.join(' ');
1164
- const message = `error: unknown command '${this.args[0]}'. See '${fullCommand} ${this._helpLongFlag}'.`;
1260
+ const message = `error: unknown command '${this.args[0]}'.` +
1261
+ (this._hasHelpOption ? ` See '${fullCommand} ${this._helpLongFlag}'.` : '');
1165
1262
  console.error(message);
1166
1263
  this._exit(1, 'commander.unknownCommand', message);
1167
1264
  };
@@ -1187,9 +1284,9 @@ class Command extends EventEmitter {
1187
1284
  flags = flags || '-V, --version';
1188
1285
  description = description || 'output the version number';
1189
1286
  const versionOption = new Option(flags, description);
1190
- this._versionOptionName = versionOption.long.substr(2) || 'version';
1287
+ this._versionOptionName = versionOption.attributeName();
1191
1288
  this.options.push(versionOption);
1192
- this.on('option:' + this._versionOptionName, () => {
1289
+ this.on('option:' + versionOption.name(), () => {
1193
1290
  process.stdout.write(str + '\n');
1194
1291
  this._exit(0, 'commander.version', str);
1195
1292
  });
@@ -1270,9 +1367,11 @@ class Command extends EventEmitter {
1270
1367
  const args = this._args.map((arg) => {
1271
1368
  return humanReadableArgName(arg);
1272
1369
  });
1273
- return '[options]' +
1274
- (this.commands.length ? ' [command]' : '') +
1275
- (this._args.length ? ' ' + args.join(' ') : '');
1370
+ return [].concat(
1371
+ (this.options.length || this._hasHelpOption ? '[options]' : []),
1372
+ (this.commands.length ? '[command]' : []),
1373
+ (this._args.length ? args : [])
1374
+ ).join(' ');
1276
1375
  }
1277
1376
 
1278
1377
  this._usage = str;
@@ -1415,8 +1514,8 @@ class Command extends EventEmitter {
1415
1514
  });
1416
1515
 
1417
1516
  // Implicit help
1418
- const showShortHelpFlag = this._helpShortFlag && !this._findOption(this._helpShortFlag);
1419
- const showLongHelpFlag = !this._findOption(this._helpLongFlag);
1517
+ const showShortHelpFlag = this._hasHelpOption && this._helpShortFlag && !this._findOption(this._helpShortFlag);
1518
+ const showLongHelpFlag = this._hasHelpOption && !this._findOption(this._helpLongFlag);
1420
1519
  if (showShortHelpFlag || showLongHelpFlag) {
1421
1520
  let helpFlags = this._helpFlags;
1422
1521
  if (!showShortHelpFlag) {
@@ -1477,9 +1576,8 @@ class Command extends EventEmitter {
1477
1576
  const columns = process.stdout.columns || 80;
1478
1577
  const descriptionWidth = columns - width - 5;
1479
1578
  desc.push('Arguments:');
1480
- desc.push('');
1481
1579
  this._args.forEach((arg) => {
1482
- desc.push(' ' + pad(arg.name, width) + ' ' + wrap(argsDescription[arg.name], descriptionWidth, width + 4));
1580
+ desc.push(' ' + pad(arg.name, width) + ' ' + wrap(argsDescription[arg.name] || '', descriptionWidth, width + 4));
1483
1581
  });
1484
1582
  desc.push('');
1485
1583
  }
@@ -1502,11 +1600,14 @@ class Command extends EventEmitter {
1502
1600
  const commandHelp = this.commandHelp();
1503
1601
  if (commandHelp) cmds = [commandHelp];
1504
1602
 
1505
- const options = [
1506
- 'Options:',
1507
- '' + this.optionHelp().replace(/^/gm, ' '),
1508
- ''
1509
- ];
1603
+ let options = [];
1604
+ if (this._hasHelpOption || this.options.length > 0) {
1605
+ options = [
1606
+ 'Options:',
1607
+ '' + this.optionHelp().replace(/^/gm, ' '),
1608
+ ''
1609
+ ];
1610
+ }
1510
1611
 
1511
1612
  return usage
1512
1613
  .concat(desc)
@@ -1540,24 +1641,26 @@ class Command extends EventEmitter {
1540
1641
 
1541
1642
  /**
1542
1643
  * You can pass in flags and a description to override the help
1543
- * flags and help description for your command.
1644
+ * flags and help description for your command. Pass in false to
1645
+ * disable the built-in help option.
1544
1646
  *
1545
- * @param {string} [flags]
1647
+ * @param {string | boolean} [flags]
1546
1648
  * @param {string} [description]
1547
1649
  * @return {Command} `this` command for chaining
1548
1650
  * @api public
1549
1651
  */
1550
1652
 
1551
1653
  helpOption(flags, description) {
1654
+ if (typeof flags === 'boolean') {
1655
+ this._hasHelpOption = flags;
1656
+ return this;
1657
+ }
1552
1658
  this._helpFlags = flags || this._helpFlags;
1553
1659
  this._helpDescription = description || this._helpDescription;
1554
1660
 
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();
1661
+ const helpFlags = _parseOptionFlags(this._helpFlags);
1662
+ this._helpShortFlag = helpFlags.shortFlag;
1663
+ this._helpLongFlag = helpFlags.longFlag;
1561
1664
 
1562
1665
  return this;
1563
1666
  };
@@ -1684,7 +1787,7 @@ function optionalWrap(str, width, indent) {
1684
1787
  */
1685
1788
 
1686
1789
  function outputHelpIfRequested(cmd, args) {
1687
- const helpOption = args.find(arg => arg === cmd._helpLongFlag || arg === cmd._helpShortFlag);
1790
+ const helpOption = cmd._hasHelpOption && args.find(arg => arg === cmd._helpLongFlag || arg === cmd._helpShortFlag);
1688
1791
  if (helpOption) {
1689
1792
  cmd.outputHelp();
1690
1793
  // (Do not have all displayed text available so only passing placeholder.)
@@ -1708,6 +1811,28 @@ function humanReadableArgName(arg) {
1708
1811
  : '[' + nameOutput + ']';
1709
1812
  }
1710
1813
 
1814
+ /**
1815
+ * Parse the short and long flag out of something like '-m,--mixed <value>'
1816
+ *
1817
+ * @api private
1818
+ */
1819
+
1820
+ function _parseOptionFlags(flags) {
1821
+ let shortFlag;
1822
+ let longFlag;
1823
+ // Use original very loose parsing to maintain backwards compatibility for now,
1824
+ // which allowed for example unintended `-sw, --short-word` [sic].
1825
+ const flagParts = flags.split(/[ |,]+/);
1826
+ if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1])) shortFlag = flagParts.shift();
1827
+ longFlag = flagParts.shift();
1828
+ // Add support for lone short flag without significantly changing parsing!
1829
+ if (!shortFlag && /^-[^-]$/.test(longFlag)) {
1830
+ shortFlag = longFlag;
1831
+ longFlag = undefined;
1832
+ }
1833
+ return { shortFlag, longFlag };
1834
+ }
1835
+
1711
1836
  /**
1712
1837
  * Scan arguments and increment port number for inspect calls (to avoid conflicts when spawning new command).
1713
1838
  *
@@ -1722,35 +1847,35 @@ function incrementNodeInspectorPort(args) {
1722
1847
  // --inspect-brk[=[host:]port]
1723
1848
  // --inspect-port=[host:]port
1724
1849
  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];
1850
+ if (!arg.startsWith('--inspect')) {
1851
+ return arg;
1852
+ }
1853
+ let debugOption;
1854
+ let debugHost = '127.0.0.1';
1855
+ let debugPort = '9229';
1856
+ let match;
1857
+ if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
1858
+ // e.g. --inspect
1859
+ debugOption = match[1];
1860
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
1861
+ debugOption = match[1];
1862
+ if (/^\d+$/.test(match[3])) {
1863
+ // e.g. --inspect=1234
1864
+ debugPort = match[3];
1865
+ } else {
1866
+ // e.g. --inspect=localhost
1746
1867
  debugHost = match[3];
1747
- debugPort = match[4];
1748
1868
  }
1869
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
1870
+ // e.g. --inspect=localhost:1234
1871
+ debugOption = match[1];
1872
+ debugHost = match[3];
1873
+ debugPort = match[4];
1874
+ }
1749
1875
 
1750
- if (debugOption && debugPort !== '0') {
1751
- result = `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
1752
- }
1876
+ if (debugOption && debugPort !== '0') {
1877
+ return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
1753
1878
  }
1754
- return result;
1879
+ return arg;
1755
1880
  });
1756
1881
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commander",
3
- "version": "5.1.0",
3
+ "version": "6.2.1",
4
4
  "description": "the complete solution for node.js command-line programs",
5
5
  "keywords": [
6
6
  "commander",
@@ -31,17 +31,20 @@
31
31
  ],
32
32
  "dependencies": {},
33
33
  "devDependencies": {
34
- "@types/jest": "^25.2.1",
35
- "@types/node": "^12.12.36",
36
- "@typescript-eslint/eslint-plugin": "^2.29.0",
37
- "eslint": "^6.8.0",
38
- "eslint-config-standard-with-typescript": "^15.0.1",
39
- "eslint-plugin-jest": "^23.8.2",
40
- "jest": "^25.4.0",
41
- "standard": "^14.3.3",
42
- "typescript": "^3.7.5"
34
+ "@types/jest": "^26.0.15",
35
+ "@types/node": "^14.14.2",
36
+ "@typescript-eslint/eslint-plugin": "^4.5.0",
37
+ "eslint": "^7.11.0",
38
+ "eslint-config-standard-with-typescript": "^19.0.1",
39
+ "eslint-plugin-jest": "^24.1.0",
40
+ "jest": "^26.6.0",
41
+ "standard": "^15.0.0",
42
+ "typescript": "^4.0.3"
43
43
  },
44
44
  "typings": "typings/index.d.ts",
45
+ "jest": {
46
+ "collectCoverage": true
47
+ },
45
48
  "engines": {
46
49
  "node": ">= 6"
47
50
  }
@@ -75,7 +75,7 @@ declare namespace commander {
75
75
  * ```ts
76
76
  * program
77
77
  * .command('start <service>', 'start named service')
78
- * .command('stop [service]', 'stop named serice, or all if no name supplied');
78
+ * .command('stop [service]', 'stop named service, or all if no name supplied');
79
79
  * ```
80
80
  *
81
81
  * @param nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
@@ -109,6 +109,17 @@ declare namespace commander {
109
109
  */
110
110
  arguments(desc: string): this;
111
111
 
112
+ /**
113
+ * Override default decision whether to add implicit help command.
114
+ *
115
+ * addHelpCommand() // force on
116
+ * addHelpCommand(false); // force off
117
+ * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details
118
+ *
119
+ * @returns `this` command for chaining
120
+ */
121
+ addHelpCommand(enableOrNameAndArgs?: string | boolean, description?: string): this;
122
+
112
123
  /**
113
124
  * Register callback to use as replacement for calling process.exit.
114
125
  */
@@ -201,6 +212,18 @@ declare namespace commander {
201
212
  */
202
213
  passCommandToAction(value?: boolean): this;
203
214
 
215
+ /**
216
+ * Alter parsing of short flags with optional values.
217
+ *
218
+ * @example
219
+ * // for `.option('-f,--flag [value]'):
220
+ * .combineFlagAndOptionalValue(true) // `-f80` is treated like `--flag=80`, this is the default behaviour
221
+ * .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
222
+ *
223
+ * @returns `this` command for chaining
224
+ */
225
+ combineFlagAndOptionalValue(arg?: boolean): this;
226
+
204
227
  /**
205
228
  * Allow unknown options on the command line.
206
229
  *
@@ -335,9 +358,10 @@ declare namespace commander {
335
358
 
336
359
  /**
337
360
  * You can pass in flags and a description to override the help
338
- * flags and help description for your command.
361
+ * flags and help description for your command. Pass in false
362
+ * to disable the built-in help option.
339
363
  */
340
- helpOption(flags?: string, description?: string): this;
364
+ helpOption(flags?: string | boolean, description?: string): this;
341
365
 
342
366
  /**
343
367
  * Output help information and exit.
@@ -381,6 +405,6 @@ declare namespace commander {
381
405
  }
382
406
 
383
407
  // Declaring namespace AND global
384
- // eslint-disable-next-line no-redeclare
408
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
385
409
  declare const commander: commander.CommanderStatic;
386
410
  export = commander;