commander 2.3.0 → 2.6.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.
Files changed (4) hide show
  1. package/History.md +222 -0
  2. package/Readme.md +126 -34
  3. package/index.js +238 -94
  4. package/package.json +4 -3
package/History.md ADDED
@@ -0,0 +1,222 @@
1
+ 2.6.0 / 2014-12-30
2
+ ==================
3
+
4
+ * added `Command#allowUnknownOption` method. Close #138 #318 @doozr @zhiyelee
5
+ * Add application description to the help msg. Close #112 @dalssoft
6
+
7
+ 2.5.1 / 2014-12-15
8
+ ==================
9
+
10
+ * fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee
11
+
12
+ 2.5.0 / 2014-10-24
13
+ ==================
14
+
15
+ * add support for variadic arguments. Closes #277 @whitlockjc
16
+
17
+ 2.4.0 / 2014-10-17
18
+ ==================
19
+
20
+ * fixed a bug on executing the coercion function of subcommands option. Closes #270
21
+ * added `Command.prototype.name` to retrieve command name. Closes #264 #266 @tonylukasavage
22
+ * added `Command.prototype.opts` to retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage
23
+ * fixed a bug on subcommand name. Closes #248 @jonathandelgado
24
+ * fixed function normalize doesn’t honor option terminator. Closes #216 @abbr
25
+
26
+ 2.3.0 / 2014-07-16
27
+ ==================
28
+
29
+ * add command alias'. Closes PR #210
30
+ * fix: Typos. Closes #99
31
+ * fix: Unused fs module. Closes #217
32
+
33
+ 2.2.0 / 2014-03-29
34
+ ==================
35
+
36
+ * add passing of previous option value
37
+ * fix: support subcommands on windows. Closes #142
38
+ * Now the defaultValue passed as the second argument of the coercion function.
39
+
40
+ 2.1.0 / 2013-11-21
41
+ ==================
42
+
43
+ * add: allow cflag style option params, unit test, fixes #174
44
+
45
+ 2.0.0 / 2013-07-18
46
+ ==================
47
+
48
+ * remove input methods (.prompt, .confirm, etc)
49
+
50
+ 1.3.2 / 2013-07-18
51
+ ==================
52
+
53
+ * add support for sub-commands to co-exist with the original command
54
+
55
+ 1.3.1 / 2013-07-18
56
+ ==================
57
+
58
+ * add quick .runningCommand hack so you can opt-out of other logic when running a sub command
59
+
60
+ 1.3.0 / 2013-07-09
61
+ ==================
62
+
63
+ * add EACCES error handling
64
+ * fix sub-command --help
65
+
66
+ 1.2.0 / 2013-06-13
67
+ ==================
68
+
69
+ * allow "-" hyphen as an option argument
70
+ * support for RegExp coercion
71
+
72
+ 1.1.1 / 2012-11-20
73
+ ==================
74
+
75
+ * add more sub-command padding
76
+ * fix .usage() when args are present. Closes #106
77
+
78
+ 1.1.0 / 2012-11-16
79
+ ==================
80
+
81
+ * add git-style executable subcommand support. Closes #94
82
+
83
+ 1.0.5 / 2012-10-09
84
+ ==================
85
+
86
+ * fix `--name` clobbering. Closes #92
87
+ * fix examples/help. Closes #89
88
+
89
+ 1.0.4 / 2012-09-03
90
+ ==================
91
+
92
+ * add `outputHelp()` method.
93
+
94
+ 1.0.3 / 2012-08-30
95
+ ==================
96
+
97
+ * remove invalid .version() defaulting
98
+
99
+ 1.0.2 / 2012-08-24
100
+ ==================
101
+
102
+ * add `--foo=bar` support [arv]
103
+ * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]
104
+
105
+ 1.0.1 / 2012-08-03
106
+ ==================
107
+
108
+ * fix issue #56
109
+ * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())
110
+
111
+ 1.0.0 / 2012-07-05
112
+ ==================
113
+
114
+ * add support for optional option descriptions
115
+ * add defaulting of `.version()` to package.json's version
116
+
117
+ 0.6.1 / 2012-06-01
118
+ ==================
119
+
120
+ * Added: append (yes or no) on confirmation
121
+ * Added: allow node.js v0.7.x
122
+
123
+ 0.6.0 / 2012-04-10
124
+ ==================
125
+
126
+ * Added `.prompt(obj, callback)` support. Closes #49
127
+ * Added default support to .choose(). Closes #41
128
+ * Fixed the choice example
129
+
130
+ 0.5.1 / 2011-12-20
131
+ ==================
132
+
133
+ * Fixed `password()` for recent nodes. Closes #36
134
+
135
+ 0.5.0 / 2011-12-04
136
+ ==================
137
+
138
+ * Added sub-command option support [itay]
139
+
140
+ 0.4.3 / 2011-12-04
141
+ ==================
142
+
143
+ * Fixed custom help ordering. Closes #32
144
+
145
+ 0.4.2 / 2011-11-24
146
+ ==================
147
+
148
+ * Added travis support
149
+ * Fixed: line-buffered input automatically trimmed. Closes #31
150
+
151
+ 0.4.1 / 2011-11-18
152
+ ==================
153
+
154
+ * Removed listening for "close" on --help
155
+
156
+ 0.4.0 / 2011-11-15
157
+ ==================
158
+
159
+ * Added support for `--`. Closes #24
160
+
161
+ 0.3.3 / 2011-11-14
162
+ ==================
163
+
164
+ * Fixed: wait for close event when writing help info [Jerry Hamlet]
165
+
166
+ 0.3.2 / 2011-11-01
167
+ ==================
168
+
169
+ * Fixed long flag definitions with values [felixge]
170
+
171
+ 0.3.1 / 2011-10-31
172
+ ==================
173
+
174
+ * Changed `--version` short flag to `-V` from `-v`
175
+ * Changed `.version()` so it's configurable [felixge]
176
+
177
+ 0.3.0 / 2011-10-31
178
+ ==================
179
+
180
+ * Added support for long flags only. Closes #18
181
+
182
+ 0.2.1 / 2011-10-24
183
+ ==================
184
+
185
+ * "node": ">= 0.4.x < 0.7.0". Closes #20
186
+
187
+ 0.2.0 / 2011-09-26
188
+ ==================
189
+
190
+ * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
191
+
192
+ 0.1.0 / 2011-08-24
193
+ ==================
194
+
195
+ * Added support for custom `--help` output
196
+
197
+ 0.0.5 / 2011-08-18
198
+ ==================
199
+
200
+ * Changed: when the user enters nothing prompt for password again
201
+ * Fixed issue with passwords beginning with numbers [NuckChorris]
202
+
203
+ 0.0.4 / 2011-08-15
204
+ ==================
205
+
206
+ * Fixed `Commander#args`
207
+
208
+ 0.0.3 / 2011-08-15
209
+ ==================
210
+
211
+ * Added default option value support
212
+
213
+ 0.0.2 / 2011-08-15
214
+ ==================
215
+
216
+ * Added mask support to `Command#password(str[, mask], fn)`
217
+ * Added `Command#password(str, fn)`
218
+
219
+ 0.0.1 / 2010-01-03
220
+ ==================
221
+
222
+ * Initial release
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/)
4
9
 
5
- [![Build Status](https://api.travis-ci.org/visionmedia/commander.js.svg)](http://travis-ci.org/visionmedia/commander.js)
6
10
 
7
11
  ## Installation
8
12
 
@@ -38,25 +42,6 @@ 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
 
41
- ## Automated --help
42
-
43
- The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
44
-
45
- ```
46
- $ ./examples/pizza --help
47
-
48
- Usage: pizza [options]
49
-
50
- Options:
51
-
52
- -V, --version output the version number
53
- -p, --peppers Add peppers
54
- -P, --pineapple Add pineapple
55
- -b, --bbq Add bbq sauce
56
- -c, --cheese <type> Add the specified type of cheese [marble]
57
- -h, --help output usage information
58
-
59
- ```
60
45
 
61
46
  ## Coercion
62
47
 
@@ -101,6 +86,78 @@ console.log(' verbosity: %j', program.verbose);
101
86
  console.log(' args: %j', program.args);
102
87
  ```
103
88
 
89
+ ## Variadic arguments
90
+
91
+ The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to
92
+ append `...` to the argument name. Here is an example:
93
+
94
+ ```js
95
+ #!/usr/bin/env node
96
+
97
+ /**
98
+ * Module dependencies.
99
+ */
100
+
101
+ var program = require('commander');
102
+
103
+ program
104
+ .version('0.0.1')
105
+ .command('rmdir <dir> [otherDirs...]')
106
+ .action(function (dir, otherDirs) {
107
+ console.log('rmdir %s', dir);
108
+ if (otherDirs) {
109
+ otherDirs.forEach(function (oDir) {
110
+ console.log('rmdir %s', oDir);
111
+ });
112
+ }
113
+ });
114
+
115
+ program.parse(process.argv);
116
+ ```
117
+
118
+ An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed
119
+ to your action as demonstrated above.
120
+
121
+ ## Git-style sub-commands
122
+
123
+ ```js
124
+ // file: ./examples/pm
125
+ var program = require('..');
126
+
127
+ program
128
+ .version('0.0.1')
129
+ .command('install [name]', 'install one or more packages')
130
+ .command('search [query]', 'search with optional query')
131
+ .command('list', 'list packages installed')
132
+ .parse(process.argv);
133
+ ```
134
+
135
+ 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.
136
+ The commander will try to find the executable script in __current directory__ with the name `scriptBasename-subcommand`, like `pm-install`, `pm-search`.
137
+
138
+ ## Automated --help
139
+
140
+ The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
141
+
142
+ ```
143
+ $ ./examples/pizza --help
144
+
145
+ Usage: pizza [options]
146
+
147
+ An application for pizzas ordering
148
+
149
+ Options:
150
+
151
+ -h, --help output usage information
152
+ -V, --version output the version number
153
+ -p, --peppers Add peppers
154
+ -P, --pineapple Add pineapple
155
+ -b, --bbq Add bbq sauce
156
+ -c, --cheese <type> Add the specified type of cheese [marble]
157
+ -C, --no-cheese You do not want any cheese
158
+
159
+ ```
160
+
104
161
  ## Custom help
105
162
 
106
163
  You can display arbitrary `-h, --help` information
@@ -117,11 +174,7 @@ console.log(' args: %j', program.args);
117
174
  * Module dependencies.
118
175
  */
119
176
 
120
- var program = require('../');
121
-
122
- function list(val) {
123
- return val.split(',').map(Number);
124
- }
177
+ var program = require('commander');
125
178
 
126
179
  program
127
180
  .version('0.0.1')
@@ -145,7 +198,7 @@ program.parse(process.argv);
145
198
  console.log('stuff');
146
199
  ```
147
200
 
148
- yielding the following help output:
201
+ Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run:
149
202
 
150
203
  ```
151
204
 
@@ -174,15 +227,54 @@ Examples:
174
227
 
175
228
  Output help information and exit immediately.
176
229
 
177
- ## Links
230
+ ## Examples
231
+
232
+ ```js
233
+ var program = require('commander');
234
+
235
+ program
236
+ .version('0.0.1')
237
+ .option('-C, --chdir <path>', 'change the working directory')
238
+ .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
239
+ .option('-T, --no-tests', 'ignore test hook')
240
+
241
+ program
242
+ .command('setup [env]')
243
+ .description('run setup commands for all envs')
244
+ .option("-s, --setup_mode [mode]", "Which setup mode to use")
245
+ .action(function(env, options){
246
+ var mode = options.setup_mode || "normal";
247
+ env = env || 'all';
248
+ console.log('setup for %s env(s) with %s mode', env, mode);
249
+ });
250
+
251
+ program
252
+ .command('exec <cmd>')
253
+ .alias('ex')
254
+ .description('execute the given remote cmd')
255
+ .option("-e, --exec_mode <mode>", "Which exec mode to use")
256
+ .action(function(cmd, options){
257
+ console.log('exec "%s" using %s mode', cmd, options.exec_mode);
258
+ }).on('--help', function() {
259
+ console.log(' Examples:');
260
+ console.log();
261
+ console.log(' $ deploy exec sequential');
262
+ console.log(' $ deploy exec async');
263
+ console.log();
264
+ });
265
+
266
+ program
267
+ .command('*')
268
+ .action(function(env){
269
+ console.log('deploying "%s"', env);
270
+ });
271
+
272
+ program.parse(process.argv);
273
+ ```
178
274
 
179
- - [API documentation](http://visionmedia.github.com/commander.js/)
180
- - [ascii tables](https://github.com/LearnBoost/cli-table)
181
- - [progress bars](https://github.com/visionmedia/node-progress)
182
- - [more progress bars](https://github.com/substack/node-multimeter)
183
- - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)
275
+ You can see more Demos in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
184
276
 
185
- ## License
277
+ ## License
186
278
 
187
279
  (The MIT License)
188
280
 
package/index.js CHANGED
@@ -13,7 +13,7 @@ var basename = path.basename;
13
13
  * Expose the root command.
14
14
  */
15
15
 
16
- exports = module.exports = new Command;
16
+ exports = module.exports = new Command();
17
17
 
18
18
  /**
19
19
  * Expose `Command`.
@@ -53,7 +53,7 @@ function Option(flags, description) {
53
53
  * @api private
54
54
  */
55
55
 
56
- Option.prototype.name = function(){
56
+ Option.prototype.name = function() {
57
57
  return this.long
58
58
  .replace('--', '')
59
59
  .replace('no-', '');
@@ -67,9 +67,8 @@ Option.prototype.name = function(){
67
67
  * @api private
68
68
  */
69
69
 
70
- Option.prototype.is = function(arg){
71
- return arg == this.short
72
- || arg == this.long;
70
+ Option.prototype.is = function(arg) {
71
+ return arg == this.short || arg == this.long;
73
72
  };
74
73
 
75
74
  /**
@@ -83,6 +82,7 @@ function Command(name) {
83
82
  this.commands = [];
84
83
  this.options = [];
85
84
  this._execs = [];
85
+ this._allowUnknownOption = false;
86
86
  this._args = [];
87
87
  this._name = name;
88
88
  }
@@ -116,28 +116,40 @@ Command.prototype.__proto__ = EventEmitter.prototype;
116
116
  * program
117
117
  * .command('setup')
118
118
  * .description('run remote setup commands')
119
- * .action(function(){
119
+ * .action(function() {
120
120
  * console.log('setup');
121
121
  * });
122
122
  *
123
123
  * program
124
124
  * .command('exec <cmd>')
125
125
  * .description('run the given remote command')
126
- * .action(function(cmd){
126
+ * .action(function(cmd) {
127
127
  * console.log('exec "%s"', cmd);
128
128
  * });
129
129
  *
130
130
  * program
131
+ * .command('teardown <dir> [otherDirs...]')
132
+ * .description('run teardown commands')
133
+ * .action(function(dir, otherDirs) {
134
+ * console.log('dir "%s"', dir);
135
+ * if (otherDirs) {
136
+ * otherDirs.forEach(function (oDir) {
137
+ * console.log('dir "%s"', oDir);
138
+ * });
139
+ * }
140
+ * });
141
+ *
142
+ * program
131
143
  * .command('*')
132
144
  * .description('deploy the given env')
133
- * .action(function(env){
145
+ * .action(function(env) {
134
146
  * console.log('deploying "%s"', env);
135
147
  * });
136
148
  *
137
149
  * program.parse(process.argv);
138
150
  *
139
151
  * @param {String} name
140
- * @param {String} [desc]
152
+ * @param {String} [desc] for git-style sub-commands
141
153
  * @return {Command} the new command
142
154
  * @api public
143
155
  */
@@ -145,12 +157,17 @@ Command.prototype.__proto__ = EventEmitter.prototype;
145
157
  Command.prototype.command = function(name, desc) {
146
158
  var args = name.split(/ +/);
147
159
  var cmd = new Command(args.shift());
148
- if (desc) cmd.description(desc);
149
- if (desc) this.executables = true;
150
- if (desc) this._execs[cmd._name] = true;
160
+
161
+ if (desc) {
162
+ cmd.description(desc);
163
+ this.executables = true;
164
+ this._execs[cmd._name] = true;
165
+ }
166
+
151
167
  this.commands.push(cmd);
152
168
  cmd.parseExpectedArgs(args);
153
169
  cmd.parent = this;
170
+
154
171
  if (desc) return this;
155
172
  return cmd;
156
173
  };
@@ -176,18 +193,33 @@ Command.prototype.addImplicitHelpCommand = function() {
176
193
  * @api public
177
194
  */
178
195
 
179
- Command.prototype.parseExpectedArgs = function(args){
196
+ Command.prototype.parseExpectedArgs = function(args) {
180
197
  if (!args.length) return;
181
198
  var self = this;
182
- args.forEach(function(arg){
199
+ args.forEach(function(arg) {
200
+ var argDetails = {
201
+ required: false,
202
+ name: '',
203
+ variadic: false
204
+ };
205
+
183
206
  switch (arg[0]) {
184
207
  case '<':
185
- self._args.push({ required: true, name: arg.slice(1, -1) });
208
+ argDetails.required = true;
209
+ argDetails.name = arg.slice(1, -1);
186
210
  break;
187
211
  case '[':
188
- self._args.push({ required: false, name: arg.slice(1, -1) });
212
+ argDetails.name = arg.slice(1, -1);
189
213
  break;
190
214
  }
215
+
216
+ if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {
217
+ argDetails.variadic = true;
218
+ argDetails.name = argDetails.name.slice(0, -3);
219
+ }
220
+ if (argDetails.name) {
221
+ self._args.push(argDetails);
222
+ }
191
223
  });
192
224
  return this;
193
225
  };
@@ -200,7 +232,7 @@ Command.prototype.parseExpectedArgs = function(args){
200
232
  * program
201
233
  * .command('help')
202
234
  * .description('display verbose help')
203
- * .action(function(){
235
+ * .action(function() {
204
236
  * // output help here
205
237
  * });
206
238
  *
@@ -209,9 +241,9 @@ Command.prototype.parseExpectedArgs = function(args){
209
241
  * @api public
210
242
  */
211
243
 
212
- Command.prototype.action = function(fn){
244
+ Command.prototype.action = function(fn) {
213
245
  var self = this;
214
- var listener = function(args, unknown){
246
+ var listener = function(args, unknown) {
215
247
  // Parse any so-far unknown options
216
248
  args = args || [];
217
249
  unknown = unknown || [];
@@ -231,9 +263,15 @@ Command.prototype.action = function(fn){
231
263
  // Leftover arguments need to be pushed back. Fixes issue #56
232
264
  if (parsed.args.length) args = parsed.args.concat(args);
233
265
 
234
- self._args.forEach(function(arg, i){
266
+ self._args.forEach(function(arg, i) {
235
267
  if (arg.required && null == args[i]) {
236
268
  self.missingArgument(arg.name);
269
+ } else if (arg.variadic) {
270
+ if (i !== self._args.length - 1) {
271
+ self.variadicArgNotLast(arg.name);
272
+ }
273
+
274
+ args[i] = args.splice(i);
237
275
  }
238
276
  });
239
277
 
@@ -246,7 +284,7 @@ Command.prototype.action = function(fn){
246
284
  args.push(self);
247
285
  }
248
286
 
249
- fn.apply(this, args);
287
+ fn.apply(self, args);
250
288
  };
251
289
  this.parent.on(this._name, listener);
252
290
  if (this._alias) this.parent.on(this._alias, listener);
@@ -302,14 +340,17 @@ Command.prototype.action = function(fn){
302
340
  * @api public
303
341
  */
304
342
 
305
- Command.prototype.option = function(flags, description, fn, defaultValue){
343
+ Command.prototype.option = function(flags, description, fn, defaultValue) {
306
344
  var self = this
307
345
  , option = new Option(flags, description)
308
346
  , oname = option.name()
309
347
  , name = camelcase(oname);
310
348
 
311
349
  // default as 3rd arg
312
- if ('function' != typeof fn) defaultValue = fn, fn = null;
350
+ if (typeof fn != 'function') {
351
+ defaultValue = fn;
352
+ fn = null;
353
+ }
313
354
 
314
355
  // preassign default value only for --no-*, [optional], or <required>
315
356
  if (false == option.bool || option.optional || option.required) {
@@ -324,9 +365,11 @@ Command.prototype.option = function(flags, description, fn, defaultValue){
324
365
 
325
366
  // when it's passed assign the value
326
367
  // and conditionally invoke the callback
327
- this.on(oname, function(val){
368
+ this.on(oname, function(val) {
328
369
  // coercion
329
- if (null !== val && fn) val = fn(val, undefined === self[name] ? defaultValue : self[name]);
370
+ if (null !== val && fn) val = fn(val, undefined === self[name]
371
+ ? defaultValue
372
+ : self[name]);
330
373
 
331
374
  // unassigned or bool
332
375
  if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
@@ -347,6 +390,18 @@ Command.prototype.option = function(flags, description, fn, defaultValue){
347
390
  return this;
348
391
  };
349
392
 
393
+ /**
394
+ * Allow unknown options on the command line.
395
+ *
396
+ * @param {Boolean} arg if `true` or omitted, no error will be thrown
397
+ * for unknown options.
398
+ * @api public
399
+ */
400
+ Command.prototype.allowUnknownOption = function(arg) {
401
+ this._allowUnknownOption = arguments.length === 0 || arg;
402
+ return this;
403
+ };
404
+
350
405
  /**
351
406
  * Parse `argv`, settings options and invoking commands when defined.
352
407
  *
@@ -355,7 +410,7 @@ Command.prototype.option = function(flags, description, fn, defaultValue){
355
410
  * @api public
356
411
  */
357
412
 
358
- Command.prototype.parse = function(argv){
413
+ Command.prototype.parse = function(argv) {
359
414
  // implicit help
360
415
  if (this.executables) this.addImplicitHelpCommand();
361
416
 
@@ -373,7 +428,9 @@ Command.prototype.parse = function(argv){
373
428
 
374
429
  // executable sub-commands
375
430
  var name = result.args[0];
376
- if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown);
431
+ if (this._execs[name] && typeof this._execs[name] != "function") {
432
+ return this.executeSubCommand(argv, args, parsed.unknown);
433
+ }
377
434
 
378
435
  return result;
379
436
  };
@@ -410,7 +467,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
410
467
  args = args.slice(1);
411
468
  args.unshift(local);
412
469
  var proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] });
413
- proc.on('error', function(err){
470
+ proc.on('error', function(err) {
414
471
  if (err.code == "ENOENT") {
415
472
  console.error('\n %s(1) does not exist, try --help\n', bin);
416
473
  } else if (err.code == "EACCES") {
@@ -431,7 +488,7 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
431
488
  * @api private
432
489
  */
433
490
 
434
- Command.prototype.normalize = function(args){
491
+ Command.prototype.normalize = function(args) {
435
492
  var ret = []
436
493
  , arg
437
494
  , lastOpt
@@ -439,12 +496,18 @@ Command.prototype.normalize = function(args){
439
496
 
440
497
  for (var i = 0, len = args.length; i < len; ++i) {
441
498
  arg = args[i];
442
- i > 0 && (lastOpt = this.optionFor(args[i-1]));
499
+ if (i > 0) {
500
+ lastOpt = this.optionFor(args[i-1]);
501
+ }
443
502
 
444
- if (lastOpt && lastOpt.required) {
445
- ret.push(arg);
503
+ if (arg === '--') {
504
+ // Honor option terminator
505
+ ret = ret.concat(args.slice(i));
506
+ break;
507
+ } else if (lastOpt && lastOpt.required) {
508
+ ret.push(arg);
446
509
  } else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
447
- arg.slice(1).split('').forEach(function(c){
510
+ arg.slice(1).split('').forEach(function(c) {
448
511
  ret.push('-' + c);
449
512
  });
450
513
  } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
@@ -469,10 +532,8 @@ Command.prototype.normalize = function(args){
469
532
  * @api private
470
533
  */
471
534
 
472
- Command.prototype.parseArgs = function(args, unknown){
473
- var cmds = this.commands
474
- , len = cmds.length
475
- , name;
535
+ Command.prototype.parseArgs = function(args, unknown) {
536
+ var name;
476
537
 
477
538
  if (args.length) {
478
539
  name = args[0];
@@ -502,7 +563,7 @@ Command.prototype.parseArgs = function(args, unknown){
502
563
  * @api private
503
564
  */
504
565
 
505
- Command.prototype.optionFor = function(arg){
566
+ Command.prototype.optionFor = function(arg) {
506
567
  for (var i = 0, len = this.options.length; i < len; ++i) {
507
568
  if (this.options[i].is(arg)) {
508
569
  return this.options[i];
@@ -519,7 +580,7 @@ Command.prototype.optionFor = function(arg){
519
580
  * @api public
520
581
  */
521
582
 
522
- Command.prototype.parseOptions = function(argv){
583
+ Command.prototype.parseOptions = function(argv) {
523
584
  var args = []
524
585
  , len = argv.length
525
586
  , literal
@@ -589,6 +650,23 @@ Command.prototype.parseOptions = function(argv){
589
650
  return { args: args, unknown: unknownOptions };
590
651
  };
591
652
 
653
+ /**
654
+ * Return an object containing options as key-value pairs
655
+ *
656
+ * @return {Object}
657
+ * @api public
658
+ */
659
+ Command.prototype.opts = function() {
660
+ var result = {}
661
+ , len = this.options.length;
662
+
663
+ for (var i = 0 ; i < len; i++) {
664
+ var key = this.options[i].name();
665
+ result[key] = key === 'version' ? this._version : this[key];
666
+ }
667
+ return result;
668
+ };
669
+
592
670
  /**
593
671
  * Argument `name` is missing.
594
672
  *
@@ -596,7 +674,7 @@ Command.prototype.parseOptions = function(argv){
596
674
  * @api private
597
675
  */
598
676
 
599
- Command.prototype.missingArgument = function(name){
677
+ Command.prototype.missingArgument = function(name) {
600
678
  console.error();
601
679
  console.error(" error: missing required argument `%s'", name);
602
680
  console.error();
@@ -611,7 +689,7 @@ Command.prototype.missingArgument = function(name){
611
689
  * @api private
612
690
  */
613
691
 
614
- Command.prototype.optionMissingArgument = function(option, flag){
692
+ Command.prototype.optionMissingArgument = function(option, flag) {
615
693
  console.error();
616
694
  if (flag) {
617
695
  console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag);
@@ -629,13 +707,27 @@ Command.prototype.optionMissingArgument = function(option, flag){
629
707
  * @api private
630
708
  */
631
709
 
632
- Command.prototype.unknownOption = function(flag){
710
+ Command.prototype.unknownOption = function(flag) {
711
+ if(this._allowUnknownOption) return;
633
712
  console.error();
634
713
  console.error(" error: unknown option `%s'", flag);
635
714
  console.error();
636
715
  process.exit(1);
637
716
  };
638
717
 
718
+ /**
719
+ * Variadic argument with `name` is not the last argument as required.
720
+ *
721
+ * @param {String} name
722
+ * @api private
723
+ */
724
+
725
+ Command.prototype.variadicArgNotLast = function(name) {
726
+ console.error();
727
+ console.error(" error: variadic arguments must be last `%s'", name);
728
+ console.error();
729
+ process.exit(1);
730
+ };
639
731
 
640
732
  /**
641
733
  * Set the program version to `str`.
@@ -649,27 +741,27 @@ Command.prototype.unknownOption = function(flag){
649
741
  * @api public
650
742
  */
651
743
 
652
- Command.prototype.version = function(str, flags){
744
+ Command.prototype.version = function(str, flags) {
653
745
  if (0 == arguments.length) return this._version;
654
746
  this._version = str;
655
747
  flags = flags || '-V, --version';
656
748
  this.option(flags, 'output the version number');
657
- this.on('version', function(){
658
- console.log(str);
749
+ this.on('version', function() {
750
+ process.stdout.write(str + '\n');
659
751
  process.exit(0);
660
752
  });
661
753
  return this;
662
754
  };
663
755
 
664
756
  /**
665
- * Set the description `str`.
757
+ * Set the description to `str`.
666
758
  *
667
759
  * @param {String} str
668
760
  * @return {String|Command}
669
761
  * @api public
670
762
  */
671
763
 
672
- Command.prototype.description = function(str){
764
+ Command.prototype.description = function(str) {
673
765
  if (0 == arguments.length) return this._description;
674
766
  this._description = str;
675
767
  return this;
@@ -683,7 +775,7 @@ Command.prototype.description = function(str){
683
775
  * @api public
684
776
  */
685
777
 
686
- Command.prototype.alias = function(alias){
778
+ Command.prototype.alias = function(alias) {
687
779
  if (0 == arguments.length) return this._alias;
688
780
  this._alias = alias;
689
781
  return this;
@@ -697,17 +789,14 @@ Command.prototype.alias = function(alias){
697
789
  * @api public
698
790
  */
699
791
 
700
- Command.prototype.usage = function(str){
701
- var args = this._args.map(function(arg){
702
- return arg.required
703
- ? '<' + arg.name + '>'
704
- : '[' + arg.name + ']';
792
+ Command.prototype.usage = function(str) {
793
+ var args = this._args.map(function(arg) {
794
+ return humanReadableArgName(arg);
705
795
  });
706
796
 
707
- var usage = '[options'
708
- + (this.commands.length ? '] [command' : '')
709
- + ']'
710
- + (this._args.length ? ' ' + args : '');
797
+ var usage = '[options]'
798
+ + (this.commands.length ? ' [command]' : '')
799
+ + (this._args.length ? ' ' + args.join(' ') : '');
711
800
 
712
801
  if (0 == arguments.length) return this._usage || usage;
713
802
  this._usage = str;
@@ -715,6 +804,18 @@ Command.prototype.usage = function(str){
715
804
  return this;
716
805
  };
717
806
 
807
+ /**
808
+ * Get the name of the command
809
+ *
810
+ * @param {String} name
811
+ * @return {String|Command}
812
+ * @api public
813
+ */
814
+
815
+ Command.prototype.name = function(name) {
816
+ return this._name;
817
+ };
818
+
718
819
  /**
719
820
  * Return the largest option length.
720
821
  *
@@ -722,8 +823,8 @@ Command.prototype.usage = function(str){
722
823
  * @api private
723
824
  */
724
825
 
725
- Command.prototype.largestOptionLength = function(){
726
- return this.options.reduce(function(max, option){
826
+ Command.prototype.largestOptionLength = function() {
827
+ return this.options.reduce(function(max, option) {
727
828
  return Math.max(max, option.flags.length);
728
829
  }, 0);
729
830
  };
@@ -735,14 +836,13 @@ Command.prototype.largestOptionLength = function(){
735
836
  * @api private
736
837
  */
737
838
 
738
- Command.prototype.optionHelp = function(){
839
+ Command.prototype.optionHelp = function() {
739
840
  var width = this.largestOptionLength();
740
841
 
741
842
  // Prepend the help information
742
843
  return [pad('-h, --help', width) + ' ' + 'output usage information']
743
- .concat(this.options.map(function(option){
744
- return pad(option.flags, width)
745
- + ' ' + option.description;
844
+ .concat(this.options.map(function(option) {
845
+ return pad(option.flags, width) + ' ' + option.description;
746
846
  }))
747
847
  .join('\n');
748
848
  };
@@ -754,30 +854,37 @@ Command.prototype.optionHelp = function(){
754
854
  * @api private
755
855
  */
756
856
 
757
- Command.prototype.commandHelp = function(){
857
+ Command.prototype.commandHelp = function() {
758
858
  if (!this.commands.length) return '';
759
- return [
760
- ''
761
- , ' Commands:'
762
- , ''
763
- , this.commands.map(function(cmd){
764
- var args = cmd._args.map(function(arg){
765
- return arg.required
766
- ? '<' + arg.name + '>'
767
- : '[' + arg.name + ']';
768
- }).join(' ');
769
-
770
- return cmd._name
859
+
860
+ var commands = this.commands.map(function(cmd) {
861
+ var args = cmd._args.map(function(arg) {
862
+ return humanReadableArgName(arg);
863
+ }).join(' ');
864
+
865
+ return [
866
+ cmd._name
771
867
  + (cmd._alias
772
868
  ? '|' + cmd._alias
773
869
  : '')
774
870
  + (cmd.options.length
775
871
  ? ' [options]'
776
- : '') + ' ' + args
777
- + (cmd.description()
778
- ? '\n ' + cmd.description()
779
872
  : '')
780
- + '\n';
873
+ + ' ' + args
874
+ , cmd.description()
875
+ ];
876
+ });
877
+
878
+ var width = commands.reduce(function(max, command) {
879
+ return Math.max(max, command[0].length);
880
+ }, 0);
881
+
882
+ return [
883
+ ''
884
+ , ' Commands:'
885
+ , ''
886
+ , commands.map(function(cmd) {
887
+ return pad(cmd[0], width) + ' ' + cmd[1];
781
888
  }).join('\n').replace(/^/gm, ' ')
782
889
  , ''
783
890
  ].join('\n');
@@ -790,21 +897,42 @@ Command.prototype.commandHelp = function(){
790
897
  * @api private
791
898
  */
792
899
 
793
- Command.prototype.helpInformation = function(){
794
- return [
795
- ''
796
- , ' Usage: ' + this._name
797
- + (this._alias
798
- ? '|' + this._alias
799
- : '')
800
- + ' ' + this.usage()
801
- , '' + this.commandHelp()
802
- , ' Options:'
900
+ Command.prototype.helpInformation = function() {
901
+ var desc = [];
902
+ if (this._description) {
903
+ desc = [
904
+ ' ' + this._description
905
+ , ''
906
+ ];
907
+ }
908
+
909
+ var cmdName = this._name;
910
+ if(this._alias) {
911
+ cmdName = cmdName + '|' + this._alias;
912
+ }
913
+ var usage = [
914
+ ''
915
+ ,' Usage: ' + cmdName + ' ' + this.usage()
916
+ , ''
917
+ ];
918
+
919
+ var cmds = [];
920
+ var commandHelp = this.commandHelp();
921
+ if (commandHelp) cmds = [commandHelp];
922
+
923
+ var options = [
924
+ ' Options:'
803
925
  , ''
804
926
  , '' + this.optionHelp().replace(/^/gm, ' ')
805
927
  , ''
806
928
  , ''
807
- ].join('\n');
929
+ ];
930
+
931
+ return usage
932
+ .concat(cmds)
933
+ .concat(desc)
934
+ .concat(options)
935
+ .join('\n');
808
936
  };
809
937
 
810
938
  /**
@@ -813,7 +941,7 @@ Command.prototype.helpInformation = function(){
813
941
  * @api public
814
942
  */
815
943
 
816
- Command.prototype.outputHelp = function(){
944
+ Command.prototype.outputHelp = function() {
817
945
  process.stdout.write(this.helpInformation());
818
946
  this.emit('--help');
819
947
  };
@@ -824,7 +952,7 @@ Command.prototype.outputHelp = function(){
824
952
  * @api public
825
953
  */
826
954
 
827
- Command.prototype.help = function(){
955
+ Command.prototype.help = function() {
828
956
  this.outputHelp();
829
957
  process.exit();
830
958
  };
@@ -838,7 +966,7 @@ Command.prototype.help = function(){
838
966
  */
839
967
 
840
968
  function camelcase(flag) {
841
- return flag.split('-').reduce(function(str, word){
969
+ return flag.split('-').reduce(function(str, word) {
842
970
  return str + word[0].toUpperCase() + word.slice(1);
843
971
  });
844
972
  }
@@ -874,3 +1002,19 @@ function outputHelpIfNecessary(cmd, options) {
874
1002
  }
875
1003
  }
876
1004
  }
1005
+
1006
+ /**
1007
+ * Takes an argument an returns its human readable equivalent for help usage.
1008
+ *
1009
+ * @param {Object} arg
1010
+ * @return {String}
1011
+ * @api private
1012
+ */
1013
+
1014
+ function humanReadableArgName(arg) {
1015
+ var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
1016
+
1017
+ return arg.required
1018
+ ? '<' + nameOutput + '>'
1019
+ : '[' + nameOutput + ']'
1020
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "commander"
3
- , "version": "2.3.0"
3
+ , "version": "2.6.0"
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"