commander 2.7.0 → 2.9.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/History.md +28 -1
- package/Readme.md +47 -7
- package/index.js +98 -39
- package/package.json +3 -2
package/History.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
|
|
2
|
-
2.
|
|
2
|
+
2.9.0 / 2015-10-13
|
|
3
|
+
==================
|
|
4
|
+
|
|
5
|
+
* Add option `isDefault` to set default subcommand #415 @Qix-
|
|
6
|
+
* Add callback to allow filtering or post-processing of help text #434 @djulien
|
|
7
|
+
* Fix `undefined` text in help information close #414 #416 @zhiyelee
|
|
8
|
+
|
|
9
|
+
2.8.1 / 2015-04-22
|
|
10
|
+
==================
|
|
11
|
+
|
|
12
|
+
* Back out `support multiline description` Close #396 #397
|
|
13
|
+
|
|
14
|
+
2.8.0 / 2015-04-07
|
|
15
|
+
==================
|
|
16
|
+
|
|
17
|
+
* Add `process.execArg` support, execution args like `--harmony` will be passed to sub-commands #387 @DigitalIO @zhiyelee
|
|
18
|
+
* Fix bug in Git-style sub-commands #372 @zhiyelee
|
|
19
|
+
* Allow commands to be hidden from help #383 @tonylukasavage
|
|
20
|
+
* When git-style sub-commands are in use, yet none are called, display help #382 @claylo
|
|
21
|
+
* Add ability to specify arguments syntax for top-level command #258 @rrthomas
|
|
22
|
+
* Support multiline descriptions #208 @zxqfox
|
|
23
|
+
|
|
24
|
+
2.7.1 / 2015-03-11
|
|
25
|
+
==================
|
|
26
|
+
|
|
27
|
+
* Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367.
|
|
28
|
+
|
|
29
|
+
2.7.0 / 2015-03-09
|
|
3
30
|
==================
|
|
4
31
|
|
|
5
32
|
* Fix git-style bug when installed globally. Close #335 #349 @zhiyelee
|
package/Readme.md
CHANGED
|
@@ -31,14 +31,14 @@ program
|
|
|
31
31
|
.version('0.0.1')
|
|
32
32
|
.option('-p, --peppers', 'Add peppers')
|
|
33
33
|
.option('-P, --pineapple', 'Add pineapple')
|
|
34
|
-
.option('-b, --bbq', 'Add bbq sauce')
|
|
34
|
+
.option('-b, --bbq-sauce', 'Add bbq sauce')
|
|
35
35
|
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
|
|
36
36
|
.parse(process.argv);
|
|
37
37
|
|
|
38
38
|
console.log('you ordered a pizza with:');
|
|
39
39
|
if (program.peppers) console.log(' - peppers');
|
|
40
40
|
if (program.pineapple) console.log(' - pineapple');
|
|
41
|
-
if (program.
|
|
41
|
+
if (program.bbqSauce) console.log(' - bbq');
|
|
42
42
|
console.log(' - %s cheese', program.cheese);
|
|
43
43
|
```
|
|
44
44
|
|
|
@@ -132,6 +132,31 @@ program.parse(process.argv);
|
|
|
132
132
|
An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed
|
|
133
133
|
to your action as demonstrated above.
|
|
134
134
|
|
|
135
|
+
## Specify the argument syntax
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
#!/usr/bin/env node
|
|
139
|
+
|
|
140
|
+
var program = require('../');
|
|
141
|
+
|
|
142
|
+
program
|
|
143
|
+
.version('0.0.1')
|
|
144
|
+
.arguments('<cmd> [env]')
|
|
145
|
+
.action(function (cmd, env) {
|
|
146
|
+
cmdValue = cmd;
|
|
147
|
+
envValue = env;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
program.parse(process.argv);
|
|
151
|
+
|
|
152
|
+
if (typeof cmdValue === 'undefined') {
|
|
153
|
+
console.error('no command given!');
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
console.log('command:', cmdValue);
|
|
157
|
+
console.log('environment:', envValue || "no environment given");
|
|
158
|
+
```
|
|
159
|
+
|
|
135
160
|
## Git-style sub-commands
|
|
136
161
|
|
|
137
162
|
```js
|
|
@@ -142,14 +167,22 @@ program
|
|
|
142
167
|
.version('0.0.1')
|
|
143
168
|
.command('install [name]', 'install one or more packages')
|
|
144
169
|
.command('search [query]', 'search with optional query')
|
|
145
|
-
.command('list', 'list packages installed')
|
|
170
|
+
.command('list', 'list packages installed', {isDefault: true})
|
|
146
171
|
.parse(process.argv);
|
|
147
172
|
```
|
|
148
173
|
|
|
149
174
|
When `.command()` is invoked with a description argument, no `.action(callback)` should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools.
|
|
150
175
|
The commander will try to search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-command`, like `pm-install`, `pm-search`.
|
|
151
176
|
|
|
152
|
-
|
|
177
|
+
Options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the option from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified.
|
|
178
|
+
|
|
179
|
+
If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
|
|
180
|
+
|
|
181
|
+
### `--harmony`
|
|
182
|
+
|
|
183
|
+
You can enable `--harmony` option in two ways:
|
|
184
|
+
* Use `#! /usr/bin/env node --harmony` in the sub-commands scripts. Note some os version don’t support this pattern.
|
|
185
|
+
* Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning sub-command process.
|
|
153
186
|
|
|
154
187
|
## Automated --help
|
|
155
188
|
|
|
@@ -235,14 +268,16 @@ Examples:
|
|
|
235
268
|
|
|
236
269
|
```
|
|
237
270
|
|
|
238
|
-
## .outputHelp()
|
|
271
|
+
## .outputHelp(cb)
|
|
239
272
|
|
|
240
273
|
Output help information without exiting.
|
|
274
|
+
Optional callback cb allows post-processing of help text before it is displayed.
|
|
241
275
|
|
|
242
276
|
If you want to display help by default (e.g. if no command was provided), you can use something like:
|
|
243
277
|
|
|
244
278
|
```js
|
|
245
279
|
var program = require('commander');
|
|
280
|
+
var colors = require('colors');
|
|
246
281
|
|
|
247
282
|
program
|
|
248
283
|
.version('0.0.1')
|
|
@@ -250,13 +285,18 @@ program
|
|
|
250
285
|
.parse(process.argv);
|
|
251
286
|
|
|
252
287
|
if (!process.argv.slice(2).length) {
|
|
253
|
-
program.outputHelp();
|
|
288
|
+
program.outputHelp(make_red);
|
|
254
289
|
}
|
|
290
|
+
|
|
291
|
+
function make_red(txt) {
|
|
292
|
+
return colors.red(txt); //display the help text in red on the console
|
|
293
|
+
}
|
|
255
294
|
```
|
|
256
295
|
|
|
257
|
-
## .help()
|
|
296
|
+
## .help(cb)
|
|
258
297
|
|
|
259
298
|
Output help information and exit immediately.
|
|
299
|
+
Optional callback cb allows post-processing of help text before it is displayed.
|
|
260
300
|
|
|
261
301
|
## Examples
|
|
262
302
|
|
package/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
/**
|
|
3
2
|
* Module dependencies.
|
|
4
3
|
*/
|
|
@@ -83,10 +82,10 @@ Option.prototype.is = function(arg) {
|
|
|
83
82
|
function Command(name) {
|
|
84
83
|
this.commands = [];
|
|
85
84
|
this.options = [];
|
|
86
|
-
this._execs =
|
|
85
|
+
this._execs = {};
|
|
87
86
|
this._allowUnknownOption = false;
|
|
88
87
|
this._args = [];
|
|
89
|
-
this._name = name;
|
|
88
|
+
this._name = name || '';
|
|
90
89
|
}
|
|
91
90
|
|
|
92
91
|
/**
|
|
@@ -156,7 +155,8 @@ Command.prototype.__proto__ = EventEmitter.prototype;
|
|
|
156
155
|
* @api public
|
|
157
156
|
*/
|
|
158
157
|
|
|
159
|
-
Command.prototype.command = function(name, desc) {
|
|
158
|
+
Command.prototype.command = function(name, desc, opts) {
|
|
159
|
+
opts = opts || {};
|
|
160
160
|
var args = name.split(/ +/);
|
|
161
161
|
var cmd = new Command(args.shift());
|
|
162
162
|
|
|
@@ -164,8 +164,10 @@ Command.prototype.command = function(name, desc) {
|
|
|
164
164
|
cmd.description(desc);
|
|
165
165
|
this.executables = true;
|
|
166
166
|
this._execs[cmd._name] = true;
|
|
167
|
+
if (opts.isDefault) this.defaultExecutable = cmd._name;
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
cmd._noHelp = !!opts.noHelp;
|
|
169
171
|
this.commands.push(cmd);
|
|
170
172
|
cmd.parseExpectedArgs(args);
|
|
171
173
|
cmd.parent = this;
|
|
@@ -174,6 +176,16 @@ Command.prototype.command = function(name, desc) {
|
|
|
174
176
|
return cmd;
|
|
175
177
|
};
|
|
176
178
|
|
|
179
|
+
/**
|
|
180
|
+
* Define argument syntax for the top-level command.
|
|
181
|
+
*
|
|
182
|
+
* @api public
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
Command.prototype.arguments = function (desc) {
|
|
186
|
+
return this.parseExpectedArgs(desc.split(/ +/));
|
|
187
|
+
};
|
|
188
|
+
|
|
177
189
|
/**
|
|
178
190
|
* Add an implicit `help [cmd]` subcommand
|
|
179
191
|
* which invokes `--help` for the given command.
|
|
@@ -288,8 +300,10 @@ Command.prototype.action = function(fn) {
|
|
|
288
300
|
|
|
289
301
|
fn.apply(self, args);
|
|
290
302
|
};
|
|
291
|
-
this.parent
|
|
292
|
-
|
|
303
|
+
var parent = this.parent || this;
|
|
304
|
+
var name = parent === this ? '*' : this._name;
|
|
305
|
+
parent.on(name, listener);
|
|
306
|
+
if (this._alias) parent.on(this._alias, listener);
|
|
293
307
|
return this;
|
|
294
308
|
};
|
|
295
309
|
|
|
@@ -431,6 +445,12 @@ Command.prototype.parse = function(argv) {
|
|
|
431
445
|
// guess name
|
|
432
446
|
this._name = this._name || basename(argv[1], '.js');
|
|
433
447
|
|
|
448
|
+
// github-style sub-commands with no sub-command
|
|
449
|
+
if (this.executables && argv.length < 3 && !this.defaultExecutable) {
|
|
450
|
+
// this user needs help
|
|
451
|
+
argv.push('--help');
|
|
452
|
+
}
|
|
453
|
+
|
|
434
454
|
// process argv
|
|
435
455
|
var parsed = this.parseOptions(this.normalize(argv.slice(2)));
|
|
436
456
|
var args = this.args = parsed.args;
|
|
@@ -441,6 +461,10 @@ Command.prototype.parse = function(argv) {
|
|
|
441
461
|
var name = result.args[0];
|
|
442
462
|
if (this._execs[name] && typeof this._execs[name] != "function") {
|
|
443
463
|
return this.executeSubCommand(argv, args, parsed.unknown);
|
|
464
|
+
} else if (this.defaultExecutable) {
|
|
465
|
+
// use the default subcommand
|
|
466
|
+
args.unshift(name = this.defaultExecutable);
|
|
467
|
+
return this.executeSubCommand(argv, args, parsed.unknown);
|
|
444
468
|
}
|
|
445
469
|
|
|
446
470
|
return result;
|
|
@@ -469,30 +493,48 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
|
|
|
469
493
|
|
|
470
494
|
// executable
|
|
471
495
|
var f = argv[1];
|
|
472
|
-
|
|
496
|
+
// name of the subcommand, link `pm-install`
|
|
497
|
+
var bin = basename(f, '.js') + '-' + args[0];
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
// In case of globally installed, get the base dir where executable
|
|
501
|
+
// subcommand file should be located at
|
|
502
|
+
var baseDir
|
|
503
|
+
, link = readlink(f);
|
|
504
|
+
|
|
505
|
+
// when symbolink is relative path
|
|
473
506
|
if (link !== f && link.charAt(0) !== '/') {
|
|
474
507
|
link = path.join(dirname(f), link)
|
|
475
508
|
}
|
|
476
|
-
|
|
477
|
-
var bin = basename(f, '.js') + '-' + args[0];
|
|
509
|
+
baseDir = dirname(link);
|
|
478
510
|
|
|
479
511
|
// prefer local `./<bin>` to bin in the $PATH
|
|
480
|
-
var
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
512
|
+
var localBin = path.join(baseDir, bin);
|
|
513
|
+
|
|
514
|
+
// whether bin file is a js script with explicit `.js` extension
|
|
515
|
+
var isExplicitJS = false;
|
|
516
|
+
if (exists(localBin + '.js')) {
|
|
517
|
+
bin = localBin + '.js';
|
|
518
|
+
isExplicitJS = true;
|
|
519
|
+
} else if (exists(localBin)) {
|
|
520
|
+
bin = localBin;
|
|
521
|
+
}
|
|
487
522
|
|
|
488
|
-
// run it
|
|
489
523
|
args = args.slice(1);
|
|
490
524
|
|
|
491
525
|
var proc;
|
|
492
526
|
if (process.platform !== 'win32') {
|
|
493
|
-
|
|
527
|
+
if (isExplicitJS) {
|
|
528
|
+
args.unshift(localBin);
|
|
529
|
+
// add executable arguments to spawn
|
|
530
|
+
args = (process.execArgv || []).concat(args);
|
|
531
|
+
|
|
532
|
+
proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] });
|
|
533
|
+
} else {
|
|
534
|
+
proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] });
|
|
535
|
+
}
|
|
494
536
|
} else {
|
|
495
|
-
args.unshift(
|
|
537
|
+
args.unshift(localBin);
|
|
496
538
|
proc = spawn(process.execPath, args, { stdio: 'inherit'});
|
|
497
539
|
}
|
|
498
540
|
|
|
@@ -506,6 +548,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
|
|
|
506
548
|
process.exit(1);
|
|
507
549
|
});
|
|
508
550
|
|
|
551
|
+
// Store the reference to the child process
|
|
509
552
|
this.runningCommand = proc;
|
|
510
553
|
};
|
|
511
554
|
|
|
@@ -568,8 +611,8 @@ Command.prototype.parseArgs = function(args, unknown) {
|
|
|
568
611
|
|
|
569
612
|
if (args.length) {
|
|
570
613
|
name = args[0];
|
|
571
|
-
if (this.listeners(
|
|
572
|
-
this.emit(
|
|
614
|
+
if (this.listeners(name).length) {
|
|
615
|
+
this.emit(args.shift(), args, unknown);
|
|
573
616
|
} else {
|
|
574
617
|
this.emit('*', args);
|
|
575
618
|
}
|
|
@@ -793,7 +836,7 @@ Command.prototype.version = function(str, flags) {
|
|
|
793
836
|
*/
|
|
794
837
|
|
|
795
838
|
Command.prototype.description = function(str) {
|
|
796
|
-
if (0
|
|
839
|
+
if (0 === arguments.length) return this._description;
|
|
797
840
|
this._description = str;
|
|
798
841
|
return this;
|
|
799
842
|
};
|
|
@@ -872,10 +915,10 @@ Command.prototype.optionHelp = function() {
|
|
|
872
915
|
|
|
873
916
|
// Prepend the help information
|
|
874
917
|
return [pad('-h, --help', width) + ' ' + 'output usage information']
|
|
875
|
-
|
|
876
|
-
|
|
918
|
+
.concat(this.options.map(function(option) {
|
|
919
|
+
return pad(option.flags, width) + ' ' + option.description;
|
|
877
920
|
}))
|
|
878
|
-
|
|
921
|
+
.join('\n');
|
|
879
922
|
};
|
|
880
923
|
|
|
881
924
|
/**
|
|
@@ -888,21 +931,19 @@ Command.prototype.optionHelp = function() {
|
|
|
888
931
|
Command.prototype.commandHelp = function() {
|
|
889
932
|
if (!this.commands.length) return '';
|
|
890
933
|
|
|
891
|
-
var commands = this.commands.
|
|
934
|
+
var commands = this.commands.filter(function(cmd) {
|
|
935
|
+
return !cmd._noHelp;
|
|
936
|
+
}).map(function(cmd) {
|
|
892
937
|
var args = cmd._args.map(function(arg) {
|
|
893
938
|
return humanReadableArgName(arg);
|
|
894
939
|
}).join(' ');
|
|
895
940
|
|
|
896
941
|
return [
|
|
897
942
|
cmd._name
|
|
898
|
-
+ (cmd._alias
|
|
899
|
-
|
|
900
|
-
: '')
|
|
901
|
-
+ (cmd.options.length
|
|
902
|
-
? ' [options]'
|
|
903
|
-
: '')
|
|
943
|
+
+ (cmd._alias ? '|' + cmd._alias : '')
|
|
944
|
+
+ (cmd.options.length ? ' [options]' : '')
|
|
904
945
|
+ ' ' + args
|
|
905
|
-
|
|
946
|
+
, cmd.description()
|
|
906
947
|
];
|
|
907
948
|
});
|
|
908
949
|
|
|
@@ -911,11 +952,12 @@ Command.prototype.commandHelp = function() {
|
|
|
911
952
|
}, 0);
|
|
912
953
|
|
|
913
954
|
return [
|
|
914
|
-
|
|
955
|
+
''
|
|
915
956
|
, ' Commands:'
|
|
916
957
|
, ''
|
|
917
958
|
, commands.map(function(cmd) {
|
|
918
|
-
|
|
959
|
+
var desc = cmd[1] ? ' ' + cmd[1] : '';
|
|
960
|
+
return pad(cmd[0], width) + desc;
|
|
919
961
|
}).join('\n').replace(/^/gm, ' ')
|
|
920
962
|
, ''
|
|
921
963
|
].join('\n');
|
|
@@ -972,8 +1014,13 @@ Command.prototype.helpInformation = function() {
|
|
|
972
1014
|
* @api public
|
|
973
1015
|
*/
|
|
974
1016
|
|
|
975
|
-
Command.prototype.outputHelp = function() {
|
|
976
|
-
|
|
1017
|
+
Command.prototype.outputHelp = function(cb) {
|
|
1018
|
+
if (!cb) {
|
|
1019
|
+
cb = function(passthru) {
|
|
1020
|
+
return passthru;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
process.stdout.write(cb(this.helpInformation()));
|
|
977
1024
|
this.emit('--help');
|
|
978
1025
|
};
|
|
979
1026
|
|
|
@@ -983,8 +1030,8 @@ Command.prototype.outputHelp = function() {
|
|
|
983
1030
|
* @api public
|
|
984
1031
|
*/
|
|
985
1032
|
|
|
986
|
-
Command.prototype.help = function() {
|
|
987
|
-
this.outputHelp();
|
|
1033
|
+
Command.prototype.help = function(cb) {
|
|
1034
|
+
this.outputHelp(cb);
|
|
988
1035
|
process.exit();
|
|
989
1036
|
};
|
|
990
1037
|
|
|
@@ -1049,3 +1096,15 @@ function humanReadableArgName(arg) {
|
|
|
1049
1096
|
? '<' + nameOutput + '>'
|
|
1050
1097
|
: '[' + nameOutput + ']'
|
|
1051
1098
|
}
|
|
1099
|
+
|
|
1100
|
+
// for versions before node v0.8 when there weren't `fs.existsSync`
|
|
1101
|
+
function exists(file) {
|
|
1102
|
+
try {
|
|
1103
|
+
if (fs.statSync(file).isFile()) {
|
|
1104
|
+
return true;
|
|
1105
|
+
}
|
|
1106
|
+
} catch (e) {
|
|
1107
|
+
return false;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "commander",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "the complete solution for node.js command-line programs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"command",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"url": "https://github.com/tj/commander.js.git"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"should": ">= 0.0.1"
|
|
17
|
+
"should": ">= 0.0.1",
|
|
18
|
+
"sinon": ">=1.17.1"
|
|
18
19
|
},
|
|
19
20
|
"scripts": {
|
|
20
21
|
"test": "make test"
|