coa 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. package/.npmignore +6 -0
  2. package/.nyc_output/1f2a0db5a6d6559149db56d397f47cfc.json +1 -0
  3. package/.nyc_output/75b82d38f2186df930141082076e11c6.json +1 -0
  4. package/.travis.yml +9 -0
  5. package/GNUmakefile +34 -0
  6. package/README.md +1 -19
  7. package/coverage/base.css +212 -0
  8. package/coverage/coa/index.html +93 -0
  9. package/coverage/coa/index.js.html +68 -0
  10. package/coverage/coa/lib/arg.js.html +239 -0
  11. package/coverage/coa/lib/cmd.js.html +1556 -0
  12. package/coverage/coa/lib/coaobject.js.html +365 -0
  13. package/coverage/coa/lib/coaparam.js.html +440 -0
  14. package/coverage/coa/lib/color.js.html +131 -0
  15. package/coverage/coa/lib/completion.js.html +593 -0
  16. package/coverage/coa/lib/index.html +197 -0
  17. package/coverage/coa/lib/index.js.html +107 -0
  18. package/coverage/coa/lib/opt.js.html +524 -0
  19. package/coverage/coa/lib/shell.js.html +107 -0
  20. package/coverage/index.html +106 -0
  21. package/coverage/prettify.css +1 -0
  22. package/coverage/prettify.js +1 -0
  23. package/coverage/sort-arrow-sprite.png +0 -0
  24. package/coverage/sorter.js +158 -0
  25. package/index.js +1 -1
  26. package/lib/arg.js +161 -44
  27. package/lib/cmd.js +547 -434
  28. package/lib/color.js +22 -19
  29. package/lib/completion.js +119 -161
  30. package/lib/index.js +10 -14
  31. package/lib/opt.js +313 -130
  32. package/lib/shell.js +13 -13
  33. package/package.json +14 -19
  34. package/qq.js +17 -0
  35. package/src/arg.coffee +130 -0
  36. package/src/cmd.coffee +456 -0
  37. package/src/color.coffee +25 -0
  38. package/src/completion.coffee +156 -0
  39. package/src/index.coffee +5 -0
  40. package/src/opt.coffee +243 -0
  41. package/src/shell.coffee +10 -0
  42. package/test/coa.js +496 -0
  43. package/test/mocha.opts +2 -0
  44. package/test/shell-test.js +60 -0
  45. package/tests/api-h.js +9 -0
  46. package/tests/h.js +6 -0
  47. package/LICENSE +0 -21
  48. package/lib/coaobject.js +0 -100
  49. package/lib/coaparam.js +0 -125
package/lib/cmd.js CHANGED
@@ -1,492 +1,605 @@
1
- 'use strict';
1
+ // Generated by CoffeeScript 1.6.3
2
+ var Cmd, Color, PATH, Q, UTIL,
3
+ __slice = [].slice;
2
4
 
3
- const
4
- UTIL = require('util'),
5
- PATH = require('path'),
6
- EOL = require('os').EOL,
5
+ UTIL = require('util');
7
6
 
8
- Q = require('q'),
7
+ PATH = require('path');
9
8
 
10
- CoaObject = require('./coaobject'),
11
- Color = require('./color'),
12
- Opt = require('./opt'),
13
- Arg = require('./arg'),
14
- completion = require('./completion');
9
+ Color = require('./color').Color;
10
+
11
+ Q = require('q');
15
12
 
16
13
  /**
17
- * Command
18
- *
19
- * Top level entity. Commands may have options and arguments.
20
- *
21
- * @namespace
22
- * @class Cmd
23
- * @extends CoaObject
24
- */
25
- class Cmd extends CoaObject {
26
- /**
27
- * @constructs
28
- * @param {COA.Cmd} [cmd] parent command
29
- */
30
- constructor(cmd) {
31
- super(cmd);
32
-
33
- this._parent(cmd);
34
- this._cmds = [];
35
- this._cmdsByName = {};
36
- this._opts = [];
37
- this._optsByKey = {};
38
- this._args = [];
39
- this._api = null;
40
- this._ext = false;
41
- }
14
+ Command
42
15
 
43
- static create(cmd) {
44
- return new Cmd(cmd);
45
- }
16
+ Top level entity. Commands may have options and arguments.
17
+ @namespace
18
+ @class Presents command
19
+ */
46
20
 
47
- /**
48
- * Returns object containing all its subcommands as methods
49
- * to use from other programs.
50
- *
51
- * @returns {Object}
52
- */
53
- get api() {
54
- // Need _this here because of passed arguments into _api
55
- const _this = this;
56
- this._api || (this._api = function () {
57
- return _this.invoke.apply(_this, arguments);
58
- });
59
21
 
60
- const cmds = this._cmdsByName;
61
- Object.keys(cmds).forEach(cmd => { this._api[cmd] = cmds[cmd].api; });
22
+ exports.Cmd = Cmd = (function() {
23
+ /**
24
+ @constructs
25
+ @param {COA.Cmd} [cmd] parent command
26
+ */
62
27
 
63
- return this._api;
28
+ function Cmd(cmd) {
29
+ if (!(this instanceof Cmd)) {
30
+ return new Cmd(cmd);
64
31
  }
65
-
66
- _parent(cmd) {
67
- this._cmd = cmd || this;
68
-
69
- this.isRootCmd ||
70
- cmd._cmds.push(this) &&
71
- this._name &&
72
- (this._cmd._cmdsByName[this._name] = this);
73
-
74
- return this;
32
+ this._parent(cmd);
33
+ this._cmds = [];
34
+ this._cmdsByName = {};
35
+ this._opts = [];
36
+ this._optsByKey = {};
37
+ this._args = [];
38
+ this._ext = false;
39
+ }
40
+
41
+ Cmd.get = function(propertyName, func) {
42
+ return Object.defineProperty(this.prototype, propertyName, {
43
+ configurable: true,
44
+ enumerable: true,
45
+ get: func
46
+ });
47
+ };
48
+
49
+ /**
50
+ Returns object containing all its subcommands as methods
51
+ to use from other programs.
52
+ @returns {Object}
53
+ */
54
+
55
+
56
+ Cmd.get('api', function() {
57
+ var c, _fn,
58
+ _this = this;
59
+ if (!this._api) {
60
+ this._api = function() {
61
+ return _this.invoke.apply(_this, arguments);
62
+ };
75
63
  }
76
-
77
- get isRootCmd() {
78
- return this._cmd === this;
64
+ _fn = function(c) {
65
+ return _this._api[c] = _this._cmdsByName[c].api;
66
+ };
67
+ for (c in this._cmdsByName) {
68
+ _fn(c);
79
69
  }
70
+ return this._api;
71
+ });
72
+
73
+ Cmd.prototype._parent = function(cmd) {
74
+ this._cmd = cmd || this;
75
+ if (cmd) {
76
+ cmd._cmds.push(this);
77
+ if (this._name) {
78
+ this._cmd._cmdsByName[this._name] = this;
79
+ }
80
+ }
81
+ return this;
82
+ };
80
83
 
81
- /**
82
- * Set a canonical command identifier to be used anywhere in the API.
83
- *
84
- * @param {String} name - command name
85
- * @returns {COA.Cmd} - this instance (for chainability)
86
- */
87
- name(name) {
88
- super.name(name);
84
+ /**
85
+ Set a canonical command identifier to be used anywhere in the API.
86
+ @param {String} _name command name
87
+ @returns {COA.Cmd} this instance (for chainability)
88
+ */
89
89
 
90
- this.isRootCmd ||
91
- (this._cmd._cmdsByName[name] = this);
92
90
 
93
- return this;
91
+ Cmd.prototype.name = function(_name) {
92
+ this._name = _name;
93
+ if (this._cmd !== this) {
94
+ this._cmd._cmdsByName[_name] = this;
94
95
  }
96
+ return this;
97
+ };
95
98
 
96
- /**
97
- * Create new or add existing subcommand for current command.
98
- *
99
- * @param {COA.Cmd} [cmd] existing command instance
100
- * @returns {COA.Cmd} new subcommand instance
101
- */
102
- cmd(cmd) {
103
- return cmd?
104
- cmd._parent(this)
105
- : new Cmd(this);
106
- }
99
+ /**
100
+ Set a long description for command to be used anywhere in text messages.
101
+ @param {String} _title command title
102
+ @returns {COA.Cmd} this instance (for chainability)
103
+ */
107
104
 
108
- /**
109
- * Create option for current command.
110
- *
111
- * @returns {COA.Opt} new option instance
112
- */
113
- opt() {
114
- return new Opt(this);
115
- }
116
105
 
117
- /**
118
- * Create argument for current command.
119
- *
120
- * @returns {COA.Opt} new argument instance
121
- */
122
- arg() {
123
- return new Arg(this);
124
- }
106
+ Cmd.prototype.title = function(_title) {
107
+ this._title = _title;
108
+ return this;
109
+ };
125
110
 
126
- /**
127
- * Add (or set) action for current command.
128
- *
129
- * @param {Function} act - action function,
130
- * invoked in the context of command instance
131
- * and has the parameters:
132
- * - {Object} opts - parsed options
133
- * - {String[]} args - parsed arguments
134
- * - {Object} res - actions result accumulator
135
- * It can return rejected promise by Cmd.reject (in case of error)
136
- * or any other value treated as result.
137
- * @param {Boolean} [force=false] flag for set action instead add to existings
138
- * @returns {COA.Cmd} - this instance (for chainability)
139
- */
140
- act(act, force) {
141
- if(!act) return this;
142
-
143
- (!this._act || force) && (this._act = []);
144
- this._act.push(act);
145
-
146
- return this;
147
- }
111
+ /**
112
+ Create new or add existing subcommand for current command.
113
+ @param {COA.Cmd} [cmd] existing command instance
114
+ @returns {COA.Cmd} new subcommand instance
115
+ */
148
116
 
149
- /**
150
- * Make command "helpful", i.e. add -h --help flags for print usage.
151
- *
152
- * @returns {COA.Cmd} - this instance (for chainability)
153
- */
154
- helpful() {
155
- return this.opt()
156
- .name('help')
157
- .title('Help')
158
- .short('h')
159
- .long('help')
160
- .flag()
161
- .only()
162
- .act(function() {
163
- return this.usage();
164
- })
165
- .end();
166
- }
167
117
 
168
- /**
169
- * Adds shell completion to command, adds "completion" subcommand,
170
- * that makes all the magic.
171
- * Must be called only on root command.
172
- *
173
- * @returns {COA.Cmd} - this instance (for chainability)
174
- */
175
- completable() {
176
- return this.cmd()
177
- .name('completion')
178
- .apply(completion)
179
- .end();
118
+ Cmd.prototype.cmd = function(cmd) {
119
+ if (cmd) {
120
+ return cmd._parent(this);
121
+ } else {
122
+ return new Cmd(this);
180
123
  }
181
-
182
- /**
183
- * Allow command to be extendable by external node.js modules.
184
- *
185
- * @param {String} [pattern] Pattern of node.js module to find subcommands at.
186
- * @returns {COA.Cmd} - this instance (for chainability)
187
- */
188
- extendable(pattern) {
189
- this._ext = pattern || true;
190
- return this;
124
+ };
125
+
126
+ /**
127
+ Create option for current command.
128
+ @returns {COA.Opt} new option instance
129
+ */
130
+
131
+
132
+ Cmd.prototype.opt = function() {
133
+ return new (require('./opt').Opt)(this);
134
+ };
135
+
136
+ /**
137
+ Create argument for current command.
138
+ @returns {COA.Opt} new argument instance
139
+ */
140
+
141
+
142
+ Cmd.prototype.arg = function() {
143
+ return new (require('./arg').Arg)(this);
144
+ };
145
+
146
+ /**
147
+ Add (or set) action for current command.
148
+ @param {Function} act action function,
149
+ invoked in the context of command instance
150
+ and has the parameters:
151
+ - {Object} opts parsed options
152
+ - {Array} args parsed arguments
153
+ - {Object} res actions result accumulator
154
+ It can return rejected promise by Cmd.reject (in case of error)
155
+ or any other value treated as result.
156
+ @param {Boolean} [force=false] flag for set action instead add to existings
157
+ @returns {COA.Cmd} this instance (for chainability)
158
+ */
159
+
160
+
161
+ Cmd.prototype.act = function(act, force) {
162
+ if (!act) {
163
+ return this;
191
164
  }
192
-
193
- _exit(msg, code) {
194
- return process.once('exit', function() {
195
- msg && console[code === 0 ? 'log' : 'error'](msg);
196
- process.exit(code || 0);
197
- });
165
+ if (!force && this._act) {
166
+ this._act.push(act);
167
+ } else {
168
+ this._act = [act];
198
169
  }
199
-
200
- /**
201
- * Build full usage text for current command instance.
202
- *
203
- * @returns {String} usage text
204
- */
205
- usage() {
206
- const res = [];
207
-
208
- this._title && res.push(this._fullTitle());
209
-
210
- res.push('', 'Usage:');
211
-
212
- this._cmds.length
213
- && res.push([
214
- '', '', Color('lred', this._fullName()), Color('lblue', 'COMMAND'),
215
- Color('lgreen', '[OPTIONS]'), Color('lpurple', '[ARGS]')
216
- ].join(' '));
217
-
218
- (this._opts.length + this._args.length)
219
- && res.push([
220
- '', '', Color('lred', this._fullName()),
221
- Color('lgreen', '[OPTIONS]'), Color('lpurple', '[ARGS]')
222
- ].join(' '));
223
-
224
- res.push(
225
- this._usages(this._cmds, 'Commands'),
226
- this._usages(this._opts, 'Options'),
227
- this._usages(this._args, 'Arguments')
228
- );
229
-
230
- return res.join(EOL);
170
+ return this;
171
+ };
172
+
173
+ /**
174
+ Set custom additional completion for current command.
175
+ @param {Function} completion generation function,
176
+ invoked in the context of command instance.
177
+ Accepts parameters:
178
+ - {Object} opts completion options
179
+ It can return promise or any other value treated as result.
180
+ @returns {COA.Cmd} this instance (for chainability)
181
+ */
182
+
183
+
184
+ Cmd.prototype.comp = function(_comp) {
185
+ this._comp = _comp;
186
+ return this;
187
+ };
188
+
189
+ /**
190
+ Apply function with arguments in context of command instance.
191
+ @param {Function} fn
192
+ @param {Array} args
193
+ @returns {COA.Cmd} this instance (for chainability)
194
+ */
195
+
196
+
197
+ Cmd.prototype.apply = function() {
198
+ var args, fn;
199
+ fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
200
+ fn.apply(this, args);
201
+ return this;
202
+ };
203
+
204
+ /**
205
+ Make command "helpful", i.e. add -h --help flags for print usage.
206
+ @returns {COA.Cmd} this instance (for chainability)
207
+ */
208
+
209
+
210
+ Cmd.prototype.helpful = function() {
211
+ return this.opt().name('help').title('Help').short('h').long('help').flag().only().act(function() {
212
+ return this.usage();
213
+ }).end();
214
+ };
215
+
216
+ /**
217
+ Adds shell completion to command, adds "completion" subcommand,
218
+ that makes all the magic.
219
+ Must be called only on root command.
220
+ @returns {COA.Cmd} this instance (for chainability)
221
+ */
222
+
223
+
224
+ Cmd.prototype.completable = function() {
225
+ return this.cmd().name('completion').apply(require('./completion')).end();
226
+ };
227
+
228
+ /**
229
+ Allow command to be extendable by external node.js modules.
230
+ @param {String} [pattern] Pattern of node.js module to find subcommands at.
231
+ @returns {COA.Cmd} this instance (for chainability)
232
+ */
233
+
234
+
235
+ Cmd.prototype.extendable = function(pattern) {
236
+ this._ext = pattern || true;
237
+ return this;
238
+ };
239
+
240
+ Cmd.prototype._exit = function(msg, code) {
241
+ return process.once('exit', function() {
242
+ if (msg) {
243
+ console.error(msg);
244
+ }
245
+ return process.exit(code || 0);
246
+ });
247
+ };
248
+
249
+ /**
250
+ Build full usage text for current command instance.
251
+ @returns {String} usage text
252
+ */
253
+
254
+
255
+ Cmd.prototype.usage = function() {
256
+ var res;
257
+ res = [];
258
+ if (this._title) {
259
+ res.push(this._fullTitle());
231
260
  }
232
-
233
- _usage() {
234
- return Color('lblue', this._name) + ' : ' + this._title;
261
+ res.push('', 'Usage:');
262
+ if (this._cmds.length) {
263
+ res.push(['', '', Color('lred', this._fullName()), Color('lblue', 'COMMAND'), Color('lgreen', '[OPTIONS]'), Color('lpurple', '[ARGS]')].join(' '));
235
264
  }
236
-
237
- _usages(os, title) {
238
- if(!os.length) return;
239
-
240
- return ['', title + ':']
241
- .concat(os.map(o => ` ${o._usage()}`))
242
- .join(EOL);
265
+ if (this._opts.length + this._args.length) {
266
+ res.push(['', '', Color('lred', this._fullName()), Color('lgreen', '[OPTIONS]'), Color('lpurple', '[ARGS]')].join(' '));
243
267
  }
244
-
245
- _fullTitle() {
246
- return `${this.isRootCmd? '' : this._cmd._fullTitle() + EOL}${this._title}`;
268
+ res.push(this._usages(this._cmds, 'Commands'), this._usages(this._opts, 'Options'), this._usages(this._args, 'Arguments'));
269
+ return res.join('\n');
270
+ };
271
+
272
+ Cmd.prototype._usage = function() {
273
+ return Color('lblue', this._name) + ' : ' + this._title;
274
+ };
275
+
276
+ Cmd.prototype._usages = function(os, title) {
277
+ var o, res, _i, _len;
278
+ if (!os.length) {
279
+ return;
247
280
  }
248
-
249
- _fullName() {
250
- return `${this.isRootCmd? '' : this._cmd._fullName() + ' '}${PATH.basename(this._name)}`;
281
+ res = ['', title + ':'];
282
+ for (_i = 0, _len = os.length; _i < _len; _i++) {
283
+ o = os[_i];
284
+ res.push(' ' + o._usage());
251
285
  }
252
-
253
- _ejectOpt(opts, opt) {
254
- const pos = opts.indexOf(opt);
255
- if(pos === -1) return;
256
-
257
- return opts[pos]._arr?
258
- opts[pos] :
259
- opts.splice(pos, 1)[0];
286
+ return res.join('\n');
287
+ };
288
+
289
+ Cmd.prototype._fullTitle = function() {
290
+ return (this._cmd === this ? '' : this._cmd._fullTitle() + '\n') + this._title;
291
+ };
292
+
293
+ Cmd.prototype._fullName = function() {
294
+ return (this._cmd === this ? '' : this._cmd._fullName() + ' ') + PATH.basename(this._name);
295
+ };
296
+
297
+ Cmd.prototype._ejectOpt = function(opts, opt) {
298
+ var pos;
299
+ if ((pos = opts.indexOf(opt)) >= 0) {
300
+ if (opts[pos]._arr) {
301
+ return opts[pos];
302
+ } else {
303
+ return opts.splice(pos, 1)[0];
304
+ }
260
305
  }
261
-
262
- _checkRequired(opts, args) {
263
- if(this._opts.some(opt => opt._only && opts.hasOwnProperty(opt._name))) return;
264
-
265
- const all = this._opts.concat(this._args);
266
- let i;
267
- while(i = all.shift())
268
- if(i._req && i._checkParsed(opts, args))
269
- return this.reject(i._requiredText());
306
+ };
307
+
308
+ Cmd.prototype._checkRequired = function(opts, args) {
309
+ var all, i;
310
+ if (!(this._opts.filter(function(o) {
311
+ return o._only && o._name in opts;
312
+ })).length) {
313
+ all = this._opts.concat(this._args);
314
+ while (i = all.shift()) {
315
+ if (i._req && i._checkParsed(opts, args)) {
316
+ return this.reject(i._requiredText());
317
+ }
318
+ }
270
319
  }
320
+ };
271
321
 
272
- _parseCmd(argv, unparsed) {
273
- unparsed || (unparsed = []);
274
-
275
- let i,
276
- optSeen = false;
277
- while(i = argv.shift()) {
278
- i.indexOf('-') || (optSeen = true);
279
-
280
- if(optSeen || !/^\w[\w-_]*$/.test(i)) {
281
- unparsed.push(i);
282
- continue;
322
+ Cmd.prototype._parseCmd = function(argv, unparsed) {
323
+ var c, cmd, cmdDesc, e, i, optSeen, pkg;
324
+ if (unparsed == null) {
325
+ unparsed = [];
326
+ }
327
+ argv = argv.concat();
328
+ optSeen = false;
329
+ while (i = argv.shift()) {
330
+ if (!i.indexOf('-')) {
331
+ optSeen = true;
332
+ }
333
+ if (!optSeen && /^\w[\w-_]*$/.test(i)) {
334
+ cmd = this._cmdsByName[i];
335
+ if (!cmd && this._ext) {
336
+ if (typeof this._ext === 'string') {
337
+ if (~this._ext.indexOf('%s')) {
338
+ pkg = UTIL.format(this._ext, i);
339
+ } else {
340
+ pkg = this._ext + i;
283
341
  }
284
-
285
- let pkg, cmd = this._cmdsByName[i];
286
- if(!cmd && this._ext) {
287
- if(this._ext === true) {
288
- pkg = i;
289
- let c = this;
290
- while(true) { // eslint-disable-line
291
- pkg = c._name + '-' + pkg;
292
- if(c.isRootCmd) break;
293
- c = c._cmd;
294
- }
295
- } else if(typeof this._ext === 'string')
296
- pkg = ~this._ext.indexOf('%s')?
297
- UTIL.format(this._ext, i) :
298
- this._ext + i;
299
-
300
- let cmdDesc;
301
- try {
302
- cmdDesc = require(pkg);
303
- } catch(e) {
304
- // Dummy
305
- }
306
-
307
- if(cmdDesc) {
308
- if(typeof cmdDesc === 'function') {
309
- this.cmd().name(i).apply(cmdDesc).end();
310
- } else if(typeof cmdDesc === 'object') {
311
- this.cmd(cmdDesc);
312
- cmdDesc.name(i);
313
- } else throw new Error('Error: Unsupported command declaration type, '
314
- + 'should be a function or COA.Cmd() object');
315
-
316
- cmd = this._cmdsByName[i];
317
- }
342
+ } else if (this._ext === true) {
343
+ pkg = i;
344
+ c = this;
345
+ while (true) {
346
+ pkg = c._name + '-' + pkg;
347
+ if (c._cmd === c) {
348
+ break;
349
+ }
350
+ c = c._cmd;
318
351
  }
319
-
320
- if(cmd) return cmd._parseCmd(argv, unparsed);
321
-
322
- unparsed.push(i);
352
+ }
353
+ try {
354
+ cmdDesc = require(pkg);
355
+ } catch (_error) {
356
+ e = _error;
357
+ }
358
+ if (cmdDesc) {
359
+ if (typeof cmdDesc === 'function') {
360
+ this.cmd().name(i).apply(cmdDesc).end();
361
+ } else if (typeof cmdDesc === 'object') {
362
+ this.cmd(cmdDesc);
363
+ cmdDesc.name(i);
364
+ } else {
365
+ throw new Error('Error: Unsupported command declaration type, ' + 'should be function or COA.Cmd() object');
366
+ }
367
+ cmd = this._cmdsByName[i];
368
+ }
323
369
  }
324
-
325
- return { cmd : this, argv : unparsed };
370
+ if (cmd) {
371
+ return cmd._parseCmd(argv, unparsed);
372
+ }
373
+ }
374
+ unparsed.push(i);
326
375
  }
327
-
328
- _parseOptsAndArgs(argv) {
329
- const opts = {},
330
- args = {},
331
- nonParsedOpts = this._opts.concat(),
332
- nonParsedArgs = this._args.concat();
333
-
334
- let res, i;
335
- while(i = argv.shift()) {
336
- if(i !== '--' && i[0] === '-') {
337
- const m = i.match(/^(--\w[\w-_]*)=(.*)$/);
338
- if(m) {
339
- i = m[1];
340
- this._optsByKey[i]._flag || argv.unshift(m[2]);
341
- }
342
-
343
- const opt = this._ejectOpt(nonParsedOpts, this._optsByKey[i]);
344
- if(!opt) return this.reject(`Unknown option: ${i}`);
345
-
346
- if(Q.isRejected(res = opt._parse(argv, opts))) return res;
347
-
348
- continue;
376
+ return {
377
+ cmd: this,
378
+ argv: unparsed
379
+ };
380
+ };
381
+
382
+ Cmd.prototype._parseOptsAndArgs = function(argv) {
383
+ var a, arg, args, i, m, nonParsedArgs, nonParsedOpts, opt, opts, res;
384
+ opts = {};
385
+ args = {};
386
+ nonParsedOpts = this._opts.concat();
387
+ nonParsedArgs = this._args.concat();
388
+ while (i = argv.shift()) {
389
+ if (i !== '--' && !i.indexOf('-')) {
390
+ if (m = i.match(/^(--\w[\w-_]*)=(.*)$/)) {
391
+ i = m[1];
392
+ if (!this._optsByKey[i]._flag) {
393
+ argv.unshift(m[2]);
394
+ }
395
+ }
396
+ if (opt = this._ejectOpt(nonParsedOpts, this._optsByKey[i])) {
397
+ if (Q.isRejected(res = opt._parse(argv, opts))) {
398
+ return res;
399
+ }
400
+ } else {
401
+ return this.reject("Unknown option: " + i);
402
+ }
403
+ } else {
404
+ if (i === '--') {
405
+ i = argv.splice(0);
406
+ }
407
+ i = Array.isArray(i) ? i : [i];
408
+ while (a = i.shift()) {
409
+ if (arg = nonParsedArgs.shift()) {
410
+ if (arg._arr) {
411
+ nonParsedArgs.unshift(arg);
349
412
  }
350
-
351
- i === '--' && (i = argv.splice(0));
352
- Array.isArray(i) || (i = [i]);
353
-
354
- let a;
355
- while(a = i.shift()) {
356
- let arg = nonParsedArgs.shift();
357
- if(!arg) return this.reject(`Unknown argument: ${a}`);
358
-
359
- arg._arr && nonParsedArgs.unshift(arg);
360
- if(Q.isRejected(res = arg._parse(a, args))) return res;
413
+ if (Q.isRejected(res = arg._parse(a, args))) {
414
+ return res;
361
415
  }
416
+ } else {
417
+ return this.reject("Unknown argument: " + a);
418
+ }
362
419
  }
420
+ }
421
+ }
422
+ return {
423
+ opts: this._setDefaults(opts, nonParsedOpts),
424
+ args: this._setDefaults(args, nonParsedArgs)
425
+ };
426
+ };
427
+
428
+ Cmd.prototype._setDefaults = function(params, desc) {
429
+ var i, _i, _len;
430
+ for (_i = 0, _len = desc.length; _i < _len; _i++) {
431
+ i = desc[_i];
432
+ if (!(i._name in params) && '_def' in i) {
433
+ i._saveVal(params, i._def);
434
+ }
435
+ }
436
+ return params;
437
+ };
438
+
439
+ Cmd.prototype._processParams = function(params, desc) {
440
+ var i, n, notExists, res, v, vals, _i, _j, _len, _len1;
441
+ notExists = [];
442
+ for (_i = 0, _len = desc.length; _i < _len; _i++) {
443
+ i = desc[_i];
444
+ n = i._name;
445
+ if (!(n in params)) {
446
+ notExists.push(i);
447
+ continue;
448
+ }
449
+ vals = params[n];
450
+ delete params[n];
451
+ if (!Array.isArray(vals)) {
452
+ vals = [vals];
453
+ }
454
+ for (_j = 0, _len1 = vals.length; _j < _len1; _j++) {
455
+ v = vals[_j];
456
+ if (Q.isRejected(res = i._saveVal(params, v))) {
457
+ return res;
458
+ }
459
+ }
460
+ }
461
+ return this._setDefaults(params, notExists);
462
+ };
363
463
 
464
+ Cmd.prototype._parseArr = function(argv) {
465
+ return Q.when(this._parseCmd(argv), function(p) {
466
+ return Q.when(p.cmd._parseOptsAndArgs(p.argv), function(r) {
364
467
  return {
365
- opts : this._setDefaults(opts, nonParsedOpts),
366
- args : this._setDefaults(args, nonParsedArgs)
468
+ cmd: p.cmd,
469
+ opts: r.opts,
470
+ args: r.args
367
471
  };
472
+ });
473
+ });
474
+ };
475
+
476
+ Cmd.prototype._do = function(input) {
477
+ var _this = this;
478
+ return Q.when(input, function(input) {
479
+ var cmd;
480
+ cmd = input.cmd;
481
+ return [_this._checkRequired].concat(cmd._act || []).reduce(function(res, act) {
482
+ return Q.when(res, function(res) {
483
+ return act.call(cmd, input.opts, input.args, res);
484
+ });
485
+ }, void 0);
486
+ });
487
+ };
488
+
489
+ /**
490
+ Parse arguments from simple format like NodeJS process.argv
491
+ and run ahead current program, i.e. call process.exit when all actions done.
492
+ @param {Array} argv
493
+ @returns {COA.Cmd} this instance (for chainability)
494
+ */
495
+
496
+
497
+ Cmd.prototype.run = function(argv) {
498
+ var cb,
499
+ _this = this;
500
+ if (argv == null) {
501
+ argv = process.argv.slice(2);
368
502
  }
503
+ cb = function(code) {
504
+ return function(res) {
505
+ var _ref, _ref1;
506
+ if (res) {
507
+ return _this._exit((_ref = res.stack) != null ? _ref : res.toString(), (_ref1 = res.exitCode) != null ? _ref1 : code);
508
+ } else {
509
+ return _this._exit();
510
+ }
511
+ };
512
+ };
513
+ Q.when(this["do"](argv), cb(0), cb(1)).done();
514
+ return this;
515
+ };
369
516
 
370
- _setDefaults(params, desc) {
371
- for(const item of desc)
372
- item._def &&
373
- !params.hasOwnProperty(item._name) &&
374
- item._saveVal(params, item._def);
375
-
376
- return params;
377
- }
378
-
379
- _processParams(params, desc) {
380
- const notExists = [];
381
-
382
- for(const item of desc) {
383
- const n = item._name;
384
-
385
- if(!params.hasOwnProperty(n)) {
386
- notExists.push(item);
387
- continue;
388
- }
389
-
390
- const vals = Array.isArray(params[n])? params[n] : [params[n]];
391
- delete params[n];
517
+ /**
518
+ Convenient function to run command from tests.
519
+ @param {Array} argv
520
+ @returns {Q.Promise}
521
+ */
392
522
 
393
- let res;
394
- for(const v of vals)
395
- if(Q.isRejected(res = item._saveVal(params, v)))
396
- return res;
397
- }
398
523
 
399
- return this._setDefaults(params, notExists);
524
+ Cmd.prototype["do"] = function(argv) {
525
+ return this._do(this._parseArr(argv || []));
526
+ };
527
+
528
+ /**
529
+ Invoke specified (or current) command using provided
530
+ options and arguments.
531
+ @param {String|Array} cmds subcommand to invoke (optional)
532
+ @param {Object} opts command options (optional)
533
+ @param {Object} args command arguments (optional)
534
+ @returns {Q.Promise}
535
+ */
536
+
537
+
538
+ Cmd.prototype.invoke = function(cmds, opts, args) {
539
+ var _this = this;
540
+ if (cmds == null) {
541
+ cmds = [];
400
542
  }
401
-
402
- _parseArr(argv) {
403
- return Q.when(this._parseCmd(argv), p =>
404
- Q.when(p.cmd._parseOptsAndArgs(p.argv), r => ({
405
- cmd : p.cmd,
406
- opts : r.opts,
407
- args : r.args
408
- })));
543
+ if (opts == null) {
544
+ opts = {};
409
545
  }
410
-
411
- _do(inputPromise) {
412
- return Q.when(inputPromise, input => {
413
- return [this._checkRequired]
414
- .concat(input.cmd._act || [])
415
- .reduce((res, act) =>
416
- Q.when(res, prev => act.call(input.cmd, input.opts, input.args, prev)),
417
- undefined);
418
- });
546
+ if (args == null) {
547
+ args = {};
419
548
  }
549
+ if (typeof cmds === 'string') {
550
+ cmds = cmds.split(' ');
551
+ }
552
+ if (arguments.length < 3) {
553
+ if (!Array.isArray(cmds)) {
554
+ args = opts;
555
+ opts = cmds;
556
+ cmds = [];
557
+ }
558
+ }
559
+ return Q.when(this._parseCmd(cmds), function(p) {
560
+ if (p.argv.length) {
561
+ return _this.reject("Unknown command: " + cmds.join(' '));
562
+ }
563
+ return Q.all([_this._processParams(opts, _this._opts), _this._processParams(args, _this._args)]).spread(function(opts, args) {
564
+ return _this._do({
565
+ cmd: p.cmd,
566
+ opts: opts,
567
+ args: args
568
+ }).fail(function(res) {
569
+ if (res && res.exitCode === 0) {
570
+ return res.toString();
571
+ } else {
572
+ return _this.reject(res);
573
+ }
574
+ });
575
+ });
576
+ });
577
+ };
420
578
 
421
- /**
422
- * Parse arguments from simple format like NodeJS process.argv
423
- * and run ahead current program, i.e. call process.exit when all actions done.
424
- *
425
- * @param {String[]} argv - arguments
426
- * @returns {COA.Cmd} - this instance (for chainability)
427
- */
428
- run(argv) {
429
- argv || (argv = process.argv.slice(2));
579
+ /**
580
+ Return reject of actions results promise with error code.
581
+ Use in .act() for return with error.
582
+ @param {Object} reject reason
583
+ You can customize toString() method and exitCode property
584
+ of reason object.
585
+ @returns {Q.promise} rejected promise
586
+ */
430
587
 
431
- const cb = code =>
432
- res => res?
433
- this._exit(res.stack || res.toString(), (res.hasOwnProperty('exitCode')? res.exitCode : code) || 0) :
434
- this._exit();
435
588
 
436
- Q.when(this.do(argv), cb(0), cb(1)).done();
589
+ Cmd.prototype.reject = function(reason) {
590
+ return Q.reject(reason);
591
+ };
437
592
 
438
- return this;
439
- }
593
+ /**
594
+ Finish chain for current subcommand and return parent command instance.
595
+ @returns {COA.Cmd} parent command
596
+ */
440
597
 
441
- /**
442
- * Invoke specified (or current) command using provided
443
- * options and arguments.
444
- *
445
- * @param {String|String[]} [cmds] - subcommand to invoke (optional)
446
- * @param {Object} [opts] - command options (optional)
447
- * @param {Object} [args] - command arguments (optional)
448
- * @returns {Q.Promise}
449
- */
450
- invoke(cmds, opts, args) {
451
- cmds || (cmds = []);
452
- opts || (opts = {});
453
- args || (args = {});
454
- typeof cmds === 'string' && (cmds = cmds.split(' '));
455
-
456
- if(arguments.length < 3 && !Array.isArray(cmds)) {
457
- args = opts;
458
- opts = cmds;
459
- cmds = [];
460
- }
461
598
 
462
- return Q.when(this._parseCmd(cmds), p => {
463
- if(p.argv.length)
464
- return this.reject(`Unknown command: ${cmds.join(' ')}`);
465
-
466
- return Q.all([
467
- this._processParams(opts, this._opts),
468
- this._processParams(args, this._args)
469
- ]).spread((_opts, _args) =>
470
- this._do({
471
- cmd : p.cmd,
472
- opts : _opts,
473
- args : _args
474
- })
475
- .fail(res => (res && res.exitCode === 0)?
476
- res.toString() :
477
- this.reject(res)));
478
- });
479
- }
480
- }
599
+ Cmd.prototype.end = function() {
600
+ return this._cmd;
601
+ };
481
602
 
482
- /**
483
- * Convenient function to run command from tests.
484
- *
485
- * @param {String[]} argv - arguments
486
- * @returns {Q.Promise}
487
- */
488
- Cmd.prototype.do = function(argv) {
489
- return this._do(this._parseArr(argv || []));
490
- };
603
+ return Cmd;
491
604
 
492
- module.exports = Cmd;
605
+ })();