commander 2.20.3 → 3.0.2
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 +104 -8
- package/Readme.md +343 -159
- package/index.js +231 -122
- package/package.json +2 -2
- package/typings/index.d.ts +55 -65
package/index.js
CHANGED
|
@@ -45,7 +45,7 @@ function Option(flags, description) {
|
|
|
45
45
|
this.flags = flags;
|
|
46
46
|
this.required = flags.indexOf('<') >= 0;
|
|
47
47
|
this.optional = flags.indexOf('[') >= 0;
|
|
48
|
-
this.
|
|
48
|
+
this.negate = flags.indexOf('-no-') !== -1;
|
|
49
49
|
flags = flags.split(/[ ,|]+/);
|
|
50
50
|
if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
|
|
51
51
|
this.long = flags.shift();
|
|
@@ -60,9 +60,7 @@ function Option(flags, description) {
|
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
62
|
Option.prototype.name = function() {
|
|
63
|
-
return this.long
|
|
64
|
-
.replace('--', '')
|
|
65
|
-
.replace('no-', '');
|
|
63
|
+
return this.long.replace(/^--/, '');
|
|
66
64
|
};
|
|
67
65
|
|
|
68
66
|
/**
|
|
@@ -74,7 +72,7 @@ Option.prototype.name = function() {
|
|
|
74
72
|
*/
|
|
75
73
|
|
|
76
74
|
Option.prototype.attributeName = function() {
|
|
77
|
-
return camelcase(this.name());
|
|
75
|
+
return camelcase(this.name().replace(/^no-/, ''));
|
|
78
76
|
};
|
|
79
77
|
|
|
80
78
|
/**
|
|
@@ -99,89 +97,67 @@ Option.prototype.is = function(arg) {
|
|
|
99
97
|
function Command(name) {
|
|
100
98
|
this.commands = [];
|
|
101
99
|
this.options = [];
|
|
102
|
-
this._execs =
|
|
100
|
+
this._execs = new Set();
|
|
103
101
|
this._allowUnknownOption = false;
|
|
104
102
|
this._args = [];
|
|
105
103
|
this._name = name || '';
|
|
104
|
+
|
|
105
|
+
this._helpFlags = '-h, --help';
|
|
106
|
+
this._helpDescription = 'output usage information';
|
|
107
|
+
this._helpShortFlag = '-h';
|
|
108
|
+
this._helpLongFlag = '--help';
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* The `.action()` callback is invoked when the
|
|
112
|
-
* command `name` is specified via __ARGV__,
|
|
113
|
-
* and the remaining arguments are applied to the
|
|
114
|
-
* function for access.
|
|
112
|
+
* Define a command.
|
|
115
113
|
*
|
|
116
|
-
*
|
|
117
|
-
* will be passed as the first arg, followed by
|
|
118
|
-
* the rest of __ARGV__ remaining.
|
|
114
|
+
* There are two styles of command: pay attention to where to put the description.
|
|
119
115
|
*
|
|
120
116
|
* Examples:
|
|
121
117
|
*
|
|
118
|
+
* // Command implemented using action handler (description is supplied separately to `.command`)
|
|
122
119
|
* program
|
|
123
|
-
* .
|
|
124
|
-
* .
|
|
125
|
-
* .
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* program
|
|
129
|
-
* .command('setup')
|
|
130
|
-
* .description('run remote setup commands')
|
|
131
|
-
* .action(function() {
|
|
132
|
-
* console.log('setup');
|
|
133
|
-
* });
|
|
134
|
-
*
|
|
135
|
-
* program
|
|
136
|
-
* .command('exec <cmd>')
|
|
137
|
-
* .description('run the given remote command')
|
|
138
|
-
* .action(function(cmd) {
|
|
139
|
-
* console.log('exec "%s"', cmd);
|
|
120
|
+
* .command('clone <source> [destination]')
|
|
121
|
+
* .description('clone a repository into a newly created directory')
|
|
122
|
+
* .action((source, destination) => {
|
|
123
|
+
* console.log('clone command called');
|
|
140
124
|
* });
|
|
141
125
|
*
|
|
126
|
+
* // Command implemented using separate executable file (description is second parameter to `.command`)
|
|
142
127
|
* program
|
|
143
|
-
* .command('
|
|
144
|
-
* .
|
|
145
|
-
* .action(function(dir, otherDirs) {
|
|
146
|
-
* console.log('dir "%s"', dir);
|
|
147
|
-
* if (otherDirs) {
|
|
148
|
-
* otherDirs.forEach(function (oDir) {
|
|
149
|
-
* console.log('dir "%s"', oDir);
|
|
150
|
-
* });
|
|
151
|
-
* }
|
|
152
|
-
* });
|
|
128
|
+
* .command('start <service>', 'start named service')
|
|
129
|
+
* .command('stop [service]', 'stop named serice, or all if no name supplied');
|
|
153
130
|
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* console.log('deploying "%s"', env);
|
|
159
|
-
* });
|
|
160
|
-
*
|
|
161
|
-
* program.parse(process.argv);
|
|
162
|
-
*
|
|
163
|
-
* @param {String} name
|
|
164
|
-
* @param {String} [desc] for git-style sub-commands
|
|
165
|
-
* @return {Command} the new command
|
|
131
|
+
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
|
|
132
|
+
* @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
|
|
133
|
+
* @param {Object} [execOpts] - configuration options (for executable)
|
|
134
|
+
* @return {Command} returns new command for action handler, or top-level command for executable command
|
|
166
135
|
* @api public
|
|
167
136
|
*/
|
|
168
137
|
|
|
169
|
-
Command.prototype.command = function(
|
|
138
|
+
Command.prototype.command = function(nameAndArgs, actionOptsOrExecDesc, execOpts) {
|
|
139
|
+
var desc = actionOptsOrExecDesc;
|
|
140
|
+
var opts = execOpts;
|
|
170
141
|
if (typeof desc === 'object' && desc !== null) {
|
|
171
142
|
opts = desc;
|
|
172
143
|
desc = null;
|
|
173
144
|
}
|
|
174
145
|
opts = opts || {};
|
|
175
|
-
var args =
|
|
146
|
+
var args = nameAndArgs.split(/ +/);
|
|
176
147
|
var cmd = new Command(args.shift());
|
|
177
148
|
|
|
178
149
|
if (desc) {
|
|
179
150
|
cmd.description(desc);
|
|
180
151
|
this.executables = true;
|
|
181
|
-
this._execs
|
|
152
|
+
this._execs.add(cmd._name);
|
|
182
153
|
if (opts.isDefault) this.defaultExecutable = cmd._name;
|
|
183
154
|
}
|
|
184
155
|
cmd._noHelp = !!opts.noHelp;
|
|
156
|
+
cmd._helpFlags = this._helpFlags;
|
|
157
|
+
cmd._helpDescription = this._helpDescription;
|
|
158
|
+
cmd._helpShortFlag = this._helpShortFlag;
|
|
159
|
+
cmd._helpLongFlag = this._helpLongFlag;
|
|
160
|
+
cmd._executableFile = opts.executableFile; // Custom name for executable file
|
|
185
161
|
this.commands.push(cmd);
|
|
186
162
|
cmd.parseExpectedArgs(args);
|
|
187
163
|
cmd.parent = this;
|
|
@@ -335,14 +311,17 @@ Command.prototype.action = function(fn) {
|
|
|
335
311
|
*
|
|
336
312
|
* Examples:
|
|
337
313
|
*
|
|
338
|
-
* // simple boolean defaulting to
|
|
314
|
+
* // simple boolean defaulting to undefined
|
|
339
315
|
* program.option('-p, --pepper', 'add pepper');
|
|
340
316
|
*
|
|
317
|
+
* program.pepper
|
|
318
|
+
* // => undefined
|
|
319
|
+
*
|
|
341
320
|
* --pepper
|
|
342
321
|
* program.pepper
|
|
343
|
-
* // =>
|
|
322
|
+
* // => true
|
|
344
323
|
*
|
|
345
|
-
* // simple boolean defaulting to true
|
|
324
|
+
* // simple boolean defaulting to true (unless non-negated option is also defined)
|
|
346
325
|
* program.option('-C, --no-cheese', 'remove cheese');
|
|
347
326
|
*
|
|
348
327
|
* program.cheese
|
|
@@ -379,6 +358,8 @@ Command.prototype.option = function(flags, description, fn, defaultValue) {
|
|
|
379
358
|
// default as 3rd arg
|
|
380
359
|
if (typeof fn !== 'function') {
|
|
381
360
|
if (fn instanceof RegExp) {
|
|
361
|
+
// This is a bit simplistic (especially no error messages), and probably better handled by caller using custom option processing.
|
|
362
|
+
// No longer documented in README, but still present for backwards compatibility.
|
|
382
363
|
var regex = fn;
|
|
383
364
|
fn = function(val, def) {
|
|
384
365
|
var m = regex.exec(val);
|
|
@@ -390,10 +371,13 @@ Command.prototype.option = function(flags, description, fn, defaultValue) {
|
|
|
390
371
|
}
|
|
391
372
|
}
|
|
392
373
|
|
|
393
|
-
// preassign default value
|
|
394
|
-
if (
|
|
395
|
-
// when --no
|
|
396
|
-
if (
|
|
374
|
+
// preassign default value for --no-*, [optional], <required>, or plain flag if boolean value
|
|
375
|
+
if (option.negate || option.optional || option.required || typeof defaultValue === 'boolean') {
|
|
376
|
+
// when --no-foo we make sure default is true, unless a --foo option is already defined
|
|
377
|
+
if (option.negate) {
|
|
378
|
+
var opts = self.opts();
|
|
379
|
+
defaultValue = Object.prototype.hasOwnProperty.call(opts, name) ? opts[name] : true;
|
|
380
|
+
}
|
|
397
381
|
// preassign only if we have a default
|
|
398
382
|
if (defaultValue !== undefined) {
|
|
399
383
|
self[name] = defaultValue;
|
|
@@ -412,19 +396,19 @@ Command.prototype.option = function(flags, description, fn, defaultValue) {
|
|
|
412
396
|
val = fn(val, self[name] === undefined ? defaultValue : self[name]);
|
|
413
397
|
}
|
|
414
398
|
|
|
415
|
-
// unassigned or
|
|
399
|
+
// unassigned or boolean value
|
|
416
400
|
if (typeof self[name] === 'boolean' || typeof self[name] === 'undefined') {
|
|
417
|
-
// if no value,
|
|
401
|
+
// if no value, negate false, and we have a default, then use it!
|
|
418
402
|
if (val == null) {
|
|
419
|
-
self[name] = option.
|
|
420
|
-
?
|
|
421
|
-
:
|
|
403
|
+
self[name] = option.negate
|
|
404
|
+
? false
|
|
405
|
+
: defaultValue || true;
|
|
422
406
|
} else {
|
|
423
407
|
self[name] = val;
|
|
424
408
|
}
|
|
425
409
|
} else if (val !== null) {
|
|
426
410
|
// reassign
|
|
427
|
-
self[name] = val;
|
|
411
|
+
self[name] = option.negate ? false : val;
|
|
428
412
|
}
|
|
429
413
|
});
|
|
430
414
|
|
|
@@ -464,36 +448,58 @@ Command.prototype.parse = function(argv) {
|
|
|
464
448
|
// github-style sub-commands with no sub-command
|
|
465
449
|
if (this.executables && argv.length < 3 && !this.defaultExecutable) {
|
|
466
450
|
// this user needs help
|
|
467
|
-
argv.push(
|
|
451
|
+
argv.push(this._helpLongFlag);
|
|
468
452
|
}
|
|
469
453
|
|
|
470
454
|
// process argv
|
|
471
|
-
var
|
|
455
|
+
var normalized = this.normalize(argv.slice(2));
|
|
456
|
+
var parsed = this.parseOptions(normalized);
|
|
472
457
|
var args = this.args = parsed.args;
|
|
473
458
|
|
|
474
459
|
var result = this.parseArgs(this.args, parsed.unknown);
|
|
475
460
|
|
|
461
|
+
if (args[0] === 'help' && args.length === 1) this.help();
|
|
462
|
+
|
|
463
|
+
// <cmd> --help
|
|
464
|
+
if (args[0] === 'help') {
|
|
465
|
+
args[0] = args[1];
|
|
466
|
+
args[1] = this._helpLongFlag;
|
|
467
|
+
}
|
|
468
|
+
|
|
476
469
|
// executable sub-commands
|
|
470
|
+
// (Debugging note for future: args[0] is not right if an action has been called)
|
|
477
471
|
var name = result.args[0];
|
|
472
|
+
var subCommand = null;
|
|
478
473
|
|
|
479
|
-
|
|
480
|
-
// check alias of sub commands
|
|
474
|
+
// Look for subcommand
|
|
481
475
|
if (name) {
|
|
482
|
-
|
|
476
|
+
subCommand = this.commands.find(function(command) {
|
|
477
|
+
return command._name === name;
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Look for alias
|
|
482
|
+
if (!subCommand && name) {
|
|
483
|
+
subCommand = this.commands.find(function(command) {
|
|
483
484
|
return command.alias() === name;
|
|
484
|
-
})
|
|
485
|
+
});
|
|
486
|
+
if (subCommand) {
|
|
487
|
+
name = subCommand._name;
|
|
488
|
+
args[0] = name;
|
|
489
|
+
}
|
|
485
490
|
}
|
|
486
491
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
492
|
+
// Look for default subcommand
|
|
493
|
+
if (!subCommand && this.defaultExecutable) {
|
|
494
|
+
name = this.defaultExecutable;
|
|
495
|
+
args.unshift(name);
|
|
496
|
+
subCommand = this.commands.find(function(command) {
|
|
497
|
+
return command._name === name;
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (this._execs.has(name)) {
|
|
502
|
+
return this.executeSubCommand(argv, args, parsed.unknown, subCommand ? subCommand._executableFile : undefined);
|
|
497
503
|
}
|
|
498
504
|
|
|
499
505
|
return result;
|
|
@@ -505,31 +511,33 @@ Command.prototype.parse = function(argv) {
|
|
|
505
511
|
* @param {Array} argv
|
|
506
512
|
* @param {Array} args
|
|
507
513
|
* @param {Array} unknown
|
|
514
|
+
* @param {String} specifySubcommand
|
|
508
515
|
* @api private
|
|
509
516
|
*/
|
|
510
517
|
|
|
511
|
-
Command.prototype.executeSubCommand = function(argv, args, unknown) {
|
|
518
|
+
Command.prototype.executeSubCommand = function(argv, args, unknown, executableFile) {
|
|
512
519
|
args = args.concat(unknown);
|
|
513
520
|
|
|
514
521
|
if (!args.length) this.help();
|
|
515
|
-
if (args[0] === 'help' && args.length === 1) this.help();
|
|
516
522
|
|
|
517
|
-
//
|
|
518
|
-
if (args[0] === 'help') {
|
|
519
|
-
args[0] = args[1];
|
|
520
|
-
args[1] = '--help';
|
|
521
|
-
}
|
|
523
|
+
var isExplicitJS = false; // Whether to use node to launch "executable"
|
|
522
524
|
|
|
523
525
|
// executable
|
|
524
|
-
var
|
|
525
|
-
// name of the subcommand,
|
|
526
|
-
var bin = basename(
|
|
526
|
+
var pm = argv[1];
|
|
527
|
+
// name of the subcommand, like `pm-install`
|
|
528
|
+
var bin = basename(pm, path.extname(pm)) + '-' + args[0];
|
|
529
|
+
if (executableFile != null) {
|
|
530
|
+
bin = executableFile;
|
|
531
|
+
// Check for same extensions as we scan for below so get consistent launch behaviour.
|
|
532
|
+
var executableExt = path.extname(executableFile);
|
|
533
|
+
isExplicitJS = executableExt === '.js' || executableExt === '.ts' || executableExt === '.mjs';
|
|
534
|
+
}
|
|
527
535
|
|
|
528
536
|
// In case of globally installed, get the base dir where executable
|
|
529
537
|
// subcommand file should be located at
|
|
530
538
|
var baseDir;
|
|
531
539
|
|
|
532
|
-
var resolvedLink = fs.realpathSync(
|
|
540
|
+
var resolvedLink = fs.realpathSync(pm);
|
|
533
541
|
|
|
534
542
|
baseDir = dirname(resolvedLink);
|
|
535
543
|
|
|
@@ -537,13 +545,15 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
|
|
|
537
545
|
var localBin = path.join(baseDir, bin);
|
|
538
546
|
|
|
539
547
|
// whether bin file is a js script with explicit `.js` or `.ts` extension
|
|
540
|
-
var isExplicitJS = false;
|
|
541
548
|
if (exists(localBin + '.js')) {
|
|
542
549
|
bin = localBin + '.js';
|
|
543
550
|
isExplicitJS = true;
|
|
544
551
|
} else if (exists(localBin + '.ts')) {
|
|
545
552
|
bin = localBin + '.ts';
|
|
546
553
|
isExplicitJS = true;
|
|
554
|
+
} else if (exists(localBin + '.mjs')) {
|
|
555
|
+
bin = localBin + '.mjs';
|
|
556
|
+
isExplicitJS = true;
|
|
547
557
|
} else if (exists(localBin)) {
|
|
548
558
|
bin = localBin;
|
|
549
559
|
}
|
|
@@ -555,7 +565,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
|
|
|
555
565
|
if (isExplicitJS) {
|
|
556
566
|
args.unshift(bin);
|
|
557
567
|
// add executable arguments to spawn
|
|
558
|
-
args = (process.execArgv
|
|
568
|
+
args = incrementNodeInspectorPort(process.execArgv).concat(args);
|
|
559
569
|
|
|
560
570
|
proc = spawn(process.argv[0], args, { stdio: 'inherit', customFds: [0, 1, 2] });
|
|
561
571
|
} else {
|
|
@@ -563,6 +573,8 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
|
|
|
563
573
|
}
|
|
564
574
|
} else {
|
|
565
575
|
args.unshift(bin);
|
|
576
|
+
// add executable arguments to spawn
|
|
577
|
+
args = incrementNodeInspectorPort(process.execArgv).concat(args);
|
|
566
578
|
proc = spawn(process.execPath, args, { stdio: 'inherit' });
|
|
567
579
|
}
|
|
568
580
|
|
|
@@ -602,7 +614,9 @@ Command.prototype.normalize = function(args) {
|
|
|
602
614
|
var ret = [],
|
|
603
615
|
arg,
|
|
604
616
|
lastOpt,
|
|
605
|
-
index
|
|
617
|
+
index,
|
|
618
|
+
short,
|
|
619
|
+
opt;
|
|
606
620
|
|
|
607
621
|
for (var i = 0, len = args.length; i < len; ++i) {
|
|
608
622
|
arg = args[i];
|
|
@@ -616,10 +630,17 @@ Command.prototype.normalize = function(args) {
|
|
|
616
630
|
break;
|
|
617
631
|
} else if (lastOpt && lastOpt.required) {
|
|
618
632
|
ret.push(arg);
|
|
619
|
-
} else if (arg.length >
|
|
620
|
-
arg.slice(
|
|
621
|
-
|
|
622
|
-
|
|
633
|
+
} else if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
|
|
634
|
+
short = arg.slice(0, 2);
|
|
635
|
+
opt = this.optionFor(short);
|
|
636
|
+
if (opt && (opt.required || opt.optional)) {
|
|
637
|
+
ret.push(short);
|
|
638
|
+
ret.push(arg.slice(2));
|
|
639
|
+
} else {
|
|
640
|
+
arg.slice(1).split('').forEach(function(c) {
|
|
641
|
+
ret.push('-' + c);
|
|
642
|
+
});
|
|
643
|
+
}
|
|
623
644
|
} else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
|
|
624
645
|
ret.push(arg.slice(0, index), arg.slice(index + 1));
|
|
625
646
|
} else {
|
|
@@ -737,7 +758,7 @@ Command.prototype.parseOptions = function(argv) {
|
|
|
737
758
|
++i;
|
|
738
759
|
}
|
|
739
760
|
this.emit('option:' + option.name(), arg);
|
|
740
|
-
//
|
|
761
|
+
// flag
|
|
741
762
|
} else {
|
|
742
763
|
this.emit('option:' + option.name());
|
|
743
764
|
}
|
|
@@ -751,7 +772,7 @@ Command.prototype.parseOptions = function(argv) {
|
|
|
751
772
|
// If the next argument looks like it might be
|
|
752
773
|
// an argument for this option, we pass it on.
|
|
753
774
|
// If it isn't, then it'll simply be ignored
|
|
754
|
-
if ((i + 1) < argv.length && argv[i + 1][0] !== '-') {
|
|
775
|
+
if ((i + 1) < argv.length && (argv[i + 1][0] !== '-' || argv[i + 1] === '-')) {
|
|
755
776
|
unknownOptions.push(argv[++i]);
|
|
756
777
|
}
|
|
757
778
|
continue;
|
|
@@ -789,7 +810,7 @@ Command.prototype.opts = function() {
|
|
|
789
810
|
*/
|
|
790
811
|
|
|
791
812
|
Command.prototype.missingArgument = function(name) {
|
|
792
|
-
console.error("error: missing required argument
|
|
813
|
+
console.error("error: missing required argument '%s'", name);
|
|
793
814
|
process.exit(1);
|
|
794
815
|
};
|
|
795
816
|
|
|
@@ -803,9 +824,9 @@ Command.prototype.missingArgument = function(name) {
|
|
|
803
824
|
|
|
804
825
|
Command.prototype.optionMissingArgument = function(option, flag) {
|
|
805
826
|
if (flag) {
|
|
806
|
-
console.error("error: option
|
|
827
|
+
console.error("error: option '%s' argument missing, got '%s'", option.flags, flag);
|
|
807
828
|
} else {
|
|
808
|
-
console.error("error: option
|
|
829
|
+
console.error("error: option '%s' argument missing", option.flags);
|
|
809
830
|
}
|
|
810
831
|
process.exit(1);
|
|
811
832
|
};
|
|
@@ -819,7 +840,7 @@ Command.prototype.optionMissingArgument = function(option, flag) {
|
|
|
819
840
|
|
|
820
841
|
Command.prototype.unknownOption = function(flag) {
|
|
821
842
|
if (this._allowUnknownOption) return;
|
|
822
|
-
console.error("error: unknown option
|
|
843
|
+
console.error("error: unknown option '%s'", flag);
|
|
823
844
|
process.exit(1);
|
|
824
845
|
};
|
|
825
846
|
|
|
@@ -831,7 +852,7 @@ Command.prototype.unknownOption = function(flag) {
|
|
|
831
852
|
*/
|
|
832
853
|
|
|
833
854
|
Command.prototype.variadicArgNotLast = function(name) {
|
|
834
|
-
console.error("error: variadic arguments must be last
|
|
855
|
+
console.error("error: variadic arguments must be last '%s'", name);
|
|
835
856
|
process.exit(1);
|
|
836
857
|
};
|
|
837
858
|
|
|
@@ -841,17 +862,21 @@ Command.prototype.variadicArgNotLast = function(name) {
|
|
|
841
862
|
* This method auto-registers the "-V, --version" flag
|
|
842
863
|
* which will print the version number when passed.
|
|
843
864
|
*
|
|
865
|
+
* You can optionally supply the flags and description to override the defaults.
|
|
866
|
+
*
|
|
844
867
|
* @param {String} str
|
|
845
868
|
* @param {String} [flags]
|
|
869
|
+
* @param {String} [description]
|
|
846
870
|
* @return {Command} for chaining
|
|
847
871
|
* @api public
|
|
848
872
|
*/
|
|
849
873
|
|
|
850
|
-
Command.prototype.version = function(str, flags) {
|
|
874
|
+
Command.prototype.version = function(str, flags, description) {
|
|
851
875
|
if (arguments.length === 0) return this._version;
|
|
852
876
|
this._version = str;
|
|
853
877
|
flags = flags || '-V, --version';
|
|
854
|
-
|
|
878
|
+
description = description || 'output the version number';
|
|
879
|
+
var versionOption = new Option(flags, description);
|
|
855
880
|
this._versionOptionName = versionOption.long.substr(2) || 'version';
|
|
856
881
|
this.options.push(versionOption);
|
|
857
882
|
this.on('option:' + this._versionOptionName, function() {
|
|
@@ -985,8 +1010,9 @@ Command.prototype.largestCommandLength = function() {
|
|
|
985
1010
|
Command.prototype.largestOptionLength = function() {
|
|
986
1011
|
var options = [].slice.call(this.options);
|
|
987
1012
|
options.push({
|
|
988
|
-
flags:
|
|
1013
|
+
flags: this._helpFlags
|
|
989
1014
|
});
|
|
1015
|
+
|
|
990
1016
|
return options.reduce(function(max, option) {
|
|
991
1017
|
return Math.max(max, option.flags.length);
|
|
992
1018
|
}, 0);
|
|
@@ -1042,8 +1068,8 @@ Command.prototype.optionHelp = function() {
|
|
|
1042
1068
|
// Append the help information
|
|
1043
1069
|
return this.options.map(function(option) {
|
|
1044
1070
|
return pad(option.flags, width) + ' ' + option.description +
|
|
1045
|
-
((option.
|
|
1046
|
-
}).concat([pad(
|
|
1071
|
+
((!option.negate && option.defaultValue !== undefined) ? ' (default: ' + JSON.stringify(option.defaultValue) + ')' : '');
|
|
1072
|
+
}).concat([pad(this._helpFlags, width) + ' ' + this._helpDescription])
|
|
1047
1073
|
.join('\n');
|
|
1048
1074
|
};
|
|
1049
1075
|
|
|
@@ -1101,8 +1127,12 @@ Command.prototype.helpInformation = function() {
|
|
|
1101
1127
|
if (this._alias) {
|
|
1102
1128
|
cmdName = cmdName + '|' + this._alias;
|
|
1103
1129
|
}
|
|
1130
|
+
var parentCmdNames = '';
|
|
1131
|
+
for (var parentCmd = this.parent; parentCmd; parentCmd = parentCmd.parent) {
|
|
1132
|
+
parentCmdNames = parentCmd.name() + ' ' + parentCmdNames;
|
|
1133
|
+
}
|
|
1104
1134
|
var usage = [
|
|
1105
|
-
'Usage: ' + cmdName + ' ' + this.usage(),
|
|
1135
|
+
'Usage: ' + parentCmdNames + cmdName + ' ' + this.usage(),
|
|
1106
1136
|
''
|
|
1107
1137
|
];
|
|
1108
1138
|
|
|
@@ -1124,7 +1154,10 @@ Command.prototype.helpInformation = function() {
|
|
|
1124
1154
|
};
|
|
1125
1155
|
|
|
1126
1156
|
/**
|
|
1127
|
-
* Output help information for this command
|
|
1157
|
+
* Output help information for this command.
|
|
1158
|
+
*
|
|
1159
|
+
* When listener(s) are available for the helpLongFlag
|
|
1160
|
+
* those callbacks are invoked.
|
|
1128
1161
|
*
|
|
1129
1162
|
* @api public
|
|
1130
1163
|
*/
|
|
@@ -1135,13 +1168,41 @@ Command.prototype.outputHelp = function(cb) {
|
|
|
1135
1168
|
return passthru;
|
|
1136
1169
|
};
|
|
1137
1170
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1171
|
+
const cbOutput = cb(this.helpInformation());
|
|
1172
|
+
if (typeof cbOutput !== 'string' && !Buffer.isBuffer(cbOutput)) {
|
|
1173
|
+
throw new Error('outputHelp callback must return a string or a Buffer');
|
|
1174
|
+
}
|
|
1175
|
+
process.stdout.write(cbOutput);
|
|
1176
|
+
this.emit(this._helpLongFlag);
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* You can pass in flags and a description to override the help
|
|
1181
|
+
* flags and help description for your command.
|
|
1182
|
+
*
|
|
1183
|
+
* @param {String} [flags]
|
|
1184
|
+
* @param {String} [description]
|
|
1185
|
+
* @return {Command}
|
|
1186
|
+
* @api public
|
|
1187
|
+
*/
|
|
1188
|
+
|
|
1189
|
+
Command.prototype.helpOption = function(flags, description) {
|
|
1190
|
+
this._helpFlags = flags || this._helpFlags;
|
|
1191
|
+
this._helpDescription = description || this._helpDescription;
|
|
1192
|
+
|
|
1193
|
+
var splitFlags = this._helpFlags.split(/[ ,|]+/);
|
|
1194
|
+
|
|
1195
|
+
if (splitFlags.length > 1) this._helpShortFlag = splitFlags.shift();
|
|
1196
|
+
|
|
1197
|
+
this._helpLongFlag = splitFlags.shift();
|
|
1198
|
+
|
|
1199
|
+
return this;
|
|
1140
1200
|
};
|
|
1141
1201
|
|
|
1142
1202
|
/**
|
|
1143
1203
|
* Output help information and exit.
|
|
1144
1204
|
*
|
|
1205
|
+
* @param {Function} [cb]
|
|
1145
1206
|
* @api public
|
|
1146
1207
|
*/
|
|
1147
1208
|
|
|
@@ -1188,8 +1249,9 @@ function pad(str, width) {
|
|
|
1188
1249
|
|
|
1189
1250
|
function outputHelpIfNecessary(cmd, options) {
|
|
1190
1251
|
options = options || [];
|
|
1252
|
+
|
|
1191
1253
|
for (var i = 0; i < options.length; i++) {
|
|
1192
|
-
if (options[i] ===
|
|
1254
|
+
if (options[i] === cmd._helpLongFlag || options[i] === cmd._helpShortFlag) {
|
|
1193
1255
|
cmd.outputHelp();
|
|
1194
1256
|
process.exit(0);
|
|
1195
1257
|
}
|
|
@@ -1197,7 +1259,7 @@ function outputHelpIfNecessary(cmd, options) {
|
|
|
1197
1259
|
}
|
|
1198
1260
|
|
|
1199
1261
|
/**
|
|
1200
|
-
* Takes an argument
|
|
1262
|
+
* Takes an argument and returns its human readable equivalent for help usage.
|
|
1201
1263
|
*
|
|
1202
1264
|
* @param {Object} arg
|
|
1203
1265
|
* @return {String}
|
|
@@ -1222,3 +1284,50 @@ function exists(file) {
|
|
|
1222
1284
|
return false;
|
|
1223
1285
|
}
|
|
1224
1286
|
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Scan arguments and increment port number for inspect calls (to avoid conflicts when spawning new command).
|
|
1290
|
+
*
|
|
1291
|
+
* @param {string[]} args - array of arguments from node.execArgv
|
|
1292
|
+
* @returns {string[]}
|
|
1293
|
+
* @api private
|
|
1294
|
+
*/
|
|
1295
|
+
|
|
1296
|
+
function incrementNodeInspectorPort(args) {
|
|
1297
|
+
// Testing for these options:
|
|
1298
|
+
// --inspect[=[host:]port]
|
|
1299
|
+
// --inspect-brk[=[host:]port]
|
|
1300
|
+
// --inspect-port=[host:]port
|
|
1301
|
+
return args.map((arg) => {
|
|
1302
|
+
var result = arg;
|
|
1303
|
+
if (arg.indexOf('--inspect') === 0) {
|
|
1304
|
+
var debugOption;
|
|
1305
|
+
var debugHost = '127.0.0.1';
|
|
1306
|
+
var debugPort = '9229';
|
|
1307
|
+
var match;
|
|
1308
|
+
if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
|
|
1309
|
+
// e.g. --inspect
|
|
1310
|
+
debugOption = match[1];
|
|
1311
|
+
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
|
|
1312
|
+
debugOption = match[1];
|
|
1313
|
+
if (/^\d+$/.test(match[3])) {
|
|
1314
|
+
// e.g. --inspect=1234
|
|
1315
|
+
debugPort = match[3];
|
|
1316
|
+
} else {
|
|
1317
|
+
// e.g. --inspect=localhost
|
|
1318
|
+
debugHost = match[3];
|
|
1319
|
+
}
|
|
1320
|
+
} else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
|
|
1321
|
+
// e.g. --inspect=localhost:1234
|
|
1322
|
+
debugOption = match[1];
|
|
1323
|
+
debugHost = match[3];
|
|
1324
|
+
debugPort = match[4];
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
if (debugOption && debugPort !== '0') {
|
|
1328
|
+
result = `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return result;
|
|
1332
|
+
});
|
|
1333
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commander",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "the complete solution for node.js command-line programs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"commander",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"eslint": "^6.4.0",
|
|
31
31
|
"should": "^13.2.3",
|
|
32
32
|
"sinon": "^7.5.0",
|
|
33
|
-
"standard": "^
|
|
33
|
+
"standard": "^13.1.0",
|
|
34
34
|
"ts-node": "^8.4.1",
|
|
35
35
|
"typescript": "^3.6.3"
|
|
36
36
|
},
|