commander 2.2.0 → 2.5.1

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.
Files changed (3) hide show
  1. package/Readme.md +61 -13
  2. package/index.js +221 -88
  3. package/package.json +4 -3
package/Readme.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # Commander.js
2
2
 
3
- The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).
3
+ [![Build Status](https://api.travis-ci.org/tj/commander.js.svg)](http://travis-ci.org/tj/commander.js)
4
+ [![NPM Version](http://img.shields.io/npm/v/commander.svg?style=flat)](https://www.npmjs.org/package/commander)
5
+ [![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://www.npmjs.org/package/commander)
6
+
7
+ The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/tj/commander).
8
+ API documentation: [http://tj.github.com/commander.js/](http://tj.github.com/commander.js/)
4
9
 
5
- [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)
6
10
 
7
11
  ## Installation
8
12
 
@@ -38,6 +42,55 @@ console.log(' - %s cheese', program.cheese);
38
42
 
39
43
  Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
40
44
 
45
+ ## Variadic arguments
46
+
47
+ The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to
48
+ append `...` to the argument name. Here is an example:
49
+
50
+ ```js
51
+ #!/usr/bin/env node
52
+
53
+ /**
54
+ * Module dependencies.
55
+ */
56
+
57
+ var program = require('commander');
58
+
59
+ program
60
+ .version('0.0.1')
61
+ .command('rmdir <dir> [otherDirs...]')
62
+ .action(function (dir, otherDirs) {
63
+ console.log('rmdir %s', dir);
64
+ if (otherDirs) {
65
+ otherDirs.forEach(function (oDir) {
66
+ console.log('rmdir %s', oDir);
67
+ });
68
+ }
69
+ });
70
+
71
+ program.parse(process.argv);
72
+ ```
73
+
74
+ An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed
75
+ to your action as demonstrated above.
76
+
77
+ ## Git-style sub-commands
78
+
79
+ ```js
80
+ // file: ./examples/pm
81
+ var program = require('..');
82
+
83
+ program
84
+ .version('0.0.1')
85
+ .command('install [name]', 'install one or more packages')
86
+ .command('search [query]', 'search with optional query')
87
+ .command('list', 'list packages installed')
88
+ .parse(process.argv);
89
+ ```
90
+
91
+ 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.
92
+ The commander will try to find the executable script in __current directory__ with the name `scriptBasename-subcommand`, like `pm-install`, `pm-search`.
93
+
41
94
  ## Automated --help
42
95
 
43
96
  The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
@@ -86,7 +139,7 @@ program
86
139
  .option('-r, --range <a>..<b>', 'A range', range)
87
140
  .option('-l, --list <items>', 'A list', list)
88
141
  .option('-o, --optional [value]', 'An optional value')
89
- .option('-c, --collect [value]', 'A repeatable value', [])
142
+ .option('-c, --collect [value]', 'A repeatable value', collect, [])
90
143
  .option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
91
144
  .parse(process.argv);
92
145
 
@@ -117,11 +170,7 @@ console.log(' args: %j', program.args);
117
170
  * Module dependencies.
118
171
  */
119
172
 
120
- var program = require('../');
121
-
122
- function list(val) {
123
- return val.split(',').map(Number);
124
- }
173
+ var program = require('commander');
125
174
 
126
175
  program
127
176
  .version('0.0.1')
@@ -145,7 +194,7 @@ program.parse(process.argv);
145
194
  console.log('stuff');
146
195
  ```
147
196
 
148
- yielding the following help output:
197
+ Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run:
149
198
 
150
199
  ```
151
200
 
@@ -176,13 +225,12 @@ Examples:
176
225
 
177
226
  ## Links
178
227
 
179
- - [API documentation](http://visionmedia.github.com/commander.js/)
180
228
  - [ascii tables](https://github.com/LearnBoost/cli-table)
181
- - [progress bars](https://github.com/visionmedia/node-progress)
229
+ - [progress bars](https://github.com/tj/node-progress)
182
230
  - [more progress bars](https://github.com/substack/node-multimeter)
183
- - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)
231
+ - [examples](https://github.com/tj/commander.js/tree/master/examples)
184
232
 
185
- ## License
233
+ ## License
186
234
 
187
235
  (The MIT License)
188
236
 
package/index.js CHANGED
@@ -5,8 +5,6 @@
5
5
 
6
6
  var EventEmitter = require('events').EventEmitter;
7
7
  var spawn = require('child_process').spawn;
8
- var fs = require('fs');
9
- var exists = fs.existsSync;
10
8
  var path = require('path');
11
9
  var dirname = path.dirname;
12
10
  var basename = path.basename;
@@ -15,7 +13,7 @@ var basename = path.basename;
15
13
  * Expose the root command.
16
14
  */
17
15
 
18
- exports = module.exports = new Command;
16
+ exports = module.exports = new Command();
19
17
 
20
18
  /**
21
19
  * Expose `Command`.
@@ -55,7 +53,7 @@ function Option(flags, description) {
55
53
  * @api private
56
54
  */
57
55
 
58
- Option.prototype.name = function(){
56
+ Option.prototype.name = function() {
59
57
  return this.long
60
58
  .replace('--', '')
61
59
  .replace('no-', '');
@@ -69,9 +67,8 @@ Option.prototype.name = function(){
69
67
  * @api private
70
68
  */
71
69
 
72
- Option.prototype.is = function(arg){
73
- return arg == this.short
74
- || arg == this.long;
70
+ Option.prototype.is = function(arg) {
71
+ return arg == this.short || arg == this.long;
75
72
  };
76
73
 
77
74
  /**
@@ -118,41 +115,58 @@ Command.prototype.__proto__ = EventEmitter.prototype;
118
115
  * program
119
116
  * .command('setup')
120
117
  * .description('run remote setup commands')
121
- * .action(function(){
118
+ * .action(function() {
122
119
  * console.log('setup');
123
120
  * });
124
121
  *
125
122
  * program
126
123
  * .command('exec <cmd>')
127
124
  * .description('run the given remote command')
128
- * .action(function(cmd){
125
+ * .action(function(cmd) {
129
126
  * console.log('exec "%s"', cmd);
130
127
  * });
131
128
  *
132
129
  * program
130
+ * .command('teardown <dir> [otherDirs...]')
131
+ * .description('run teardown commands')
132
+ * .action(function(dir, otherDirs) {
133
+ * console.log('dir "%s"', dir);
134
+ * if (otherDirs) {
135
+ * otherDirs.forEach(function (oDir) {
136
+ * console.log('dir "%s"', oDir);
137
+ * });
138
+ * }
139
+ * });
140
+ *
141
+ * program
133
142
  * .command('*')
134
143
  * .description('deploy the given env')
135
- * .action(function(env){
144
+ * .action(function(env) {
136
145
  * console.log('deploying "%s"', env);
137
146
  * });
138
147
  *
139
148
  * program.parse(process.argv);
140
149
  *
141
150
  * @param {String} name
142
- * @param {String} [desc]
151
+ * @param {String} [desc] for git-style sub-commands
143
152
  * @return {Command} the new command
144
153
  * @api public
145
154
  */
146
155
 
147
- Command.prototype.command = function(name, desc){
156
+ Command.prototype.command = function(name, desc) {
148
157
  var args = name.split(/ +/);
149
158
  var cmd = new Command(args.shift());
150
- if (desc) cmd.description(desc);
151
- if (desc) this.executables = true;
152
- if (desc) this._execs[cmd._name] = true;
159
+
160
+ if (desc) {
161
+ cmd.description(desc);
162
+ this.executables = true;
163
+ this._execs[cmd._name] = true;
164
+ }
165
+
153
166
  this.commands.push(cmd);
154
167
  cmd.parseExpectedArgs(args);
155
168
  cmd.parent = this;
169
+
156
170
  if (desc) return this;
157
171
  return cmd;
158
172
  };
@@ -178,18 +192,33 @@ Command.prototype.addImplicitHelpCommand = function() {
178
192
  * @api public
179
193
  */
180
194
 
181
- Command.prototype.parseExpectedArgs = function(args){
195
+ Command.prototype.parseExpectedArgs = function(args) {
182
196
  if (!args.length) return;
183
197
  var self = this;
184
- args.forEach(function(arg){
198
+ args.forEach(function(arg) {
199
+ var argDetails = {
200
+ required: false,
201
+ name: '',
202
+ variadic: false
203
+ };
204
+
185
205
  switch (arg[0]) {
186
206
  case '<':
187
- self._args.push({ required: true, name: arg.slice(1, -1) });
207
+ argDetails.required = true;
208
+ argDetails.name = arg.slice(1, -1);
188
209
  break;
189
210
  case '[':
190
- self._args.push({ required: false, name: arg.slice(1, -1) });
211
+ argDetails.name = arg.slice(1, -1);
191
212
  break;
192
213
  }
214
+
215
+ if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {
216
+ argDetails.variadic = true;
217
+ argDetails.name = argDetails.name.slice(0, -3);
218
+ }
219
+ if (argDetails.name) {
220
+ self._args.push(argDetails);
221
+ }
193
222
  });
194
223
  return this;
195
224
  };
@@ -202,7 +231,7 @@ Command.prototype.parseExpectedArgs = function(args){
202
231
  * program
203
232
  * .command('help')
204
233
  * .description('display verbose help')
205
- * .action(function(){
234
+ * .action(function() {
206
235
  * // output help here
207
236
  * });
208
237
  *
@@ -211,11 +240,13 @@ Command.prototype.parseExpectedArgs = function(args){
211
240
  * @api public
212
241
  */
213
242
 
214
- Command.prototype.action = function(fn){
243
+ Command.prototype.action = function(fn) {
215
244
  var self = this;
216
- this.parent.on(this._name, function(args, unknown){
245
+ var listener = function(args, unknown) {
217
246
  // Parse any so-far unknown options
247
+ args = args || [];
218
248
  unknown = unknown || [];
249
+
219
250
  var parsed = self.parseOptions(unknown);
220
251
 
221
252
  // Output help if necessary
@@ -231,9 +262,15 @@ Command.prototype.action = function(fn){
231
262
  // Leftover arguments need to be pushed back. Fixes issue #56
232
263
  if (parsed.args.length) args = parsed.args.concat(args);
233
264
 
234
- self._args.forEach(function(arg, i){
265
+ self._args.forEach(function(arg, i) {
235
266
  if (arg.required && null == args[i]) {
236
267
  self.missingArgument(arg.name);
268
+ } else if (arg.variadic) {
269
+ if (i !== self._args.length - 1) {
270
+ self.variadicArgNotLast(arg.name);
271
+ }
272
+
273
+ args[i] = args.splice(i);
237
274
  }
238
275
  });
239
276
 
@@ -246,8 +283,10 @@ Command.prototype.action = function(fn){
246
283
  args.push(self);
247
284
  }
248
285
 
249
- fn.apply(this, args);
250
- });
286
+ fn.apply(self, args);
287
+ };
288
+ this.parent.on(this._name, listener);
289
+ if (this._alias) this.parent.on(this._alias, listener);
251
290
  return this;
252
291
  };
253
292
 
@@ -272,7 +311,7 @@ Command.prototype.action = function(fn){
272
311
  * program.pepper
273
312
  * // => Boolean
274
313
  *
275
- * // simple boolean defaulting to false
314
+ * // simple boolean defaulting to true
276
315
  * program.option('-C, --no-cheese', 'remove cheese');
277
316
  *
278
317
  * program.cheese
@@ -280,7 +319,7 @@ Command.prototype.action = function(fn){
280
319
  *
281
320
  * --no-cheese
282
321
  * program.cheese
283
- * // => true
322
+ * // => false
284
323
  *
285
324
  * // required argument
286
325
  * program.option('-C, --chdir <path>', 'change the working directory');
@@ -300,14 +339,17 @@ Command.prototype.action = function(fn){
300
339
  * @api public
301
340
  */
302
341
 
303
- Command.prototype.option = function(flags, description, fn, defaultValue){
342
+ Command.prototype.option = function(flags, description, fn, defaultValue) {
304
343
  var self = this
305
344
  , option = new Option(flags, description)
306
345
  , oname = option.name()
307
346
  , name = camelcase(oname);
308
347
 
309
348
  // default as 3rd arg
310
- if ('function' != typeof fn) defaultValue = fn, fn = null;
349
+ if (typeof fn != 'function') {
350
+ defaultValue = fn;
351
+ fn = null;
352
+ }
311
353
 
312
354
  // preassign default value only for --no-*, [optional], or <required>
313
355
  if (false == option.bool || option.optional || option.required) {
@@ -322,9 +364,11 @@ Command.prototype.option = function(flags, description, fn, defaultValue){
322
364
 
323
365
  // when it's passed assign the value
324
366
  // and conditionally invoke the callback
325
- this.on(oname, function(val){
367
+ this.on(oname, function(val) {
326
368
  // coercion
327
- if (null !== val && fn) val = fn(val, undefined === self[name] ? defaultValue : self[name]);
369
+ if (null !== val && fn) val = fn(val, undefined === self[name]
370
+ ? defaultValue
371
+ : self[name]);
328
372
 
329
373
  // unassigned or bool
330
374
  if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
@@ -353,7 +397,7 @@ Command.prototype.option = function(flags, description, fn, defaultValue){
353
397
  * @api public
354
398
  */
355
399
 
356
- Command.prototype.parse = function(argv){
400
+ Command.prototype.parse = function(argv) {
357
401
  // implicit help
358
402
  if (this.executables) this.addImplicitHelpCommand();
359
403
 
@@ -371,7 +415,9 @@ Command.prototype.parse = function(argv){
371
415
 
372
416
  // executable sub-commands
373
417
  var name = result.args[0];
374
- if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown);
418
+ if (this._execs[name] && typeof this._execs[name] != "function") {
419
+ return this.executeSubCommand(argv, args, parsed.unknown);
420
+ }
375
421
 
376
422
  return result;
377
423
  };
@@ -408,7 +454,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
408
454
  args = args.slice(1);
409
455
  args.unshift(local);
410
456
  var proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] });
411
- proc.on('error', function(err){
457
+ proc.on('error', function(err) {
412
458
  if (err.code == "ENOENT") {
413
459
  console.error('\n %s(1) does not exist, try --help\n', bin);
414
460
  } else if (err.code == "EACCES") {
@@ -429,7 +475,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
429
475
  * @api private
430
476
  */
431
477
 
432
- Command.prototype.normalize = function(args){
478
+ Command.prototype.normalize = function(args) {
433
479
  var ret = []
434
480
  , arg
435
481
  , lastOpt
@@ -437,12 +483,18 @@ Command.prototype.normalize = function(args){
437
483
 
438
484
  for (var i = 0, len = args.length; i < len; ++i) {
439
485
  arg = args[i];
440
- i > 0 && (lastOpt = this.optionFor(args[i-1]));
486
+ if (i > 0) {
487
+ lastOpt = this.optionFor(args[i-1]);
488
+ }
441
489
 
442
- if (lastOpt && lastOpt.required) {
443
- ret.push(arg);
490
+ if (arg === '--') {
491
+ // Honor option terminator
492
+ ret = ret.concat(args.slice(i));
493
+ break;
494
+ } else if (lastOpt && lastOpt.required) {
495
+ ret.push(arg);
444
496
  } else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
445
- arg.slice(1).split('').forEach(function(c){
497
+ arg.slice(1).split('').forEach(function(c) {
446
498
  ret.push('-' + c);
447
499
  });
448
500
  } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
@@ -467,10 +519,8 @@ Command.prototype.normalize = function(args){
467
519
  * @api private
468
520
  */
469
521
 
470
- Command.prototype.parseArgs = function(args, unknown){
471
- var cmds = this.commands
472
- , len = cmds.length
473
- , name;
522
+ Command.prototype.parseArgs = function(args, unknown) {
523
+ var name;
474
524
 
475
525
  if (args.length) {
476
526
  name = args[0];
@@ -500,7 +550,7 @@ Command.prototype.parseArgs = function(args, unknown){
500
550
  * @api private
501
551
  */
502
552
 
503
- Command.prototype.optionFor = function(arg){
553
+ Command.prototype.optionFor = function(arg) {
504
554
  for (var i = 0, len = this.options.length; i < len; ++i) {
505
555
  if (this.options[i].is(arg)) {
506
556
  return this.options[i];
@@ -517,7 +567,7 @@ Command.prototype.optionFor = function(arg){
517
567
  * @api public
518
568
  */
519
569
 
520
- Command.prototype.parseOptions = function(argv){
570
+ Command.prototype.parseOptions = function(argv) {
521
571
  var args = []
522
572
  , len = argv.length
523
573
  , literal
@@ -587,6 +637,23 @@ Command.prototype.parseOptions = function(argv){
587
637
  return { args: args, unknown: unknownOptions };
588
638
  };
589
639
 
640
+ /**
641
+ * Return an object containing options as key-value pairs
642
+ *
643
+ * @return {Object}
644
+ * @api public
645
+ */
646
+ Command.prototype.opts = function() {
647
+ var result = {}
648
+ , len = this.options.length;
649
+
650
+ for (var i = 0 ; i < len; i++) {
651
+ var key = this.options[i].name();
652
+ result[key] = key === 'version' ? this._version : this[key];
653
+ }
654
+ return result;
655
+ };
656
+
590
657
  /**
591
658
  * Argument `name` is missing.
592
659
  *
@@ -594,7 +661,7 @@ Command.prototype.parseOptions = function(argv){
594
661
  * @api private
595
662
  */
596
663
 
597
- Command.prototype.missingArgument = function(name){
664
+ Command.prototype.missingArgument = function(name) {
598
665
  console.error();
599
666
  console.error(" error: missing required argument `%s'", name);
600
667
  console.error();
@@ -609,7 +676,7 @@ Command.prototype.missingArgument = function(name){
609
676
  * @api private
610
677
  */
611
678
 
612
- Command.prototype.optionMissingArgument = function(option, flag){
679
+ Command.prototype.optionMissingArgument = function(option, flag) {
613
680
  console.error();
614
681
  if (flag) {
615
682
  console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag);
@@ -627,13 +694,26 @@ Command.prototype.optionMissingArgument = function(option, flag){
627
694
  * @api private
628
695
  */
629
696
 
630
- Command.prototype.unknownOption = function(flag){
697
+ Command.prototype.unknownOption = function(flag) {
631
698
  console.error();
632
699
  console.error(" error: unknown option `%s'", flag);
633
700
  console.error();
634
701
  process.exit(1);
635
702
  };
636
703
 
704
+ /**
705
+ * Variadic argument with `name` is not the last argument as required.
706
+ *
707
+ * @param {String} name
708
+ * @api private
709
+ */
710
+
711
+ Command.prototype.variadicArgNotLast = function(name) {
712
+ console.error();
713
+ console.error(" error: variadic arguments must be last `%s'", name);
714
+ console.error();
715
+ process.exit(1);
716
+ };
637
717
 
638
718
  /**
639
719
  * Set the program version to `str`.
@@ -647,32 +727,46 @@ Command.prototype.unknownOption = function(flag){
647
727
  * @api public
648
728
  */
649
729
 
650
- Command.prototype.version = function(str, flags){
730
+ Command.prototype.version = function(str, flags) {
651
731
  if (0 == arguments.length) return this._version;
652
732
  this._version = str;
653
733
  flags = flags || '-V, --version';
654
734
  this.option(flags, 'output the version number');
655
- this.on('version', function(){
656
- console.log(str);
735
+ this.on('version', function() {
736
+ process.stdout.write(str + '\n');
657
737
  process.exit(0);
658
738
  });
659
739
  return this;
660
740
  };
661
741
 
662
742
  /**
663
- * Set the description `str`.
743
+ * Set the description to `str`.
664
744
  *
665
745
  * @param {String} str
666
746
  * @return {String|Command}
667
747
  * @api public
668
748
  */
669
749
 
670
- Command.prototype.description = function(str){
750
+ Command.prototype.description = function(str) {
671
751
  if (0 == arguments.length) return this._description;
672
752
  this._description = str;
673
753
  return this;
674
754
  };
675
755
 
756
+ /**
757
+ * Set an alias for the command
758
+ *
759
+ * @param {String} alias
760
+ * @return {String|Command}
761
+ * @api public
762
+ */
763
+
764
+ Command.prototype.alias = function(alias) {
765
+ if (0 == arguments.length) return this._alias;
766
+ this._alias = alias;
767
+ return this;
768
+ };
769
+
676
770
  /**
677
771
  * Set / get the command usage `str`.
678
772
  *
@@ -681,17 +775,14 @@ Command.prototype.description = function(str){
681
775
  * @api public
682
776
  */
683
777
 
684
- Command.prototype.usage = function(str){
685
- var args = this._args.map(function(arg){
686
- return arg.required
687
- ? '<' + arg.name + '>'
688
- : '[' + arg.name + ']';
778
+ Command.prototype.usage = function(str) {
779
+ var args = this._args.map(function(arg) {
780
+ return humanReadableArgName(arg);
689
781
  });
690
782
 
691
- var usage = '[options'
692
- + (this.commands.length ? '] [command' : '')
693
- + ']'
694
- + (this._args.length ? ' ' + args : '');
783
+ var usage = '[options]'
784
+ + (this.commands.length ? ' [command]' : '')
785
+ + (this._args.length ? ' ' + args.join(' ') : '');
695
786
 
696
787
  if (0 == arguments.length) return this._usage || usage;
697
788
  this._usage = str;
@@ -699,6 +790,18 @@ Command.prototype.usage = function(str){
699
790
  return this;
700
791
  };
701
792
 
793
+ /**
794
+ * Get the name of the command
795
+ *
796
+ * @param {String} name
797
+ * @return {String|Command}
798
+ * @api public
799
+ */
800
+
801
+ Command.prototype.name = function(name) {
802
+ return this._name;
803
+ };
804
+
702
805
  /**
703
806
  * Return the largest option length.
704
807
  *
@@ -706,8 +809,8 @@ Command.prototype.usage = function(str){
706
809
  * @api private
707
810
  */
708
811
 
709
- Command.prototype.largestOptionLength = function(){
710
- return this.options.reduce(function(max, option){
812
+ Command.prototype.largestOptionLength = function() {
813
+ return this.options.reduce(function(max, option) {
711
814
  return Math.max(max, option.flags.length);
712
815
  }, 0);
713
816
  };
@@ -719,14 +822,13 @@ Command.prototype.largestOptionLength = function(){
719
822
  * @api private
720
823
  */
721
824
 
722
- Command.prototype.optionHelp = function(){
825
+ Command.prototype.optionHelp = function() {
723
826
  var width = this.largestOptionLength();
724
827
 
725
828
  // Prepend the help information
726
829
  return [pad('-h, --help', width) + ' ' + 'output usage information']
727
- .concat(this.options.map(function(option){
728
- return pad(option.flags, width)
729
- + ' ' + option.description;
830
+ .concat(this.options.map(function(option) {
831
+ return pad(option.flags, width) + ' ' + option.description;
730
832
  }))
731
833
  .join('\n');
732
834
  };
@@ -738,26 +840,37 @@ Command.prototype.optionHelp = function(){
738
840
  * @api private
739
841
  */
740
842
 
741
- Command.prototype.commandHelp = function(){
843
+ Command.prototype.commandHelp = function() {
742
844
  if (!this.commands.length) return '';
845
+
846
+ var commands = this.commands.map(function(cmd) {
847
+ var args = cmd._args.map(function(arg) {
848
+ return humanReadableArgName(arg);
849
+ }).join(' ');
850
+
851
+ return [
852
+ cmd._name
853
+ + (cmd._alias
854
+ ? '|' + cmd._alias
855
+ : '')
856
+ + (cmd.options.length
857
+ ? ' [options]'
858
+ : '')
859
+ + ' ' + args
860
+ , cmd.description()
861
+ ];
862
+ });
863
+
864
+ var width = commands.reduce(function(max, command) {
865
+ return Math.max(max, command[0].length);
866
+ }, 0);
867
+
743
868
  return [
744
869
  ''
745
870
  , ' Commands:'
746
871
  , ''
747
- , this.commands.map(function(cmd){
748
- var args = cmd._args.map(function(arg){
749
- return arg.required
750
- ? '<' + arg.name + '>'
751
- : '[' + arg.name + ']';
752
- }).join(' ');
753
-
754
- return pad(cmd._name
755
- + (cmd.options.length
756
- ? ' [options]'
757
- : '') + ' ' + args, 22)
758
- + (cmd.description()
759
- ? ' ' + cmd.description()
760
- : '');
872
+ , commands.map(function(cmd) {
873
+ return pad(cmd[0], width) + ' ' + cmd[1];
761
874
  }).join('\n').replace(/^/gm, ' ')
762
875
  , ''
763
876
  ].join('\n');
@@ -770,10 +883,14 @@ Command.prototype.commandHelp = function(){
770
883
  * @api private
771
884
  */
772
885
 
773
- Command.prototype.helpInformation = function(){
886
+ Command.prototype.helpInformation = function() {
774
887
  return [
775
888
  ''
776
- , ' Usage: ' + this._name + ' ' + this.usage()
889
+ , ' Usage: ' + this._name
890
+ + (this._alias
891
+ ? '|' + this._alias
892
+ : '')
893
+ + ' ' + this.usage()
777
894
  , '' + this.commandHelp()
778
895
  , ' Options:'
779
896
  , ''
@@ -789,7 +906,7 @@ Command.prototype.helpInformation = function(){
789
906
  * @api public
790
907
  */
791
908
 
792
- Command.prototype.outputHelp = function(){
909
+ Command.prototype.outputHelp = function() {
793
910
  process.stdout.write(this.helpInformation());
794
911
  this.emit('--help');
795
912
  };
@@ -800,7 +917,7 @@ Command.prototype.outputHelp = function(){
800
917
  * @api public
801
918
  */
802
919
 
803
- Command.prototype.help = function(){
920
+ Command.prototype.help = function() {
804
921
  this.outputHelp();
805
922
  process.exit();
806
923
  };
@@ -814,7 +931,7 @@ Command.prototype.help = function(){
814
931
  */
815
932
 
816
933
  function camelcase(flag) {
817
- return flag.split('-').reduce(function(str, word){
934
+ return flag.split('-').reduce(function(str, word) {
818
935
  return str + word[0].toUpperCase() + word.slice(1);
819
936
  });
820
937
  }
@@ -850,3 +967,19 @@ function outputHelpIfNecessary(cmd, options) {
850
967
  }
851
968
  }
852
969
  }
970
+
971
+ /**
972
+ * Takes an argument an returns its human readable equivalent for help usage.
973
+ *
974
+ * @param {Object} arg
975
+ * @return {String}
976
+ * @api private
977
+ */
978
+
979
+ function humanReadableArgName(arg) {
980
+ var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
981
+
982
+ return arg.required
983
+ ? '<' + nameOutput + '>'
984
+ : '[' + nameOutput + ']'
985
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "commander"
3
- , "version": "2.2.0"
3
+ , "version": "2.5.1"
4
4
  , "description": "the complete solution for node.js command-line programs"
5
- , "keywords": ["command", "option", "parser", "prompt", "stdin"]
5
+ , "keywords": ["command", "option", "parser", "prompt"]
6
6
  , "author": "TJ Holowaychuk <tj@vision-media.ca>"
7
- , "repository": { "type": "git", "url": "https://github.com/visionmedia/commander.js.git" }
7
+ , "license": "MIT"
8
+ , "repository": { "type": "git", "url": "https://github.com/tj/commander.js.git" }
8
9
  , "devDependencies": { "should": ">= 0.0.1" }
9
10
  , "scripts": { "test": "make test" }
10
11
  , "main": "index"