yargs 3.7.1 → 3.9.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.
package/lib/usage.js CHANGED
@@ -1,406 +1,314 @@
1
1
  // this file handles outputting usage instructions,
2
2
  // failures, etc. keeps logging in one place.
3
- var decamelize = require('decamelize'),
4
- wordwrap = require('wordwrap'),
5
- wsize = require('window-size');
3
+ var cliui = require('cliui'),
4
+ decamelize = require('decamelize'),
5
+ wsize = require('window-size')
6
6
 
7
7
  module.exports = function (yargs) {
8
- var self = {};
9
-
10
- // methods for ouputting/building failure message.
11
- var fails = [];
12
- self.failFn = function (f) {
13
- fails.push(f);
14
- };
15
-
16
- var failMessage = null;
17
- var showHelpOnFail = true;
18
- self.showHelpOnFail = function (enabled, message) {
19
- if (typeof enabled === 'string') {
20
- message = enabled;
21
- enabled = true;
22
- }
23
- else if (typeof enabled === 'undefined') {
24
- enabled = true;
25
- }
26
- failMessage = message;
27
- showHelpOnFail = enabled;
28
- return self;
29
- };
30
-
31
- self.fail = function (msg) {
32
- if (fails.length) {
33
- fails.forEach(function (f) {
34
- f(msg);
35
- });
36
- } else {
37
- if (showHelpOnFail) yargs.showHelp("error");
38
- if (msg) console.error(msg);
39
- if (failMessage) {
40
- if (msg) console.error("");
41
- console.error(failMessage);
42
- }
43
- if (yargs.getExitProcess()){
44
- process.exit(1);
45
- }else{
46
- throw new Error(msg);
47
- }
48
- }
49
- };
50
-
51
- // methods for ouputting/building help (usage) message.
52
- var usage;
53
- self.usage = function (msg) {
54
- usage = msg;
55
- };
56
-
57
- var examples = [];
58
- self.example = function (cmd, description) {
59
- examples.push([cmd, description || '']);
60
- };
61
-
62
- var commands = [];
63
- self.command = function (cmd, description) {
64
- commands.push([cmd, description || '']);
65
- };
66
- self.getCommands = function () {
67
- return commands;
68
- };
69
-
70
- var descriptions = {};
71
- self.describe = function (key, desc) {
72
- if (typeof key === 'object') {
73
- Object.keys(key).forEach(function (k) {
74
- self.describe(k, key[k]);
75
- });
76
- }
77
- else {
78
- descriptions[key] = desc;
79
- }
80
- };
81
- self.getDescriptions = function() {
82
- return descriptions;
8
+ var self = {}
9
+
10
+ // methods for ouputting/building failure message.
11
+ var fails = []
12
+ self.failFn = function (f) {
13
+ fails.push(f)
14
+ }
15
+
16
+ var failMessage = null
17
+ var showHelpOnFail = true
18
+ self.showHelpOnFail = function (enabled, message) {
19
+ if (typeof enabled === 'string') {
20
+ message = enabled
21
+ enabled = true
22
+ } else if (typeof enabled === 'undefined') {
23
+ enabled = true
83
24
  }
84
-
85
- var epilog;
86
- self.epilog = function (msg) {
87
- epilog = msg;
88
- };
89
-
90
- var wrap = windowWidth();
91
- self.wrap = function (cols) {
92
- wrap = cols;
93
- };
94
-
95
- self.help = function () {
96
- normalizeAliases();
97
-
98
- var demanded = yargs.getDemanded(),
99
- options = yargs.getOptions(),
100
- keys = Object.keys(
101
- Object.keys(descriptions)
102
- .concat(Object.keys(demanded))
103
- .concat(Object.keys(options.default))
104
- .reduce(function (acc, key) {
105
- if (key !== '_') acc[key] = true;
106
- return acc;
107
- }, {})
108
- );
109
-
110
- var help = keys.length ? [ 'Options:' ] : [];
111
-
112
- // your application's commands, i.e., non-option
113
- // arguments populated in '_'.
114
- if (commands.length) {
115
- help.unshift('');
116
-
117
- var commandsTable = {};
118
- commands.forEach(function(command) {
119
- commandsTable[command[0]] = {
120
- desc: command[1],
121
- extra: ''
122
- };
123
- });
124
-
125
- help = ['Commands:'].concat(formatTable(commandsTable, 5), help);
126
- }
127
-
128
- // the usage string.
129
- if (usage) {
130
- var u = usage.replace(/\$0/g, yargs.$0);
131
- if (wrap) u = wordwrap(0, wrap)(u);
132
- help.unshift(u, '');
133
- }
134
-
135
- // the options table.
136
- var aliasKeys = (Object.keys(options.alias) || [])
137
- .concat(Object.keys(yargs.parsed.newAliases) || []);
138
-
139
- keys = keys.filter(function(key) {
140
- return !yargs.parsed.newAliases[key] && aliasKeys.every(function(alias) {
141
- return -1 == (options.alias[alias] || []).indexOf(key);
142
- });
143
- });
144
-
145
- var switches = keys.reduce(function (acc, key) {
146
- acc[key] = [ key ].concat(options.alias[key] || [])
147
- .map(function (sw) {
148
- return (sw.length > 1 ? '--' : '-') + sw
149
- })
150
- .join(', ')
151
- ;
152
- return acc;
153
- }, {});
154
-
155
- var switchTable = {};
156
- keys.forEach(function (key) {
157
- var kswitch = switches[key];
158
- var desc = descriptions[key] || '';
159
- var type = null;
160
-
161
- if (~options.boolean.indexOf(key)) type = '[boolean]';
162
- if (~options.count.indexOf(key)) type = '[count]';
163
- if (~options.string.indexOf(key)) type = '[string]';
164
- if (~options.normalize.indexOf(key)) type = '[string]';
165
- if (~options.array.indexOf(key)) type = '[array]';
166
-
167
- var extra = [
168
- type,
169
- demanded[key]
170
- ? '[required]'
171
- : null
172
- ,
173
- defaultString(options.default[key], options.defaultDescription[key])
174
- ].filter(Boolean).join(' ');
175
-
176
- switchTable[kswitch] = {
177
- desc: desc,
178
- extra: extra
179
- };
180
- });
181
- help.push.apply(help, formatTable(switchTable, 3));
182
-
183
- if (keys.length) help.push('');
184
-
185
- // describe some common use-cases for your application.
186
- if (examples.length) {
187
- examples.forEach(function (example) {
188
- example[0] = example[0].replace(/\$0/g, yargs.$0);
189
- });
190
-
191
- var examplesTable = {};
192
- examples.forEach(function(example) {
193
- examplesTable[example[0]] = {
194
- desc: example[1],
195
- extra: ''
196
- };
197
- });
198
-
199
- help.push.apply(help, ['Examples:'].concat(formatTable(examplesTable, 5), ''));
200
- }
201
-
202
- // the usage string.
203
- if (epilog) {
204
- var e = epilog.replace(/\$0/g, yargs.$0);
205
- if (wrap) e = wordwrap(0, wrap)(e);
206
- help.push(e, '');
207
- }
208
-
209
- return help.join('\n');
210
- };
211
-
212
- // make sure any options set for aliases,
213
- // are copied to the keys being aliased.
214
- function normalizeAliases () {
215
- var options = yargs.getOptions(),
216
- demanded = yargs.getDemanded();
217
-
218
- (Object.keys(options.alias) || []).forEach(function(key) {
219
- options.alias[key].forEach(function(alias) {
220
- // copy descriptions.
221
- if (descriptions[alias]) self.describe(key, descriptions[alias]);
222
- // copy demanded.
223
- if (demanded[alias]) yargs.demand(key, demanded[alias].msg);
224
-
225
- // type messages.
226
- if (~options.boolean.indexOf(alias)) yargs.boolean(key);
227
- if (~options.count.indexOf(alias)) yargs.count(key);
228
- if (~options.string.indexOf(alias)) yargs.string(key);
229
- if (~options.normalize.indexOf(alias)) yargs.normalize(key);
230
- if (~options.array.indexOf(alias)) yargs.array(key);
231
- });
232
- });
233
- };
234
-
235
- self.showHelp = function (level) {
236
- level = level || 'error';
237
- console[level](self.help());
25
+ failMessage = message
26
+ showHelpOnFail = enabled
27
+ return self
28
+ }
29
+
30
+ self.fail = function (msg) {
31
+ if (fails.length) {
32
+ fails.forEach(function (f) {
33
+ f(msg)
34
+ })
35
+ } else {
36
+ if (showHelpOnFail) yargs.showHelp('error')
37
+ if (msg) console.error(msg)
38
+ if (failMessage) {
39
+ if (msg) console.error('')
40
+ console.error(failMessage)
41
+ }
42
+ if (yargs.getExitProcess()) {
43
+ process.exit(1)
44
+ } else {
45
+ throw new Error(msg)
46
+ }
238
47
  }
239
-
240
- self.functionDescription = function (fn, defaultDescription) {
241
- if (defaultDescription) {
242
- return defaultDescription;
243
- }
244
- var description = fn.name ? decamelize(fn.name, '-') : 'generated-value';
245
- return ['(', description, ')'].join('');
48
+ }
49
+
50
+ // methods for ouputting/building help (usage) message.
51
+ var usage
52
+ self.usage = function (msg) {
53
+ usage = msg
54
+ }
55
+
56
+ var examples = []
57
+ self.example = function (cmd, description) {
58
+ examples.push([cmd, description || ''])
59
+ }
60
+
61
+ var commands = []
62
+ self.command = function (cmd, description) {
63
+ commands.push([cmd, description || ''])
64
+ }
65
+ self.getCommands = function () {
66
+ return commands
67
+ }
68
+
69
+ var descriptions = {}
70
+ self.describe = function (key, desc) {
71
+ if (typeof key === 'object') {
72
+ Object.keys(key).forEach(function (k) {
73
+ self.describe(k, key[k])
74
+ })
75
+ } else {
76
+ descriptions[key] = desc
246
77
  }
247
-
248
- // format the default-value-string displayed in
249
- // the right-hand column.
250
- function defaultString(value, defaultDescription) {
251
- var string = '[default: ';
252
-
253
- if (value === undefined) return null;
254
-
255
- if (defaultDescription) {
256
- string += defaultDescription;
257
- } else {
258
- switch (typeof value) {
259
- case 'string':
260
- string += JSON.stringify(value);
261
- break;
262
- case 'object':
263
- string += JSON.stringify(value);
264
- break;
265
- default:
266
- string += value;
267
- }
268
- }
269
-
270
- return string + ']';
78
+ }
79
+ self.getDescriptions = function () {
80
+ return descriptions
81
+ }
82
+
83
+ var epilog
84
+ self.epilog = function (msg) {
85
+ epilog = msg
86
+ }
87
+
88
+ var wrap = windowWidth()
89
+ self.wrap = function (cols) {
90
+ wrap = cols
91
+ }
92
+
93
+ self.help = function () {
94
+ normalizeAliases()
95
+
96
+ var demanded = yargs.getDemanded(),
97
+ options = yargs.getOptions(),
98
+ keys = Object.keys(
99
+ Object.keys(descriptions)
100
+ .concat(Object.keys(demanded))
101
+ .concat(Object.keys(options.default))
102
+ .reduce(function (acc, key) {
103
+ if (key !== '_') acc[key] = true
104
+ return acc
105
+ }, {})
106
+ ),
107
+ ui = cliui({
108
+ width: wrap,
109
+ wrap: !!wrap
110
+ })
111
+
112
+ // the usage string.
113
+ if (usage) {
114
+ var u = usage.replace(/\$0/g, yargs.$0)
115
+ ui.div(u + '\n')
271
116
  }
272
117
 
273
- // word-wrapped two-column layout used by
274
- // examples, options, commands.
275
- function formatTable (table, padding) {
276
- var output = [];
277
-
278
- // size of left-hand-column.
279
- var llen = longest(Object.keys(table));
280
-
281
- // don't allow the left-column to take up
282
- // more than half of the screen.
283
- if (wrap) {
284
- llen = Math.min(llen, parseInt(wrap / 2));
285
- }
286
-
287
- // size of right-column.
288
- var desclen = longest(Object.keys(table).map(function (k) {
289
- return table[k].desc;
290
- }));
291
-
292
- Object.keys(table).forEach(function(left) {
293
- var desc = table[left].desc,
294
- extra = table[left].extra,
295
- leftLines = null;
296
-
297
- if (wrap) {
298
- desc = wordwrap(llen + padding + 1, wrap)(desc)
299
- .slice(llen + padding + 1);
300
- }
301
-
302
- // if we need to wrap the left-hand-column,
303
- // split it on to multiple lines.
304
- if (wrap && left.length > llen) {
305
- leftLines = wordwrap(2, llen)(left.trim()).split('\n');
306
- left = '';
307
- }
308
-
309
- var lpadding = new Array(
310
- Math.max(llen - left.length + padding, 0)
311
- ).join(' ');
312
-
313
- var dpadding = new Array(
314
- Math.max(desclen - desc.length + 1, 0)
315
- ).join(' ');
316
-
317
- if (!wrap && dpadding.length > 0) {
318
- desc += dpadding;
319
- }
320
-
321
- var prelude = ' ' + left + lpadding;
322
-
323
- var body = [ desc, extra ].filter(Boolean).join(' ');
324
-
325
- if (wrap) {
326
- var dlines = desc.split('\n');
327
- var dlen = dlines.slice(-1)[0].length
328
- + (dlines.length === 1 ? prelude.length : 0)
329
-
330
- if (extra.length > wrap) {
331
- body = desc + '\n' + wordwrap(llen + 4, wrap)(extra)
332
- } else {
333
- body = desc + (dlen + extra.length > wrap - 2
334
- ? '\n'
335
- + new Array(wrap - extra.length + 1).join(' ')
336
- + extra
337
- : new Array(wrap - extra.length - dlen + 1).join(' ')
338
- + extra
339
- );
340
- }
341
- }
342
-
343
- if (leftLines) { // handle word-wrapping the left-hand-column.
344
- var rightLines = body.split('\n'),
345
- firstLine = prelude + rightLines[0],
346
- lineCount = Math.max(leftLines.length, rightLines.length);
347
-
348
- for (var i = 0; i < lineCount; i++) {
349
- var left = leftLines[i],
350
- right = i ? rightLines[i] : firstLine;
351
-
352
- output.push(strcpy(left, right, firstLine.length));
353
- }
354
- } else {
355
- output.push(prelude + body);
356
- }
357
- });
358
-
359
- return output;
118
+ // your application's commands, i.e., non-option
119
+ // arguments populated in '_'.
120
+ if (commands.length) {
121
+ ui.div('Commands:')
122
+
123
+ commands.forEach(function (command) {
124
+ ui.div(
125
+ {text: command[0], padding: [0, 2, 0, 2], width: maxWidth(commands) + 4},
126
+ {text: command[1]}
127
+ )
128
+ })
129
+
130
+ ui.div()
360
131
  }
361
132
 
362
- // find longest string in array of strings.
363
- function longest (xs) {
364
- return Math.max.apply(
365
- null,
366
- xs.map(function (x) { return x.length })
367
- );
133
+ // the options table.
134
+ var aliasKeys = (Object.keys(options.alias) || [])
135
+ .concat(Object.keys(yargs.parsed.newAliases) || [])
136
+
137
+ keys = keys.filter(function (key) {
138
+ return !yargs.parsed.newAliases[key] && aliasKeys.every(function (alias) {
139
+ return (options.alias[alias] || []).indexOf(key) === -1
140
+ })
141
+ })
142
+
143
+ var switches = keys.reduce(function (acc, key) {
144
+ acc[key] = [ key ].concat(options.alias[key] || [])
145
+ .map(function (sw) {
146
+ return (sw.length > 1 ? '--' : '-') + sw
147
+ })
148
+ .join(', ')
149
+
150
+ return acc
151
+ }, {})
152
+
153
+ if (keys.length) {
154
+ ui.div('Options:')
155
+
156
+ keys.forEach(function (key) {
157
+ var kswitch = switches[key]
158
+ var desc = descriptions[key] || ''
159
+ var type = null
160
+
161
+ if (~options.boolean.indexOf(key)) type = '[boolean]'
162
+ if (~options.count.indexOf(key)) type = '[count]'
163
+ if (~options.string.indexOf(key)) type = '[string]'
164
+ if (~options.normalize.indexOf(key)) type = '[string]'
165
+ if (~options.array.indexOf(key)) type = '[array]'
166
+
167
+ var extra = [
168
+ type,
169
+ demanded[key] ? '[required]' : null,
170
+ defaultString(options.default[key], options.defaultDescription[key])
171
+ ].filter(Boolean).join(' ')
172
+
173
+ ui.span(
174
+ {text: kswitch, padding: [0, 2, 0, 2], width: maxWidth(switches) + 4},
175
+ desc
176
+ )
177
+
178
+ if (extra) ui.div({text: extra, padding: [0, 0, 0, 2], align: 'right'})
179
+ else ui.div()
180
+ })
181
+
182
+ ui.div()
368
183
  }
369
184
 
370
- // copy one string into another, used when
371
- // formatting usage table.
372
- function strcpy (source, destination, width) {
373
- var str = ''
185
+ // describe some common use-cases for your application.
186
+ if (examples.length) {
187
+ ui.div('Examples:')
188
+
189
+ examples.forEach(function (example) {
190
+ example[0] = example[0].replace(/\$0/g, yargs.$0)
191
+ })
374
192
 
375
- source = source || '';
376
- destination = destination || new Array(width).join(' ');
193
+ examples.forEach(function (example) {
194
+ ui.div(
195
+ {text: example[0], padding: [0, 2, 0, 2], width: maxWidth(examples) + 4},
196
+ example[1]
197
+ )
198
+ })
377
199
 
378
- for (var i = 0; i < destination.length; i++) {
379
- var char = destination.charAt(i);
200
+ ui.div()
201
+ }
202
+
203
+ // the usage string.
204
+ if (epilog) {
205
+ var e = epilog.replace(/\$0/g, yargs.$0)
206
+ ui.div(e + '\n')
207
+ }
380
208
 
381
- if (char === ' ') char = source.charAt(i) || char;
209
+ return ui.toString()
210
+ }
382
211
 
383
- str += char;
384
- }
212
+ // return the maximum width of a string
213
+ // in the left-hand column of a table.
214
+ function maxWidth (table) {
215
+ var width = 0
385
216
 
386
- return str;
217
+ // table might be of the form [leftColumn],
218
+ // or {key: leftColumn}}
219
+ if (!Array.isArray(table)) {
220
+ table = Object.keys(table).map(function (key) {
221
+ return [table[key]]
222
+ })
387
223
  }
388
224
 
389
- // guess the width of the console window, max-width 100.
390
- function windowWidth() {
391
- return wsize.width ? Math.min(80, wsize.width) : null;
225
+ table.forEach(function (v) {
226
+ width = Math.max(v[0].length, width)
227
+ })
228
+
229
+ // if we've enabled 'wrap' we should limit
230
+ // the max-width of the left-column.
231
+ if (wrap) width = Math.min(width, parseInt(wrap * 0.5, 10))
232
+
233
+ return width
234
+ }
235
+
236
+ // make sure any options set for aliases,
237
+ // are copied to the keys being aliased.
238
+ function normalizeAliases () {
239
+ var options = yargs.getOptions(),
240
+ demanded = yargs.getDemanded()
241
+
242
+ ;(Object.keys(options.alias) || []).forEach(function (key) {
243
+ options.alias[key].forEach(function (alias) {
244
+ // copy descriptions.
245
+ if (descriptions[alias]) self.describe(key, descriptions[alias])
246
+ // copy demanded.
247
+ if (demanded[alias]) yargs.demand(key, demanded[alias].msg)
248
+
249
+ // type messages.
250
+ if (~options.boolean.indexOf(alias)) yargs.boolean(key)
251
+ if (~options.count.indexOf(alias)) yargs.count(key)
252
+ if (~options.string.indexOf(alias)) yargs.string(key)
253
+ if (~options.normalize.indexOf(alias)) yargs.normalize(key)
254
+ if (~options.array.indexOf(alias)) yargs.array(key)
255
+ })
256
+ })
257
+ }
258
+
259
+ self.showHelp = function (level) {
260
+ level = level || 'error'
261
+ console[level](self.help())
262
+ }
263
+
264
+ self.functionDescription = function (fn, defaultDescription) {
265
+ if (defaultDescription) {
266
+ return defaultDescription
392
267
  }
268
+ var description = fn.name ? decamelize(fn.name, '-') : 'generated-value'
269
+ return ['(', description, ')'].join('')
270
+ }
271
+
272
+ // format the default-value-string displayed in
273
+ // the right-hand column.
274
+ function defaultString (value, defaultDescription) {
275
+ var string = '[default: '
276
+
277
+ if (value === undefined) return null
278
+
279
+ if (defaultDescription) {
280
+ string += defaultDescription
281
+ } else {
282
+ switch (typeof value) {
283
+ case 'string':
284
+ string += JSON.stringify(value)
285
+ break
286
+ case 'object':
287
+ string += JSON.stringify(value)
288
+ break
289
+ default:
290
+ string += value
291
+ }
292
+ }
293
+
294
+ return string + ']'
295
+ }
296
+
297
+ // guess the width of the console window, max-width 80.
298
+ function windowWidth () {
299
+ return wsize.width ? Math.min(80, wsize.width) : null
300
+ }
393
301
 
394
- // logic for displaying application version.
395
- var version = null;
396
- self.version = function (ver, opt, msg) {
397
- version = ver;
398
- };
302
+ // logic for displaying application version.
303
+ var version = null
304
+ self.version = function (ver, opt, msg) {
305
+ version = ver
306
+ }
399
307
 
400
- self.showVersion = function() {
401
- if (typeof version === 'function') console.log(version());
402
- else console.log(version);
403
- };
308
+ self.showVersion = function () {
309
+ if (typeof version === 'function') console.log(version())
310
+ else console.log(version)
311
+ }
404
312
 
405
- return self;
313
+ return self
406
314
  }