commander 12.0.0-1 → 12.1.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 +13 -10
- package/esm.mjs +1 -1
- package/lib/argument.js +9 -5
- package/lib/command.js +406 -196
- package/lib/error.js +0 -4
- package/lib/help.js +101 -38
- package/lib/option.js +11 -8
- package/lib/suggestSimilar.js +5 -4
- package/package.json +23 -19
- package/typings/index.d.ts +110 -40
package/lib/command.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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');
|
|
@@ -60,9 +60,11 @@ class Command extends EventEmitter {
|
|
|
60
60
|
this._outputConfiguration = {
|
|
61
61
|
writeOut: (str) => process.stdout.write(str),
|
|
62
62
|
writeErr: (str) => process.stderr.write(str),
|
|
63
|
-
getOutHelpWidth: () =>
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
getOutHelpWidth: () =>
|
|
64
|
+
process.stdout.isTTY ? process.stdout.columns : undefined,
|
|
65
|
+
getErrHelpWidth: () =>
|
|
66
|
+
process.stderr.isTTY ? process.stderr.columns : undefined,
|
|
67
|
+
outputError: (str, write) => write(str),
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
this._hidden = false;
|
|
@@ -89,7 +91,8 @@ class Command extends EventEmitter {
|
|
|
89
91
|
this._helpConfiguration = sourceCommand._helpConfiguration;
|
|
90
92
|
this._exitCallback = sourceCommand._exitCallback;
|
|
91
93
|
this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
|
|
92
|
-
this._combineFlagAndOptionalValue =
|
|
94
|
+
this._combineFlagAndOptionalValue =
|
|
95
|
+
sourceCommand._combineFlagAndOptionalValue;
|
|
93
96
|
this._allowExcessArguments = sourceCommand._allowExcessArguments;
|
|
94
97
|
this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
|
|
95
98
|
this._showHelpAfterError = sourceCommand._showHelpAfterError;
|
|
@@ -105,6 +108,7 @@ class Command extends EventEmitter {
|
|
|
105
108
|
|
|
106
109
|
_getCommandAndAncestors() {
|
|
107
110
|
const result = [];
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
108
112
|
for (let command = this; command; command = command.parent) {
|
|
109
113
|
result.push(command);
|
|
110
114
|
}
|
|
@@ -131,8 +135,8 @@ class Command extends EventEmitter {
|
|
|
131
135
|
* .command('stop [service]', 'stop named service, or all if no name supplied');
|
|
132
136
|
*
|
|
133
137
|
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
|
|
134
|
-
* @param {(
|
|
135
|
-
* @param {
|
|
138
|
+
* @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
|
|
139
|
+
* @param {object} [execOpts] - configuration options (for executable)
|
|
136
140
|
* @return {Command} returns new command for action handler, or `this` for executable command
|
|
137
141
|
*/
|
|
138
142
|
|
|
@@ -192,8 +196,8 @@ class Command extends EventEmitter {
|
|
|
192
196
|
* You can customise the help by overriding Help properties using configureHelp(),
|
|
193
197
|
* or with a subclass of Help by overriding createHelp().
|
|
194
198
|
*
|
|
195
|
-
* @param {
|
|
196
|
-
* @return {(Command|
|
|
199
|
+
* @param {object} [configuration] - configuration options
|
|
200
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
197
201
|
*/
|
|
198
202
|
|
|
199
203
|
configureHelp(configuration) {
|
|
@@ -218,8 +222,8 @@ class Command extends EventEmitter {
|
|
|
218
222
|
* // functions based on what is being written out
|
|
219
223
|
* outputError(str, write) // used for displaying errors, and not used for displaying help
|
|
220
224
|
*
|
|
221
|
-
* @param {
|
|
222
|
-
* @return {(Command|
|
|
225
|
+
* @param {object} [configuration] - configuration options
|
|
226
|
+
* @return {(Command | object)} `this` command for chaining, or stored configuration
|
|
223
227
|
*/
|
|
224
228
|
|
|
225
229
|
configureOutput(configuration) {
|
|
@@ -258,7 +262,7 @@ class Command extends EventEmitter {
|
|
|
258
262
|
* See .command() for creating an attached subcommand which inherits settings from its parent.
|
|
259
263
|
*
|
|
260
264
|
* @param {Command} cmd - new subcommand
|
|
261
|
-
* @param {
|
|
265
|
+
* @param {object} [opts] - configuration options
|
|
262
266
|
* @return {Command} `this` command for chaining
|
|
263
267
|
*/
|
|
264
268
|
|
|
@@ -334,9 +338,12 @@ class Command extends EventEmitter {
|
|
|
334
338
|
*/
|
|
335
339
|
|
|
336
340
|
arguments(names) {
|
|
337
|
-
names
|
|
338
|
-
|
|
339
|
-
|
|
341
|
+
names
|
|
342
|
+
.trim()
|
|
343
|
+
.split(/ +/)
|
|
344
|
+
.forEach((detail) => {
|
|
345
|
+
this.argument(detail);
|
|
346
|
+
});
|
|
340
347
|
return this;
|
|
341
348
|
}
|
|
342
349
|
|
|
@@ -349,10 +356,18 @@ class Command extends EventEmitter {
|
|
|
349
356
|
addArgument(argument) {
|
|
350
357
|
const previousArgument = this.registeredArguments.slice(-1)[0];
|
|
351
358
|
if (previousArgument && previousArgument.variadic) {
|
|
352
|
-
throw new Error(
|
|
359
|
+
throw new Error(
|
|
360
|
+
`only the last argument can be variadic '${previousArgument.name()}'`,
|
|
361
|
+
);
|
|
353
362
|
}
|
|
354
|
-
if (
|
|
355
|
-
|
|
363
|
+
if (
|
|
364
|
+
argument.required &&
|
|
365
|
+
argument.defaultValue !== undefined &&
|
|
366
|
+
argument.parseArg === undefined
|
|
367
|
+
) {
|
|
368
|
+
throw new Error(
|
|
369
|
+
`a default value for a required argument is never used: '${argument.name()}'`,
|
|
370
|
+
);
|
|
356
371
|
}
|
|
357
372
|
this.registeredArguments.push(argument);
|
|
358
373
|
return this;
|
|
@@ -361,6 +376,7 @@ class Command extends EventEmitter {
|
|
|
361
376
|
/**
|
|
362
377
|
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.
|
|
363
378
|
*
|
|
379
|
+
* @example
|
|
364
380
|
* program.helpCommand('help [cmd]');
|
|
365
381
|
* program.helpCommand('help [cmd]', 'show help');
|
|
366
382
|
* program.helpCommand(false); // suppress default help command
|
|
@@ -419,8 +435,11 @@ class Command extends EventEmitter {
|
|
|
419
435
|
* @package
|
|
420
436
|
*/
|
|
421
437
|
_getHelpCommand() {
|
|
422
|
-
const hasImplicitHelpCommand =
|
|
423
|
-
|
|
438
|
+
const hasImplicitHelpCommand =
|
|
439
|
+
this._addImplicitHelpCommand ??
|
|
440
|
+
(this.commands.length &&
|
|
441
|
+
!this._actionHandler &&
|
|
442
|
+
!this._findCommand('help'));
|
|
424
443
|
|
|
425
444
|
if (hasImplicitHelpCommand) {
|
|
426
445
|
if (this._helpCommand === undefined) {
|
|
@@ -568,14 +587,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
568
587
|
* Register option if no conflicts found, or throw on conflict.
|
|
569
588
|
*
|
|
570
589
|
* @param {Option} option
|
|
571
|
-
* @
|
|
590
|
+
* @private
|
|
572
591
|
*/
|
|
573
592
|
|
|
574
593
|
_registerOption(option) {
|
|
575
|
-
const matchingOption =
|
|
594
|
+
const matchingOption =
|
|
595
|
+
(option.short && this._findOption(option.short)) ||
|
|
576
596
|
(option.long && this._findOption(option.long));
|
|
577
597
|
if (matchingOption) {
|
|
578
|
-
const matchingFlag =
|
|
598
|
+
const matchingFlag =
|
|
599
|
+
option.long && this._findOption(option.long)
|
|
600
|
+
? option.long
|
|
601
|
+
: option.short;
|
|
579
602
|
throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
|
|
580
603
|
- already used by option '${matchingOption.flags}'`);
|
|
581
604
|
}
|
|
@@ -588,7 +611,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
588
611
|
* Register command if no conflicts found, or throw on conflict.
|
|
589
612
|
*
|
|
590
613
|
* @param {Command} command
|
|
591
|
-
* @
|
|
614
|
+
* @private
|
|
592
615
|
*/
|
|
593
616
|
|
|
594
617
|
_registerCommand(command) {
|
|
@@ -596,11 +619,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
596
619
|
return [cmd.name()].concat(cmd.aliases());
|
|
597
620
|
};
|
|
598
621
|
|
|
599
|
-
const alreadyUsed = knownBy(command).find((name) =>
|
|
622
|
+
const alreadyUsed = knownBy(command).find((name) =>
|
|
623
|
+
this._findCommand(name),
|
|
624
|
+
);
|
|
600
625
|
if (alreadyUsed) {
|
|
601
626
|
const existingCmd = knownBy(this._findCommand(alreadyUsed)).join('|');
|
|
602
627
|
const newCmd = knownBy(command).join('|');
|
|
603
|
-
throw new Error(
|
|
628
|
+
throw new Error(
|
|
629
|
+
`cannot add command '${newCmd}' as already have command '${existingCmd}'`,
|
|
630
|
+
);
|
|
604
631
|
}
|
|
605
632
|
|
|
606
633
|
this.commands.push(command);
|
|
@@ -623,7 +650,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
623
650
|
// --no-foo is special and defaults foo to true, unless a --foo option is already defined
|
|
624
651
|
const positiveLongFlag = option.long.replace(/^--no-/, '--');
|
|
625
652
|
if (!this._findOption(positiveLongFlag)) {
|
|
626
|
-
this.setOptionValueWithSource(
|
|
653
|
+
this.setOptionValueWithSource(
|
|
654
|
+
name,
|
|
655
|
+
option.defaultValue === undefined ? true : option.defaultValue,
|
|
656
|
+
'default',
|
|
657
|
+
);
|
|
627
658
|
}
|
|
628
659
|
} else if (option.defaultValue !== undefined) {
|
|
629
660
|
this.setOptionValueWithSource(name, option.defaultValue, 'default');
|
|
@@ -676,11 +707,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
676
707
|
/**
|
|
677
708
|
* Internal implementation shared by .option() and .requiredOption()
|
|
678
709
|
*
|
|
710
|
+
* @return {Command} `this` command for chaining
|
|
679
711
|
* @private
|
|
680
712
|
*/
|
|
681
713
|
_optionEx(config, flags, description, fn, defaultValue) {
|
|
682
714
|
if (typeof flags === 'object' && flags instanceof Option) {
|
|
683
|
-
throw new Error(
|
|
715
|
+
throw new Error(
|
|
716
|
+
'To add an Option object use addOption() instead of option() or requiredOption()',
|
|
717
|
+
);
|
|
684
718
|
}
|
|
685
719
|
const option = this.createOption(flags, description);
|
|
686
720
|
option.makeOptionMandatory(!!config.mandatory);
|
|
@@ -728,20 +762,26 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
728
762
|
}
|
|
729
763
|
|
|
730
764
|
/**
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
765
|
+
* Add a required option which must have a value after parsing. This usually means
|
|
766
|
+
* the option must be specified on the command line. (Otherwise the same as .option().)
|
|
767
|
+
*
|
|
768
|
+
* The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
|
|
769
|
+
*
|
|
770
|
+
* @param {string} flags
|
|
771
|
+
* @param {string} [description]
|
|
772
|
+
* @param {(Function|*)} [parseArg] - custom option processing function or default value
|
|
773
|
+
* @param {*} [defaultValue]
|
|
774
|
+
* @return {Command} `this` command for chaining
|
|
775
|
+
*/
|
|
742
776
|
|
|
743
777
|
requiredOption(flags, description, parseArg, defaultValue) {
|
|
744
|
-
return this._optionEx(
|
|
778
|
+
return this._optionEx(
|
|
779
|
+
{ mandatory: true },
|
|
780
|
+
flags,
|
|
781
|
+
description,
|
|
782
|
+
parseArg,
|
|
783
|
+
defaultValue,
|
|
784
|
+
);
|
|
745
785
|
}
|
|
746
786
|
|
|
747
787
|
/**
|
|
@@ -752,7 +792,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
752
792
|
* program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour
|
|
753
793
|
* program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
|
|
754
794
|
*
|
|
755
|
-
* @param {boolean} [combine
|
|
795
|
+
* @param {boolean} [combine] - if `true` or omitted, an optional value can be specified directly after the flag.
|
|
796
|
+
* @return {Command} `this` command for chaining
|
|
756
797
|
*/
|
|
757
798
|
combineFlagAndOptionalValue(combine = true) {
|
|
758
799
|
this._combineFlagAndOptionalValue = !!combine;
|
|
@@ -762,8 +803,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
762
803
|
/**
|
|
763
804
|
* Allow unknown options on the command line.
|
|
764
805
|
*
|
|
765
|
-
* @param {boolean} [allowUnknown
|
|
766
|
-
* for
|
|
806
|
+
* @param {boolean} [allowUnknown] - if `true` or omitted, no error will be thrown for unknown options.
|
|
807
|
+
* @return {Command} `this` command for chaining
|
|
767
808
|
*/
|
|
768
809
|
allowUnknownOption(allowUnknown = true) {
|
|
769
810
|
this._allowUnknownOption = !!allowUnknown;
|
|
@@ -773,8 +814,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
773
814
|
/**
|
|
774
815
|
* Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
|
|
775
816
|
*
|
|
776
|
-
* @param {boolean} [allowExcess
|
|
777
|
-
* for
|
|
817
|
+
* @param {boolean} [allowExcess] - if `true` or omitted, no error will be thrown for excess arguments.
|
|
818
|
+
* @return {Command} `this` command for chaining
|
|
778
819
|
*/
|
|
779
820
|
allowExcessArguments(allowExcess = true) {
|
|
780
821
|
this._allowExcessArguments = !!allowExcess;
|
|
@@ -786,7 +827,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
786
827
|
* subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
|
|
787
828
|
* The default behaviour is non-positional and global options may appear anywhere on the command line.
|
|
788
829
|
*
|
|
789
|
-
* @param {boolean} [positional
|
|
830
|
+
* @param {boolean} [positional]
|
|
831
|
+
* @return {Command} `this` command for chaining
|
|
790
832
|
*/
|
|
791
833
|
enablePositionalOptions(positional = true) {
|
|
792
834
|
this._enablePositionalOptions = !!positional;
|
|
@@ -799,8 +841,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
799
841
|
* positional options to have been enabled on the program (parent commands).
|
|
800
842
|
* The default behaviour is non-positional and options may appear before or after command-arguments.
|
|
801
843
|
*
|
|
802
|
-
* @param {boolean} [passThrough
|
|
803
|
-
* for
|
|
844
|
+
* @param {boolean} [passThrough] for unknown options.
|
|
845
|
+
* @return {Command} `this` command for chaining
|
|
804
846
|
*/
|
|
805
847
|
passThroughOptions(passThrough = true) {
|
|
806
848
|
this._passThroughOptions = !!passThrough;
|
|
@@ -813,25 +855,33 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
813
855
|
*/
|
|
814
856
|
|
|
815
857
|
_checkForBrokenPassThrough() {
|
|
816
|
-
if (
|
|
817
|
-
|
|
858
|
+
if (
|
|
859
|
+
this.parent &&
|
|
860
|
+
this._passThroughOptions &&
|
|
861
|
+
!this.parent._enablePositionalOptions
|
|
862
|
+
) {
|
|
863
|
+
throw new Error(
|
|
864
|
+
`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`,
|
|
865
|
+
);
|
|
818
866
|
}
|
|
819
867
|
}
|
|
820
868
|
|
|
821
869
|
/**
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
870
|
+
* Whether to store option values as properties on command object,
|
|
871
|
+
* or store separately (specify false). In both cases the option values can be accessed using .opts().
|
|
872
|
+
*
|
|
873
|
+
* @param {boolean} [storeAsProperties=true]
|
|
874
|
+
* @return {Command} `this` command for chaining
|
|
875
|
+
*/
|
|
828
876
|
|
|
829
877
|
storeOptionsAsProperties(storeAsProperties = true) {
|
|
830
878
|
if (this.options.length) {
|
|
831
879
|
throw new Error('call .storeOptionsAsProperties() before adding options');
|
|
832
880
|
}
|
|
833
881
|
if (Object.keys(this._optionValues).length) {
|
|
834
|
-
throw new Error(
|
|
882
|
+
throw new Error(
|
|
883
|
+
'call .storeOptionsAsProperties() before setting option values',
|
|
884
|
+
);
|
|
835
885
|
}
|
|
836
886
|
this._storeOptionsAsProperties = !!storeAsProperties;
|
|
837
887
|
return this;
|
|
@@ -841,7 +891,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
841
891
|
* Retrieve option value.
|
|
842
892
|
*
|
|
843
893
|
* @param {string} key
|
|
844
|
-
* @return {
|
|
894
|
+
* @return {object} value
|
|
845
895
|
*/
|
|
846
896
|
|
|
847
897
|
getOptionValue(key) {
|
|
@@ -855,7 +905,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
855
905
|
* Store option value.
|
|
856
906
|
*
|
|
857
907
|
* @param {string} key
|
|
858
|
-
* @param {
|
|
908
|
+
* @param {object} value
|
|
859
909
|
* @return {Command} `this` command for chaining
|
|
860
910
|
*/
|
|
861
911
|
|
|
@@ -864,13 +914,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
864
914
|
}
|
|
865
915
|
|
|
866
916
|
/**
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
917
|
+
* Store option value and where the value came from.
|
|
918
|
+
*
|
|
919
|
+
* @param {string} key
|
|
920
|
+
* @param {object} value
|
|
921
|
+
* @param {string} source - expected values are default/config/env/cli/implied
|
|
922
|
+
* @return {Command} `this` command for chaining
|
|
923
|
+
*/
|
|
874
924
|
|
|
875
925
|
setOptionValueWithSource(key, value, source) {
|
|
876
926
|
if (this._storeOptionsAsProperties) {
|
|
@@ -883,24 +933,24 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
883
933
|
}
|
|
884
934
|
|
|
885
935
|
/**
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
936
|
+
* Get source of option value.
|
|
937
|
+
* Expected values are default | config | env | cli | implied
|
|
938
|
+
*
|
|
939
|
+
* @param {string} key
|
|
940
|
+
* @return {string}
|
|
941
|
+
*/
|
|
892
942
|
|
|
893
943
|
getOptionValueSource(key) {
|
|
894
944
|
return this._optionValueSources[key];
|
|
895
945
|
}
|
|
896
946
|
|
|
897
947
|
/**
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
948
|
+
* Get source of option value. See also .optsWithGlobals().
|
|
949
|
+
* Expected values are default | config | env | cli | implied
|
|
950
|
+
*
|
|
951
|
+
* @param {string} key
|
|
952
|
+
* @return {string}
|
|
953
|
+
*/
|
|
904
954
|
|
|
905
955
|
getOptionValueSourceWithGlobals(key) {
|
|
906
956
|
// global overwrites local, like optsWithGlobals
|
|
@@ -926,17 +976,30 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
926
976
|
}
|
|
927
977
|
parseOptions = parseOptions || {};
|
|
928
978
|
|
|
929
|
-
//
|
|
930
|
-
if (argv === undefined) {
|
|
931
|
-
|
|
932
|
-
// @ts-ignore: unknown property
|
|
933
|
-
if (process.versions && process.versions.electron) {
|
|
979
|
+
// auto-detect argument conventions if nothing supplied
|
|
980
|
+
if (argv === undefined && parseOptions.from === undefined) {
|
|
981
|
+
if (process.versions?.electron) {
|
|
934
982
|
parseOptions.from = 'electron';
|
|
935
983
|
}
|
|
984
|
+
// check node specific options for scenarios where user CLI args follow executable without scriptname
|
|
985
|
+
const execArgv = process.execArgv ?? [];
|
|
986
|
+
if (
|
|
987
|
+
execArgv.includes('-e') ||
|
|
988
|
+
execArgv.includes('--eval') ||
|
|
989
|
+
execArgv.includes('-p') ||
|
|
990
|
+
execArgv.includes('--print')
|
|
991
|
+
) {
|
|
992
|
+
parseOptions.from = 'eval'; // internal usage, not documented
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// default to using process.argv
|
|
997
|
+
if (argv === undefined) {
|
|
998
|
+
argv = process.argv;
|
|
936
999
|
}
|
|
937
1000
|
this.rawArgs = argv.slice();
|
|
938
1001
|
|
|
939
|
-
//
|
|
1002
|
+
// extract the user args and scriptPath
|
|
940
1003
|
let userArgs;
|
|
941
1004
|
switch (parseOptions.from) {
|
|
942
1005
|
case undefined:
|
|
@@ -945,7 +1008,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
945
1008
|
userArgs = argv.slice(2);
|
|
946
1009
|
break;
|
|
947
1010
|
case 'electron':
|
|
948
|
-
// @ts-ignore: unknown property
|
|
1011
|
+
// @ts-ignore: because defaultApp is an unknown property
|
|
949
1012
|
if (process.defaultApp) {
|
|
950
1013
|
this._scriptPath = argv[1];
|
|
951
1014
|
userArgs = argv.slice(2);
|
|
@@ -956,12 +1019,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
956
1019
|
case 'user':
|
|
957
1020
|
userArgs = argv.slice(0);
|
|
958
1021
|
break;
|
|
1022
|
+
case 'eval':
|
|
1023
|
+
userArgs = argv.slice(1);
|
|
1024
|
+
break;
|
|
959
1025
|
default:
|
|
960
|
-
throw new Error(
|
|
1026
|
+
throw new Error(
|
|
1027
|
+
`unexpected parse option { from: '${parseOptions.from}' }`,
|
|
1028
|
+
);
|
|
961
1029
|
}
|
|
962
1030
|
|
|
963
1031
|
// Find default name for program from arguments.
|
|
964
|
-
if (!this._name && this._scriptPath)
|
|
1032
|
+
if (!this._name && this._scriptPath)
|
|
1033
|
+
this.nameFromFilename(this._scriptPath);
|
|
965
1034
|
this._name = this._name || 'program';
|
|
966
1035
|
|
|
967
1036
|
return userArgs;
|
|
@@ -970,16 +1039,22 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
970
1039
|
/**
|
|
971
1040
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
972
1041
|
*
|
|
973
|
-
*
|
|
974
|
-
*
|
|
1042
|
+
* Use parseAsync instead of parse if any of your action handlers are async.
|
|
1043
|
+
*
|
|
1044
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
1045
|
+
*
|
|
1046
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1047
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1048
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1049
|
+
* - `'user'`: just user arguments
|
|
975
1050
|
*
|
|
976
1051
|
* @example
|
|
977
|
-
* program.parse(process.argv
|
|
978
|
-
* program.parse(); //
|
|
1052
|
+
* program.parse(); // parse process.argv and auto-detect electron and special node flags
|
|
1053
|
+
* program.parse(process.argv); // assume argv[0] is app and argv[1] is script
|
|
979
1054
|
* program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
980
1055
|
*
|
|
981
1056
|
* @param {string[]} [argv] - optional, defaults to process.argv
|
|
982
|
-
* @param {
|
|
1057
|
+
* @param {object} [parseOptions] - optionally specify style of options with from: node/user/electron
|
|
983
1058
|
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
|
|
984
1059
|
* @return {Command} `this` command for chaining
|
|
985
1060
|
*/
|
|
@@ -994,18 +1069,20 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
994
1069
|
/**
|
|
995
1070
|
* Parse `argv`, setting options and invoking commands when defined.
|
|
996
1071
|
*
|
|
997
|
-
*
|
|
1072
|
+
* Call with no parameters to parse `process.argv`. Detects Electron and special node options like `node --eval`. Easy mode!
|
|
998
1073
|
*
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1074
|
+
* Or call with an array of strings to parse, and optionally where the user arguments start by specifying where the arguments are `from`:
|
|
1075
|
+
* - `'node'`: default, `argv[0]` is the application and `argv[1]` is the script being run, with user arguments after that
|
|
1076
|
+
* - `'electron'`: `argv[0]` is the application and `argv[1]` varies depending on whether the electron application is packaged
|
|
1077
|
+
* - `'user'`: just user arguments
|
|
1001
1078
|
*
|
|
1002
1079
|
* @example
|
|
1003
|
-
* await program.parseAsync(process.argv
|
|
1004
|
-
* await program.parseAsync(); //
|
|
1080
|
+
* await program.parseAsync(); // parse process.argv and auto-detect electron and special node flags
|
|
1081
|
+
* await program.parseAsync(process.argv); // assume argv[0] is app and argv[1] is script
|
|
1005
1082
|
* await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
|
|
1006
1083
|
*
|
|
1007
1084
|
* @param {string[]} [argv]
|
|
1008
|
-
* @param {
|
|
1085
|
+
* @param {object} [parseOptions]
|
|
1009
1086
|
* @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'
|
|
1010
1087
|
* @return {Promise}
|
|
1011
1088
|
*/
|
|
@@ -1037,7 +1114,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1037
1114
|
if (sourceExt.includes(path.extname(baseName))) return undefined;
|
|
1038
1115
|
|
|
1039
1116
|
// Try all the extensions.
|
|
1040
|
-
const foundExt = sourceExt.find(ext =>
|
|
1117
|
+
const foundExt = sourceExt.find((ext) =>
|
|
1118
|
+
fs.existsSync(`${localBin}${ext}`),
|
|
1119
|
+
);
|
|
1041
1120
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1042
1121
|
|
|
1043
1122
|
return undefined;
|
|
@@ -1048,7 +1127,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1048
1127
|
this._checkForConflictingOptions();
|
|
1049
1128
|
|
|
1050
1129
|
// executableFile and executableDir might be full path, or just a name
|
|
1051
|
-
let executableFile =
|
|
1130
|
+
let executableFile =
|
|
1131
|
+
subcommand._executableFile || `${this._name}-${subcommand._name}`;
|
|
1052
1132
|
let executableDir = this._executableDir || '';
|
|
1053
1133
|
if (this._scriptPath) {
|
|
1054
1134
|
let resolvedScriptPath; // resolve possible symlink for installed npm binary
|
|
@@ -1057,7 +1137,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1057
1137
|
} catch (err) {
|
|
1058
1138
|
resolvedScriptPath = this._scriptPath;
|
|
1059
1139
|
}
|
|
1060
|
-
executableDir = path.resolve(
|
|
1140
|
+
executableDir = path.resolve(
|
|
1141
|
+
path.dirname(resolvedScriptPath),
|
|
1142
|
+
executableDir,
|
|
1143
|
+
);
|
|
1061
1144
|
}
|
|
1062
1145
|
|
|
1063
1146
|
// Look for a local file in preference to a command in PATH.
|
|
@@ -1066,9 +1149,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1066
1149
|
|
|
1067
1150
|
// Legacy search using prefix of script name instead of command name
|
|
1068
1151
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1069
|
-
const legacyName = path.basename(
|
|
1152
|
+
const legacyName = path.basename(
|
|
1153
|
+
this._scriptPath,
|
|
1154
|
+
path.extname(this._scriptPath),
|
|
1155
|
+
);
|
|
1070
1156
|
if (legacyName !== this._name) {
|
|
1071
|
-
localFile = findFile(
|
|
1157
|
+
localFile = findFile(
|
|
1158
|
+
executableDir,
|
|
1159
|
+
`${legacyName}-${subcommand._name}`,
|
|
1160
|
+
);
|
|
1072
1161
|
}
|
|
1073
1162
|
}
|
|
1074
1163
|
executableFile = localFile || executableFile;
|
|
@@ -1094,12 +1183,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1094
1183
|
proc = childProcess.spawn(process.execPath, args, { stdio: 'inherit' });
|
|
1095
1184
|
}
|
|
1096
1185
|
|
|
1097
|
-
if (!proc.killed) {
|
|
1186
|
+
if (!proc.killed) {
|
|
1187
|
+
// testing mainly to avoid leak warnings during unit tests with mocked spawn
|
|
1098
1188
|
const signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
|
|
1099
1189
|
signals.forEach((signal) => {
|
|
1100
|
-
// @ts-ignore
|
|
1101
1190
|
process.on(signal, () => {
|
|
1102
1191
|
if (proc.killed === false && proc.exitCode === null) {
|
|
1192
|
+
// @ts-ignore because signals not typed to known strings
|
|
1103
1193
|
proc.kill(signal);
|
|
1104
1194
|
}
|
|
1105
1195
|
});
|
|
@@ -1108,16 +1198,22 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1108
1198
|
|
|
1109
1199
|
// By default terminate process when spawned process terminates.
|
|
1110
1200
|
const exitCallback = this._exitCallback;
|
|
1111
|
-
proc.on('close', (code
|
|
1201
|
+
proc.on('close', (code) => {
|
|
1112
1202
|
code = code ?? 1; // code is null if spawned process terminated due to a signal
|
|
1113
1203
|
if (!exitCallback) {
|
|
1114
1204
|
process.exit(code);
|
|
1115
1205
|
} else {
|
|
1116
|
-
exitCallback(
|
|
1206
|
+
exitCallback(
|
|
1207
|
+
new CommanderError(
|
|
1208
|
+
code,
|
|
1209
|
+
'commander.executeSubCommandAsync',
|
|
1210
|
+
'(close)',
|
|
1211
|
+
),
|
|
1212
|
+
);
|
|
1117
1213
|
}
|
|
1118
1214
|
});
|
|
1119
1215
|
proc.on('error', (err) => {
|
|
1120
|
-
// @ts-ignore
|
|
1216
|
+
// @ts-ignore: because err.code is an unknown property
|
|
1121
1217
|
if (err.code === 'ENOENT') {
|
|
1122
1218
|
const executableDirMessage = executableDir
|
|
1123
1219
|
? `searched for local subcommand relative to directory '${executableDir}'`
|
|
@@ -1127,14 +1223,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1127
1223
|
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
1128
1224
|
- ${executableDirMessage}`;
|
|
1129
1225
|
throw new Error(executableMissing);
|
|
1130
|
-
|
|
1226
|
+
// @ts-ignore: because err.code is an unknown property
|
|
1131
1227
|
} else if (err.code === 'EACCES') {
|
|
1132
1228
|
throw new Error(`'${executableFile}' not executable`);
|
|
1133
1229
|
}
|
|
1134
1230
|
if (!exitCallback) {
|
|
1135
1231
|
process.exit(1);
|
|
1136
1232
|
} else {
|
|
1137
|
-
const wrappedError = new CommanderError(
|
|
1233
|
+
const wrappedError = new CommanderError(
|
|
1234
|
+
1,
|
|
1235
|
+
'commander.executeSubCommandAsync',
|
|
1236
|
+
'(error)',
|
|
1237
|
+
);
|
|
1138
1238
|
wrappedError.nestedError = err;
|
|
1139
1239
|
exitCallback(wrappedError);
|
|
1140
1240
|
}
|
|
@@ -1153,7 +1253,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1153
1253
|
if (!subCommand) this.help({ error: true });
|
|
1154
1254
|
|
|
1155
1255
|
let promiseChain;
|
|
1156
|
-
promiseChain = this._chainOrCallSubCommandHook(
|
|
1256
|
+
promiseChain = this._chainOrCallSubCommandHook(
|
|
1257
|
+
promiseChain,
|
|
1258
|
+
subCommand,
|
|
1259
|
+
'preSubcommand',
|
|
1260
|
+
);
|
|
1157
1261
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
1158
1262
|
if (subCommand._executableHandler) {
|
|
1159
1263
|
this._executeSubCommand(subCommand, operands.concat(unknown));
|
|
@@ -1181,9 +1285,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1181
1285
|
}
|
|
1182
1286
|
|
|
1183
1287
|
// Fallback to parsing the help flag to invoke the help.
|
|
1184
|
-
return this._dispatchSubcommand(
|
|
1185
|
-
|
|
1186
|
-
|
|
1288
|
+
return this._dispatchSubcommand(
|
|
1289
|
+
subcommandName,
|
|
1290
|
+
[],
|
|
1291
|
+
[this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? '--help'],
|
|
1292
|
+
);
|
|
1187
1293
|
}
|
|
1188
1294
|
|
|
1189
1295
|
/**
|
|
@@ -1200,7 +1306,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1200
1306
|
}
|
|
1201
1307
|
});
|
|
1202
1308
|
// too many
|
|
1203
|
-
if (
|
|
1309
|
+
if (
|
|
1310
|
+
this.registeredArguments.length > 0 &&
|
|
1311
|
+
this.registeredArguments[this.registeredArguments.length - 1].variadic
|
|
1312
|
+
) {
|
|
1204
1313
|
return;
|
|
1205
1314
|
}
|
|
1206
1315
|
if (this.args.length > this.registeredArguments.length) {
|
|
@@ -1220,7 +1329,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1220
1329
|
let parsedValue = value;
|
|
1221
1330
|
if (value !== null && argument.parseArg) {
|
|
1222
1331
|
const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
|
|
1223
|
-
parsedValue = this._callParseArg(
|
|
1332
|
+
parsedValue = this._callParseArg(
|
|
1333
|
+
argument,
|
|
1334
|
+
value,
|
|
1335
|
+
previous,
|
|
1336
|
+
invalidValueMessage,
|
|
1337
|
+
);
|
|
1224
1338
|
}
|
|
1225
1339
|
return parsedValue;
|
|
1226
1340
|
};
|
|
@@ -1285,8 +1399,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1285
1399
|
const hooks = [];
|
|
1286
1400
|
this._getCommandAndAncestors()
|
|
1287
1401
|
.reverse()
|
|
1288
|
-
.filter(cmd => cmd._lifeCycleHooks[event] !== undefined)
|
|
1289
|
-
.forEach(hookedCommand => {
|
|
1402
|
+
.filter((cmd) => cmd._lifeCycleHooks[event] !== undefined)
|
|
1403
|
+
.forEach((hookedCommand) => {
|
|
1290
1404
|
hookedCommand._lifeCycleHooks[event].forEach((callback) => {
|
|
1291
1405
|
hooks.push({ hookedCommand, callback });
|
|
1292
1406
|
});
|
|
@@ -1342,14 +1456,26 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1342
1456
|
if (operands && this._findCommand(operands[0])) {
|
|
1343
1457
|
return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
|
|
1344
1458
|
}
|
|
1345
|
-
if (
|
|
1459
|
+
if (
|
|
1460
|
+
this._getHelpCommand() &&
|
|
1461
|
+
operands[0] === this._getHelpCommand().name()
|
|
1462
|
+
) {
|
|
1346
1463
|
return this._dispatchHelpCommand(operands[1]);
|
|
1347
1464
|
}
|
|
1348
1465
|
if (this._defaultCommandName) {
|
|
1349
1466
|
this._outputHelpIfRequested(unknown); // Run the help for default command from parent rather than passing to default command
|
|
1350
|
-
return this._dispatchSubcommand(
|
|
1467
|
+
return this._dispatchSubcommand(
|
|
1468
|
+
this._defaultCommandName,
|
|
1469
|
+
operands,
|
|
1470
|
+
unknown,
|
|
1471
|
+
);
|
|
1351
1472
|
}
|
|
1352
|
-
if (
|
|
1473
|
+
if (
|
|
1474
|
+
this.commands.length &&
|
|
1475
|
+
this.args.length === 0 &&
|
|
1476
|
+
!this._actionHandler &&
|
|
1477
|
+
!this._defaultCommandName
|
|
1478
|
+
) {
|
|
1353
1479
|
// probably missing subcommand and no handler, user needs help (and exit)
|
|
1354
1480
|
this.help({ error: true });
|
|
1355
1481
|
}
|
|
@@ -1372,7 +1498,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1372
1498
|
|
|
1373
1499
|
let promiseChain;
|
|
1374
1500
|
promiseChain = this._chainOrCallHooks(promiseChain, 'preAction');
|
|
1375
|
-
promiseChain = this._chainOrCall(promiseChain, () =>
|
|
1501
|
+
promiseChain = this._chainOrCall(promiseChain, () =>
|
|
1502
|
+
this._actionHandler(this.processedArgs),
|
|
1503
|
+
);
|
|
1376
1504
|
if (this.parent) {
|
|
1377
1505
|
promiseChain = this._chainOrCall(promiseChain, () => {
|
|
1378
1506
|
this.parent.emit(commandEvent, operands, unknown); // legacy
|
|
@@ -1386,7 +1514,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1386
1514
|
this._processArguments();
|
|
1387
1515
|
this.parent.emit(commandEvent, operands, unknown); // legacy
|
|
1388
1516
|
} else if (operands.length) {
|
|
1389
|
-
if (this._findCommand('*')) {
|
|
1517
|
+
if (this._findCommand('*')) {
|
|
1518
|
+
// legacy default command
|
|
1390
1519
|
return this._dispatchSubcommand('*', operands, unknown);
|
|
1391
1520
|
}
|
|
1392
1521
|
if (this.listenerCount('command:*')) {
|
|
@@ -1413,10 +1542,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1413
1542
|
* Find matching command.
|
|
1414
1543
|
*
|
|
1415
1544
|
* @private
|
|
1545
|
+
* @return {Command | undefined}
|
|
1416
1546
|
*/
|
|
1417
1547
|
_findCommand(name) {
|
|
1418
1548
|
if (!name) return undefined;
|
|
1419
|
-
return this.commands.find(
|
|
1549
|
+
return this.commands.find(
|
|
1550
|
+
(cmd) => cmd._name === name || cmd._aliases.includes(name),
|
|
1551
|
+
);
|
|
1420
1552
|
}
|
|
1421
1553
|
|
|
1422
1554
|
/**
|
|
@@ -1424,11 +1556,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1424
1556
|
*
|
|
1425
1557
|
* @param {string} arg
|
|
1426
1558
|
* @return {Option}
|
|
1427
|
-
* @package
|
|
1559
|
+
* @package
|
|
1428
1560
|
*/
|
|
1429
1561
|
|
|
1430
1562
|
_findOption(arg) {
|
|
1431
|
-
return this.options.find(option => option.is(arg));
|
|
1563
|
+
return this.options.find((option) => option.is(arg));
|
|
1432
1564
|
}
|
|
1433
1565
|
|
|
1434
1566
|
/**
|
|
@@ -1442,7 +1574,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1442
1574
|
// Walk up hierarchy so can call in subcommand after checking for displaying help.
|
|
1443
1575
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
1444
1576
|
cmd.options.forEach((anOption) => {
|
|
1445
|
-
if (
|
|
1577
|
+
if (
|
|
1578
|
+
anOption.mandatory &&
|
|
1579
|
+
cmd.getOptionValue(anOption.attributeName()) === undefined
|
|
1580
|
+
) {
|
|
1446
1581
|
cmd.missingMandatoryOptionValue(anOption);
|
|
1447
1582
|
}
|
|
1448
1583
|
});
|
|
@@ -1455,23 +1590,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1455
1590
|
* @private
|
|
1456
1591
|
*/
|
|
1457
1592
|
_checkForConflictingLocalOptions() {
|
|
1458
|
-
const definedNonDefaultOptions = this.options.filter(
|
|
1459
|
-
(
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
return false;
|
|
1463
|
-
}
|
|
1464
|
-
return this.getOptionValueSource(optionKey) !== 'default';
|
|
1593
|
+
const definedNonDefaultOptions = this.options.filter((option) => {
|
|
1594
|
+
const optionKey = option.attributeName();
|
|
1595
|
+
if (this.getOptionValue(optionKey) === undefined) {
|
|
1596
|
+
return false;
|
|
1465
1597
|
}
|
|
1466
|
-
|
|
1598
|
+
return this.getOptionValueSource(optionKey) !== 'default';
|
|
1599
|
+
});
|
|
1467
1600
|
|
|
1468
1601
|
const optionsWithConflicting = definedNonDefaultOptions.filter(
|
|
1469
|
-
(option) => option.conflictsWith.length > 0
|
|
1602
|
+
(option) => option.conflictsWith.length > 0,
|
|
1470
1603
|
);
|
|
1471
1604
|
|
|
1472
1605
|
optionsWithConflicting.forEach((option) => {
|
|
1473
1606
|
const conflictingAndDefined = definedNonDefaultOptions.find((defined) =>
|
|
1474
|
-
option.conflictsWith.includes(defined.attributeName())
|
|
1607
|
+
option.conflictsWith.includes(defined.attributeName()),
|
|
1475
1608
|
);
|
|
1476
1609
|
if (conflictingAndDefined) {
|
|
1477
1610
|
this._conflictingOption(option, conflictingAndDefined);
|
|
@@ -1551,7 +1684,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1551
1684
|
value = args.shift();
|
|
1552
1685
|
}
|
|
1553
1686
|
this.emit(`option:${option.name()}`, value);
|
|
1554
|
-
} else {
|
|
1687
|
+
} else {
|
|
1688
|
+
// boolean flag
|
|
1555
1689
|
this.emit(`option:${option.name()}`);
|
|
1556
1690
|
}
|
|
1557
1691
|
activeVariadicOption = option.variadic ? option : null;
|
|
@@ -1563,7 +1697,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1563
1697
|
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
|
|
1564
1698
|
const option = this._findOption(`-${arg[1]}`);
|
|
1565
1699
|
if (option) {
|
|
1566
|
-
if (
|
|
1700
|
+
if (
|
|
1701
|
+
option.required ||
|
|
1702
|
+
(option.optional && this._combineFlagAndOptionalValue)
|
|
1703
|
+
) {
|
|
1567
1704
|
// option with value following in same argument
|
|
1568
1705
|
this.emit(`option:${option.name()}`, arg.slice(2));
|
|
1569
1706
|
} else {
|
|
@@ -1594,12 +1731,19 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1594
1731
|
}
|
|
1595
1732
|
|
|
1596
1733
|
// If using positionalOptions, stop processing our options at subcommand.
|
|
1597
|
-
if (
|
|
1734
|
+
if (
|
|
1735
|
+
(this._enablePositionalOptions || this._passThroughOptions) &&
|
|
1736
|
+
operands.length === 0 &&
|
|
1737
|
+
unknown.length === 0
|
|
1738
|
+
) {
|
|
1598
1739
|
if (this._findCommand(arg)) {
|
|
1599
1740
|
operands.push(arg);
|
|
1600
1741
|
if (args.length > 0) unknown.push(...args);
|
|
1601
1742
|
break;
|
|
1602
|
-
} else if (
|
|
1743
|
+
} else if (
|
|
1744
|
+
this._getHelpCommand() &&
|
|
1745
|
+
arg === this._getHelpCommand().name()
|
|
1746
|
+
) {
|
|
1603
1747
|
operands.push(arg);
|
|
1604
1748
|
if (args.length > 0) operands.push(...args);
|
|
1605
1749
|
break;
|
|
@@ -1627,7 +1771,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1627
1771
|
/**
|
|
1628
1772
|
* Return an object containing local option values as key-value pairs.
|
|
1629
1773
|
*
|
|
1630
|
-
* @return {
|
|
1774
|
+
* @return {object}
|
|
1631
1775
|
*/
|
|
1632
1776
|
opts() {
|
|
1633
1777
|
if (this._storeOptionsAsProperties) {
|
|
@@ -1637,7 +1781,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1637
1781
|
|
|
1638
1782
|
for (let i = 0; i < len; i++) {
|
|
1639
1783
|
const key = this.options[i].attributeName();
|
|
1640
|
-
result[key] =
|
|
1784
|
+
result[key] =
|
|
1785
|
+
key === this._versionOptionName ? this._version : this[key];
|
|
1641
1786
|
}
|
|
1642
1787
|
return result;
|
|
1643
1788
|
}
|
|
@@ -1648,13 +1793,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1648
1793
|
/**
|
|
1649
1794
|
* Return an object containing merged local and global option values as key-value pairs.
|
|
1650
1795
|
*
|
|
1651
|
-
* @return {
|
|
1796
|
+
* @return {object}
|
|
1652
1797
|
*/
|
|
1653
1798
|
optsWithGlobals() {
|
|
1654
1799
|
// globals overwrite locals
|
|
1655
1800
|
return this._getCommandAndAncestors().reduce(
|
|
1656
1801
|
(combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()),
|
|
1657
|
-
{}
|
|
1802
|
+
{},
|
|
1658
1803
|
);
|
|
1659
1804
|
}
|
|
1660
1805
|
|
|
@@ -1662,13 +1807,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1662
1807
|
* Display error message and exit (or call exitOverride).
|
|
1663
1808
|
*
|
|
1664
1809
|
* @param {string} message
|
|
1665
|
-
* @param {
|
|
1810
|
+
* @param {object} [errorOptions]
|
|
1666
1811
|
* @param {string} [errorOptions.code] - an id string representing the error
|
|
1667
1812
|
* @param {number} [errorOptions.exitCode] - used with process.exit
|
|
1668
1813
|
*/
|
|
1669
1814
|
error(message, errorOptions) {
|
|
1670
1815
|
// output handling
|
|
1671
|
-
this._outputConfiguration.outputError(
|
|
1816
|
+
this._outputConfiguration.outputError(
|
|
1817
|
+
`${message}\n`,
|
|
1818
|
+
this._outputConfiguration.writeErr,
|
|
1819
|
+
);
|
|
1672
1820
|
if (typeof this._showHelpAfterError === 'string') {
|
|
1673
1821
|
this._outputConfiguration.writeErr(`${this._showHelpAfterError}\n`);
|
|
1674
1822
|
} else if (this._showHelpAfterError) {
|
|
@@ -1694,11 +1842,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1694
1842
|
if (option.envVar && option.envVar in process.env) {
|
|
1695
1843
|
const optionKey = option.attributeName();
|
|
1696
1844
|
// Priority check. Do not overwrite cli or options from unknown source (client-code).
|
|
1697
|
-
if (
|
|
1698
|
-
|
|
1845
|
+
if (
|
|
1846
|
+
this.getOptionValue(optionKey) === undefined ||
|
|
1847
|
+
['default', 'config', 'env'].includes(
|
|
1848
|
+
this.getOptionValueSource(optionKey),
|
|
1849
|
+
)
|
|
1850
|
+
) {
|
|
1851
|
+
if (option.required || option.optional) {
|
|
1852
|
+
// option can take a value
|
|
1699
1853
|
// keep very simple, optional always takes value
|
|
1700
1854
|
this.emit(`optionEnv:${option.name()}`, process.env[option.envVar]);
|
|
1701
|
-
} else {
|
|
1855
|
+
} else {
|
|
1856
|
+
// boolean
|
|
1702
1857
|
// keep very simple, only care that envVar defined and not the value
|
|
1703
1858
|
this.emit(`optionEnv:${option.name()}`);
|
|
1704
1859
|
}
|
|
@@ -1715,17 +1870,30 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1715
1870
|
_parseOptionsImplied() {
|
|
1716
1871
|
const dualHelper = new DualOptions(this.options);
|
|
1717
1872
|
const hasCustomOptionValue = (optionKey) => {
|
|
1718
|
-
return
|
|
1873
|
+
return (
|
|
1874
|
+
this.getOptionValue(optionKey) !== undefined &&
|
|
1875
|
+
!['default', 'implied'].includes(this.getOptionValueSource(optionKey))
|
|
1876
|
+
);
|
|
1719
1877
|
};
|
|
1720
1878
|
this.options
|
|
1721
|
-
.filter(
|
|
1722
|
-
|
|
1723
|
-
|
|
1879
|
+
.filter(
|
|
1880
|
+
(option) =>
|
|
1881
|
+
option.implied !== undefined &&
|
|
1882
|
+
hasCustomOptionValue(option.attributeName()) &&
|
|
1883
|
+
dualHelper.valueFromOption(
|
|
1884
|
+
this.getOptionValue(option.attributeName()),
|
|
1885
|
+
option,
|
|
1886
|
+
),
|
|
1887
|
+
)
|
|
1724
1888
|
.forEach((option) => {
|
|
1725
1889
|
Object.keys(option.implied)
|
|
1726
|
-
.filter(impliedKey => !hasCustomOptionValue(impliedKey))
|
|
1727
|
-
.forEach(impliedKey => {
|
|
1728
|
-
this.setOptionValueWithSource(
|
|
1890
|
+
.filter((impliedKey) => !hasCustomOptionValue(impliedKey))
|
|
1891
|
+
.forEach((impliedKey) => {
|
|
1892
|
+
this.setOptionValueWithSource(
|
|
1893
|
+
impliedKey,
|
|
1894
|
+
option.implied[impliedKey],
|
|
1895
|
+
'implied',
|
|
1896
|
+
);
|
|
1729
1897
|
});
|
|
1730
1898
|
});
|
|
1731
1899
|
}
|
|
@@ -1779,12 +1947,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1779
1947
|
const findBestOptionFromValue = (option) => {
|
|
1780
1948
|
const optionKey = option.attributeName();
|
|
1781
1949
|
const optionValue = this.getOptionValue(optionKey);
|
|
1782
|
-
const negativeOption = this.options.find(
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
(
|
|
1787
|
-
)
|
|
1950
|
+
const negativeOption = this.options.find(
|
|
1951
|
+
(target) => target.negate && optionKey === target.attributeName(),
|
|
1952
|
+
);
|
|
1953
|
+
const positiveOption = this.options.find(
|
|
1954
|
+
(target) => !target.negate && optionKey === target.attributeName(),
|
|
1955
|
+
);
|
|
1956
|
+
if (
|
|
1957
|
+
negativeOption &&
|
|
1958
|
+
((negativeOption.presetArg === undefined && optionValue === false) ||
|
|
1959
|
+
(negativeOption.presetArg !== undefined &&
|
|
1960
|
+
optionValue === negativeOption.presetArg))
|
|
1961
|
+
) {
|
|
1788
1962
|
return negativeOption;
|
|
1789
1963
|
}
|
|
1790
1964
|
return positiveOption || option;
|
|
@@ -1818,11 +1992,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1818
1992
|
if (flag.startsWith('--') && this._showSuggestionAfterError) {
|
|
1819
1993
|
// Looping to pick up the global options too
|
|
1820
1994
|
let candidateFlags = [];
|
|
1995
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1821
1996
|
let command = this;
|
|
1822
1997
|
do {
|
|
1823
|
-
const moreFlags = command
|
|
1824
|
-
.
|
|
1825
|
-
.
|
|
1998
|
+
const moreFlags = command
|
|
1999
|
+
.createHelp()
|
|
2000
|
+
.visibleOptions(command)
|
|
2001
|
+
.filter((option) => option.long)
|
|
2002
|
+
.map((option) => option.long);
|
|
1826
2003
|
candidateFlags = candidateFlags.concat(moreFlags);
|
|
1827
2004
|
command = command.parent;
|
|
1828
2005
|
} while (command && !command._enablePositionalOptions);
|
|
@@ -1844,7 +2021,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1844
2021
|
if (this._allowExcessArguments) return;
|
|
1845
2022
|
|
|
1846
2023
|
const expected = this.registeredArguments.length;
|
|
1847
|
-
const s =
|
|
2024
|
+
const s = expected === 1 ? '' : 's';
|
|
1848
2025
|
const forSubcommand = this.parent ? ` for '${this.name()}'` : '';
|
|
1849
2026
|
const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
|
|
1850
2027
|
this.error(message, { code: 'commander.excessArguments' });
|
|
@@ -1862,11 +2039,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1862
2039
|
|
|
1863
2040
|
if (this._showSuggestionAfterError) {
|
|
1864
2041
|
const candidateNames = [];
|
|
1865
|
-
this.createHelp()
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
2042
|
+
this.createHelp()
|
|
2043
|
+
.visibleCommands(this)
|
|
2044
|
+
.forEach((command) => {
|
|
2045
|
+
candidateNames.push(command.name());
|
|
2046
|
+
// just visible alias
|
|
2047
|
+
if (command.alias()) candidateNames.push(command.alias());
|
|
2048
|
+
});
|
|
1870
2049
|
suggestion = suggestSimilar(unknownName, candidateNames);
|
|
1871
2050
|
}
|
|
1872
2051
|
|
|
@@ -1907,11 +2086,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1907
2086
|
* Set the description.
|
|
1908
2087
|
*
|
|
1909
2088
|
* @param {string} [str]
|
|
1910
|
-
* @param {
|
|
2089
|
+
* @param {object} [argsDescription]
|
|
1911
2090
|
* @return {(string|Command)}
|
|
1912
2091
|
*/
|
|
1913
2092
|
description(str, argsDescription) {
|
|
1914
|
-
if (str === undefined && argsDescription === undefined)
|
|
2093
|
+
if (str === undefined && argsDescription === undefined)
|
|
2094
|
+
return this._description;
|
|
1915
2095
|
this._description = str;
|
|
1916
2096
|
if (argsDescription) {
|
|
1917
2097
|
this._argsDescription = argsDescription;
|
|
@@ -1944,18 +2124,27 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1944
2124
|
if (alias === undefined) return this._aliases[0]; // just return first, for backwards compatibility
|
|
1945
2125
|
|
|
1946
2126
|
/** @type {Command} */
|
|
2127
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1947
2128
|
let command = this;
|
|
1948
|
-
if (
|
|
2129
|
+
if (
|
|
2130
|
+
this.commands.length !== 0 &&
|
|
2131
|
+
this.commands[this.commands.length - 1]._executableHandler
|
|
2132
|
+
) {
|
|
1949
2133
|
// assume adding alias for last added executable subcommand, rather than this
|
|
1950
2134
|
command = this.commands[this.commands.length - 1];
|
|
1951
2135
|
}
|
|
1952
2136
|
|
|
1953
|
-
if (alias === command._name)
|
|
2137
|
+
if (alias === command._name)
|
|
2138
|
+
throw new Error("Command alias can't be the same as its name");
|
|
1954
2139
|
const matchingCommand = this.parent?._findCommand(alias);
|
|
1955
2140
|
if (matchingCommand) {
|
|
1956
2141
|
// c.f. _registerCommand
|
|
1957
|
-
const existingCmd = [matchingCommand.name()]
|
|
1958
|
-
|
|
2142
|
+
const existingCmd = [matchingCommand.name()]
|
|
2143
|
+
.concat(matchingCommand.aliases())
|
|
2144
|
+
.join('|');
|
|
2145
|
+
throw new Error(
|
|
2146
|
+
`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`,
|
|
2147
|
+
);
|
|
1959
2148
|
}
|
|
1960
2149
|
|
|
1961
2150
|
command._aliases.push(alias);
|
|
@@ -1993,11 +2182,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1993
2182
|
const args = this.registeredArguments.map((arg) => {
|
|
1994
2183
|
return humanReadableArgName(arg);
|
|
1995
2184
|
});
|
|
1996
|
-
return []
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2185
|
+
return []
|
|
2186
|
+
.concat(
|
|
2187
|
+
this.options.length || this._helpOption !== null ? '[options]' : [],
|
|
2188
|
+
this.commands.length ? '[command]' : [],
|
|
2189
|
+
this.registeredArguments.length ? args : [],
|
|
2190
|
+
)
|
|
2191
|
+
.join(' ');
|
|
2001
2192
|
}
|
|
2002
2193
|
|
|
2003
2194
|
this._usage = str;
|
|
@@ -2064,7 +2255,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2064
2255
|
helpInformation(contextOptions) {
|
|
2065
2256
|
const helper = this.createHelp();
|
|
2066
2257
|
if (helper.helpWidth === undefined) {
|
|
2067
|
-
helper.helpWidth =
|
|
2258
|
+
helper.helpWidth =
|
|
2259
|
+
contextOptions && contextOptions.error
|
|
2260
|
+
? this._outputConfiguration.getErrHelpWidth()
|
|
2261
|
+
: this._outputConfiguration.getOutHelpWidth();
|
|
2068
2262
|
}
|
|
2069
2263
|
return helper.formatHelp(this, helper);
|
|
2070
2264
|
}
|
|
@@ -2103,13 +2297,18 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2103
2297
|
}
|
|
2104
2298
|
const context = this._getHelpContext(contextOptions);
|
|
2105
2299
|
|
|
2106
|
-
this._getCommandAndAncestors()
|
|
2300
|
+
this._getCommandAndAncestors()
|
|
2301
|
+
.reverse()
|
|
2302
|
+
.forEach((command) => command.emit('beforeAllHelp', context));
|
|
2107
2303
|
this.emit('beforeHelp', context);
|
|
2108
2304
|
|
|
2109
2305
|
let helpInformation = this.helpInformation(context);
|
|
2110
2306
|
if (deprecatedCallback) {
|
|
2111
2307
|
helpInformation = deprecatedCallback(helpInformation);
|
|
2112
|
-
if (
|
|
2308
|
+
if (
|
|
2309
|
+
typeof helpInformation !== 'string' &&
|
|
2310
|
+
!Buffer.isBuffer(helpInformation)
|
|
2311
|
+
) {
|
|
2113
2312
|
throw new Error('outputHelp callback must return a string or a Buffer');
|
|
2114
2313
|
}
|
|
2115
2314
|
}
|
|
@@ -2119,7 +2318,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2119
2318
|
this.emit(this._getHelpOption().long); // deprecated
|
|
2120
2319
|
}
|
|
2121
2320
|
this.emit('afterHelp', context);
|
|
2122
|
-
this._getCommandAndAncestors().forEach(command =>
|
|
2321
|
+
this._getCommandAndAncestors().forEach((command) =>
|
|
2322
|
+
command.emit('afterAllHelp', context),
|
|
2323
|
+
);
|
|
2123
2324
|
}
|
|
2124
2325
|
|
|
2125
2326
|
/**
|
|
@@ -2159,7 +2360,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2159
2360
|
* Returns null if has been disabled with .helpOption(false).
|
|
2160
2361
|
*
|
|
2161
2362
|
* @returns {(Option | null)} the help option
|
|
2162
|
-
* @package
|
|
2363
|
+
* @package
|
|
2163
2364
|
*/
|
|
2164
2365
|
_getHelpOption() {
|
|
2165
2366
|
// Lazy create help option on demand.
|
|
@@ -2192,7 +2393,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2192
2393
|
help(contextOptions) {
|
|
2193
2394
|
this.outputHelp(contextOptions);
|
|
2194
2395
|
let exitCode = process.exitCode || 0;
|
|
2195
|
-
if (
|
|
2396
|
+
if (
|
|
2397
|
+
exitCode === 0 &&
|
|
2398
|
+
contextOptions &&
|
|
2399
|
+
typeof contextOptions !== 'function' &&
|
|
2400
|
+
contextOptions.error
|
|
2401
|
+
) {
|
|
2196
2402
|
exitCode = 1;
|
|
2197
2403
|
}
|
|
2198
2404
|
// message: do not have all displayed text available so only passing placeholder.
|
|
@@ -2240,7 +2446,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2240
2446
|
|
|
2241
2447
|
_outputHelpIfRequested(args) {
|
|
2242
2448
|
const helpOption = this._getHelpOption();
|
|
2243
|
-
const helpRequested = helpOption && args.find(arg => helpOption.is(arg));
|
|
2449
|
+
const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
|
|
2244
2450
|
if (helpRequested) {
|
|
2245
2451
|
this.outputHelp();
|
|
2246
2452
|
// (Do not have all displayed text available so only passing placeholder.)
|
|
@@ -2273,7 +2479,9 @@ function incrementNodeInspectorPort(args) {
|
|
|
2273
2479
|
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
|
|
2274
2480
|
// e.g. --inspect
|
|
2275
2481
|
debugOption = match[1];
|
|
2276
|
-
} else if (
|
|
2482
|
+
} else if (
|
|
2483
|
+
(match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null
|
|
2484
|
+
) {
|
|
2277
2485
|
debugOption = match[1];
|
|
2278
2486
|
if (/^\d+$/.test(match[3])) {
|
|
2279
2487
|
// e.g. --inspect=1234
|
|
@@ -2282,7 +2490,9 @@ function incrementNodeInspectorPort(args) {
|
|
|
2282
2490
|
// e.g. --inspect=localhost
|
|
2283
2491
|
debugHost = match[3];
|
|
2284
2492
|
}
|
|
2285
|
-
} else if (
|
|
2493
|
+
} else if (
|
|
2494
|
+
(match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null
|
|
2495
|
+
) {
|
|
2286
2496
|
// e.g. --inspect=localhost:1234
|
|
2287
2497
|
debugOption = match[1];
|
|
2288
2498
|
debugHost = match[3];
|