commander 12.0.0 → 13.0.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +15 -29
- package/esm.mjs +1 -1
- package/lib/argument.js +9 -5
- package/lib/command.js +509 -223
- package/lib/error.js +0 -4
- package/lib/help.js +336 -84
- package/lib/option.js +40 -19
- package/lib/suggestSimilar.js +5 -4
- package/package.json +23 -21
- package/typings/index.d.ts +174 -44
package/lib/command.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const EventEmitter = require('events').EventEmitter;
|
|
2
|
-
const childProcess = require('child_process');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const process = require('process');
|
|
1
|
+
const EventEmitter = require('node:events').EventEmitter;
|
|
2
|
+
const childProcess = require('node:child_process');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const process = require('node:process');
|
|
6
6
|
|
|
7
7
|
const { Argument, humanReadableArgName } = require('./argument.js');
|
|
8
8
|
const { CommanderError } = require('./error.js');
|
|
9
|
-
const { Help } = require('./help.js');
|
|
9
|
+
const { Help, stripColor } = require('./help.js');
|
|
10
10
|
const { Option, DualOptions } = require('./option.js');
|
|
11
11
|
const { suggestSimilar } = require('./suggestSimilar');
|
|
12
12
|
|
|
@@ -25,7 +25,7 @@ class Command extends EventEmitter {
|
|
|
25
25
|
this.options = [];
|
|
26
26
|
this.parent = null;
|
|
27
27
|
this._allowUnknownOption = false;
|
|
28
|
-
this._allowExcessArguments =
|
|
28
|
+
this._allowExcessArguments = false;
|
|
29
29
|
/** @type {Argument[]} */
|
|
30
30
|
this.registeredArguments = [];
|
|
31
31
|
this._args = this.registeredArguments; // deprecated old name
|
|
@@ -56,13 +56,20 @@ class Command extends EventEmitter {
|
|
|
56
56
|
this._showHelpAfterError = false;
|
|
57
57
|
this._showSuggestionAfterError = true;
|
|
58
58
|
|
|
59
|
-
// see
|
|
59
|
+
// see configureOutput() for docs
|
|
60
60
|
this._outputConfiguration = {
|
|
61
61
|
writeOut: (str) => process.stdout.write(str),
|
|
62
62
|
writeErr: (str) => process.stderr.write(str),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
outputError: (str, write) => write(str),
|
|
64
|
+
getOutHelpWidth: () =>
|
|
65
|
+
process.stdout.isTTY ? process.stdout.columns : undefined,
|
|
66
|
+
getErrHelpWidth: () =>
|
|
67
|
+
process.stderr.isTTY ? process.stderr.columns : undefined,
|
|
68
|
+
getOutHasColors: () =>
|
|
69
|
+
useColor() ?? (process.stdout.isTTY && process.stdout.hasColors?.()),
|
|
70
|
+
getErrHasColors: () =>
|
|
71
|
+
useColor() ?? (process.stderr.isTTY && process.stderr.hasColors?.()),
|
|
72
|
+
stripColor: (str) => stripColor(str),
|
|
66
73
|
};
|
|
67
74
|
|
|
68
75
|
this._hidden = false;
|
|
@@ -89,7 +96,8 @@ class Command extends EventEmitter {
|
|
|
89
96
|
this._helpConfiguration = sourceCommand._helpConfiguration;
|
|
90
97
|
this._exitCallback = sourceCommand._exitCallback;
|
|
91
98
|
this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
|
|
92
|
-
this._combineFlagAndOptionalValue =
|
|
99
|
+
this._combineFlagAndOptionalValue =
|
|
100
|
+
sourceCommand._combineFlagAndOptionalValue;
|
|
93
101
|
this._allowExcessArguments = sourceCommand._allowExcessArguments;
|
|
94
102
|
this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
|
|
95
103
|
this._showHelpAfterError = sourceCommand._showHelpAfterError;
|
|
@@ -105,6 +113,7 @@ class Command extends EventEmitter {
|
|
|
105
113
|
|
|
106
114
|
_getCommandAndAncestors() {
|
|
107
115
|
const result = [];
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
108
117
|
for (let command = this; command; command = command.parent) {
|
|
109
118
|
result.push(command);
|
|
110
119
|
}
|
|
@@ -131,8 +140,8 @@ class Command extends EventEmitter {
|
|
|
131
140
|
* .command('stop [service]', 'stop named service, or all if no name supplied');
|
|
132
141
|
*
|
|
133
142
|
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
|
|
134
|
-
* @param {(
|
|
135
|
-
* @param {
|
|
143
|
+
* @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
|
|
144
|
+
* @param {object} [execOpts] - configuration options (for executable)
|
|
136
145
|
* @return {Command} returns new command for action handler, or `this` for executable command
|
|
137
146
|
*/
|
|
138
147
|
|
|
@@ -192,8 +201,8 @@ class Command extends EventEmitter {
|
|
|
192
201
|
* You can customise the help by overriding Help properties using configureHelp(),
|
|
193
202
|
* or with a subclass of Help by overriding createHelp().
|
|
194
203
|
*
|
|
195
|
-
* @param {
|
|
196
|
-
* @return {(Command|
|
|
204
|
+
* @param {object} [configuration] - configuration options
|
|
205
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
197
206
|
*/
|
|
198
207
|
|
|
199
208
|
configureHelp(configuration) {
|
|
@@ -209,17 +218,21 @@ class Command extends EventEmitter {
|
|
|
209
218
|
*
|
|
210
219
|
* The configuration properties are all functions:
|
|
211
220
|
*
|
|
212
|
-
* //
|
|
221
|
+
* // change how output being written, defaults to stdout and stderr
|
|
213
222
|
* writeOut(str)
|
|
214
223
|
* writeErr(str)
|
|
215
|
-
* //
|
|
224
|
+
* // change how output being written for errors, defaults to writeErr
|
|
225
|
+
* outputError(str, write) // used for displaying errors and not used for displaying help
|
|
226
|
+
* // specify width for wrapping help
|
|
216
227
|
* getOutHelpWidth()
|
|
217
228
|
* getErrHelpWidth()
|
|
218
|
-
* //
|
|
219
|
-
*
|
|
229
|
+
* // color support, currently only used with Help
|
|
230
|
+
* getOutHasColors()
|
|
231
|
+
* getErrHasColors()
|
|
232
|
+
* stripColor() // used to remove ANSI escape codes if output does not have colors
|
|
220
233
|
*
|
|
221
|
-
* @param {
|
|
222
|
-
* @return {(Command|
|
|
234
|
+
* @param {object} [configuration] - configuration options
|
|
235
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
223
236
|
*/
|
|
224
237
|
|
|
225
238
|
configureOutput(configuration) {
|
|
@@ -258,7 +271,7 @@ class Command extends EventEmitter {
|
|
|
258
271
|
* See .command() for creating an attached subcommand which inherits settings from its parent.
|
|
259
272
|
*
|
|
260
273
|
* @param {Command} cmd - new subcommand
|
|
261
|
-
* @param {
|
|
274
|
+
* @param {object} [opts] - configuration options
|
|
262
275
|
* @return {Command} `this` command for chaining
|
|
263
276
|
*/
|
|
264
277
|
|
|
@@ -334,9 +347,12 @@ class Command extends EventEmitter {
|
|
|
334
347
|
*/
|
|
335
348
|
|
|
336
349
|
arguments(names) {
|
|
337
|
-
names
|
|
338
|
-
|
|
339
|
-
|
|
350
|
+
names
|
|
351
|
+
.trim()
|
|
352
|
+
.split(/ +/)
|
|
353
|
+
.forEach((detail) => {
|
|
354
|
+
this.argument(detail);
|
|
355
|
+
});
|
|
340
356
|
return this;
|
|
341
357
|
}
|
|
342
358
|
|
|
@@ -349,10 +365,18 @@ class Command extends EventEmitter {
|
|
|
349
365
|
addArgument(argument) {
|
|
350
366
|
const previousArgument = this.registeredArguments.slice(-1)[0];
|
|
351
367
|
if (previousArgument && previousArgument.variadic) {
|
|
352
|
-
throw new Error(
|
|
368
|
+
throw new Error(
|
|
369
|
+
`only the last argument can be variadic '${previousArgument.name()}'`,
|
|
370
|
+
);
|
|
353
371
|
}
|
|
354
|
-
if (
|
|
355
|
-
|
|
372
|
+
if (
|
|
373
|
+
argument.required &&
|
|
374
|
+
argument.defaultValue !== undefined &&
|
|
375
|
+
argument.parseArg === undefined
|
|
376
|
+
) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`a default value for a required argument is never used: '${argument.name()}'`,
|
|
379
|
+
);
|
|
356
380
|
}
|
|
357
381
|
this.registeredArguments.push(argument);
|
|
358
382
|
return this;
|
|
@@ -361,6 +385,7 @@ class Command extends EventEmitter {
|
|
|
361
385
|
/**
|
|
362
386
|
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.
|
|
363
387
|
*
|
|
388
|
+
* @example
|
|
364
389
|
* program.helpCommand('help [cmd]');
|
|
365
390
|
* program.helpCommand('help [cmd]', 'show help');
|
|
366
391
|
* program.helpCommand(false); // suppress default help command
|
|
@@ -419,8 +444,11 @@ class Command extends EventEmitter {
|
|
|
419
444
|
* @package
|
|
420
445
|
*/
|
|
421
446
|
_getHelpCommand() {
|
|
422
|
-
const hasImplicitHelpCommand =
|
|
423
|
-
|
|
447
|
+
const hasImplicitHelpCommand =
|
|
448
|
+
this._addImplicitHelpCommand ??
|
|
449
|
+
(this.commands.length &&
|
|
450
|
+
!this._actionHandler &&
|
|
451
|
+
!this._findCommand('help'));
|
|
424
452
|
|
|
425
453
|
if (hasImplicitHelpCommand) {
|
|
426
454
|
if (this._helpCommand === undefined) {
|
|
@@ -568,14 +596,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
568
596
|
* Register option if no conflicts found, or throw on conflict.
|
|
569
597
|
*
|
|
570
598
|
* @param {Option} option
|
|
571
|
-
* @
|
|
599
|
+
* @private
|
|
572
600
|
*/
|
|
573
601
|
|
|
574
602
|
_registerOption(option) {
|
|
575
|
-
const matchingOption =
|
|
603
|
+
const matchingOption =
|
|
604
|
+
(option.short && this._findOption(option.short)) ||
|
|
576
605
|
(option.long && this._findOption(option.long));
|
|
577
606
|
if (matchingOption) {
|
|
578
|
-
const matchingFlag =
|
|
607
|
+
const matchingFlag =
|
|
608
|
+
option.long && this._findOption(option.long)
|
|
609
|
+
? option.long
|
|
610
|
+
: option.short;
|
|
579
611
|
throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
|
|
580
612
|
- already used by option '${matchingOption.flags}'`);
|
|
581
613
|
}
|
|
@@ -588,7 +620,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
588
620
|
* Register command if no conflicts found, or throw on conflict.
|
|
589
621
|
*
|
|
590
622
|
* @param {Command} command
|
|
591
|
-
* @
|
|
623
|
+
* @private
|
|
592
624
|
*/
|
|
593
625
|
|
|
594
626
|
_registerCommand(command) {
|
|
@@ -596,11 +628,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
596
628
|
return [cmd.name()].concat(cmd.aliases());
|
|
597
629
|
};
|
|
598
630
|
|
|
599
|
-
const alreadyUsed = knownBy(command).find((name) =>
|
|
631
|
+
const alreadyUsed = knownBy(command).find((name) =>
|
|
632
|
+
this._findCommand(name),
|
|
633
|
+
);
|
|
600
634
|
if (alreadyUsed) {
|
|
601
635
|
const existingCmd = knownBy(this._findCommand(alreadyUsed)).join('|');
|
|
602
636
|
const newCmd = knownBy(command).join('|');
|
|
603
|
-
throw new Error(
|
|
637
|
+
throw new Error(
|
|
638
|
+
`cannot add command '${newCmd}' as already have command '${existingCmd}'`,
|
|
639
|
+
);
|
|
604
640
|
}
|
|
605
641
|
|
|
606
642
|
this.commands.push(command);
|
|
@@ -623,7 +659,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
623
659
|
// --no-foo is special and defaults foo to true, unless a --foo option is already defined
|
|
624
660
|
const positiveLongFlag = option.long.replace(/^--no-/, '--');
|
|
625
661
|
if (!this._findOption(positiveLongFlag)) {
|
|
626
|
-
this.setOptionValueWithSource(
|
|
662
|
+
this.setOptionValueWithSource(
|
|
663
|
+
name,
|
|
664
|
+
option.defaultValue === undefined ? true : option.defaultValue,
|
|
665
|
+
'default',
|
|
666
|
+
);
|
|
627
667
|
}
|
|
628
668
|
} else if (option.defaultValue !== undefined) {
|
|
629
669
|
this.setOptionValueWithSource(name, option.defaultValue, 'default');
|
|
@@ -676,11 +716,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
676
716
|
/**
|
|
677
717
|
* Internal implementation shared by .option() and .requiredOption()
|
|
678
718
|
*
|
|
719
|
+
* @return {Command} `this` command for chaining
|
|
679
720
|
* @private
|
|
680
721
|
*/
|
|
681
722
|
_optionEx(config, flags, description, fn, defaultValue) {
|
|
682
723
|
if (typeof flags === 'object' && flags instanceof Option) {
|
|
683
|
-
throw new Error(
|
|
724
|
+
throw new Error(
|
|
725
|
+
'To add an Option object use addOption() instead of option() or requiredOption()',
|
|
726
|
+
);
|
|
684
727
|
}
|
|
685
728
|
const option = this.createOption(flags, description);
|
|
686
729
|
option.makeOptionMandatory(!!config.mandatory);
|
|
@@ -728,20 +771,26 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
728
771
|
}
|
|
729
772
|
|
|
730
773
|
/**
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
774
|
+
* Add a required option which must have a value after parsing. This usually means
|
|
775
|
+
* the option must be specified on the command line. (Otherwise the same as .option().)
|
|
776
|
+
*
|
|
777
|
+
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
|
|
778
|
+
*
|
|
779
|
+
* @param {string} flags
|
|
780
|
+
* @param {string} [description]
|
|
781
|
+
* @param {(Function|*)} [parseArg] - custom option processing function or default value
|
|
782
|
+
* @param {*} [defaultValue]
|
|
783
|
+
* @return {Command} `this` command for chaining
|
|
784
|
+
*/
|
|
742
785
|
|
|
743
786
|
requiredOption(flags, description, parseArg, defaultValue) {
|
|
744
|
-
return this._optionEx(
|
|
787
|
+
return this._optionEx(
|
|
788
|
+
{ mandatory: true },
|
|
789
|
+
flags,
|
|
790
|
+
description,
|
|
791
|
+
parseArg,
|
|
792
|
+
defaultValue,
|
|
793
|
+
);
|
|
745
794
|
}
|
|
746
795
|
|
|
747
796
|
/**
|
|
@@ -752,7 +801,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
752
801
|
* program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
|
|
753
802
|
* program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
|
|
754
803
|
*
|
|
755
|
-
* @param {boolean} [combine
|
|
804
|
+
* @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
|
|
805
|
+
* @return {Command} `this` command for chaining
|
|
756
806
|
*/
|
|
757
807
|
combineFlagAndOptionalValue(combine = true) {
|
|
758
808
|
this._combineFlagAndOptionalValue = !!combine;
|
|
@@ -762,8 +812,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
762
812
|
/**
|
|
763
813
|
* Allow unknown options on the command line.
|
|
764
814
|
*
|
|
765
|
-
* @param {boolean} [allowUnknown
|
|
766
|
-
* for
|
|
815
|
+
* @param {boolean} [allowUnknown] - if `true` or omitted, no error will be thrown for unknown options.
|
|
816
|
+
* @return {Command} `this` command for chaining
|
|
767
817
|
*/
|
|
768
818
|
allowUnknownOption(allowUnknown = true) {
|
|
769
819
|
this._allowUnknownOption = !!allowUnknown;
|
|
@@ -773,8 +823,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
773
823
|
/**
|
|
774
824
|
* Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
|
|
775
825
|
*
|
|
776
|
-
* @param {boolean} [allowExcess
|
|
777
|
-
* for
|
|
826
|
+
* @param {boolean} [allowExcess] - if `true` or omitted, no error will be thrown for excess arguments.
|
|
827
|
+
* @return {Command} `this` command for chaining
|
|
778
828
|
*/
|
|
779
829
|
allowExcessArguments(allowExcess = true) {
|
|
780
830
|
this._allowExcessArguments = !!allowExcess;
|
|
@@ -786,7 +836,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
786
836
|
* subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
|
|
787
837
|
* The default behaviour is non-positional and global options may appear anywhere on the command line.
|
|
788
838
|
*
|
|
789
|
-
* @param {boolean} [positional
|
|
839
|
+
* @param {boolean} [positional]
|
|
840
|
+
* @return {Command} `this` command for chaining
|
|
790
841
|
*/
|
|
791
842
|
enablePositionalOptions(positional = true) {
|
|
792
843
|
this._enablePositionalOptions = !!positional;
|
|
@@ -799,8 +850,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
799
850
|
* positional options to have been enabled on the program (parent commands).
|
|
800
851
|
* The default behaviour is non-positional and options may appear before or after command-arguments.
|
|
801
852
|
*
|
|
802
|
-
* @param {boolean} [passThrough
|
|
803
|
-
* for
|
|
853
|
+
* @param {boolean} [passThrough] for unknown options.
|
|
854
|
+
* @return {Command} `this` command for chaining
|
|
804
855
|
*/
|
|
805
856
|
passThroughOptions(passThrough = true) {
|
|
806
857
|
this._passThroughOptions = !!passThrough;
|
|
@@ -813,25 +864,33 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
813
864
|
*/
|
|
814
865
|
|
|
815
866
|
_checkForBrokenPassThrough() {
|
|
816
|
-
if (
|
|
817
|
-
|
|
867
|
+
if (
|
|
868
|
+
this.parent &&
|
|
869
|
+
this._passThroughOptions &&
|
|
870
|
+
!this.parent._enablePositionalOptions
|
|
871
|
+
) {
|
|
872
|
+
throw new Error(
|
|
873
|
+
`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`,
|
|
874
|
+
);
|
|
818
875
|
}
|
|
819
876
|
}
|
|
820
877
|
|
|
821
878
|
/**
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
879
|
+
* Whether to store option values as properties on command object,
|
|
880
|
+
* or store separately (specify false). In both cases the option values can be accessed using .opts().
|
|
881
|
+
*
|
|
882
|
+
* @param {boolean} [storeAsProperties=true]
|
|
883
|
+
* @return {Command} `this` command for chaining
|
|
884
|
+
*/
|
|
828
885
|
|
|
829
886
|
storeOptionsAsProperties(storeAsProperties = true) {
|
|
830
887
|
if (this.options.length) {
|
|
831
888
|
throw new Error('call .storeOptionsAsProperties() before adding options');
|
|
832
889
|
}
|
|
833
890
|
if (Object.keys(this._optionValues).length) {
|
|
834
|
-
throw new Error(
|
|
891
|
+
throw new Error(
|
|
892
|
+
'call .storeOptionsAsProperties() before setting option values',
|
|
893
|
+
);
|
|
835
894
|
}
|
|
836
895
|
this._storeOptionsAsProperties = !!storeAsProperties;
|
|
837
896
|
return this;
|
|
@@ -841,7 +900,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
841
900
|
* Retrieve option value.
|
|
842
901
|
*
|
|
843
902
|
* @param {string} key
|
|
844
|
-
* @return {
|
|
903
|
+
* @return {object} value
|
|
845
904
|
*/
|
|
846
905
|
|
|
847
906
|
getOptionValue(key) {
|
|
@@ -855,7 +914,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
855
914
|
* Store option value.
|
|
856
915
|
*
|
|
857
916
|
* @param {string} key
|
|
858
|
-
* @param {
|
|
917
|
+
* @param {object} value
|
|
859
918
|
* @return {Command} `this` command for chaining
|
|
860
919
|
*/
|
|
861
920
|
|
|
@@ -864,13 +923,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
864
923
|
}
|
|
865
924
|
|
|
866
925
|
/**
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
926
|
+
* Store option value and where the value came from.
|
|
927
|
+
*
|
|
928
|
+
* @param {string} key
|
|
929
|
+
* @param {object} value
|
|
930
|
+
* @param {string} source - expected values are default/config/env/cli/implied
|
|
931
|
+
* @return {Command} `this` command for chaining
|
|
932
|
+
*/
|
|
874
933
|
|
|
875
934
|
setOptionValueWithSource(key, value, source) {
|
|
876
935
|
if (this._storeOptionsAsProperties) {
|
|
@@ -883,24 +942,24 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
883
942
|
}
|
|
884
943
|
|
|
885
944
|
/**
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
945
|
+
* Get source of option value.
|
|
946
|
+
* Expected values are default | config | env | cli | implied
|
|
947
|
+
*
|
|
948
|
+
* @param {string} key
|
|
949
|
+
* @return {string}
|
|
950
|
+
*/
|
|
892
951
|
|
|
893
952
|
getOptionValueSource(key) {
|
|
894
953
|
return this._optionValueSources[key];
|
|
895
954
|
}
|
|
896
955
|
|
|
897
956
|
/**
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
957
|
+
* Get source of option value. See also .optsWithGlobals().
|
|
958
|
+
* Expected values are default | config | env | cli | implied
|
|
959
|
+
*
|
|
960
|
+
* @param {string} key
|
|
961
|
+
* @return {string}
|
|
962
|
+
*/
|
|
904
963
|
|
|
905
964
|
getOptionValueSourceWithGlobals(key) {
|
|
906
965
|
// global overwrites local, like optsWithGlobals
|
|
@@ -926,17 +985,30 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
926
985
|
}
|
|
927
986
|
parseOptions = parseOptions || {};
|
|
928
987
|
|
|
929
|
-
//
|
|
930
|
-
if (argv === undefined) {
|
|
931
|
-
|
|
932
|
-
// @ts-ignore: unknown property
|
|
933
|
-
if (process.versions && process.versions.electron) {
|
|
988
|
+
// auto-detect argument conventions if nothing supplied
|
|
989
|
+
if (argv === undefined && parseOptions.from === undefined) {
|
|
990
|
+
if (process.versions?.electron) {
|
|
934
991
|
parseOptions.from = 'electron';
|
|
935
992
|
}
|
|
993
|
+
// check node specific options for scenarios where user CLI args follow executable without scriptname
|
|
994
|
+
const execArgv = process.execArgv ?? [];
|
|
995
|
+
if (
|
|
996
|
+
execArgv.includes('-e') ||
|
|
997
|
+
execArgv.includes('--eval') ||
|
|
998
|
+
execArgv.includes('-p') ||
|
|
999
|
+
execArgv.includes('--print')
|
|
1000
|
+
) {
|
|
1001
|
+
parseOptions.from = 'eval'; // internal usage, not documented
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// default to using process.argv
|
|
1006
|
+
if (argv === undefined) {
|
|
1007
|
+
argv = process.argv;
|
|
936
1008
|
}
|
|
937
1009
|
this.rawArgs = argv.slice();
|
|
938
1010
|
|
|
939
|
-
//
|
|
1011
|
+
// extract the user args and scriptPath
|
|
940
1012
|
let userArgs;
|
|
941
1013
|
switch (parseOptions.from) {
|
|
942
1014
|
case undefined:
|
|
@@ -945,7 +1017,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
945
1017
|
userArgs = argv.slice(2);
|
|
946
1018
|
break;
|
|
947
1019
|
case 'electron':
|
|
948
|
-
// @ts-ignore: unknown property
|
|
1020
|
+
// @ts-ignore: because defaultApp is an unknown property
|
|
949
1021
|
if (process.defaultApp) {
|
|
950
1022
|
this._scriptPath = argv[1];
|
|
951
1023
|
userArgs = argv.slice(2);
|
|
@@ -956,12 +1028,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
956
1028
|
case 'user':
|
|
957
1029
|
userArgs = argv.slice(0);
|
|
958
1030
|
break;
|
|
1031
|
+
case 'eval':
|
|
1032
|
+
userArgs = argv.slice(1);
|
|
1033
|
+
break;
|
|
959
1034
|
default:
|
|
960
|
-
throw new Error(
|
|
1035
|
+
throw new Error(
|
|
1036
|
+
`unexpected parse option { from: '${parseOptions.from}' }`,
|
|
1037
|
+
);
|
|
961
1038
|
}
|
|
962
1039
|
|
|
963
1040
|
// Find default name for program from arguments.
|
|
964
|
-
if (!this._name && this._scriptPath)
|
|
1041
|
+
if (!this._name && this._scriptPath)
|
|
1042
|
+
this.nameFromFilename(this._scriptPath);
|
|
965
1043
|
this._name = this._name || 'program';
|
|
966
1044
|
|
|
967
1045
|
return userArgs;
|
|
@@ -970,16 +1048,22 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
970
1048
|
/**
|
|
971
1049
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
972
1050
|
*
|
|
973
|
-
*
|
|
974
|
-
*
|
|
1051
|
+
* Use parseAsync instead of parse if any of your action handlers are async.
|
|
1052
|
+
*
|
|
1053
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
1054
|
+
*
|
|
1055
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1056
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1057
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1058
|
+
* - `'user'`: just user arguments
|
|
975
1059
|
*
|
|
976
1060
|
* @example
|
|
977
|
-
* program.parse(process.argv
|
|
978
|
-
* program.parse(); //
|
|
1061
|
+
* program.parse(); // parse process.argv and auto-detect electron and special node flags
|
|
1062
|
+
* program.parse(process.argv); // assume argv[0] is app and argv[1] is script
|
|
979
1063
|
* program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
980
1064
|
*
|
|
981
1065
|
* @param {string[]} [argv] - optional, defaults to process.argv
|
|
982
|
-
* @param {
|
|
1066
|
+
* @param {object} [parseOptions] - optionally specify style of options with from: node/user/electron
|
|
983
1067
|
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
|
|
984
1068
|
* @return {Command} `this` command for chaining
|
|
985
1069
|
*/
|
|
@@ -994,18 +1078,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
994
1078
|
/**
|
|
995
1079
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
996
1080
|
*
|
|
997
|
-
*
|
|
1081
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
998
1082
|
*
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1083
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1084
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1085
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1086
|
+
* - `'user'`: just user arguments
|
|
1001
1087
|
*
|
|
1002
1088
|
* @example
|
|
1003
|
-
* await program.parseAsync(process.argv
|
|
1004
|
-
* await program.parseAsync(); //
|
|
1089
|
+
* await program.parseAsync(); // parse process.argv and auto-detect electron and special node flags
|
|
1090
|
+
* await program.parseAsync(process.argv); // assume argv[0] is app and argv[1] is script
|
|
1005
1091
|
* await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
1006
1092
|
*
|
|
1007
1093
|
* @param {string[]} [argv]
|
|
1008
|
-
* @param {
|
|
1094
|
+
* @param {object} [parseOptions]
|
|
1009
1095
|
* @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
|
|
1010
1096
|
* @return {Promise}
|
|
1011
1097
|
*/
|
|
@@ -1037,7 +1123,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1037
1123
|
if (sourceExt.includes(path.extname(baseName))) return undefined;
|
|
1038
1124
|
|
|
1039
1125
|
// Try all the extensions.
|
|
1040
|
-
const foundExt = sourceExt.find(ext =>
|
|
1126
|
+
const foundExt = sourceExt.find((ext) =>
|
|
1127
|
+
fs.existsSync(`${localBin}${ext}`),
|
|
1128
|
+
);
|
|
1041
1129
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1042
1130
|
|
|
1043
1131
|
return undefined;
|
|
@@ -1048,16 +1136,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1048
1136
|
this._checkForConflictingOptions();
|
|
1049
1137
|
|
|
1050
1138
|
// executableFile and executableDir might be full path, or just a name
|
|
1051
|
-
let executableFile =
|
|
1139
|
+
let executableFile =
|
|
1140
|
+
subcommand._executableFile || `${this._name}-${subcommand._name}`;
|
|
1052
1141
|
let executableDir = this._executableDir || '';
|
|
1053
1142
|
if (this._scriptPath) {
|
|
1054
1143
|
let resolvedScriptPath; // resolve possible symlink for installed npm binary
|
|
1055
1144
|
try {
|
|
1056
1145
|
resolvedScriptPath = fs.realpathSync(this._scriptPath);
|
|
1057
|
-
} catch
|
|
1146
|
+
} catch {
|
|
1058
1147
|
resolvedScriptPath = this._scriptPath;
|
|
1059
1148
|
}
|
|
1060
|
-
executableDir = path.resolve(
|
|
1149
|
+
executableDir = path.resolve(
|
|
1150
|
+
path.dirname(resolvedScriptPath),
|
|
1151
|
+
executableDir,
|
|
1152
|
+
);
|
|
1061
1153
|
}
|
|
1062
1154
|
|
|
1063
1155
|
// Look for a local file in preference to a command in PATH.
|
|
@@ -1066,9 +1158,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1066
1158
|
|
|
1067
1159
|
// Legacy search using prefix of script name instead of command name
|
|
1068
1160
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1069
|
-
const legacyName = path.basename(
|
|
1161
|
+
const legacyName = path.basename(
|
|
1162
|
+
this._scriptPath,
|
|
1163
|
+
path.extname(this._scriptPath),
|
|
1164
|
+
);
|
|
1070
1165
|
if (legacyName !== this._name) {
|
|
1071
|
-
localFile = findFile(
|
|
1166
|
+
localFile = findFile(
|
|
1167
|
+
executableDir,
|
|
1168
|
+
`${legacyName}-${subcommand._name}`,
|
|
1169
|
+
);
|
|
1072
1170
|
}
|
|
1073
1171
|
}
|
|
1074
1172
|
executableFile = localFile || executableFile;
|
|
@@ -1094,12 +1192,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1094
1192
|
proc = childProcess.spawn(process.execPath, args, { stdio: 'inherit' });
|
|
1095
1193
|
}
|
|
1096
1194
|
|
|
1097
|
-
if (!proc.killed) {
|
|
1195
|
+
if (!proc.killed) {
|
|
1196
|
+
// testing mainly to avoid leak warnings during unit tests with mocked spawn
|
|
1098
1197
|
const signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
1099
1198
|
signals.forEach((signal) => {
|
|
1100
|
-
// @ts-ignore
|
|
1101
1199
|
process.on(signal, () => {
|
|
1102
1200
|
if (proc.killed === false && proc.exitCode === null) {
|
|
1201
|
+
// @ts-ignore because signals not typed to known strings
|
|
1103
1202
|
proc.kill(signal);
|
|
1104
1203
|
}
|
|
1105
1204
|
});
|
|
@@ -1108,16 +1207,22 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1108
1207
|
|
|
1109
1208
|
// By default terminate process when spawned process terminates.
|
|
1110
1209
|
const exitCallback = this._exitCallback;
|
|
1111
|
-
proc.on('close', (code
|
|
1210
|
+
proc.on('close', (code) => {
|
|
1112
1211
|
code = code ?? 1; // code is null if spawned process terminated due to a signal
|
|
1113
1212
|
if (!exitCallback) {
|
|
1114
1213
|
process.exit(code);
|
|
1115
1214
|
} else {
|
|
1116
|
-
exitCallback(
|
|
1215
|
+
exitCallback(
|
|
1216
|
+
new CommanderError(
|
|
1217
|
+
code,
|
|
1218
|
+
'commander.executeSubCommandAsync',
|
|
1219
|
+
'(close)',
|
|
1220
|
+
),
|
|
1221
|
+
);
|
|
1117
1222
|
}
|
|
1118
1223
|
});
|
|
1119
1224
|
proc.on('error', (err) => {
|
|
1120
|
-
// @ts-ignore
|
|
1225
|
+
// @ts-ignore: because err.code is an unknown property
|
|
1121
1226
|
if (err.code === 'ENOENT') {
|
|
1122
1227
|
const executableDirMessage = executableDir
|
|
1123
1228
|
? `searched for local subcommand relative to directory '${executableDir}'`
|
|
@@ -1127,14 +1232,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1127
1232
|
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
1128
1233
|
- ${executableDirMessage}`;
|
|
1129
1234
|
throw new Error(executableMissing);
|
|
1130
|
-
|
|
1235
|
+
// @ts-ignore: because err.code is an unknown property
|
|
1131
1236
|
} else if (err.code === 'EACCES') {
|
|
1132
1237
|
throw new Error(`'${executableFile}' not executable`);
|
|
1133
1238
|
}
|
|
1134
1239
|
if (!exitCallback) {
|
|
1135
1240
|
process.exit(1);
|
|
1136
1241
|
} else {
|
|
1137
|
-
const wrappedError = new CommanderError(
|
|
1242
|
+
const wrappedError = new CommanderError(
|
|
1243
|
+
1,
|
|
1244
|
+
'commander.executeSubCommandAsync',
|
|
1245
|
+
'(error)',
|
|
1246
|
+
);
|
|
1138
1247
|
wrappedError.nestedError = err;
|
|
1139
1248
|
exitCallback(wrappedError);
|
|
1140
1249
|
}
|
|
@@ -1153,7 +1262,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1153
1262
|
if (!subCommand) this.help({ error: true });
|
|
1154
1263
|
|
|
1155
1264
|
let promiseChain;
|
|
1156
|
-
promiseChain = this._chainOrCallSubCommandHook(
|
|
1265
|
+
promiseChain = this._chainOrCallSubCommandHook(
|
|
1266
|
+
promiseChain,
|
|
1267
|
+
subCommand,
|
|
1268
|
+
'preSubcommand',
|
|
1269
|
+
);
|
|
1157
1270
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
1158
1271
|
if (subCommand._executableHandler) {
|
|
1159
1272
|
this._executeSubCommand(subCommand, operands.concat(unknown));
|
|
@@ -1181,9 +1294,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1181
1294
|
}
|
|
1182
1295
|
|
|
1183
1296
|
// Fallback to parsing the help flag to invoke the help.
|
|
1184
|
-
return this._dispatchSubcommand(
|
|
1185
|
-
|
|
1186
|
-
|
|
1297
|
+
return this._dispatchSubcommand(
|
|
1298
|
+
subcommandName,
|
|
1299
|
+
[],
|
|
1300
|
+
[this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? '--help'],
|
|
1301
|
+
);
|
|
1187
1302
|
}
|
|
1188
1303
|
|
|
1189
1304
|
/**
|
|
@@ -1200,7 +1315,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1200
1315
|
}
|
|
1201
1316
|
});
|
|
1202
1317
|
// too many
|
|
1203
|
-
if (
|
|
1318
|
+
if (
|
|
1319
|
+
this.registeredArguments.length > 0 &&
|
|
1320
|
+
this.registeredArguments[this.registeredArguments.length - 1].variadic
|
|
1321
|
+
) {
|
|
1204
1322
|
return;
|
|
1205
1323
|
}
|
|
1206
1324
|
if (this.args.length > this.registeredArguments.length) {
|
|
@@ -1220,7 +1338,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1220
1338
|
let parsedValue = value;
|
|
1221
1339
|
if (value !== null && argument.parseArg) {
|
|
1222
1340
|
const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
|
|
1223
|
-
parsedValue = this._callParseArg(
|
|
1341
|
+
parsedValue = this._callParseArg(
|
|
1342
|
+
argument,
|
|
1343
|
+
value,
|
|
1344
|
+
previous,
|
|
1345
|
+
invalidValueMessage,
|
|
1346
|
+
);
|
|
1224
1347
|
}
|
|
1225
1348
|
return parsedValue;
|
|
1226
1349
|
};
|
|
@@ -1285,8 +1408,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1285
1408
|
const hooks = [];
|
|
1286
1409
|
this._getCommandAndAncestors()
|
|
1287
1410
|
.reverse()
|
|
1288
|
-
.filter(cmd => cmd._lifeCycleHooks[event] !== undefined)
|
|
1289
|
-
.forEach(hookedCommand => {
|
|
1411
|
+
.filter((cmd) => cmd._lifeCycleHooks[event] !== undefined)
|
|
1412
|
+
.forEach((hookedCommand) => {
|
|
1290
1413
|
hookedCommand._lifeCycleHooks[event].forEach((callback) => {
|
|
1291
1414
|
hooks.push({ hookedCommand, callback });
|
|
1292
1415
|
});
|
|
@@ -1342,14 +1465,26 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1342
1465
|
if (operands && this._findCommand(operands[0])) {
|
|
1343
1466
|
return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
|
|
1344
1467
|
}
|
|
1345
|
-
if (
|
|
1468
|
+
if (
|
|
1469
|
+
this._getHelpCommand() &&
|
|
1470
|
+
operands[0] === this._getHelpCommand().name()
|
|
1471
|
+
) {
|
|
1346
1472
|
return this._dispatchHelpCommand(operands[1]);
|
|
1347
1473
|
}
|
|
1348
1474
|
if (this._defaultCommandName) {
|
|
1349
1475
|
this._outputHelpIfRequested(unknown); // Run the help for default command from parent rather than passing to default command
|
|
1350
|
-
return this._dispatchSubcommand(
|
|
1476
|
+
return this._dispatchSubcommand(
|
|
1477
|
+
this._defaultCommandName,
|
|
1478
|
+
operands,
|
|
1479
|
+
unknown,
|
|
1480
|
+
);
|
|
1351
1481
|
}
|
|
1352
|
-
if (
|
|
1482
|
+
if (
|
|
1483
|
+
this.commands.length &&
|
|
1484
|
+
this.args.length === 0 &&
|
|
1485
|
+
!this._actionHandler &&
|
|
1486
|
+
!this._defaultCommandName
|
|
1487
|
+
) {
|
|
1353
1488
|
// probably missing subcommand and no handler, user needs help (and exit)
|
|
1354
1489
|
this.help({ error: true });
|
|
1355
1490
|
}
|
|
@@ -1372,7 +1507,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1372
1507
|
|
|
1373
1508
|
let promiseChain;
|
|
1374
1509
|
promiseChain = this._chainOrCallHooks(promiseChain, 'preAction');
|
|
1375
|
-
promiseChain = this._chainOrCall(promiseChain, () =>
|
|
1510
|
+
promiseChain = this._chainOrCall(promiseChain, () =>
|
|
1511
|
+
this._actionHandler(this.processedArgs),
|
|
1512
|
+
);
|
|
1376
1513
|
if (this.parent) {
|
|
1377
1514
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
1378
1515
|
this.parent.emit(commandEvent, operands, unknown); // legacy
|
|
@@ -1386,7 +1523,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1386
1523
|
this._processArguments();
|
|
1387
1524
|
this.parent.emit(commandEvent, operands, unknown); // legacy
|
|
1388
1525
|
} else if (operands.length) {
|
|
1389
|
-
if (this._findCommand('*')) {
|
|
1526
|
+
if (this._findCommand('*')) {
|
|
1527
|
+
// legacy default command
|
|
1390
1528
|
return this._dispatchSubcommand('*', operands, unknown);
|
|
1391
1529
|
}
|
|
1392
1530
|
if (this.listenerCount('command:*')) {
|
|
@@ -1413,10 +1551,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1413
1551
|
* Find matching command.
|
|
1414
1552
|
*
|
|
1415
1553
|
* @private
|
|
1554
|
+
* @return {Command | undefined}
|
|
1416
1555
|
*/
|
|
1417
1556
|
_findCommand(name) {
|
|
1418
1557
|
if (!name) return undefined;
|
|
1419
|
-
return this.commands.find(
|
|
1558
|
+
return this.commands.find(
|
|
1559
|
+
(cmd) => cmd._name === name || cmd._aliases.includes(name),
|
|
1560
|
+
);
|
|
1420
1561
|
}
|
|
1421
1562
|
|
|
1422
1563
|
/**
|
|
@@ -1424,11 +1565,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1424
1565
|
*
|
|
1425
1566
|
* @param {string} arg
|
|
1426
1567
|
* @return {Option}
|
|
1427
|
-
* @package
|
|
1568
|
+
* @package
|
|
1428
1569
|
*/
|
|
1429
1570
|
|
|
1430
1571
|
_findOption(arg) {
|
|
1431
|
-
return this.options.find(option => option.is(arg));
|
|
1572
|
+
return this.options.find((option) => option.is(arg));
|
|
1432
1573
|
}
|
|
1433
1574
|
|
|
1434
1575
|
/**
|
|
@@ -1442,7 +1583,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1442
1583
|
// Walk up hierarchy so can call in subcommand after checking for displaying help.
|
|
1443
1584
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
1444
1585
|
cmd.options.forEach((anOption) => {
|
|
1445
|
-
if (
|
|
1586
|
+
if (
|
|
1587
|
+
anOption.mandatory &&
|
|
1588
|
+
cmd.getOptionValue(anOption.attributeName()) === undefined
|
|
1589
|
+
) {
|
|
1446
1590
|
cmd.missingMandatoryOptionValue(anOption);
|
|
1447
1591
|
}
|
|
1448
1592
|
});
|
|
@@ -1455,23 +1599,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1455
1599
|
* @private
|
|
1456
1600
|
*/
|
|
1457
1601
|
_checkForConflictingLocalOptions() {
|
|
1458
|
-
const definedNonDefaultOptions = this.options.filter(
|
|
1459
|
-
(
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
return false;
|
|
1463
|
-
}
|
|
1464
|
-
return this.getOptionValueSource(optionKey) !== 'default';
|
|
1602
|
+
const definedNonDefaultOptions = this.options.filter((option) => {
|
|
1603
|
+
const optionKey = option.attributeName();
|
|
1604
|
+
if (this.getOptionValue(optionKey) === undefined) {
|
|
1605
|
+
return false;
|
|
1465
1606
|
}
|
|
1466
|
-
|
|
1607
|
+
return this.getOptionValueSource(optionKey) !== 'default';
|
|
1608
|
+
});
|
|
1467
1609
|
|
|
1468
1610
|
const optionsWithConflicting = definedNonDefaultOptions.filter(
|
|
1469
|
-
(option) => option.conflictsWith.length > 0
|
|
1611
|
+
(option) => option.conflictsWith.length > 0,
|
|
1470
1612
|
);
|
|
1471
1613
|
|
|
1472
1614
|
optionsWithConflicting.forEach((option) => {
|
|
1473
1615
|
const conflictingAndDefined = definedNonDefaultOptions.find((defined) =>
|
|
1474
|
-
option.conflictsWith.includes(defined.attributeName())
|
|
1616
|
+
option.conflictsWith.includes(defined.attributeName()),
|
|
1475
1617
|
);
|
|
1476
1618
|
if (conflictingAndDefined) {
|
|
1477
1619
|
this._conflictingOption(option, conflictingAndDefined);
|
|
@@ -1551,7 +1693,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1551
1693
|
value = args.shift();
|
|
1552
1694
|
}
|
|
1553
1695
|
this.emit(`option:${option.name()}`, value);
|
|
1554
|
-
} else {
|
|
1696
|
+
} else {
|
|
1697
|
+
// boolean flag
|
|
1555
1698
|
this.emit(`option:${option.name()}`);
|
|
1556
1699
|
}
|
|
1557
1700
|
activeVariadicOption = option.variadic ? option : null;
|
|
@@ -1563,7 +1706,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1563
1706
|
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
|
|
1564
1707
|
const option = this._findOption(`-${arg[1]}`);
|
|
1565
1708
|
if (option) {
|
|
1566
|
-
if (
|
|
1709
|
+
if (
|
|
1710
|
+
option.required ||
|
|
1711
|
+
(option.optional && this._combineFlagAndOptionalValue)
|
|
1712
|
+
) {
|
|
1567
1713
|
// option with value following in same argument
|
|
1568
1714
|
this.emit(`option:${option.name()}`, arg.slice(2));
|
|
1569
1715
|
} else {
|
|
@@ -1594,12 +1740,19 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1594
1740
|
}
|
|
1595
1741
|
|
|
1596
1742
|
// If using positionalOptions, stop processing our options at subcommand.
|
|
1597
|
-
if (
|
|
1743
|
+
if (
|
|
1744
|
+
(this._enablePositionalOptions || this._passThroughOptions) &&
|
|
1745
|
+
operands.length === 0 &&
|
|
1746
|
+
unknown.length === 0
|
|
1747
|
+
) {
|
|
1598
1748
|
if (this._findCommand(arg)) {
|
|
1599
1749
|
operands.push(arg);
|
|
1600
1750
|
if (args.length > 0) unknown.push(...args);
|
|
1601
1751
|
break;
|
|
1602
|
-
} else if (
|
|
1752
|
+
} else if (
|
|
1753
|
+
this._getHelpCommand() &&
|
|
1754
|
+
arg === this._getHelpCommand().name()
|
|
1755
|
+
) {
|
|
1603
1756
|
operands.push(arg);
|
|
1604
1757
|
if (args.length > 0) operands.push(...args);
|
|
1605
1758
|
break;
|
|
@@ -1627,7 +1780,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1627
1780
|
/**
|
|
1628
1781
|
* Return an object containing local option values as key-value pairs.
|
|
1629
1782
|
*
|
|
1630
|
-
* @return {
|
|
1783
|
+
* @return {object}
|
|
1631
1784
|
*/
|
|
1632
1785
|
opts() {
|
|
1633
1786
|
if (this._storeOptionsAsProperties) {
|
|
@@ -1637,7 +1790,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1637
1790
|
|
|
1638
1791
|
for (let i = 0; i < len; i++) {
|
|
1639
1792
|
const key = this.options[i].attributeName();
|
|
1640
|
-
result[key] =
|
|
1793
|
+
result[key] =
|
|
1794
|
+
key === this._versionOptionName ? this._version : this[key];
|
|
1641
1795
|
}
|
|
1642
1796
|
return result;
|
|
1643
1797
|
}
|
|
@@ -1648,13 +1802,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1648
1802
|
/**
|
|
1649
1803
|
* Return an object containing merged local and global option values as key-value pairs.
|
|
1650
1804
|
*
|
|
1651
|
-
* @return {
|
|
1805
|
+
* @return {object}
|
|
1652
1806
|
*/
|
|
1653
1807
|
optsWithGlobals() {
|
|
1654
1808
|
// globals overwrite locals
|
|
1655
1809
|
return this._getCommandAndAncestors().reduce(
|
|
1656
1810
|
(combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()),
|
|
1657
|
-
{}
|
|
1811
|
+
{},
|
|
1658
1812
|
);
|
|
1659
1813
|
}
|
|
1660
1814
|
|
|
@@ -1662,13 +1816,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1662
1816
|
* Display error message and exit (or call exitOverride).
|
|
1663
1817
|
*
|
|
1664
1818
|
* @param {string} message
|
|
1665
|
-
* @param {
|
|
1819
|
+
* @param {object} [errorOptions]
|
|
1666
1820
|
* @param {string} [errorOptions.code] - an id string representing the error
|
|
1667
1821
|
* @param {number} [errorOptions.exitCode] - used with process.exit
|
|
1668
1822
|
*/
|
|
1669
1823
|
error(message, errorOptions) {
|
|
1670
1824
|
// output handling
|
|
1671
|
-
this._outputConfiguration.outputError(
|
|
1825
|
+
this._outputConfiguration.outputError(
|
|
1826
|
+
`${message}\n`,
|
|
1827
|
+
this._outputConfiguration.writeErr,
|
|
1828
|
+
);
|
|
1672
1829
|
if (typeof this._showHelpAfterError === 'string') {
|
|
1673
1830
|
this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`);
|
|
1674
1831
|
} else if (this._showHelpAfterError) {
|
|
@@ -1694,11 +1851,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1694
1851
|
if (option.envVar && option.envVar in process.env) {
|
|
1695
1852
|
const optionKey = option.attributeName();
|
|
1696
1853
|
// Priority check. Do not overwrite cli or options from unknown source (client-code).
|
|
1697
|
-
if (
|
|
1698
|
-
|
|
1854
|
+
if (
|
|
1855
|
+
this.getOptionValue(optionKey) === undefined ||
|
|
1856
|
+
['default', 'config', 'env'].includes(
|
|
1857
|
+
this.getOptionValueSource(optionKey),
|
|
1858
|
+
)
|
|
1859
|
+
) {
|
|
1860
|
+
if (option.required || option.optional) {
|
|
1861
|
+
// option can take a value
|
|
1699
1862
|
// keep very simple, optional always takes value
|
|
1700
1863
|
this.emit(`optionEnv:${option.name()}`, process.env[option.envVar]);
|
|
1701
|
-
} else {
|
|
1864
|
+
} else {
|
|
1865
|
+
// boolean
|
|
1702
1866
|
// keep very simple, only care that envVar defined and not the value
|
|
1703
1867
|
this.emit(`optionEnv:${option.name()}`);
|
|
1704
1868
|
}
|
|
@@ -1715,17 +1879,30 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1715
1879
|
_parseOptionsImplied() {
|
|
1716
1880
|
const dualHelper = new DualOptions(this.options);
|
|
1717
1881
|
const hasCustomOptionValue = (optionKey) => {
|
|
1718
|
-
return
|
|
1882
|
+
return (
|
|
1883
|
+
this.getOptionValue(optionKey) !== undefined &&
|
|
1884
|
+
!['default', 'implied'].includes(this.getOptionValueSource(optionKey))
|
|
1885
|
+
);
|
|
1719
1886
|
};
|
|
1720
1887
|
this.options
|
|
1721
|
-
.filter(
|
|
1722
|
-
|
|
1723
|
-
|
|
1888
|
+
.filter(
|
|
1889
|
+
(option) =>
|
|
1890
|
+
option.implied !== undefined &&
|
|
1891
|
+
hasCustomOptionValue(option.attributeName()) &&
|
|
1892
|
+
dualHelper.valueFromOption(
|
|
1893
|
+
this.getOptionValue(option.attributeName()),
|
|
1894
|
+
option,
|
|
1895
|
+
),
|
|
1896
|
+
)
|
|
1724
1897
|
.forEach((option) => {
|
|
1725
1898
|
Object.keys(option.implied)
|
|
1726
|
-
.filter(impliedKey => !hasCustomOptionValue(impliedKey))
|
|
1727
|
-
.forEach(impliedKey => {
|
|
1728
|
-
this.setOptionValueWithSource(
|
|
1899
|
+
.filter((impliedKey) => !hasCustomOptionValue(impliedKey))
|
|
1900
|
+
.forEach((impliedKey) => {
|
|
1901
|
+
this.setOptionValueWithSource(
|
|
1902
|
+
impliedKey,
|
|
1903
|
+
option.implied[impliedKey],
|
|
1904
|
+
'implied',
|
|
1905
|
+
);
|
|
1729
1906
|
});
|
|
1730
1907
|
});
|
|
1731
1908
|
}
|
|
@@ -1779,12 +1956,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1779
1956
|
const findBestOptionFromValue = (option) => {
|
|
1780
1957
|
const optionKey = option.attributeName();
|
|
1781
1958
|
const optionValue = this.getOptionValue(optionKey);
|
|
1782
|
-
const negativeOption = this.options.find(
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
(
|
|
1787
|
-
)
|
|
1959
|
+
const negativeOption = this.options.find(
|
|
1960
|
+
(target) => target.negate && optionKey === target.attributeName(),
|
|
1961
|
+
);
|
|
1962
|
+
const positiveOption = this.options.find(
|
|
1963
|
+
(target) => !target.negate && optionKey === target.attributeName(),
|
|
1964
|
+
);
|
|
1965
|
+
if (
|
|
1966
|
+
negativeOption &&
|
|
1967
|
+
((negativeOption.presetArg === undefined && optionValue === false) ||
|
|
1968
|
+
(negativeOption.presetArg !== undefined &&
|
|
1969
|
+
optionValue === negativeOption.presetArg))
|
|
1970
|
+
) {
|
|
1788
1971
|
return negativeOption;
|
|
1789
1972
|
}
|
|
1790
1973
|
return positiveOption || option;
|
|
@@ -1818,11 +2001,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1818
2001
|
if (flag.startsWith('--') && this._showSuggestionAfterError) {
|
|
1819
2002
|
// Looping to pick up the global options too
|
|
1820
2003
|
let candidateFlags = [];
|
|
2004
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1821
2005
|
let command = this;
|
|
1822
2006
|
do {
|
|
1823
|
-
const moreFlags = command
|
|
1824
|
-
.
|
|
1825
|
-
.
|
|
2007
|
+
const moreFlags = command
|
|
2008
|
+
.createHelp()
|
|
2009
|
+
.visibleOptions(command)
|
|
2010
|
+
.filter((option) => option.long)
|
|
2011
|
+
.map((option) => option.long);
|
|
1826
2012
|
candidateFlags = candidateFlags.concat(moreFlags);
|
|
1827
2013
|
command = command.parent;
|
|
1828
2014
|
} while (command && !command._enablePositionalOptions);
|
|
@@ -1844,7 +2030,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1844
2030
|
if (this._allowExcessArguments) return;
|
|
1845
2031
|
|
|
1846
2032
|
const expected = this.registeredArguments.length;
|
|
1847
|
-
const s =
|
|
2033
|
+
const s = expected === 1 ? '' : 's';
|
|
1848
2034
|
const forSubcommand = this.parent ? ` for '${this.name()}'` : '';
|
|
1849
2035
|
const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
|
|
1850
2036
|
this.error(message, { code: 'commander.excessArguments' });
|
|
@@ -1862,11 +2048,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1862
2048
|
|
|
1863
2049
|
if (this._showSuggestionAfterError) {
|
|
1864
2050
|
const candidateNames = [];
|
|
1865
|
-
this.createHelp()
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2051
|
+
this.createHelp()
|
|
2052
|
+
.visibleCommands(this)
|
|
2053
|
+
.forEach((command) => {
|
|
2054
|
+
candidateNames.push(command.name());
|
|
2055
|
+
// just visible alias
|
|
2056
|
+
if (command.alias()) candidateNames.push(command.alias());
|
|
2057
|
+
});
|
|
1870
2058
|
suggestion = suggestSimilar(unknownName, candidateNames);
|
|
1871
2059
|
}
|
|
1872
2060
|
|
|
@@ -1907,11 +2095,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1907
2095
|
* Set the description.
|
|
1908
2096
|
*
|
|
1909
2097
|
* @param {string} [str]
|
|
1910
|
-
* @param {
|
|
2098
|
+
* @param {object} [argsDescription]
|
|
1911
2099
|
* @return {(string|Command)}
|
|
1912
2100
|
*/
|
|
1913
2101
|
description(str, argsDescription) {
|
|
1914
|
-
if (str === undefined && argsDescription === undefined)
|
|
2102
|
+
if (str === undefined && argsDescription === undefined)
|
|
2103
|
+
return this._description;
|
|
1915
2104
|
this._description = str;
|
|
1916
2105
|
if (argsDescription) {
|
|
1917
2106
|
this._argsDescription = argsDescription;
|
|
@@ -1944,18 +2133,27 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1944
2133
|
if (alias === undefined) return this._aliases[0]; // just return first, for backwards compatibility
|
|
1945
2134
|
|
|
1946
2135
|
/** @type {Command} */
|
|
2136
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1947
2137
|
let command = this;
|
|
1948
|
-
if (
|
|
2138
|
+
if (
|
|
2139
|
+
this.commands.length !== 0 &&
|
|
2140
|
+
this.commands[this.commands.length - 1]._executableHandler
|
|
2141
|
+
) {
|
|
1949
2142
|
// assume adding alias for last added executable subcommand, rather than this
|
|
1950
2143
|
command = this.commands[this.commands.length - 1];
|
|
1951
2144
|
}
|
|
1952
2145
|
|
|
1953
|
-
if (alias === command._name)
|
|
2146
|
+
if (alias === command._name)
|
|
2147
|
+
throw new Error("Command alias can't be the same as its name");
|
|
1954
2148
|
const matchingCommand = this.parent?._findCommand(alias);
|
|
1955
2149
|
if (matchingCommand) {
|
|
1956
2150
|
// c.f. _registerCommand
|
|
1957
|
-
const existingCmd = [matchingCommand.name()]
|
|
1958
|
-
|
|
2151
|
+
const existingCmd = [matchingCommand.name()]
|
|
2152
|
+
.concat(matchingCommand.aliases())
|
|
2153
|
+
.join('|');
|
|
2154
|
+
throw new Error(
|
|
2155
|
+
`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`,
|
|
2156
|
+
);
|
|
1959
2157
|
}
|
|
1960
2158
|
|
|
1961
2159
|
command._aliases.push(alias);
|
|
@@ -1993,11 +2191,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1993
2191
|
const args = this.registeredArguments.map((arg) => {
|
|
1994
2192
|
return humanReadableArgName(arg);
|
|
1995
2193
|
});
|
|
1996
|
-
return []
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2194
|
+
return []
|
|
2195
|
+
.concat(
|
|
2196
|
+
this.options.length || this._helpOption !== null ? '[options]' : [],
|
|
2197
|
+
this.commands.length ? '[command]' : [],
|
|
2198
|
+
this.registeredArguments.length ? args : [],
|
|
2199
|
+
)
|
|
2200
|
+
.join(' ');
|
|
2001
2201
|
}
|
|
2002
2202
|
|
|
2003
2203
|
this._usage = str;
|
|
@@ -2063,28 +2263,49 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2063
2263
|
|
|
2064
2264
|
helpInformation(contextOptions) {
|
|
2065
2265
|
const helper = this.createHelp();
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2266
|
+
const context = this._getOutputContext(contextOptions);
|
|
2267
|
+
helper.prepareContext({
|
|
2268
|
+
error: context.error,
|
|
2269
|
+
helpWidth: context.helpWidth,
|
|
2270
|
+
outputHasColors: context.hasColors,
|
|
2271
|
+
});
|
|
2272
|
+
const text = helper.formatHelp(this, helper);
|
|
2273
|
+
if (context.hasColors) return text;
|
|
2274
|
+
return this._outputConfiguration.stripColor(text);
|
|
2070
2275
|
}
|
|
2071
2276
|
|
|
2072
2277
|
/**
|
|
2278
|
+
* @typedef HelpContext
|
|
2279
|
+
* @type {object}
|
|
2280
|
+
* @property {boolean} error
|
|
2281
|
+
* @property {number} helpWidth
|
|
2282
|
+
* @property {boolean} hasColors
|
|
2283
|
+
* @property {function} write - includes stripColor if needed
|
|
2284
|
+
*
|
|
2285
|
+
* @returns {HelpContext}
|
|
2073
2286
|
* @private
|
|
2074
2287
|
*/
|
|
2075
2288
|
|
|
2076
|
-
|
|
2289
|
+
_getOutputContext(contextOptions) {
|
|
2077
2290
|
contextOptions = contextOptions || {};
|
|
2078
|
-
const
|
|
2079
|
-
let
|
|
2080
|
-
|
|
2081
|
-
|
|
2291
|
+
const error = !!contextOptions.error;
|
|
2292
|
+
let baseWrite;
|
|
2293
|
+
let hasColors;
|
|
2294
|
+
let helpWidth;
|
|
2295
|
+
if (error) {
|
|
2296
|
+
baseWrite = (str) => this._outputConfiguration.writeErr(str);
|
|
2297
|
+
hasColors = this._outputConfiguration.getErrHasColors();
|
|
2298
|
+
helpWidth = this._outputConfiguration.getErrHelpWidth();
|
|
2082
2299
|
} else {
|
|
2083
|
-
|
|
2300
|
+
baseWrite = (str) => this._outputConfiguration.writeOut(str);
|
|
2301
|
+
hasColors = this._outputConfiguration.getOutHasColors();
|
|
2302
|
+
helpWidth = this._outputConfiguration.getOutHelpWidth();
|
|
2084
2303
|
}
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2304
|
+
const write = (str) => {
|
|
2305
|
+
if (!hasColors) str = this._outputConfiguration.stripColor(str);
|
|
2306
|
+
return baseWrite(str);
|
|
2307
|
+
};
|
|
2308
|
+
return { error, write, hasColors, helpWidth };
|
|
2088
2309
|
}
|
|
2089
2310
|
|
|
2090
2311
|
/**
|
|
@@ -2101,25 +2322,39 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2101
2322
|
deprecatedCallback = contextOptions;
|
|
2102
2323
|
contextOptions = undefined;
|
|
2103
2324
|
}
|
|
2104
|
-
const context = this._getHelpContext(contextOptions);
|
|
2105
2325
|
|
|
2106
|
-
|
|
2107
|
-
|
|
2326
|
+
const outputContext = this._getOutputContext(contextOptions);
|
|
2327
|
+
/** @type {HelpTextEventContext} */
|
|
2328
|
+
const eventContext = {
|
|
2329
|
+
error: outputContext.error,
|
|
2330
|
+
write: outputContext.write,
|
|
2331
|
+
command: this,
|
|
2332
|
+
};
|
|
2333
|
+
|
|
2334
|
+
this._getCommandAndAncestors()
|
|
2335
|
+
.reverse()
|
|
2336
|
+
.forEach((command) => command.emit('beforeAllHelp', eventContext));
|
|
2337
|
+
this.emit('beforeHelp', eventContext);
|
|
2108
2338
|
|
|
2109
|
-
let helpInformation = this.helpInformation(
|
|
2339
|
+
let helpInformation = this.helpInformation({ error: outputContext.error });
|
|
2110
2340
|
if (deprecatedCallback) {
|
|
2111
2341
|
helpInformation = deprecatedCallback(helpInformation);
|
|
2112
|
-
if (
|
|
2342
|
+
if (
|
|
2343
|
+
typeof helpInformation !== 'string' &&
|
|
2344
|
+
!Buffer.isBuffer(helpInformation)
|
|
2345
|
+
) {
|
|
2113
2346
|
throw new Error('outputHelp callback must return a string or a Buffer');
|
|
2114
2347
|
}
|
|
2115
2348
|
}
|
|
2116
|
-
|
|
2349
|
+
outputContext.write(helpInformation);
|
|
2117
2350
|
|
|
2118
2351
|
if (this._getHelpOption()?.long) {
|
|
2119
2352
|
this.emit(this._getHelpOption().long); // deprecated
|
|
2120
2353
|
}
|
|
2121
|
-
this.emit('afterHelp',
|
|
2122
|
-
this._getCommandAndAncestors().forEach(command =>
|
|
2354
|
+
this.emit('afterHelp', eventContext);
|
|
2355
|
+
this._getCommandAndAncestors().forEach((command) =>
|
|
2356
|
+
command.emit('afterAllHelp', eventContext),
|
|
2357
|
+
);
|
|
2123
2358
|
}
|
|
2124
2359
|
|
|
2125
2360
|
/**
|
|
@@ -2138,6 +2373,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2138
2373
|
helpOption(flags, description) {
|
|
2139
2374
|
// Support disabling built-in help option.
|
|
2140
2375
|
if (typeof flags === 'boolean') {
|
|
2376
|
+
// true is not an expected value. Do something sensible but no unit-test.
|
|
2377
|
+
// istanbul ignore if
|
|
2141
2378
|
if (flags) {
|
|
2142
2379
|
this._helpOption = this._helpOption ?? undefined; // preserve existing option
|
|
2143
2380
|
} else {
|
|
@@ -2159,7 +2396,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2159
2396
|
* Returns null if has been disabled with .helpOption(false).
|
|
2160
2397
|
*
|
|
2161
2398
|
* @returns {(Option | null)} the help option
|
|
2162
|
-
* @package
|
|
2399
|
+
* @package
|
|
2163
2400
|
*/
|
|
2164
2401
|
_getHelpOption() {
|
|
2165
2402
|
// Lazy create help option on demand.
|
|
@@ -2191,14 +2428,28 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2191
2428
|
|
|
2192
2429
|
help(contextOptions) {
|
|
2193
2430
|
this.outputHelp(contextOptions);
|
|
2194
|
-
let exitCode = process.exitCode
|
|
2195
|
-
if (
|
|
2431
|
+
let exitCode = Number(process.exitCode ?? 0); // process.exitCode does allow a string or an integer, but we prefer just a number
|
|
2432
|
+
if (
|
|
2433
|
+
exitCode === 0 &&
|
|
2434
|
+
contextOptions &&
|
|
2435
|
+
typeof contextOptions !== 'function' &&
|
|
2436
|
+
contextOptions.error
|
|
2437
|
+
) {
|
|
2196
2438
|
exitCode = 1;
|
|
2197
2439
|
}
|
|
2198
2440
|
// message: do not have all displayed text available so only passing placeholder.
|
|
2199
2441
|
this._exit(exitCode, 'commander.help', '(outputHelp)');
|
|
2200
2442
|
}
|
|
2201
2443
|
|
|
2444
|
+
/**
|
|
2445
|
+
* // Do a little typing to coordinate emit and listener for the help text events.
|
|
2446
|
+
* @typedef HelpTextEventContext
|
|
2447
|
+
* @type {object}
|
|
2448
|
+
* @property {boolean} error
|
|
2449
|
+
* @property {Command} command
|
|
2450
|
+
* @property {function} write
|
|
2451
|
+
*/
|
|
2452
|
+
|
|
2202
2453
|
/**
|
|
2203
2454
|
* Add additional text to be displayed with the built-in help.
|
|
2204
2455
|
*
|
|
@@ -2209,14 +2460,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2209
2460
|
* @param {(string | Function)} text - string to add, or a function returning a string
|
|
2210
2461
|
* @return {Command} `this` command for chaining
|
|
2211
2462
|
*/
|
|
2463
|
+
|
|
2212
2464
|
addHelpText(position, text) {
|
|
2213
2465
|
const allowedValues = ['beforeAll', 'before', 'after', 'afterAll'];
|
|
2214
2466
|
if (!allowedValues.includes(position)) {
|
|
2215
2467
|
throw new Error(`Unexpected value for position to addHelpText.
|
|
2216
2468
|
Expecting one of '${allowedValues.join("', '")}'`);
|
|
2217
2469
|
}
|
|
2470
|
+
|
|
2218
2471
|
const helpEvent = `${position}Help`;
|
|
2219
|
-
this.on(helpEvent, (context) => {
|
|
2472
|
+
this.on(helpEvent, (/** @type {HelpTextEventContext} */ context) => {
|
|
2220
2473
|
let helpStr;
|
|
2221
2474
|
if (typeof text === 'function') {
|
|
2222
2475
|
helpStr = text({ error: context.error, command: context.command });
|
|
@@ -2240,7 +2493,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2240
2493
|
|
|
2241
2494
|
_outputHelpIfRequested(args) {
|
|
2242
2495
|
const helpOption = this._getHelpOption();
|
|
2243
|
-
const helpRequested = helpOption && args.find(arg => helpOption.is(arg));
|
|
2496
|
+
const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
|
|
2244
2497
|
if (helpRequested) {
|
|
2245
2498
|
this.outputHelp();
|
|
2246
2499
|
// (Do not have all displayed text available so only passing placeholder.)
|
|
@@ -2273,7 +2526,9 @@ function incrementNodeInspectorPort(args) {
|
|
|
2273
2526
|
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
|
|
2274
2527
|
// e.g. --inspect
|
|
2275
2528
|
debugOption = match[1];
|
|
2276
|
-
} else if (
|
|
2529
|
+
} else if (
|
|
2530
|
+
(match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null
|
|
2531
|
+
) {
|
|
2277
2532
|
debugOption = match[1];
|
|
2278
2533
|
if (/^\d+$/.test(match[3])) {
|
|
2279
2534
|
// e.g. --inspect=1234
|
|
@@ -2282,7 +2537,9 @@ function incrementNodeInspectorPort(args) {
|
|
|
2282
2537
|
// e.g. --inspect=localhost
|
|
2283
2538
|
debugHost = match[3];
|
|
2284
2539
|
}
|
|
2285
|
-
} else if (
|
|
2540
|
+
} else if (
|
|
2541
|
+
(match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null
|
|
2542
|
+
) {
|
|
2286
2543
|
// e.g. --inspect=localhost:1234
|
|
2287
2544
|
debugOption = match[1];
|
|
2288
2545
|
debugHost = match[3];
|
|
@@ -2296,4 +2553,33 @@ function incrementNodeInspectorPort(args) {
|
|
|
2296
2553
|
});
|
|
2297
2554
|
}
|
|
2298
2555
|
|
|
2556
|
+
/**
|
|
2557
|
+
* @returns {boolean | undefined}
|
|
2558
|
+
* @package
|
|
2559
|
+
*/
|
|
2560
|
+
function useColor() {
|
|
2561
|
+
// Test for common conventions.
|
|
2562
|
+
// NB: the observed behaviour is in combination with how author adds color! For example:
|
|
2563
|
+
// - we do not test NODE_DISABLE_COLORS, but util:styletext does
|
|
2564
|
+
// - we do test NO_COLOR, but Chalk does not
|
|
2565
|
+
//
|
|
2566
|
+
// References:
|
|
2567
|
+
// https://no-color.org
|
|
2568
|
+
// https://bixense.com/clicolors/
|
|
2569
|
+
// https://github.com/nodejs/node/blob/0a00217a5f67ef4a22384cfc80eb6dd9a917fdc1/lib/internal/tty.js#L109
|
|
2570
|
+
// https://github.com/chalk/supports-color/blob/c214314a14bcb174b12b3014b2b0a8de375029ae/index.js#L33
|
|
2571
|
+
// (https://force-color.org recent web page from 2023, does not match major javascript implementations)
|
|
2572
|
+
|
|
2573
|
+
if (
|
|
2574
|
+
process.env.NO_COLOR ||
|
|
2575
|
+
process.env.FORCE_COLOR === '0' ||
|
|
2576
|
+
process.env.FORCE_COLOR === 'false'
|
|
2577
|
+
)
|
|
2578
|
+
return false;
|
|
2579
|
+
if (process.env.FORCE_COLOR || process.env.CLICOLOR_FORCE !== undefined)
|
|
2580
|
+
return true;
|
|
2581
|
+
return undefined;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2299
2584
|
exports.Command = Command;
|
|
2585
|
+
exports.useColor = useColor; // exporting for tests
|