commander 4.0.0-1 → 4.1.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
@@ -7,25 +7,54 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
7
7
 
8
8
  <!-- markdownlint-disable MD024 -->
9
9
 
10
- ## [4.0.0-1] Prerelease (2019-10-08)
10
+ ## [4.1.1] (2020-02-02)
11
+
12
+ ### Fixed
13
+
14
+ * TypeScript definition for `.action()` should include Promise for async ([#1157])
15
+
16
+ ## [4.1.0] (2020-01-06)
11
17
 
12
18
  ### Added
13
19
 
14
- * support for declaring required options with `.requiredOptions()` ([#1071])
20
+ * two routines to change how option values are handled, and eliminate name clashes with command properties ([#933] [#1102])
21
+ * see storeOptionsAsProperties and passCommandToAction in README
22
+ * `.parseAsync` to use instead of `.parse` if supply async action handlers ([#806] [#1118])
15
23
 
16
- ## [4.0.0-0] Prerelease (2019-10-01)
24
+ ### Fixed
25
+
26
+ * Remove trailing blanks from wrapped help text ([#1096])
27
+
28
+ ### Changed
29
+
30
+ * update dependencies
31
+ * extend security coverage for Commander 2.x to 2020-02-03
32
+ * improvements to README
33
+ * improvements to TypeScript definition documentation
34
+ * move old versions out of main CHANGELOG
35
+ * removed explicit use of `ts-node` in tests
36
+
37
+ ## [4.0.1] (2019-11-12)
38
+
39
+ ### Fixed
40
+
41
+ * display help when requested, even if there are missing required options ([#1091])
42
+
43
+ ## [4.0.0] (2019-11-02)
17
44
 
18
45
  ### Added
19
46
 
20
47
  * automatically wrap and indent help descriptions for options and commands ([#1051])
21
48
  * `.exitOverride()` allows override of calls to `process.exit` for additional error handling and to keep program running ([#1040])
22
- * dev: work in progress GitHub Actions support ([#1027])
49
+ * support for declaring required options with `.requiredOptions()` ([#1071])
50
+ * GitHub Actions support ([#1027])
51
+ * translation links in README
23
52
 
24
53
  ### Changed
25
54
 
26
55
  * dev: switch tests from Sinon+Should to Jest with major rewrite of tests ([#1035])
27
56
  * call default subcommand even when there are unknown options ([#1047])
28
- * *Breaking* Commander is only officially supported on Node 8 and above ([#1053])
57
+ * *Breaking* Commander is only officially supported on Node 8 and above, and requires Node 6 ([#1053])
29
58
 
30
59
  ### Fixed
31
60
 
@@ -34,6 +63,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
34
63
  * complain about unknown options when program argument supplied and action handler ([#1049])
35
64
  * this changes parameters to `command:*` event to include unknown arguments
36
65
  * removed deprecated `customFds` option from call to `child_process.spawn` ([#1052])
66
+ * rework TypeScript declarations to bring all types into imported namespace ([#1081])
67
+
68
+ ### Migration Tips
69
+
70
+ #### Testing for no arguments
71
+
72
+ If you were previously using code like:
73
+
74
+ ```js
75
+ if (!program.args.length) ...
76
+ ```
77
+
78
+ a partial replacement is:
79
+
80
+ ```js
81
+ if (program.rawArgs.length < 3) ...
82
+ ```
83
+
84
+ ## [4.0.0-1] Prerelease (2019-10-08)
85
+
86
+ (Released in 4.0.0)
87
+
88
+ ## [4.0.0-0] Prerelease (2019-10-01)
89
+
90
+ (Released in 4.0.0)
37
91
 
38
92
  ## [2.20.1] (2019-09-29)
39
93
 
@@ -71,7 +125,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
71
125
 
72
126
  * help for sub commands with custom executableFile ([#1018])
73
127
 
74
- ## 3.0.0 / 2019-08-08
128
+ ## [3.0.0] / 2019-08-08
75
129
 
76
130
  * Add option to specify executable file name ([#999])
77
131
  * e.g. `.command('clone', 'clone description', { executableFile: 'myClone' })`
@@ -328,152 +382,16 @@ program
328
382
 
329
383
  * remove input methods (.prompt, .confirm, etc)
330
384
 
331
- ## 1.3.2 / 2013-07-18
332
-
333
- * add support for sub-commands to co-exist with the original command
334
-
335
- ## 1.3.1 / 2013-07-18
336
-
337
- * add quick .runningCommand hack so you can opt-out of other logic when running a sub command
338
-
339
- ## 1.3.0 / 2013-07-09
340
-
341
- * add EACCES error handling
342
- * fix sub-command --help
343
-
344
- ## 1.2.0 / 2013-06-13
345
-
346
- * allow "-" hyphen as an option argument
347
- * support for RegExp coercion
348
-
349
- ## 1.1.1 / 2012-11-20
350
-
351
- * add more sub-command padding
352
- * fix .usage() when args are present. Closes #106
353
-
354
- ## 1.1.0 / 2012-11-16
355
-
356
- * add git-style executable subcommand support. Closes #94
357
-
358
- ## 1.0.5 / 2012-10-09
359
-
360
- * fix `--name` clobbering. Closes #92
361
- * fix examples/help. Closes #89
362
-
363
- ## 1.0.4 / 2012-09-03
364
-
365
- * add `outputHelp()` method.
366
-
367
- ## 1.0.3 / 2012-08-30
368
-
369
- * remove invalid .version() defaulting
370
-
371
- ## 1.0.2 / 2012-08-24
372
-
373
- * add `--foo=bar` support [arv]
374
- * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]
375
-
376
- ## 1.0.1 / 2012-08-03
377
-
378
- * fix issue #56
379
- * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())
380
-
381
- ## 1.0.0 / 2012-07-05
382
-
383
- * add support for optional option descriptions
384
- * add defaulting of `.version()` to package.json's version
385
-
386
- ## 0.6.1 / 2012-06-01
387
-
388
- * Added: append (yes or no) on confirmation
389
- * Added: allow node.js v0.7.x
390
-
391
- ## 0.6.0 / 2012-04-10
392
-
393
- * Added `.prompt(obj, callback)` support. Closes #49
394
- * Added default support to .choose(). Closes #41
395
- * Fixed the choice example
396
-
397
- ## 0.5.1 / 2011-12-20
398
-
399
- * Fixed `password()` for recent nodes. Closes #36
400
-
401
- ## 0.5.0 / 2011-12-04
402
-
403
- * Added sub-command option support [itay]
404
-
405
- ## 0.4.3 / 2011-12-04
406
-
407
- * Fixed custom help ordering. Closes #32
408
-
409
- ## 0.4.2 / 2011-11-24
410
-
411
- * Added travis support
412
- * Fixed: line-buffered input automatically trimmed. Closes #31
413
-
414
- ## 0.4.1 / 2011-11-18
415
-
416
- * Removed listening for "close" on --help
417
-
418
- ## 0.4.0 / 2011-11-15
419
-
420
- * Added support for `--`. Closes #24
421
-
422
- ## 0.3.3 / 2011-11-14
423
-
424
- * Fixed: wait for close event when writing help info [Jerry Hamlet]
425
-
426
- ## 0.3.2 / 2011-11-01
427
-
428
- * Fixed long flag definitions with values [felixge]
429
-
430
- ## 0.3.1 / 2011-10-31
431
-
432
- * Changed `--version` short flag to `-V` from `-v`
433
- * Changed `.version()` so it's configurable [felixge]
434
-
435
- ## 0.3.0 / 2011-10-31
436
-
437
- * Added support for long flags only. Closes #18
438
-
439
- ## 0.2.1 / 2011-10-24
440
-
441
- * "node": ">= 0.4.x < 0.7.0". Closes #20
442
-
443
- ## 0.2.0 / 2011-09-26
444
-
445
- * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
446
-
447
- ## 0.1.0 / 2011-08-24
448
-
449
- * Added support for custom `--help` output
450
-
451
- ## 0.0.5 / 2011-08-18
452
-
453
- * Changed: when the user enters nothing prompt for password again
454
- * Fixed issue with passwords beginning with numbers [NuckChorris]
455
-
456
- ## 0.0.4 / 2011-08-15
457
-
458
- * Fixed `Commander#args`
459
-
460
- ## 0.0.3 / 2011-08-15
461
-
462
- * Added default option value support
463
-
464
- ## 0.0.2 / 2011-08-15
465
-
466
- * Added mask support to `Command#password(str[, mask], fn)`
467
- * Added `Command#password(str, fn)`
468
-
469
- ## 0.0.1 / 2010-01-03
385
+ ## Older versions
470
386
 
471
- * Initial release
387
+ * [1.x](./changelogs/CHANGELOG-1.md)
388
+ * [0.x](./changelogs/CHANGELOG-0.md)
472
389
 
473
390
  [#599]: https://github.com/tj/commander.js/issues/599
474
391
  [#611]: https://github.com/tj/commander.js/issues/611
475
392
  [#697]: https://github.com/tj/commander.js/issues/697
476
393
  [#795]: https://github.com/tj/commander.js/issues/795
394
+ [#806]: https://github.com/tj/commander.js/issues/806
477
395
  [#915]: https://github.com/tj/commander.js/issues/915
478
396
  [#938]: https://github.com/tj/commander.js/issues/938
479
397
  [#963]: https://github.com/tj/commander.js/issues/963
@@ -482,6 +400,7 @@ program
482
400
  [#987]: https://github.com/tj/commander.js/issues/987
483
401
  [#990]: https://github.com/tj/commander.js/issues/990
484
402
  [#991]: https://github.com/tj/commander.js/issues/991
403
+ [#993]: https://github.com/tj/commander.js/issues/993
485
404
  [#999]: https://github.com/tj/commander.js/issues/999
486
405
  [#1010]: https://github.com/tj/commander.js/pull/1010
487
406
  [#1018]: https://github.com/tj/commander.js/pull/1018
@@ -497,10 +416,21 @@ program
497
416
  [#1052]: https://github.com/tj/commander.js/pull/1052
498
417
  [#1053]: https://github.com/tj/commander.js/pull/1053
499
418
  [#1071]: https://github.com/tj/commander.js/pull/1071
419
+ [#1081]: https://github.com/tj/commander.js/pull/1081
420
+ [#1091]: https://github.com/tj/commander.js/pull/1091
421
+ [#1096]: https://github.com/tj/commander.js/pull/1096
422
+ [#1102]: https://github.com/tj/commander.js/pull/1102
423
+ [#1118]: https://github.com/tj/commander.js/pull/1118
424
+ [#1157]: https://github.com/tj/commander.js/pull/1157
500
425
 
501
426
  [Unreleased]: https://github.com/tj/commander.js/compare/master...develop
427
+ [4.1.1]: https://github.com/tj/commander.js/compare/v4.0.0..v4.1.1
428
+ [4.1.0]: https://github.com/tj/commander.js/compare/v4.0.1..v4.1.0
429
+ [4.0.1]: https://github.com/tj/commander.js/compare/v4.0.0..v4.0.1
430
+ [4.0.0]: https://github.com/tj/commander.js/compare/v3.0.2..v4.0.0
502
431
  [4.0.0-1]: https://github.com/tj/commander.js/compare/v4.0.0-0..v4.0.0-1
503
432
  [4.0.0-0]: https://github.com/tj/commander.js/compare/v3.0.2...v4.0.0-0
504
433
  [3.0.2]: https://github.com/tj/commander.js/compare/v3.0.1...v3.0.2
505
434
  [3.0.1]: https://github.com/tj/commander.js/compare/v3.0.0...v3.0.1
435
+ [3.0.0]: https://github.com/tj/commander.js/compare/v2.20.1...v3.0.0
506
436
  [2.20.1]: https://github.com/tj/commander.js/compare/v2.20.0...v2.20.1
package/Readme.md CHANGED
@@ -7,9 +7,11 @@
7
7
 
8
8
  The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/commander-rb/commander).
9
9
 
10
+ Read this in other languages: English | [简体中文](./Readme_zh-CN.md)
11
+
10
12
  - [Commander.js](#commanderjs)
11
13
  - [Installation](#installation)
12
- - [Declaring _program_ variable](#declaring-program-variable)
14
+ - [Declaring program variable](#declaring-program-variable)
13
15
  - [Options](#options)
14
16
  - [Common option types, boolean and value](#common-option-types-boolean-and-value)
15
17
  - [Default option value](#default-option-value)
@@ -29,13 +31,15 @@ The complete solution for [node.js](http://nodejs.org) command-line interfaces,
29
31
  - [.help(cb)](#helpcb)
30
32
  - [Custom event listeners](#custom-event-listeners)
31
33
  - [Bits and pieces](#bits-and-pieces)
34
+ - [Avoiding option name clashes](#avoiding-option-name-clashes)
32
35
  - [TypeScript](#typescript)
33
- - [Node options such as `--harmony`](#node-options-such-as---harmony)
36
+ - [Node options such as --harmony](#node-options-such-as---harmony)
34
37
  - [Node debugging](#node-debugging)
35
38
  - [Override exit handling](#override-exit-handling)
36
39
  - [Examples](#examples)
37
40
  - [License](#license)
38
41
  - [Support](#support)
42
+ - [Commander for enterprise](#commander-for-enterprise)
39
43
 
40
44
  ## Installation
41
45
 
@@ -67,6 +71,8 @@ Options are defined with the `.option()` method, also serving as documentation f
67
71
 
68
72
  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. Multiple short flags may be combined as a single arg, for example `-abc` is equivalent to `-a -b -c`.
69
73
 
74
+ See also optional new behaviour to [avoid name clashes](#avoiding-option-name-clashes).
75
+
70
76
  ### Common option types, boolean and value
71
77
 
72
78
  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.
@@ -371,6 +377,19 @@ program
371
377
  program.parse(process.argv)
372
378
  ```
373
379
 
380
+ You may supply an `async` action handler, in which case you call `.parseAsync` rather than `.parse`.
381
+
382
+ ```js
383
+ async function run() { /* code goes here */ }
384
+
385
+ async function main() {
386
+ program
387
+ .command('run')
388
+ .action(run);
389
+ await program.parseAsync(process.argv);
390
+ }
391
+ ```
392
+
374
393
  A command's options on the command line are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated.
375
394
 
376
395
  Configuration options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the command from the generated help output.
@@ -547,6 +566,43 @@ program.on('command:*', function () {
547
566
 
548
567
  ## Bits and pieces
549
568
 
569
+ ### Avoiding option name clashes
570
+
571
+ The original and default behaviour is that the option values are stored
572
+ as properties on the program, and the action handler is passed a
573
+ command object with the options values stored as properties.
574
+ This is very convenient to code, but the downside is possible clashes with
575
+ existing properties of Command.
576
+
577
+ There are two new routines to change the behaviour, and the default behaviour may change in the future:
578
+
579
+ - `storeOptionsAsProperties`: whether to store option values as properties on command object, or store separately (specify false) and access using `.opts()`
580
+ - `passCommandToAction`: whether to pass command to action handler,
581
+ or just the options (specify false)
582
+
583
+ ```js
584
+ // file: ./examples/storeOptionsAsProperties.action.js
585
+ program
586
+ .storeOptionsAsProperties(false)
587
+ .passCommandToAction(false);
588
+
589
+ program
590
+ .name('my-program-name')
591
+ .option('-n,--name <name>');
592
+
593
+ program
594
+ .command('show')
595
+ .option('-a,--action <action>')
596
+ .action((options) => {
597
+ console.log(options.action);
598
+ });
599
+
600
+ program.parse(process.argv);
601
+
602
+ const programOptions = program.opts();
603
+ console.log(programOptions.name);
604
+ ```
605
+
550
606
  ### TypeScript
551
607
 
552
608
  The Commander package includes its TypeScript Definition file, but also requires the node types which you need to install yourself. e.g.
@@ -645,10 +701,13 @@ More Demos can be found in the [examples](https://github.com/tj/commander.js/tre
645
701
 
646
702
  ## Support
647
703
 
648
- Commander is supported on Node 8 and above. (Commander is likely to still work on older versions of Node, but is not tested below Node 8.)
704
+ Commander 4.x is supported on Node 8 and above, and is likely to work with Node 6 but not tested.
705
+ (For versions of Node below Node 6, use Commander 3.x or 2.x.)
649
706
 
650
707
  The main forum for free and community support is the project [Issues](https://github.com/tj/commander.js/issues) on GitHub.
651
708
 
652
- [Professionally supported commander is now available](https://tidelift.com/subscription/pkg/npm-commander?utm_source=npm-commander&utm_medium=referral&utm_campaign=readme)
709
+ ### Commander for enterprise
710
+
711
+ Available as part of the Tidelift Subscription
653
712
 
654
- Tidelift gives software development teams a single source for purchasing and maintaining their software, with professional grade assurances from the experts who know it best, while seamlessly integrating with existing tools.
713
+ The maintainers of Commander and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-commander?utm_source=npm-commander&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
package/index.js CHANGED
@@ -115,7 +115,7 @@ exports.CommanderError = CommanderError;
115
115
  /**
116
116
  * Initialize a new `Command`.
117
117
  *
118
- * @param {String} name
118
+ * @param {String} [name]
119
119
  * @api public
120
120
  */
121
121
 
@@ -126,6 +126,10 @@ function Command(name) {
126
126
  this._allowUnknownOption = false;
127
127
  this._args = [];
128
128
  this._name = name || '';
129
+ this._optionValues = {};
130
+ this._storeOptionsAsProperties = true; // backwards compatible by default
131
+ this._passCommandToAction = true; // backwards compatible by default
132
+ this._actionResults = [];
129
133
 
130
134
  this._helpFlags = '-h, --help';
131
135
  this._helpDescription = 'output usage information';
@@ -151,7 +155,7 @@ function Command(name) {
151
155
  * // Command implemented using separate executable file (description is second parameter to `.command`)
152
156
  * program
153
157
  * .command('start <service>', 'start named service')
154
- * .command('stop [service]', 'stop named serice, or all if no name supplied');
158
+ * .command('stop [service]', 'stop named service, or all if no name supplied');
155
159
  *
156
160
  * @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
157
161
  * @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
@@ -183,6 +187,8 @@ Command.prototype.command = function(nameAndArgs, actionOptsOrExecDesc, execOpts
183
187
  cmd._helpShortFlag = this._helpShortFlag;
184
188
  cmd._helpLongFlag = this._helpLongFlag;
185
189
  cmd._exitCallback = this._exitCallback;
190
+ cmd._storeOptionsAsProperties = this._storeOptionsAsProperties;
191
+ cmd._passCommandToAction = this._passCommandToAction;
186
192
 
187
193
  cmd._executableFile = opts.executableFile; // Custom name for executable file
188
194
  this.commands.push(cmd);
@@ -323,7 +329,8 @@ Command.prototype.action = function(fn) {
323
329
  var parsed = self.parseOptions(unknown);
324
330
 
325
331
  // Output help if necessary
326
- outputHelpIfNecessary(self, parsed.unknown);
332
+ outputHelpIfRequested(self, parsed.unknown);
333
+ self._checkForMissingMandatoryOptions();
327
334
 
328
335
  // If there are still any unknown options, then we simply
329
336
  // die, unless someone asked for help, in which case we give it
@@ -350,13 +357,23 @@ Command.prototype.action = function(fn) {
350
357
  // The .action callback takes an extra parameter which is the command itself.
351
358
  var expectedArgsCount = self._args.length;
352
359
  var actionArgs = args.slice(0, expectedArgsCount);
353
- actionArgs[expectedArgsCount] = self;
360
+ if (self._passCommandToAction) {
361
+ actionArgs[expectedArgsCount] = self;
362
+ } else {
363
+ actionArgs[expectedArgsCount] = self.opts();
364
+ }
354
365
  // Add the extra arguments so available too.
355
366
  if (args.length > expectedArgsCount) {
356
367
  actionArgs.push(args.slice(expectedArgsCount));
357
368
  }
358
369
 
359
- fn.apply(self, actionArgs);
370
+ const actionResult = fn.apply(self, actionArgs);
371
+ // Remember result in case it is async. Assume parseAsync getting called on root.
372
+ let rootCommand = self;
373
+ while (rootCommand.parent) {
374
+ rootCommand = rootCommand.parent;
375
+ }
376
+ rootCommand._actionResults.push(actionResult);
360
377
  };
361
378
  var parent = this.parent || this;
362
379
  var name = parent === this ? '*' : this._name;
@@ -404,12 +421,12 @@ Command.prototype._optionEx = function(config, flags, description, fn, defaultVa
404
421
  if (option.negate || option.optional || option.required || typeof defaultValue === 'boolean') {
405
422
  // when --no-foo we make sure default is true, unless a --foo option is already defined
406
423
  if (option.negate) {
407
- var opts = self.opts();
408
- defaultValue = Object.prototype.hasOwnProperty.call(opts, name) ? opts[name] : true;
424
+ const positiveLongFlag = option.long.replace(/^--no-/, '--');
425
+ defaultValue = self.optionFor(positiveLongFlag) ? self._getOptionValue(name) : true;
409
426
  }
410
427
  // preassign only if we have a default
411
428
  if (defaultValue !== undefined) {
412
- self[name] = defaultValue;
429
+ self._setOptionValue(name, defaultValue);
413
430
  option.defaultValue = defaultValue;
414
431
  }
415
432
  }
@@ -422,22 +439,22 @@ Command.prototype._optionEx = function(config, flags, description, fn, defaultVa
422
439
  this.on('option:' + oname, function(val) {
423
440
  // coercion
424
441
  if (val !== null && fn) {
425
- val = fn(val, self[name] === undefined ? defaultValue : self[name]);
442
+ val = fn(val, self._getOptionValue(name) === undefined ? defaultValue : self._getOptionValue(name));
426
443
  }
427
444
 
428
445
  // unassigned or boolean value
429
- if (typeof self[name] === 'boolean' || typeof self[name] === 'undefined') {
446
+ if (typeof self._getOptionValue(name) === 'boolean' || typeof self._getOptionValue(name) === 'undefined') {
430
447
  // if no value, negate false, and we have a default, then use it!
431
448
  if (val == null) {
432
- self[name] = option.negate
449
+ self._setOptionValue(name, option.negate
433
450
  ? false
434
- : defaultValue || true;
451
+ : defaultValue || true);
435
452
  } else {
436
- self[name] = val;
453
+ self._setOptionValue(name, val);
437
454
  }
438
455
  } else if (val !== null) {
439
456
  // reassign
440
- self[name] = option.negate ? false : val;
457
+ self._setOptionValue(name, option.negate ? false : val);
441
458
  }
442
459
  });
443
460
 
@@ -531,7 +548,70 @@ Command.prototype.allowUnknownOption = function(arg) {
531
548
  };
532
549
 
533
550
  /**
534
- * Parse `argv`, settings options and invoking commands when defined.
551
+ * Whether to store option values as properties on command object,
552
+ * or store separately (specify false). In both cases the option values can be accessed using .opts().
553
+ *
554
+ * @param {boolean} value
555
+ * @return {Command} Command for chaining
556
+ * @api public
557
+ */
558
+
559
+ Command.prototype.storeOptionsAsProperties = function(value) {
560
+ this._storeOptionsAsProperties = (value === undefined) || value;
561
+ if (this.options.length) {
562
+ // This is for programmer, not end user.
563
+ console.error('Commander usage error: call storeOptionsAsProperties before adding options');
564
+ }
565
+ return this;
566
+ };
567
+
568
+ /**
569
+ * Whether to pass command to action handler,
570
+ * or just the options (specify false).
571
+ *
572
+ * @param {boolean} value
573
+ * @return {Command} Command for chaining
574
+ * @api public
575
+ */
576
+
577
+ Command.prototype.passCommandToAction = function(value) {
578
+ this._passCommandToAction = (value === undefined) || value;
579
+ return this;
580
+ };
581
+
582
+ /**
583
+ * Store option value
584
+ *
585
+ * @param {String} key
586
+ * @param {Object} value
587
+ * @api private
588
+ */
589
+
590
+ Command.prototype._setOptionValue = function(key, value) {
591
+ if (this._storeOptionsAsProperties) {
592
+ this[key] = value;
593
+ } else {
594
+ this._optionValues[key] = value;
595
+ }
596
+ };
597
+
598
+ /**
599
+ * Retrieve option value
600
+ *
601
+ * @param {String} key
602
+ * @return {Object} value
603
+ * @api private
604
+ */
605
+
606
+ Command.prototype._getOptionValue = function(key) {
607
+ if (this._storeOptionsAsProperties) {
608
+ return this[key];
609
+ }
610
+ return this._optionValues[key];
611
+ };
612
+
613
+ /**
614
+ * Parse `argv`, setting options and invoking commands when defined.
535
615
  *
536
616
  * @param {Array} argv
537
617
  * @return {Command} for chaining
@@ -563,10 +643,17 @@ Command.prototype.parse = function(argv) {
563
643
 
564
644
  if (args[0] === 'help' && args.length === 1) this.help();
565
645
 
646
+ // Note for future: we could return early if we found an action handler in parseArgs, as none of following code needed?
647
+
566
648
  // <cmd> --help
567
649
  if (args[0] === 'help') {
568
650
  args[0] = args[1];
569
651
  args[1] = this._helpLongFlag;
652
+ } else {
653
+ // If calling through to executable subcommand we could check for help flags before failing,
654
+ // but a somewhat unlikely case since program options not passed to executable subcommands.
655
+ // Wait for reports to see if check needed and what usage pattern is.
656
+ this._checkForMissingMandatoryOptions();
570
657
  }
571
658
 
572
659
  // executable sub-commands
@@ -608,13 +695,27 @@ Command.prototype.parse = function(argv) {
608
695
  return result;
609
696
  };
610
697
 
698
+ /**
699
+ * Parse `argv`, setting options and invoking commands when defined.
700
+ *
701
+ * Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.
702
+ *
703
+ * @param {Array} argv
704
+ * @return {Promise}
705
+ * @api public
706
+ */
707
+ Command.prototype.parseAsync = function(argv) {
708
+ this.parse(argv);
709
+ return Promise.all(this._actionResults);
710
+ };
711
+
611
712
  /**
612
713
  * Execute a sub-command executable.
613
714
  *
614
715
  * @param {Array} argv
615
716
  * @param {Array} args
616
717
  * @param {Array} unknown
617
- * @param {String} specifySubcommand
718
+ * @param {String} executableFile
618
719
  * @api private
619
720
  */
620
721
 
@@ -793,7 +894,7 @@ Command.prototype.parseArgs = function(args, unknown) {
793
894
  this.emit('command:*', args, unknown);
794
895
  }
795
896
  } else {
796
- outputHelpIfNecessary(this, unknown);
897
+ outputHelpIfRequested(this, unknown);
797
898
 
798
899
  // If there were no args and we have unknown options,
799
900
  // then they are extraneous and we need to error.
@@ -832,12 +933,14 @@ Command.prototype.optionFor = function(arg) {
832
933
  */
833
934
 
834
935
  Command.prototype._checkForMissingMandatoryOptions = function() {
835
- const self = this;
836
- this.options.forEach((anOption) => {
837
- if (anOption.mandatory && (self[anOption.attributeName()] === undefined)) {
838
- self.missingMandatoryOptionValue(anOption);
839
- }
840
- });
936
+ // Walk up hierarchy so can call from action handler after checking for displaying help.
937
+ for (var cmd = this; cmd; cmd = cmd.parent) {
938
+ cmd.options.forEach((anOption) => {
939
+ if (anOption.mandatory && (cmd._getOptionValue(anOption.attributeName()) === undefined)) {
940
+ cmd.missingMandatoryOptionValue(anOption);
941
+ }
942
+ });
943
+ }
841
944
  };
842
945
 
843
946
  /**
@@ -845,7 +948,7 @@ Command.prototype._checkForMissingMandatoryOptions = function() {
845
948
  * void of these options.
846
949
  *
847
950
  * @param {Array} argv
848
- * @return {Array}
951
+ * @return {{args: Array, unknown: Array}}
849
952
  * @api public
850
953
  */
851
954
 
@@ -916,8 +1019,6 @@ Command.prototype.parseOptions = function(argv) {
916
1019
  args.push(arg);
917
1020
  }
918
1021
 
919
- this._checkForMissingMandatoryOptions();
920
-
921
1022
  return { args: args, unknown: unknownOptions };
922
1023
  };
923
1024
 
@@ -928,14 +1029,19 @@ Command.prototype.parseOptions = function(argv) {
928
1029
  * @api public
929
1030
  */
930
1031
  Command.prototype.opts = function() {
931
- var result = {},
932
- len = this.options.length;
933
-
934
- for (var i = 0; i < len; i++) {
935
- var key = this.options[i].attributeName();
936
- result[key] = key === this._versionOptionName ? this._version : this[key];
1032
+ if (this._storeOptionsAsProperties) {
1033
+ // Preserve original behaviour so backwards compatible when still using properties
1034
+ var result = {},
1035
+ len = this.options.length;
1036
+
1037
+ for (var i = 0; i < len; i++) {
1038
+ var key = this.options[i].attributeName();
1039
+ result[key] = key === this._versionOptionName ? this._version : this[key];
1040
+ }
1041
+ return result;
937
1042
  }
938
- return result;
1043
+
1044
+ return this._optionValues;
939
1045
  };
940
1046
 
941
1047
  /**
@@ -954,8 +1060,8 @@ Command.prototype.missingArgument = function(name) {
954
1060
  /**
955
1061
  * `Option` is missing an argument, but received `flag` or nothing.
956
1062
  *
957
- * @param {String} option
958
- * @param {String} flag
1063
+ * @param {Option} option
1064
+ * @param {String} [flag]
959
1065
  * @api private
960
1066
  */
961
1067
 
@@ -973,7 +1079,7 @@ Command.prototype.optionMissingArgument = function(option, flag) {
973
1079
  /**
974
1080
  * `Option` does not have a value, and is a mandatory option.
975
1081
  *
976
- * @param {String} option
1082
+ * @param {Option} option
977
1083
  * @api private
978
1084
  */
979
1085
 
@@ -1033,9 +1139,10 @@ Command.prototype.version = function(str, flags, description) {
1033
1139
  var versionOption = new Option(flags, description);
1034
1140
  this._versionOptionName = versionOption.long.substr(2) || 'version';
1035
1141
  this.options.push(versionOption);
1142
+ var self = this;
1036
1143
  this.on('option:' + this._versionOptionName, function() {
1037
1144
  process.stdout.write(str + '\n');
1038
- this._exit(0, 'commander.version', str);
1145
+ self._exit(0, 'commander.version', str);
1039
1146
  });
1040
1147
  return this;
1041
1148
  };
@@ -1044,7 +1151,7 @@ Command.prototype.version = function(str, flags, description) {
1044
1151
  * Set the description to `str`.
1045
1152
  *
1046
1153
  * @param {String} str
1047
- * @param {Object} argsDescription
1154
+ * @param {Object} [argsDescription]
1048
1155
  * @return {String|Command}
1049
1156
  * @api public
1050
1157
  */
@@ -1081,7 +1188,7 @@ Command.prototype.alias = function(alias) {
1081
1188
  /**
1082
1189
  * Set / get the command usage `str`.
1083
1190
  *
1084
- * @param {String} str
1191
+ * @param {String} [str]
1085
1192
  * @return {String|Command}
1086
1193
  * @api public
1087
1194
  */
@@ -1104,7 +1211,7 @@ Command.prototype.usage = function(str) {
1104
1211
  /**
1105
1212
  * Get or set the name of the command
1106
1213
  *
1107
- * @param {String} str
1214
+ * @param {String} [str]
1108
1215
  * @return {String|Command}
1109
1216
  * @api public
1110
1217
  */
@@ -1421,7 +1528,7 @@ function wrap(str, width, indent) {
1421
1528
  if (line.slice(-1) === '\n') {
1422
1529
  line = line.slice(0, line.length - 1);
1423
1530
  }
1424
- return ((i > 0 && indent) ? Array(indent + 1).join(' ') : '') + line;
1531
+ return ((i > 0 && indent) ? Array(indent + 1).join(' ') : '') + line.trimRight();
1425
1532
  }).join('\n');
1426
1533
  }
1427
1534
 
@@ -1448,14 +1555,14 @@ function optionalWrap(str, width, indent) {
1448
1555
  }
1449
1556
 
1450
1557
  /**
1451
- * Output help information if necessary
1558
+ * Output help information if help flags specified
1452
1559
  *
1453
- * @param {Command} command to output help for
1454
- * @param {Array} array of options to search for -h or --help
1560
+ * @param {Command} cmd - command to output help for
1561
+ * @param {Array} options - array of options to search for -h or --help
1455
1562
  * @api private
1456
1563
  */
1457
1564
 
1458
- function outputHelpIfNecessary(cmd, options) {
1565
+ function outputHelpIfRequested(cmd, options) {
1459
1566
  options = options || [];
1460
1567
 
1461
1568
  for (var i = 0; i < options.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commander",
3
- "version": "4.0.0-1",
3
+ "version": "4.1.1",
4
4
  "description": "the complete solution for node.js command-line programs",
5
5
  "keywords": [
6
6
  "commander",
@@ -26,14 +26,16 @@
26
26
  ],
27
27
  "dependencies": {},
28
28
  "devDependencies": {
29
- "@types/jest": "^24.0.18",
30
- "@types/node": "^12.7.5",
31
- "eslint": "^6.4.0",
32
- "eslint-plugin-jest": "^22.17.0",
29
+ "@types/jest": "^24.0.23",
30
+ "@types/node": "^12.12.11",
31
+ "eslint": "^6.7.0",
32
+ "eslint-plugin-jest": "^22.21.0",
33
33
  "jest": "^24.8.0",
34
34
  "standard": "^14.3.1",
35
- "ts-node": "^8.4.1",
36
- "typescript": "^3.6.3"
35
+ "typescript": "^3.7.2"
37
36
  },
38
- "typings": "typings/index.d.ts"
37
+ "typings": "typings/index.d.ts",
38
+ "engines": {
39
+ "node": ">= 6"
40
+ }
39
41
  }
@@ -1,22 +1,19 @@
1
- // Type definitions for commander 2.11
2
- // Project: https://github.com/visionmedia/commander.js
3
- // Definitions by: Alan Agius <https://github.com/alan-agius4>, Marcelo Dezem <https://github.com/mdezem>, vvakame <https://github.com/vvakame>, Jules Randolph <https://github.com/sveinburne>
4
- // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
1
+ // Type definitions for commander
2
+ // Original definitions by: Alan Agius <https://github.com/alan-agius4>, Marcelo Dezem <https://github.com/mdezem>, vvakame <https://github.com/vvakame>, Jules Randolph <https://github.com/sveinburne>
5
3
 
6
4
  ///<reference types="node" />
7
5
 
8
- declare namespace local {
6
+ declare namespace commander {
9
7
 
10
- class CommanderError extends Error {
8
+ interface CommanderError extends Error {
11
9
  code: string;
12
10
  exitCode: number;
13
11
  message: string;
14
12
  nestedError?: string;
15
-
16
- constructor(exitCode: number, code: string, message: string);
17
13
  }
14
+ type CommanderErrorConstructor = { new (exitCode: number, code: string, message: string): CommanderError };
18
15
 
19
- class Option {
16
+ interface Option {
20
17
  flags: string;
21
18
  required: boolean; // A value must be supplied when the option is specified.
22
19
  optional: boolean; // A value is optional when the option is specified.
@@ -25,28 +22,14 @@ declare namespace local {
25
22
  short?: string;
26
23
  long: string;
27
24
  description: string;
28
-
29
- /**
30
- * Initialize a new `Option` with the given `flags` and `description`.
31
- *
32
- * @param {string} flags
33
- * @param {string} [description]
34
- */
35
- constructor(flags: string, description?: string);
36
25
  }
26
+ type OptionConstructor = { new (flags: string, description?: string): Option };
37
27
 
38
- class Command extends NodeJS.EventEmitter {
28
+ interface Command extends NodeJS.EventEmitter {
39
29
  [key: string]: any; // options as properties
40
30
 
41
31
  args: string[];
42
32
 
43
- /**
44
- * Initialize a new `Command`.
45
- *
46
- * @param {string} [name]
47
- */
48
- constructor(name?: string);
49
-
50
33
  /**
51
34
  * Set the program version to `str`.
52
35
  *
@@ -54,7 +37,6 @@ declare namespace local {
54
37
  * which will print the version number when passed.
55
38
  *
56
39
  * You can optionally supply the flags and description to override the defaults.
57
- *
58
40
  */
59
41
  version(str: string, flags?: string, description?: string): Command;
60
42
 
@@ -78,7 +60,7 @@ declare namespace local {
78
60
  * @param opts - configuration options
79
61
  * @returns new command
80
62
  */
81
- command(nameAndArgs: string, opts?: commander.CommandOptions): Command;
63
+ command(nameAndArgs: string, opts?: CommandOptions): Command;
82
64
  /**
83
65
  * Define a command, implemented in a separate executable file.
84
66
  *
@@ -102,8 +84,7 @@ declare namespace local {
102
84
  /**
103
85
  * Define argument syntax for the top-level command.
104
86
  *
105
- * @param {string} desc
106
- * @returns {Command} for chaining
87
+ * @returns Command for chaining
107
88
  */
108
89
  arguments(desc: string): Command;
109
90
 
@@ -112,8 +93,7 @@ declare namespace local {
112
93
  *
113
94
  * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
114
95
  *
115
- * @param {string[]} args
116
- * @returns {Command} for chaining
96
+ * @returns Command for chaining
117
97
  */
118
98
  parseExpectedArgs(args: string[]): Command;
119
99
 
@@ -133,10 +113,9 @@ declare namespace local {
133
113
  * // output help here
134
114
  * });
135
115
  *
136
- * @param {(...args: any[]) => void} fn
137
- * @returns {Command} for chaining
116
+ * @returns Command for chaining
138
117
  */
139
- action(fn: (...args: any[]) => void): Command;
118
+ action(fn: (...args: any[]) => void | Promise<void>): Command;
140
119
 
141
120
  /**
142
121
  * Define option with `flags`, `description` and optional
@@ -178,11 +157,7 @@ declare namespace local {
178
157
  * // optional argument
179
158
  * program.option('-c, --cheese [type]', 'add cheese [marble]');
180
159
  *
181
- * @param {string} flags
182
- * @param {string} [description]
183
- * @param {((arg1: any, arg2: any) => void) | RegExp} [fn] function or default
184
- * @param {*} [defaultValue]
185
- * @returns {Command} for chaining
160
+ * @returns Command for chaining
186
161
  */
187
162
  option(flags: string, description?: string, fn?: ((arg1: any, arg2: any) => void) | RegExp, defaultValue?: any): Command;
188
163
  option(flags: string, description?: string, defaultValue?: any): Command;
@@ -196,77 +171,98 @@ declare namespace local {
196
171
  requiredOption(flags: string, description?: string, fn?: ((arg1: any, arg2: any) => void) | RegExp, defaultValue?: any): Command;
197
172
  requiredOption(flags: string, description?: string, defaultValue?: any): Command;
198
173
 
174
+
175
+ /**
176
+ * Whether to store option values as properties on command object,
177
+ * or store separately (specify false). In both cases the option values can be accessed using .opts().
178
+ *
179
+ * @return Command for chaining
180
+ */
181
+ storeOptionsAsProperties(value?: boolean): Command;
182
+
183
+ /**
184
+ * Whether to pass command to action handler,
185
+ * or just the options (specify false).
186
+ *
187
+ * @return Command for chaining
188
+ */
189
+ passCommandToAction(value?: boolean): Command;
190
+
199
191
  /**
200
192
  * Allow unknown options on the command line.
201
193
  *
202
- * @param {boolean} [arg] if `true` or omitted, no error will be thrown for unknown options.
203
- * @returns {Command} for chaining
194
+ * @param [arg] if `true` or omitted, no error will be thrown for unknown options.
195
+ * @returns Command for chaining
204
196
  */
205
197
  allowUnknownOption(arg?: boolean): Command;
206
198
 
207
199
  /**
208
- * Parse `argv`, settings options and invoking commands when defined.
200
+ * Parse `argv`, setting options and invoking commands when defined.
209
201
  *
210
- * @param {string[]} argv
211
- * @returns {Command} for chaining
202
+ * @returns Command for chaining
212
203
  */
213
204
  parse(argv: string[]): Command;
214
205
 
215
206
  /**
216
- * Parse options from `argv` returning `argv` void of these options.
207
+ * Parse `argv`, setting options and invoking commands when defined.
208
+ *
209
+ * Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.
217
210
  *
218
- * @param {string[]} argv
219
- * @returns {ParseOptionsResult}
211
+ * @returns Promise
212
+ */
213
+ parseAsync(argv: string[]): Promise<any>;
214
+
215
+ /**
216
+ * Parse options from `argv` returning `argv` void of these options.
220
217
  */
221
218
  parseOptions(argv: string[]): commander.ParseOptionsResult;
222
219
 
223
220
  /**
224
221
  * Return an object containing options as key-value pairs
225
- *
226
- * @returns {{[key: string]: any}}
227
222
  */
228
223
  opts(): { [key: string]: any };
229
224
 
230
225
  /**
231
- * Set the description to `str`.
232
- *
233
- * @param {string} str
234
- * @param {{[argName: string]: string}} argsDescription
235
- * @return {(Command | string)}
226
+ * Set the description.
227
+ *
228
+ * @returns Command for chaining
236
229
  */
237
230
  description(str: string, argsDescription?: {[argName: string]: string}): Command;
231
+ /**
232
+ * Get the description.
233
+ */
238
234
  description(): string;
239
235
 
240
236
  /**
241
237
  * Set an alias for the command.
242
- *
243
- * @param {string} alias
244
- * @return {(Command | string)}
238
+ *
239
+ * @returns Command for chaining
245
240
  */
246
241
  alias(alias: string): Command;
242
+ /**
243
+ * Get alias for the command.
244
+ */
247
245
  alias(): string;
248
246
 
249
247
  /**
250
- * Set or get the command usage.
251
- *
252
- * @param {string} str
253
- * @return {(Command | string)}
248
+ * Set the command usage.
249
+ *
250
+ * @returns Command for chaining
254
251
  */
255
252
  usage(str: string): Command;
253
+ /**
254
+ * Get the command usage.
255
+ */
256
256
  usage(): string;
257
257
 
258
258
  /**
259
259
  * Set the name of the command.
260
- *
261
- * @param {string} str
262
- * @return {Command}
260
+ *
261
+ * @returns Command for chaining
263
262
  */
264
263
  name(str: string): Command;
265
-
266
264
  /**
267
265
  * Get the name of the command.
268
- *
269
- * @return {string}
270
266
  */
271
267
  name(): string;
272
268
 
@@ -275,8 +271,6 @@ declare namespace local {
275
271
  *
276
272
  * When listener(s) are available for the helpLongFlag
277
273
  * those callbacks are invoked.
278
- *
279
- * @param {(str: string) => string} [cb]
280
274
  */
281
275
  outputHelp(cb?: (str: string) => string): void;
282
276
 
@@ -291,14 +285,8 @@ declare namespace local {
291
285
  */
292
286
  help(cb?: (str: string) => string): never;
293
287
  }
288
+ type CommandConstructor = { new (name?: string): Command };
294
289
 
295
- }
296
-
297
- declare namespace commander {
298
-
299
- type Command = local.Command
300
-
301
- type Option = local.Option
302
290
 
303
291
  interface CommandOptions {
304
292
  noHelp?: boolean;
@@ -312,11 +300,9 @@ declare namespace commander {
312
300
  }
313
301
 
314
302
  interface CommanderStatic extends Command {
315
- Command: typeof local.Command;
316
- Option: typeof local.Option;
317
- CommandOptions: CommandOptions;
318
- ParseOptionsResult: ParseOptionsResult;
319
- CommanderError : typeof local.CommanderError;
303
+ Command: CommandConstructor;
304
+ Option: OptionConstructor;
305
+ CommanderError:CommanderErrorConstructor;
320
306
  }
321
307
 
322
308
  }