commander 1.2.0 → 2.0.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 +21 -0
  2. package/Readme.md +3 -84
  3. package/index.js +23 -328
  4. package/package.json +1 -2
package/History.md CHANGED
@@ -1,4 +1,25 @@
1
1
 
2
+ 2.0.0 / 2013-07-18
3
+ ==================
4
+
5
+ * remove input methods (.prompt, .confirm, etc)
6
+
7
+ 1.3.2 / 2013-07-18
8
+ ==================
9
+
10
+ * add support for sub-commands to co-exist with the original command
11
+
12
+ 1.3.1 / 2013-07-18
13
+ ==================
14
+
15
+ * add quick .runningCommand hack so you can opt-out of other logic when running a sub command
16
+
17
+ 1.3.0 / 2013-07-09
18
+ ==================
19
+
20
+ * add EACCES error handling
21
+ * fix sub-command --help
22
+
2
23
  1.2.0 / 2013-06-13
3
24
  ==================
4
25
 
package/Readme.md CHANGED
@@ -31,7 +31,7 @@ program
31
31
 
32
32
  console.log('you ordered a pizza with:');
33
33
  if (program.peppers) console.log(' - peppers');
34
- if (program.pineapple) console.log(' - pineappe');
34
+ if (program.pineapple) console.log(' - pineapple');
35
35
  if (program.bbq) console.log(' - bbq');
36
36
  console.log(' - %s cheese', program.cheese);
37
37
  ```
@@ -51,7 +51,7 @@ console.log(' - %s cheese', program.cheese);
51
51
 
52
52
  -V, --version output the version number
53
53
  -p, --peppers Add peppers
54
- -P, --pineapple Add pineappe
54
+ -P, --pineapple Add pineapple
55
55
  -b, --bbq Add bbq sauce
56
56
  -c, --cheese <type> Add the specified type of cheese [marble]
57
57
  -h, --help output usage information
@@ -153,87 +153,6 @@ Examples:
153
153
 
154
154
  ```
155
155
 
156
- ## .prompt(msg, fn)
157
-
158
- Single-line prompt:
159
-
160
- ```js
161
- program.prompt('name: ', function(name){
162
- console.log('hi %s', name);
163
- });
164
- ```
165
-
166
- Multi-line prompt:
167
-
168
- ```js
169
- program.prompt('description:', function(name){
170
- console.log('hi %s', name);
171
- });
172
- ```
173
-
174
- Coercion:
175
-
176
- ```js
177
- program.prompt('Age: ', Number, function(age){
178
- console.log('age: %j', age);
179
- });
180
- ```
181
-
182
- ```js
183
- program.prompt('Birthdate: ', Date, function(date){
184
- console.log('date: %s', date);
185
- });
186
- ```
187
-
188
- ```js
189
- program.prompt('Email: ', /^.+@.+\..+$/, function(email){
190
- console.log('email: %j', email);
191
- });
192
- ```
193
-
194
- ## .password(msg[, mask], fn)
195
-
196
- Prompt for password without echoing:
197
-
198
- ```js
199
- program.password('Password: ', function(pass){
200
- console.log('got "%s"', pass);
201
- process.stdin.destroy();
202
- });
203
- ```
204
-
205
- Prompt for password with mask char "*":
206
-
207
- ```js
208
- program.password('Password: ', '*', function(pass){
209
- console.log('got "%s"', pass);
210
- process.stdin.destroy();
211
- });
212
- ```
213
-
214
- ## .confirm(msg, fn)
215
-
216
- Confirm with the given `msg`:
217
-
218
- ```js
219
- program.confirm('continue? ', function(ok){
220
- console.log(' got %j', ok);
221
- });
222
- ```
223
-
224
- ## .choose(list, fn)
225
-
226
- Let the user choose from a `list`:
227
-
228
- ```js
229
- var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
230
-
231
- console.log('Choose the coolest pet:');
232
- program.choose(list, function(i){
233
- console.log('you chose %d "%s"', i, list[i]);
234
- });
235
- ```
236
-
237
156
  ## .outputHelp()
238
157
 
239
158
  Output help information without exiting.
@@ -273,4 +192,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
273
192
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
274
193
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
275
194
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
276
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
195
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/index.js CHANGED
@@ -1,22 +1,15 @@
1
- /*!
2
- * commander
3
- * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
4
- * MIT Licensed
5
- */
6
1
 
7
2
  /**
8
3
  * Module dependencies.
9
4
  */
10
5
 
11
- var EventEmitter = require('events').EventEmitter
12
- , spawn = require('child_process').spawn
13
- , keypress = require('keypress')
14
- , fs = require('fs')
15
- , exists = fs.existsSync
16
- , path = require('path')
17
- , tty = require('tty')
18
- , dirname = path.dirname
19
- , basename = path.basename;
6
+ var EventEmitter = require('events').EventEmitter;
7
+ var spawn = require('child_process').spawn;
8
+ var fs = require('fs');
9
+ var exists = fs.existsSync;
10
+ var path = require('path');
11
+ var dirname = path.dirname;
12
+ var basename = path.basename;
20
13
 
21
14
  /**
22
15
  * Expose the root command.
@@ -91,6 +84,7 @@ Option.prototype.is = function(arg){
91
84
  function Command(name) {
92
85
  this.commands = [];
93
86
  this.options = [];
87
+ this._execs = [];
94
88
  this._args = [];
95
89
  this._name = name;
96
90
  }
@@ -155,6 +149,7 @@ Command.prototype.command = function(name, desc){
155
149
  var cmd = new Command(args.shift());
156
150
  if (desc) cmd.description(desc);
157
151
  if (desc) this.executables = true;
152
+ if (desc) this._execs[cmd._name] = true;
158
153
  this.commands.push(cmd);
159
154
  cmd.parseExpectedArgs(args);
160
155
  cmd.parent = this;
@@ -372,10 +367,13 @@ Command.prototype.parse = function(argv){
372
367
  var parsed = this.parseOptions(this.normalize(argv.slice(2)));
373
368
  var args = this.args = parsed.args;
374
369
 
375
- // executable sub-commands, skip .parseArgs()
376
- if (this.executables) return this.executeSubCommand(argv, args, parsed.unknown);
370
+ var result = this.parseArgs(this.args, parsed.unknown);
371
+
372
+ // executable sub-commands
373
+ var name = result.args[0];
374
+ if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown);
377
375
 
378
- return this.parseArgs(this.args, parsed.unknown);
376
+ return result;
379
377
  };
380
378
 
381
379
  /**
@@ -405,16 +403,19 @@ Command.prototype.executeSubCommand = function(argv, args, unknown) {
405
403
 
406
404
  // check for ./<bin> first
407
405
  var local = path.join(dir, bin);
408
- if (exists(local)) bin = local;
409
406
 
410
407
  // run it
411
408
  args = args.slice(1);
412
- var proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] });
413
- proc.on('exit', function(code){
414
- if (code == 127) {
415
- console.error('\n %s(1) does not exist\n', bin);
409
+ var proc = spawn(local, args, { stdio: 'inherit', customFds: [0, 1, 2] });
410
+ proc.on('error', function(err){
411
+ if (err.code == "ENOENT") {
412
+ console.error('\n %s(1) does not exist, try --help\n', bin);
413
+ } else if (err.code == "EACCES") {
414
+ console.error('\n %s(1) not executable. try chmod or run with root\n', bin);
416
415
  }
417
416
  });
417
+
418
+ this.runningCommand = proc;
418
419
  };
419
420
 
420
421
  /**
@@ -777,300 +778,6 @@ Command.prototype.helpInformation = function(){
777
778
  ].join('\n');
778
779
  };
779
780
 
780
- /**
781
- * Prompt for a `Number`.
782
- *
783
- * @param {String} str
784
- * @param {Function} fn
785
- * @api private
786
- */
787
-
788
- Command.prototype.promptForNumber = function(str, fn){
789
- var self = this;
790
- this.promptSingleLine(str, function parseNumber(val){
791
- val = Number(val);
792
- if (isNaN(val)) return self.promptSingleLine(str + '(must be a number) ', parseNumber);
793
- fn(val);
794
- });
795
- };
796
-
797
- /**
798
- * Prompt for a `Date`.
799
- *
800
- * @param {String} str
801
- * @param {Function} fn
802
- * @api private
803
- */
804
-
805
- Command.prototype.promptForDate = function(str, fn){
806
- var self = this;
807
- this.promptSingleLine(str, function parseDate(val){
808
- val = new Date(val);
809
- if (isNaN(val.getTime())) return self.promptSingleLine(str + '(must be a date) ', parseDate);
810
- fn(val);
811
- });
812
- };
813
-
814
-
815
- /**
816
- * Prompt for a `Regular Expression`.
817
- *
818
- * @param {String} str
819
- * @param {Object} pattern regular expression object to test
820
- * @param {Function} fn
821
- * @api private
822
- */
823
-
824
- Command.prototype.promptForRegexp = function(str, pattern, fn){
825
- var self = this;
826
- this.promptSingleLine(str, function parseRegexp(val){
827
- if(!pattern.test(val)) return self.promptSingleLine(str + '(regular expression mismatch) ', parseRegexp);
828
- fn(val);
829
- });
830
- };
831
-
832
-
833
- /**
834
- * Single-line prompt.
835
- *
836
- * @param {String} str
837
- * @param {Function} fn
838
- * @api private
839
- */
840
-
841
- Command.prototype.promptSingleLine = function(str, fn){
842
- // determine if the 2nd argument is a regular expression
843
- if (arguments[1].global !== undefined && arguments[1].multiline !== undefined) {
844
- return this.promptForRegexp(str, arguments[1], arguments[2]);
845
- } else if ('function' == typeof arguments[2]) {
846
- return this['promptFor' + (fn.name || fn)](str, arguments[2]);
847
- }
848
-
849
- process.stdout.write(str);
850
- process.stdin.setEncoding('utf8');
851
- process.stdin.once('data', function(val){
852
- fn(val.trim());
853
- }).resume();
854
- };
855
-
856
- /**
857
- * Multi-line prompt.
858
- *
859
- * @param {String} str
860
- * @param {Function} fn
861
- * @api private
862
- */
863
-
864
- Command.prototype.promptMultiLine = function(str, fn){
865
- var buf = [];
866
- console.log(str);
867
- process.stdin.setEncoding('utf8');
868
- process.stdin.on('data', function(val){
869
- if ('\n' == val || '\r\n' == val) {
870
- process.stdin.removeAllListeners('data');
871
- fn(buf.join('\n'));
872
- } else {
873
- buf.push(val.trimRight());
874
- }
875
- }).resume();
876
- };
877
-
878
- /**
879
- * Prompt `str` and callback `fn(val)`
880
- *
881
- * Commander supports single-line and multi-line prompts.
882
- * To issue a single-line prompt simply add white-space
883
- * to the end of `str`, something like "name: ", whereas
884
- * for a multi-line prompt omit this "description:".
885
- *
886
- *
887
- * Examples:
888
- *
889
- * program.prompt('Username: ', function(name){
890
- * console.log('hi %s', name);
891
- * });
892
- *
893
- * program.prompt('Description:', function(desc){
894
- * console.log('description was "%s"', desc.trim());
895
- * });
896
- *
897
- * @param {String|Object} str
898
- * @param {Function} fn
899
- * @api public
900
- */
901
-
902
- Command.prototype.prompt = function(str, fn){
903
- var self = this;
904
- if ('string' == typeof str) {
905
- if (/ $/.test(str)) return this.promptSingleLine.apply(this, arguments);
906
- this.promptMultiLine(str, fn);
907
- } else {
908
- var keys = Object.keys(str)
909
- , obj = {};
910
-
911
- function next() {
912
- var key = keys.shift()
913
- , label = str[key];
914
-
915
- if (!key) return fn(obj);
916
- self.prompt(label, function(val){
917
- obj[key] = val;
918
- next();
919
- });
920
- }
921
-
922
- next();
923
- }
924
- };
925
-
926
- /**
927
- * Prompt for password with `str`, `mask` char and callback `fn(val)`.
928
- *
929
- * The mask string defaults to '', aka no output is
930
- * written while typing, you may want to use "*" etc.
931
- *
932
- * Examples:
933
- *
934
- * program.password('Password: ', function(pass){
935
- * console.log('got "%s"', pass);
936
- * process.stdin.destroy();
937
- * });
938
- *
939
- * program.password('Password: ', '*', function(pass){
940
- * console.log('got "%s"', pass);
941
- * process.stdin.destroy();
942
- * });
943
- *
944
- * @param {String} str
945
- * @param {String} mask
946
- * @param {Function} fn
947
- * @api public
948
- */
949
-
950
- Command.prototype.password = function(str, mask, fn){
951
- var self = this
952
- , buf = '';
953
-
954
- // default mask
955
- if ('function' == typeof mask) {
956
- fn = mask;
957
- mask = '';
958
- }
959
-
960
- keypress(process.stdin);
961
-
962
- function setRawMode(mode) {
963
- if (process.stdin.setRawMode) {
964
- process.stdin.setRawMode(mode);
965
- } else {
966
- tty.setRawMode(mode);
967
- }
968
- };
969
- setRawMode(true);
970
- process.stdout.write(str);
971
-
972
- // keypress
973
- process.stdin.on('keypress', function(c, key){
974
- if (key && 'enter' == key.name) {
975
- console.log();
976
- process.stdin.pause();
977
- process.stdin.removeAllListeners('keypress');
978
- setRawMode(false);
979
- if (!buf.trim().length) return self.password(str, mask, fn);
980
- fn(buf);
981
- return;
982
- }
983
-
984
- if (key && key.ctrl && 'c' == key.name) {
985
- console.log('%s', buf);
986
- process.exit();
987
- }
988
-
989
- process.stdout.write(mask);
990
- buf += c;
991
- }).resume();
992
- };
993
-
994
- /**
995
- * Confirmation prompt with `str` and callback `fn(bool)`
996
- *
997
- * Examples:
998
- *
999
- * program.confirm('continue? ', function(ok){
1000
- * console.log(' got %j', ok);
1001
- * process.stdin.destroy();
1002
- * });
1003
- *
1004
- * @param {String} str
1005
- * @param {Function} fn
1006
- * @api public
1007
- */
1008
-
1009
-
1010
- Command.prototype.confirm = function(str, fn, verbose){
1011
- var self = this;
1012
- this.prompt(str, function(ok){
1013
- if (!ok.trim()) {
1014
- if (!verbose) str += '(yes or no) ';
1015
- return self.confirm(str, fn, true);
1016
- }
1017
- fn(parseBool(ok));
1018
- });
1019
- };
1020
-
1021
- /**
1022
- * Choice prompt with `list` of items and callback `fn(index, item)`
1023
- *
1024
- * Examples:
1025
- *
1026
- * var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
1027
- *
1028
- * console.log('Choose the coolest pet:');
1029
- * program.choose(list, function(i){
1030
- * console.log('you chose %d "%s"', i, list[i]);
1031
- * process.stdin.destroy();
1032
- * });
1033
- *
1034
- * @param {Array} list
1035
- * @param {Number|Function} index or fn
1036
- * @param {Function} fn
1037
- * @api public
1038
- */
1039
-
1040
- Command.prototype.choose = function(list, index, fn){
1041
- var self = this
1042
- , hasDefault = 'number' == typeof index;
1043
-
1044
- if (!hasDefault) {
1045
- fn = index;
1046
- index = null;
1047
- }
1048
-
1049
- list.forEach(function(item, i){
1050
- if (hasDefault && i == index) {
1051
- console.log('* %d) %s', i + 1, item);
1052
- } else {
1053
- console.log(' %d) %s', i + 1, item);
1054
- }
1055
- });
1056
-
1057
- function again() {
1058
- self.prompt(' : ', function(val){
1059
- val = parseInt(val, 10) - 1;
1060
- if (hasDefault && isNaN(val)) val = index;
1061
-
1062
- if (null == list[val]) {
1063
- again();
1064
- } else {
1065
- fn(val, list[val]);
1066
- }
1067
- });
1068
- }
1069
-
1070
- again();
1071
- };
1072
-
1073
-
1074
781
  /**
1075
782
  * Output help information for this command
1076
783
  *
@@ -1107,18 +814,6 @@ function camelcase(flag) {
1107
814
  });
1108
815
  }
1109
816
 
1110
- /**
1111
- * Parse a boolean `str`.
1112
- *
1113
- * @param {String} str
1114
- * @return {Boolean}
1115
- * @api private
1116
- */
1117
-
1118
- function parseBool(str) {
1119
- return /^y|yes|ok|true$/i.test(str);
1120
- }
1121
-
1122
817
  /**
1123
818
  * Pad `str` to `width`.
1124
819
  *
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "commander"
3
- , "version": "1.2.0"
3
+ , "version": "2.0.0"
4
4
  , "description": "the complete solution for node.js command-line programs"
5
5
  , "keywords": ["command", "option", "parser", "prompt", "stdin"]
6
6
  , "author": "TJ Holowaychuk <tj@vision-media.ca>"
7
7
  , "repository": { "type": "git", "url": "https://github.com/visionmedia/commander.js.git" }
8
- , "dependencies": { "keypress": "0.1.x"}
9
8
  , "devDependencies": { "should": ">= 0.0.1" }
10
9
  , "scripts": { "test": "make test" }
11
10
  , "main": "index"