commander 5.0.0 → 6.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/CHANGELOG.md +82 -109
- package/Readme.md +90 -51
- package/index.js +281 -111
- package/package.json +9 -9
- package/typings/index.d.ts +93 -62
package/index.js
CHANGED
|
@@ -20,13 +20,18 @@ class Option {
|
|
|
20
20
|
|
|
21
21
|
constructor(flags, description) {
|
|
22
22
|
this.flags = flags;
|
|
23
|
-
this.required = flags.
|
|
24
|
-
this.optional = flags.
|
|
23
|
+
this.required = flags.includes('<'); // A value must be supplied when the option is specified.
|
|
24
|
+
this.optional = flags.includes('['); // A value is optional when the option is specified.
|
|
25
|
+
// variadic test ignores <value,...> et al which might be used to describe custom splitting of single argument
|
|
26
|
+
this.variadic = /\w\.\.\.[>\]]$/.test(flags); // The option can take multiple values.
|
|
25
27
|
this.mandatory = false; // The option must have a value after parsing, which usually means it must be specified on command line.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.
|
|
28
|
+
const optionFlags = _parseOptionFlags(flags);
|
|
29
|
+
this.short = optionFlags.shortFlag;
|
|
30
|
+
this.long = optionFlags.longFlag;
|
|
31
|
+
this.negate = false;
|
|
32
|
+
if (this.long) {
|
|
33
|
+
this.negate = this.long.startsWith('--no-');
|
|
34
|
+
}
|
|
30
35
|
this.description = description || '';
|
|
31
36
|
this.defaultValue = undefined;
|
|
32
37
|
}
|
|
@@ -39,7 +44,10 @@ class Option {
|
|
|
39
44
|
*/
|
|
40
45
|
|
|
41
46
|
name() {
|
|
42
|
-
|
|
47
|
+
if (this.long) {
|
|
48
|
+
return this.long.replace(/^--/, '');
|
|
49
|
+
}
|
|
50
|
+
return this.short.replace(/^-/, '');
|
|
43
51
|
};
|
|
44
52
|
|
|
45
53
|
/**
|
|
@@ -110,6 +118,7 @@ class Command extends EventEmitter {
|
|
|
110
118
|
this._name = name || '';
|
|
111
119
|
this._optionValues = {};
|
|
112
120
|
this._storeOptionsAsProperties = true; // backwards compatible by default
|
|
121
|
+
this._storeOptionsAsPropertiesCalled = false;
|
|
113
122
|
this._passCommandToAction = true; // backwards compatible by default
|
|
114
123
|
this._actionResults = [];
|
|
115
124
|
this._actionHandler = null;
|
|
@@ -117,9 +126,11 @@ class Command extends EventEmitter {
|
|
|
117
126
|
this._executableFile = null; // custom name for executable
|
|
118
127
|
this._defaultCommandName = null;
|
|
119
128
|
this._exitCallback = null;
|
|
120
|
-
this.
|
|
129
|
+
this._aliases = [];
|
|
130
|
+
this._combineFlagAndOptionalValue = true;
|
|
121
131
|
|
|
122
|
-
this.
|
|
132
|
+
this._hidden = false;
|
|
133
|
+
this._hasHelpOption = true;
|
|
123
134
|
this._helpFlags = '-h, --help';
|
|
124
135
|
this._helpDescription = 'display help for command';
|
|
125
136
|
this._helpShortFlag = '-h';
|
|
@@ -153,7 +164,7 @@ class Command extends EventEmitter {
|
|
|
153
164
|
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
|
|
154
165
|
* @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
|
|
155
166
|
* @param {Object} [execOpts] - configuration options (for executable)
|
|
156
|
-
* @return {Command} returns new command for action handler, or
|
|
167
|
+
* @return {Command} returns new command for action handler, or `this` for executable command
|
|
157
168
|
* @api public
|
|
158
169
|
*/
|
|
159
170
|
|
|
@@ -174,7 +185,8 @@ class Command extends EventEmitter {
|
|
|
174
185
|
}
|
|
175
186
|
if (opts.isDefault) this._defaultCommandName = cmd._name;
|
|
176
187
|
|
|
177
|
-
cmd.
|
|
188
|
+
cmd._hidden = !!(opts.noHelp || opts.hidden);
|
|
189
|
+
cmd._hasHelpOption = this._hasHelpOption;
|
|
178
190
|
cmd._helpFlags = this._helpFlags;
|
|
179
191
|
cmd._helpDescription = this._helpDescription;
|
|
180
192
|
cmd._helpShortFlag = this._helpShortFlag;
|
|
@@ -185,6 +197,7 @@ class Command extends EventEmitter {
|
|
|
185
197
|
cmd._exitCallback = this._exitCallback;
|
|
186
198
|
cmd._storeOptionsAsProperties = this._storeOptionsAsProperties;
|
|
187
199
|
cmd._passCommandToAction = this._passCommandToAction;
|
|
200
|
+
cmd._combineFlagAndOptionalValue = this._combineFlagAndOptionalValue;
|
|
188
201
|
|
|
189
202
|
cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor
|
|
190
203
|
this.commands.push(cmd);
|
|
@@ -216,11 +229,12 @@ class Command extends EventEmitter {
|
|
|
216
229
|
* See .command() for creating an attached subcommand which inherits settings from its parent.
|
|
217
230
|
*
|
|
218
231
|
* @param {Command} cmd - new subcommand
|
|
219
|
-
* @
|
|
232
|
+
* @param {Object} [opts] - configuration options
|
|
233
|
+
* @return {Command} `this` command for chaining
|
|
220
234
|
* @api public
|
|
221
235
|
*/
|
|
222
236
|
|
|
223
|
-
addCommand(cmd) {
|
|
237
|
+
addCommand(cmd, opts) {
|
|
224
238
|
if (!cmd._name) throw new Error('Command passed to .addCommand() must have a name');
|
|
225
239
|
|
|
226
240
|
// To keep things simple, block automatic name generation for deeply nested executables.
|
|
@@ -235,13 +249,17 @@ class Command extends EventEmitter {
|
|
|
235
249
|
}
|
|
236
250
|
checkExplicitNames(cmd.commands);
|
|
237
251
|
|
|
252
|
+
opts = opts || {};
|
|
253
|
+
if (opts.isDefault) this._defaultCommandName = cmd._name;
|
|
254
|
+
if (opts.noHelp || opts.hidden) cmd._hidden = true; // modifying passed command due to existing implementation
|
|
255
|
+
|
|
238
256
|
this.commands.push(cmd);
|
|
239
257
|
cmd.parent = this;
|
|
240
258
|
return this;
|
|
241
259
|
};
|
|
242
260
|
|
|
243
261
|
/**
|
|
244
|
-
* Define argument syntax for the
|
|
262
|
+
* Define argument syntax for the command.
|
|
245
263
|
*
|
|
246
264
|
* @api public
|
|
247
265
|
*/
|
|
@@ -255,9 +273,9 @@ class Command extends EventEmitter {
|
|
|
255
273
|
*
|
|
256
274
|
* addHelpCommand() // force on
|
|
257
275
|
* addHelpCommand(false); // force off
|
|
258
|
-
* addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom
|
|
276
|
+
* addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details
|
|
259
277
|
*
|
|
260
|
-
* @return {Command} for chaining
|
|
278
|
+
* @return {Command} `this` command for chaining
|
|
261
279
|
* @api public
|
|
262
280
|
*/
|
|
263
281
|
|
|
@@ -293,7 +311,7 @@ class Command extends EventEmitter {
|
|
|
293
311
|
* For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
|
|
294
312
|
*
|
|
295
313
|
* @param {Array} args
|
|
296
|
-
* @return {Command} for chaining
|
|
314
|
+
* @return {Command} `this` command for chaining
|
|
297
315
|
* @api private
|
|
298
316
|
*/
|
|
299
317
|
|
|
@@ -336,7 +354,7 @@ class Command extends EventEmitter {
|
|
|
336
354
|
* Register callback to use as replacement for calling process.exit.
|
|
337
355
|
*
|
|
338
356
|
* @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing
|
|
339
|
-
* @return {Command} for chaining
|
|
357
|
+
* @return {Command} `this` command for chaining
|
|
340
358
|
* @api public
|
|
341
359
|
*/
|
|
342
360
|
|
|
@@ -386,7 +404,7 @@ class Command extends EventEmitter {
|
|
|
386
404
|
* });
|
|
387
405
|
*
|
|
388
406
|
* @param {Function} fn
|
|
389
|
-
* @return {Command} for chaining
|
|
407
|
+
* @return {Command} `this` command for chaining
|
|
390
408
|
* @api public
|
|
391
409
|
*/
|
|
392
410
|
|
|
@@ -417,15 +435,58 @@ class Command extends EventEmitter {
|
|
|
417
435
|
return this;
|
|
418
436
|
};
|
|
419
437
|
|
|
438
|
+
/**
|
|
439
|
+
* Internal routine to check whether there is a clash storing option value with a Command property.
|
|
440
|
+
*
|
|
441
|
+
* @param {Option} option
|
|
442
|
+
* @api private
|
|
443
|
+
*/
|
|
444
|
+
|
|
445
|
+
_checkForOptionNameClash(option) {
|
|
446
|
+
if (!this._storeOptionsAsProperties || this._storeOptionsAsPropertiesCalled) {
|
|
447
|
+
// Storing options safely, or user has been explicit and up to them.
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
// User may override help, and hard to tell if worth warning.
|
|
451
|
+
if (option.name() === 'help') {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const commandProperty = this._getOptionValue(option.attributeName());
|
|
456
|
+
if (commandProperty === undefined) {
|
|
457
|
+
// no clash
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
let foundClash = true;
|
|
462
|
+
if (option.negate) {
|
|
463
|
+
// It is ok if define foo before --no-foo.
|
|
464
|
+
const positiveLongFlag = option.long.replace(/^--no-/, '--');
|
|
465
|
+
foundClash = !this._findOption(positiveLongFlag);
|
|
466
|
+
} else if (option.long) {
|
|
467
|
+
const negativeLongFlag = option.long.replace(/^--/, '--no-');
|
|
468
|
+
foundClash = !this._findOption(negativeLongFlag);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (foundClash) {
|
|
472
|
+
throw new Error(`option '${option.name()}' clashes with existing property '${option.attributeName()}' on Command
|
|
473
|
+
- call storeOptionsAsProperties(false) to store option values safely,
|
|
474
|
+
- or call storeOptionsAsProperties(true) to suppress this check,
|
|
475
|
+
- or change option name
|
|
476
|
+
|
|
477
|
+
Read more on https://git.io/JJc0W`);
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
|
|
420
481
|
/**
|
|
421
482
|
* Internal implementation shared by .option() and .requiredOption()
|
|
422
483
|
*
|
|
423
484
|
* @param {Object} config
|
|
424
485
|
* @param {string} flags
|
|
425
486
|
* @param {string} description
|
|
426
|
-
* @param {Function|*} [fn] - custom option processing function or default
|
|
487
|
+
* @param {Function|*} [fn] - custom option processing function or default value
|
|
427
488
|
* @param {*} [defaultValue]
|
|
428
|
-
* @return {Command} for chaining
|
|
489
|
+
* @return {Command} `this` command for chaining
|
|
429
490
|
* @api private
|
|
430
491
|
*/
|
|
431
492
|
|
|
@@ -435,6 +496,8 @@ class Command extends EventEmitter {
|
|
|
435
496
|
const name = option.attributeName();
|
|
436
497
|
option.mandatory = !!config.mandatory;
|
|
437
498
|
|
|
499
|
+
this._checkForOptionNameClash(option);
|
|
500
|
+
|
|
438
501
|
// default as 3rd arg
|
|
439
502
|
if (typeof fn !== 'function') {
|
|
440
503
|
if (fn instanceof RegExp) {
|
|
@@ -471,13 +534,21 @@ class Command extends EventEmitter {
|
|
|
471
534
|
// when it's passed assign the value
|
|
472
535
|
// and conditionally invoke the callback
|
|
473
536
|
this.on('option:' + oname, (val) => {
|
|
474
|
-
|
|
537
|
+
const oldValue = this._getOptionValue(name);
|
|
538
|
+
|
|
539
|
+
// custom processing
|
|
475
540
|
if (val !== null && fn) {
|
|
476
|
-
val = fn(val,
|
|
541
|
+
val = fn(val, oldValue === undefined ? defaultValue : oldValue);
|
|
542
|
+
} else if (val !== null && option.variadic) {
|
|
543
|
+
if (oldValue === defaultValue || !Array.isArray(oldValue)) {
|
|
544
|
+
val = [val];
|
|
545
|
+
} else {
|
|
546
|
+
val = oldValue.concat(val);
|
|
547
|
+
}
|
|
477
548
|
}
|
|
478
549
|
|
|
479
550
|
// unassigned or boolean value
|
|
480
|
-
if (typeof
|
|
551
|
+
if (typeof oldValue === 'boolean' || typeof oldValue === 'undefined') {
|
|
481
552
|
// if no value, negate false, and we have a default, then use it!
|
|
482
553
|
if (val == null) {
|
|
483
554
|
this._setOptionValue(name, option.negate
|
|
@@ -541,9 +612,9 @@ class Command extends EventEmitter {
|
|
|
541
612
|
*
|
|
542
613
|
* @param {string} flags
|
|
543
614
|
* @param {string} description
|
|
544
|
-
* @param {Function|*} [fn] - custom option processing function or default
|
|
615
|
+
* @param {Function|*} [fn] - custom option processing function or default value
|
|
545
616
|
* @param {*} [defaultValue]
|
|
546
|
-
* @return {Command} for chaining
|
|
617
|
+
* @return {Command} `this` command for chaining
|
|
547
618
|
* @api public
|
|
548
619
|
*/
|
|
549
620
|
|
|
@@ -551,7 +622,7 @@ class Command extends EventEmitter {
|
|
|
551
622
|
return this._optionEx({}, flags, description, fn, defaultValue);
|
|
552
623
|
};
|
|
553
624
|
|
|
554
|
-
|
|
625
|
+
/**
|
|
555
626
|
* Add a required option which must have a value after parsing. This usually means
|
|
556
627
|
* the option must be specified on the command line. (Otherwise the same as .option().)
|
|
557
628
|
*
|
|
@@ -559,9 +630,9 @@ class Command extends EventEmitter {
|
|
|
559
630
|
*
|
|
560
631
|
* @param {string} flags
|
|
561
632
|
* @param {string} description
|
|
562
|
-
* @param {Function|*} [fn] - custom option processing function or default
|
|
633
|
+
* @param {Function|*} [fn] - custom option processing function or default value
|
|
563
634
|
* @param {*} [defaultValue]
|
|
564
|
-
* @return {Command} for chaining
|
|
635
|
+
* @return {Command} `this` command for chaining
|
|
565
636
|
* @api public
|
|
566
637
|
*/
|
|
567
638
|
|
|
@@ -569,6 +640,23 @@ class Command extends EventEmitter {
|
|
|
569
640
|
return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue);
|
|
570
641
|
};
|
|
571
642
|
|
|
643
|
+
/**
|
|
644
|
+
* Alter parsing of short flags with optional values.
|
|
645
|
+
*
|
|
646
|
+
* Examples:
|
|
647
|
+
*
|
|
648
|
+
* // for `.option('-f,--flag [value]'):
|
|
649
|
+
* .combineFlagAndOptionalValue(true) // `-f80` is treated like `--flag=80`, this is the default behaviour
|
|
650
|
+
* .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
|
|
651
|
+
*
|
|
652
|
+
* @param {Boolean} [arg] - if `true` or omitted, an optional value can be specified directly after the flag.
|
|
653
|
+
* @api public
|
|
654
|
+
*/
|
|
655
|
+
combineFlagAndOptionalValue(arg) {
|
|
656
|
+
this._combineFlagAndOptionalValue = (arg === undefined) || arg;
|
|
657
|
+
return this;
|
|
658
|
+
};
|
|
659
|
+
|
|
572
660
|
/**
|
|
573
661
|
* Allow unknown options on the command line.
|
|
574
662
|
*
|
|
@@ -577,7 +665,7 @@ class Command extends EventEmitter {
|
|
|
577
665
|
* @api public
|
|
578
666
|
*/
|
|
579
667
|
allowUnknownOption(arg) {
|
|
580
|
-
this._allowUnknownOption =
|
|
668
|
+
this._allowUnknownOption = (arg === undefined) || arg;
|
|
581
669
|
return this;
|
|
582
670
|
};
|
|
583
671
|
|
|
@@ -586,11 +674,12 @@ class Command extends EventEmitter {
|
|
|
586
674
|
* or store separately (specify false). In both cases the option values can be accessed using .opts().
|
|
587
675
|
*
|
|
588
676
|
* @param {boolean} value
|
|
589
|
-
* @return {Command}
|
|
677
|
+
* @return {Command} `this` command for chaining
|
|
590
678
|
* @api public
|
|
591
679
|
*/
|
|
592
680
|
|
|
593
681
|
storeOptionsAsProperties(value) {
|
|
682
|
+
this._storeOptionsAsPropertiesCalled = true;
|
|
594
683
|
this._storeOptionsAsProperties = (value === undefined) || value;
|
|
595
684
|
if (this.options.length) {
|
|
596
685
|
throw new Error('call .storeOptionsAsProperties() before adding options');
|
|
@@ -603,7 +692,7 @@ class Command extends EventEmitter {
|
|
|
603
692
|
* or just the options (specify false).
|
|
604
693
|
*
|
|
605
694
|
* @param {boolean} value
|
|
606
|
-
* @return {Command}
|
|
695
|
+
* @return {Command} `this` command for chaining
|
|
607
696
|
* @api public
|
|
608
697
|
*/
|
|
609
698
|
|
|
@@ -658,7 +747,7 @@ class Command extends EventEmitter {
|
|
|
658
747
|
* @param {string[]} [argv] - optional, defaults to process.argv
|
|
659
748
|
* @param {Object} [parseOptions] - optionally specify style of options with from: node/user/electron
|
|
660
749
|
* @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'
|
|
661
|
-
* @return {Command} for chaining
|
|
750
|
+
* @return {Command} `this` command for chaining
|
|
662
751
|
* @api public
|
|
663
752
|
*/
|
|
664
753
|
|
|
@@ -755,7 +844,11 @@ class Command extends EventEmitter {
|
|
|
755
844
|
this._checkForMissingMandatoryOptions();
|
|
756
845
|
|
|
757
846
|
// Want the entry script as the reference for command name and directory for searching for other files.
|
|
758
|
-
|
|
847
|
+
let scriptPath = this._scriptPath;
|
|
848
|
+
// Fallback in case not set, due to how Command created or called.
|
|
849
|
+
if (!scriptPath && process.mainModule) {
|
|
850
|
+
scriptPath = process.mainModule.filename;
|
|
851
|
+
}
|
|
759
852
|
|
|
760
853
|
let baseDir;
|
|
761
854
|
try {
|
|
@@ -886,7 +979,7 @@ class Command extends EventEmitter {
|
|
|
886
979
|
this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
|
|
887
980
|
} else {
|
|
888
981
|
if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
|
|
889
|
-
//
|
|
982
|
+
// probably missing subcommand and no handler, user needs help
|
|
890
983
|
this._helpAndError();
|
|
891
984
|
}
|
|
892
985
|
|
|
@@ -932,7 +1025,7 @@ class Command extends EventEmitter {
|
|
|
932
1025
|
*/
|
|
933
1026
|
_findCommand(name) {
|
|
934
1027
|
if (!name) return undefined;
|
|
935
|
-
return this.commands.find(cmd => cmd._name === name || cmd.
|
|
1028
|
+
return this.commands.find(cmd => cmd._name === name || cmd._aliases.includes(name));
|
|
936
1029
|
};
|
|
937
1030
|
|
|
938
1031
|
/**
|
|
@@ -993,6 +1086,7 @@ class Command extends EventEmitter {
|
|
|
993
1086
|
}
|
|
994
1087
|
|
|
995
1088
|
// parse options
|
|
1089
|
+
let activeVariadicOption = null;
|
|
996
1090
|
while (args.length) {
|
|
997
1091
|
const arg = args.shift();
|
|
998
1092
|
|
|
@@ -1003,6 +1097,12 @@ class Command extends EventEmitter {
|
|
|
1003
1097
|
break;
|
|
1004
1098
|
}
|
|
1005
1099
|
|
|
1100
|
+
if (activeVariadicOption && !maybeOption(arg)) {
|
|
1101
|
+
this.emit(`option:${activeVariadicOption.name()}`, arg);
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
activeVariadicOption = null;
|
|
1105
|
+
|
|
1006
1106
|
if (maybeOption(arg)) {
|
|
1007
1107
|
const option = this._findOption(arg);
|
|
1008
1108
|
// recognised option, call listener to assign value with possible custom processing
|
|
@@ -1021,6 +1121,7 @@ class Command extends EventEmitter {
|
|
|
1021
1121
|
} else { // boolean flag
|
|
1022
1122
|
this.emit(`option:${option.name()}`);
|
|
1023
1123
|
}
|
|
1124
|
+
activeVariadicOption = option.variadic ? option : null;
|
|
1024
1125
|
continue;
|
|
1025
1126
|
}
|
|
1026
1127
|
}
|
|
@@ -1029,7 +1130,7 @@ class Command extends EventEmitter {
|
|
|
1029
1130
|
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
|
|
1030
1131
|
const option = this._findOption(`-${arg[1]}`);
|
|
1031
1132
|
if (option) {
|
|
1032
|
-
if (option.required || option.optional) {
|
|
1133
|
+
if (option.required || (option.optional && this._combineFlagAndOptionalValue)) {
|
|
1033
1134
|
// option with value following in same argument
|
|
1034
1135
|
this.emit(`option:${option.name()}`, arg.slice(2));
|
|
1035
1136
|
} else {
|
|
@@ -1156,7 +1257,8 @@ class Command extends EventEmitter {
|
|
|
1156
1257
|
partCommands.unshift(parentCmd.name());
|
|
1157
1258
|
}
|
|
1158
1259
|
const fullCommand = partCommands.join(' ');
|
|
1159
|
-
const message = `error: unknown command '${this.args[0]}'
|
|
1260
|
+
const message = `error: unknown command '${this.args[0]}'.` +
|
|
1261
|
+
(this._hasHelpOption ? ` See '${fullCommand} ${this._helpLongFlag}'.` : '');
|
|
1160
1262
|
console.error(message);
|
|
1161
1263
|
this._exit(1, 'commander.unknownCommand', message);
|
|
1162
1264
|
};
|
|
@@ -1172,19 +1274,19 @@ class Command extends EventEmitter {
|
|
|
1172
1274
|
* @param {string} str
|
|
1173
1275
|
* @param {string} [flags]
|
|
1174
1276
|
* @param {string} [description]
|
|
1175
|
-
* @return {
|
|
1277
|
+
* @return {this | string} `this` command for chaining, or version string if no arguments
|
|
1176
1278
|
* @api public
|
|
1177
1279
|
*/
|
|
1178
1280
|
|
|
1179
1281
|
version(str, flags, description) {
|
|
1180
|
-
if (
|
|
1282
|
+
if (str === undefined) return this._version;
|
|
1181
1283
|
this._version = str;
|
|
1182
1284
|
flags = flags || '-V, --version';
|
|
1183
1285
|
description = description || 'output the version number';
|
|
1184
1286
|
const versionOption = new Option(flags, description);
|
|
1185
|
-
this._versionOptionName = versionOption.
|
|
1287
|
+
this._versionOptionName = versionOption.attributeName();
|
|
1186
1288
|
this.options.push(versionOption);
|
|
1187
|
-
this.on('option:' +
|
|
1289
|
+
this.on('option:' + versionOption.name(), () => {
|
|
1188
1290
|
process.stdout.write(str + '\n');
|
|
1189
1291
|
this._exit(0, 'commander.version', str);
|
|
1190
1292
|
});
|
|
@@ -1196,36 +1298,57 @@ class Command extends EventEmitter {
|
|
|
1196
1298
|
*
|
|
1197
1299
|
* @param {string} str
|
|
1198
1300
|
* @param {Object} [argsDescription]
|
|
1199
|
-
* @return {
|
|
1301
|
+
* @return {string|Command}
|
|
1200
1302
|
* @api public
|
|
1201
1303
|
*/
|
|
1202
1304
|
|
|
1203
1305
|
description(str, argsDescription) {
|
|
1204
|
-
if (
|
|
1306
|
+
if (str === undefined && argsDescription === undefined) return this._description;
|
|
1205
1307
|
this._description = str;
|
|
1206
1308
|
this._argsDescription = argsDescription;
|
|
1207
1309
|
return this;
|
|
1208
1310
|
};
|
|
1209
1311
|
|
|
1210
1312
|
/**
|
|
1211
|
-
* Set an alias for the command
|
|
1313
|
+
* Set an alias for the command.
|
|
1212
1314
|
*
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1315
|
+
* You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
|
|
1316
|
+
*
|
|
1317
|
+
* @param {string} [alias]
|
|
1318
|
+
* @return {string|Command}
|
|
1215
1319
|
* @api public
|
|
1216
1320
|
*/
|
|
1217
1321
|
|
|
1218
1322
|
alias(alias) {
|
|
1323
|
+
if (alias === undefined) return this._aliases[0]; // just return first, for backwards compatibility
|
|
1324
|
+
|
|
1219
1325
|
let command = this;
|
|
1220
|
-
if (this.commands.length !== 0) {
|
|
1326
|
+
if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
|
|
1327
|
+
// assume adding alias for last added executable subcommand, rather than this
|
|
1221
1328
|
command = this.commands[this.commands.length - 1];
|
|
1222
1329
|
}
|
|
1223
1330
|
|
|
1224
|
-
if (arguments.length === 0) return command._alias;
|
|
1225
|
-
|
|
1226
1331
|
if (alias === command._name) throw new Error('Command alias can\'t be the same as its name');
|
|
1227
1332
|
|
|
1228
|
-
command.
|
|
1333
|
+
command._aliases.push(alias);
|
|
1334
|
+
return this;
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* Set aliases for the command.
|
|
1339
|
+
*
|
|
1340
|
+
* Only the first alias is shown in the auto-generated help.
|
|
1341
|
+
*
|
|
1342
|
+
* @param {string[]} [aliases]
|
|
1343
|
+
* @return {string[]|Command}
|
|
1344
|
+
* @api public
|
|
1345
|
+
*/
|
|
1346
|
+
|
|
1347
|
+
aliases(aliases) {
|
|
1348
|
+
// Getter for the array of aliases is the main reason for having aliases() in addition to alias().
|
|
1349
|
+
if (aliases === undefined) return this._aliases;
|
|
1350
|
+
|
|
1351
|
+
aliases.forEach((alias) => this.alias(alias));
|
|
1229
1352
|
return this;
|
|
1230
1353
|
};
|
|
1231
1354
|
|
|
@@ -1238,17 +1361,20 @@ class Command extends EventEmitter {
|
|
|
1238
1361
|
*/
|
|
1239
1362
|
|
|
1240
1363
|
usage(str) {
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
});
|
|
1364
|
+
if (str === undefined) {
|
|
1365
|
+
if (this._usage) return this._usage;
|
|
1244
1366
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1367
|
+
const args = this._args.map((arg) => {
|
|
1368
|
+
return humanReadableArgName(arg);
|
|
1369
|
+
});
|
|
1370
|
+
return [].concat(
|
|
1371
|
+
(this.options.length || this._hasHelpOption ? '[options]' : []),
|
|
1372
|
+
(this.commands.length ? '[command]' : []),
|
|
1373
|
+
(this._args.length ? args : [])
|
|
1374
|
+
).join(' ');
|
|
1375
|
+
}
|
|
1248
1376
|
|
|
1249
|
-
if (arguments.length === 0) return this._usage || usage;
|
|
1250
1377
|
this._usage = str;
|
|
1251
|
-
|
|
1252
1378
|
return this;
|
|
1253
1379
|
};
|
|
1254
1380
|
|
|
@@ -1261,7 +1387,7 @@ class Command extends EventEmitter {
|
|
|
1261
1387
|
*/
|
|
1262
1388
|
|
|
1263
1389
|
name(str) {
|
|
1264
|
-
if (
|
|
1390
|
+
if (str === undefined) return this._name;
|
|
1265
1391
|
this._name = str;
|
|
1266
1392
|
return this;
|
|
1267
1393
|
};
|
|
@@ -1275,7 +1401,7 @@ class Command extends EventEmitter {
|
|
|
1275
1401
|
|
|
1276
1402
|
prepareCommands() {
|
|
1277
1403
|
const commandDetails = this.commands.filter((cmd) => {
|
|
1278
|
-
return !cmd.
|
|
1404
|
+
return !cmd._hidden;
|
|
1279
1405
|
}).map((cmd) => {
|
|
1280
1406
|
const args = cmd._args.map((arg) => {
|
|
1281
1407
|
return humanReadableArgName(arg);
|
|
@@ -1283,7 +1409,7 @@ class Command extends EventEmitter {
|
|
|
1283
1409
|
|
|
1284
1410
|
return [
|
|
1285
1411
|
cmd._name +
|
|
1286
|
-
(cmd.
|
|
1412
|
+
(cmd._aliases[0] ? '|' + cmd._aliases[0] : '') +
|
|
1287
1413
|
(cmd.options.length ? ' [options]' : '') +
|
|
1288
1414
|
(args ? ' ' + args : ''),
|
|
1289
1415
|
cmd._description
|
|
@@ -1374,17 +1500,33 @@ class Command extends EventEmitter {
|
|
|
1374
1500
|
|
|
1375
1501
|
optionHelp() {
|
|
1376
1502
|
const width = this.padWidth();
|
|
1377
|
-
|
|
1378
1503
|
const columns = process.stdout.columns || 80;
|
|
1379
1504
|
const descriptionWidth = columns - width - 4;
|
|
1505
|
+
function padOptionDetails(flags, description) {
|
|
1506
|
+
return pad(flags, width) + ' ' + optionalWrap(description, descriptionWidth, width + 2);
|
|
1507
|
+
};
|
|
1380
1508
|
|
|
1381
|
-
//
|
|
1382
|
-
|
|
1509
|
+
// Explicit options (including version)
|
|
1510
|
+
const help = this.options.map((option) => {
|
|
1383
1511
|
const fullDesc = option.description +
|
|
1384
1512
|
((!option.negate && option.defaultValue !== undefined) ? ' (default: ' + JSON.stringify(option.defaultValue) + ')' : '');
|
|
1385
|
-
return
|
|
1386
|
-
})
|
|
1387
|
-
|
|
1513
|
+
return padOptionDetails(option.flags, fullDesc);
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
// Implicit help
|
|
1517
|
+
const showShortHelpFlag = this._hasHelpOption && this._helpShortFlag && !this._findOption(this._helpShortFlag);
|
|
1518
|
+
const showLongHelpFlag = this._hasHelpOption && !this._findOption(this._helpLongFlag);
|
|
1519
|
+
if (showShortHelpFlag || showLongHelpFlag) {
|
|
1520
|
+
let helpFlags = this._helpFlags;
|
|
1521
|
+
if (!showShortHelpFlag) {
|
|
1522
|
+
helpFlags = this._helpLongFlag;
|
|
1523
|
+
} else if (!showLongHelpFlag) {
|
|
1524
|
+
helpFlags = this._helpShortFlag;
|
|
1525
|
+
}
|
|
1526
|
+
help.push(padOptionDetails(helpFlags, this._helpDescription));
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
return help.join('\n');
|
|
1388
1530
|
};
|
|
1389
1531
|
|
|
1390
1532
|
/**
|
|
@@ -1436,15 +1578,15 @@ class Command extends EventEmitter {
|
|
|
1436
1578
|
desc.push('Arguments:');
|
|
1437
1579
|
desc.push('');
|
|
1438
1580
|
this._args.forEach((arg) => {
|
|
1439
|
-
desc.push(' ' + pad(arg.name, width) + ' ' + wrap(argsDescription[arg.name], descriptionWidth, width + 4));
|
|
1581
|
+
desc.push(' ' + pad(arg.name, width) + ' ' + wrap(argsDescription[arg.name] || '', descriptionWidth, width + 4));
|
|
1440
1582
|
});
|
|
1441
1583
|
desc.push('');
|
|
1442
1584
|
}
|
|
1443
1585
|
}
|
|
1444
1586
|
|
|
1445
1587
|
let cmdName = this._name;
|
|
1446
|
-
if (this.
|
|
1447
|
-
cmdName = cmdName + '|' + this.
|
|
1588
|
+
if (this._aliases[0]) {
|
|
1589
|
+
cmdName = cmdName + '|' + this._aliases[0];
|
|
1448
1590
|
}
|
|
1449
1591
|
let parentCmdNames = '';
|
|
1450
1592
|
for (let parentCmd = this.parent; parentCmd; parentCmd = parentCmd.parent) {
|
|
@@ -1459,11 +1601,14 @@ class Command extends EventEmitter {
|
|
|
1459
1601
|
const commandHelp = this.commandHelp();
|
|
1460
1602
|
if (commandHelp) cmds = [commandHelp];
|
|
1461
1603
|
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1604
|
+
let options = [];
|
|
1605
|
+
if (this._hasHelpOption || this.options.length > 0) {
|
|
1606
|
+
options = [
|
|
1607
|
+
'Options:',
|
|
1608
|
+
'' + this.optionHelp().replace(/^/gm, ' '),
|
|
1609
|
+
''
|
|
1610
|
+
];
|
|
1611
|
+
}
|
|
1467
1612
|
|
|
1468
1613
|
return usage
|
|
1469
1614
|
.concat(desc)
|
|
@@ -1497,23 +1642,26 @@ class Command extends EventEmitter {
|
|
|
1497
1642
|
|
|
1498
1643
|
/**
|
|
1499
1644
|
* You can pass in flags and a description to override the help
|
|
1500
|
-
* flags and help description for your command.
|
|
1645
|
+
* flags and help description for your command. Pass in false to
|
|
1646
|
+
* disable the built-in help option.
|
|
1501
1647
|
*
|
|
1502
|
-
* @param {string} [flags]
|
|
1648
|
+
* @param {string | boolean} [flags]
|
|
1503
1649
|
* @param {string} [description]
|
|
1504
|
-
* @return {Command}
|
|
1650
|
+
* @return {Command} `this` command for chaining
|
|
1505
1651
|
* @api public
|
|
1506
1652
|
*/
|
|
1507
1653
|
|
|
1508
1654
|
helpOption(flags, description) {
|
|
1655
|
+
if (typeof flags === 'boolean') {
|
|
1656
|
+
this._hasHelpOption = flags;
|
|
1657
|
+
return this;
|
|
1658
|
+
}
|
|
1509
1659
|
this._helpFlags = flags || this._helpFlags;
|
|
1510
1660
|
this._helpDescription = description || this._helpDescription;
|
|
1511
1661
|
|
|
1512
|
-
const
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
this._helpLongFlag = splitFlags.shift();
|
|
1662
|
+
const helpFlags = _parseOptionFlags(this._helpFlags);
|
|
1663
|
+
this._helpShortFlag = helpFlags.shortFlag;
|
|
1664
|
+
this._helpLongFlag = helpFlags.longFlag;
|
|
1517
1665
|
|
|
1518
1666
|
return this;
|
|
1519
1667
|
};
|
|
@@ -1640,7 +1788,7 @@ function optionalWrap(str, width, indent) {
|
|
|
1640
1788
|
*/
|
|
1641
1789
|
|
|
1642
1790
|
function outputHelpIfRequested(cmd, args) {
|
|
1643
|
-
const helpOption = args.find(arg => arg === cmd._helpLongFlag || arg === cmd._helpShortFlag);
|
|
1791
|
+
const helpOption = cmd._hasHelpOption && args.find(arg => arg === cmd._helpLongFlag || arg === cmd._helpShortFlag);
|
|
1644
1792
|
if (helpOption) {
|
|
1645
1793
|
cmd.outputHelp();
|
|
1646
1794
|
// (Do not have all displayed text available so only passing placeholder.)
|
|
@@ -1664,6 +1812,28 @@ function humanReadableArgName(arg) {
|
|
|
1664
1812
|
: '[' + nameOutput + ']';
|
|
1665
1813
|
}
|
|
1666
1814
|
|
|
1815
|
+
/**
|
|
1816
|
+
* Parse the short and long flag out of something like '-m,--mixed <value>'
|
|
1817
|
+
*
|
|
1818
|
+
* @api private
|
|
1819
|
+
*/
|
|
1820
|
+
|
|
1821
|
+
function _parseOptionFlags(flags) {
|
|
1822
|
+
let shortFlag;
|
|
1823
|
+
let longFlag;
|
|
1824
|
+
// Use original very loose parsing to maintain backwards compatibility for now,
|
|
1825
|
+
// which allowed for example unintended `-sw, --short-word` [sic].
|
|
1826
|
+
const flagParts = flags.split(/[ |,]+/);
|
|
1827
|
+
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1])) shortFlag = flagParts.shift();
|
|
1828
|
+
longFlag = flagParts.shift();
|
|
1829
|
+
// Add support for lone short flag without significantly changing parsing!
|
|
1830
|
+
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
|
|
1831
|
+
shortFlag = longFlag;
|
|
1832
|
+
longFlag = undefined;
|
|
1833
|
+
}
|
|
1834
|
+
return { shortFlag, longFlag };
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1667
1837
|
/**
|
|
1668
1838
|
* Scan arguments and increment port number for inspect calls (to avoid conflicts when spawning new command).
|
|
1669
1839
|
*
|
|
@@ -1678,35 +1848,35 @@ function incrementNodeInspectorPort(args) {
|
|
|
1678
1848
|
// --inspect-brk[=[host:]port]
|
|
1679
1849
|
// --inspect-port=[host:]port
|
|
1680
1850
|
return args.map((arg) => {
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
}
|
|
1699
|
-
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
|
|
1700
|
-
// e.g. --inspect=localhost:1234
|
|
1701
|
-
debugOption = match[1];
|
|
1851
|
+
if (!arg.startsWith('--inspect')) {
|
|
1852
|
+
return arg;
|
|
1853
|
+
}
|
|
1854
|
+
let debugOption;
|
|
1855
|
+
let debugHost = '127.0.0.1';
|
|
1856
|
+
let debugPort = '9229';
|
|
1857
|
+
let match;
|
|
1858
|
+
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
|
|
1859
|
+
// e.g. --inspect
|
|
1860
|
+
debugOption = match[1];
|
|
1861
|
+
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
|
|
1862
|
+
debugOption = match[1];
|
|
1863
|
+
if (/^\d+$/.test(match[3])) {
|
|
1864
|
+
// e.g. --inspect=1234
|
|
1865
|
+
debugPort = match[3];
|
|
1866
|
+
} else {
|
|
1867
|
+
// e.g. --inspect=localhost
|
|
1702
1868
|
debugHost = match[3];
|
|
1703
|
-
debugPort = match[4];
|
|
1704
1869
|
}
|
|
1870
|
+
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
|
|
1871
|
+
// e.g. --inspect=localhost:1234
|
|
1872
|
+
debugOption = match[1];
|
|
1873
|
+
debugHost = match[3];
|
|
1874
|
+
debugPort = match[4];
|
|
1875
|
+
}
|
|
1705
1876
|
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
}
|
|
1877
|
+
if (debugOption && debugPort !== '0') {
|
|
1878
|
+
return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
|
|
1709
1879
|
}
|
|
1710
|
-
return
|
|
1880
|
+
return arg;
|
|
1711
1881
|
});
|
|
1712
1882
|
}
|