Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / node_modules / yargs / index.js
1 var assert = require('assert')
2 var Completion = require('./lib/completion')
3 var Parser = require('./lib/parser')
4 var path = require('path')
5 var tokenizeArgString = require('./lib/tokenize-arg-string')
6 var Usage = require('./lib/usage')
7 var Validation = require('./lib/validation')
8 var Y18n = require('y18n')
9
10 Argv(process.argv.slice(2))
11
12 var exports = module.exports = Argv
13 function Argv (processArgs, cwd) {
14   processArgs = processArgs || [] // handle calling yargs().
15
16   var self = {}
17   var completion = null
18   var usage = null
19   var validation = null
20   var y18n = Y18n({
21     directory: path.resolve(__dirname, './locales'),
22     updateFiles: false
23   })
24
25   if (!cwd) cwd = process.cwd()
26
27   self.$0 = process.argv
28     .slice(0, 2)
29     .map(function (x, i) {
30       // ignore the node bin, specify this in your
31       // bin file with #!/usr/bin/env node
32       if (i === 0 && /\b(node|iojs)$/.test(x)) return
33       var b = rebase(cwd, x)
34       return x.match(/^\//) && b.length < x.length ? b : x
35     })
36     .join(' ').trim()
37
38   if (process.env._ !== undefined && process.argv[1] === process.env._) {
39     self.$0 = process.env._.replace(
40       path.dirname(process.execPath) + '/', ''
41     )
42   }
43
44   var options
45   self.resetOptions = self.reset = function () {
46     // put yargs back into its initial
47     // state, this is useful for creating a
48     // nested CLI.
49     options = {
50       array: [],
51       boolean: [],
52       string: [],
53       narg: {},
54       key: {},
55       alias: {},
56       default: {},
57       defaultDescription: {},
58       choices: {},
59       requiresArg: [],
60       count: [],
61       normalize: [],
62       config: {},
63       envPrefix: undefined
64     }
65
66     usage = Usage(self, y18n) // handle usage output.
67     validation = Validation(self, usage, y18n) // handle arg validation.
68     completion = Completion(self, usage)
69
70     demanded = {}
71     groups = {}
72
73     exitProcess = true
74     strict = false
75     helpOpt = null
76     versionOpt = null
77     commandHandlers = {}
78     self.parsed = false
79
80     return self
81   }
82   self.resetOptions()
83
84   self.boolean = function (bools) {
85     options.boolean.push.apply(options.boolean, [].concat(bools))
86     return self
87   }
88
89   self.array = function (arrays) {
90     options.array.push.apply(options.array, [].concat(arrays))
91     return self
92   }
93
94   self.nargs = function (key, n) {
95     if (typeof key === 'object') {
96       Object.keys(key).forEach(function (k) {
97         self.nargs(k, key[k])
98       })
99     } else {
100       options.narg[key] = n
101     }
102     return self
103   }
104
105   self.choices = function (key, values) {
106     if (typeof key === 'object') {
107       Object.keys(key).forEach(function (k) {
108         self.choices(k, key[k])
109       })
110     } else {
111       options.choices[key] = (options.choices[key] || []).concat(values)
112     }
113     return self
114   }
115
116   self.normalize = function (strings) {
117     options.normalize.push.apply(options.normalize, [].concat(strings))
118     return self
119   }
120
121   self.config = function (key, msg, parseFn) {
122     if (typeof msg === 'function') {
123       parseFn = msg
124       msg = null
125     }
126     self.describe(key, msg || usage.deferY18nLookup('Path to JSON config file'))
127     ;(Array.isArray(key) ? key : [key]).forEach(function (k) {
128       options.config[k] = parseFn || true
129     })
130     return self
131   }
132
133   self.example = function (cmd, description) {
134     usage.example(cmd, description)
135     return self
136   }
137
138   self.command = function (cmd, description, fn) {
139     if (description !== false) {
140       usage.command(cmd, description)
141     }
142     if (fn) commandHandlers[cmd] = fn
143     return self
144   }
145
146   var commandHandlers = {}
147   self.getCommandHandlers = function () {
148     return commandHandlers
149   }
150
151   self.string = function (strings) {
152     options.string.push.apply(options.string, [].concat(strings))
153     return self
154   }
155
156   self.default = function (key, value, defaultDescription) {
157     if (typeof key === 'object') {
158       Object.keys(key).forEach(function (k) {
159         self.default(k, key[k])
160       })
161     } else {
162       if (defaultDescription) options.defaultDescription[key] = defaultDescription
163       if (typeof value === 'function') {
164         if (!options.defaultDescription[key]) options.defaultDescription[key] = usage.functionDescription(value)
165         value = value.call()
166       }
167       options.default[key] = value
168     }
169     return self
170   }
171
172   self.alias = function (x, y) {
173     if (typeof x === 'object') {
174       Object.keys(x).forEach(function (key) {
175         self.alias(key, x[key])
176       })
177     } else {
178       // perhaps 'x' is already an alias in another list?
179       // if so we should append to x's list.
180       var aliases = null
181       Object.keys(options.alias).forEach(function (key) {
182         if (~options.alias[key].indexOf(x)) aliases = options.alias[key]
183       })
184
185       if (aliases) { // x was an alias itself.
186         aliases.push(y)
187       } else { // x is a new alias key.
188         options.alias[x] = (options.alias[x] || []).concat(y)
189       }
190
191       // wait! perhaps we've created two lists of aliases
192       // that reference each other?
193       if (options.alias[y]) {
194         Array.prototype.push.apply((options.alias[x] || aliases), options.alias[y])
195         delete options.alias[y]
196       }
197     }
198     return self
199   }
200
201   self.count = function (counts) {
202     options.count.push.apply(options.count, [].concat(counts))
203     return self
204   }
205
206   var demanded = {}
207   self.demand = self.required = self.require = function (keys, max, msg) {
208     // you can optionally provide a 'max' key,
209     // which will raise an exception if too many '_'
210     // options are provided.
211     if (typeof max !== 'number') {
212       msg = max
213       max = Infinity
214     }
215
216     if (typeof keys === 'number') {
217       if (!demanded._) demanded._ = { count: 0, msg: null, max: max }
218       demanded._.count = keys
219       demanded._.msg = msg
220     } else if (Array.isArray(keys)) {
221       keys.forEach(function (key) {
222         self.demand(key, msg)
223       })
224     } else {
225       if (typeof msg === 'string') {
226         demanded[keys] = { msg: msg }
227       } else if (msg === true || typeof msg === 'undefined') {
228         demanded[keys] = { msg: undefined }
229       }
230     }
231
232     return self
233   }
234   self.getDemanded = function () {
235     return demanded
236   }
237
238   self.requiresArg = function (requiresArgs) {
239     options.requiresArg.push.apply(options.requiresArg, [].concat(requiresArgs))
240     return self
241   }
242
243   self.implies = function (key, value) {
244     validation.implies(key, value)
245     return self
246   }
247
248   self.usage = function (msg, opts) {
249     if (!opts && typeof msg === 'object') {
250       opts = msg
251       msg = null
252     }
253
254     usage.usage(msg)
255
256     if (opts) self.options(opts)
257
258     return self
259   }
260
261   self.epilogue = self.epilog = function (msg) {
262     usage.epilog(msg)
263     return self
264   }
265
266   self.fail = function (f) {
267     usage.failFn(f)
268     return self
269   }
270
271   self.check = function (f) {
272     validation.check(f)
273     return self
274   }
275
276   self.defaults = self.default
277
278   self.describe = function (key, desc) {
279     options.key[key] = true
280     usage.describe(key, desc)
281     return self
282   }
283
284   self.parse = function (args) {
285     return parseArgs(args)
286   }
287
288   self.option = self.options = function (key, opt) {
289     if (typeof key === 'object') {
290       Object.keys(key).forEach(function (k) {
291         self.options(k, key[k])
292       })
293     } else {
294       assert(typeof opt === 'object', 'second argument to option must be an object')
295
296       options.key[key] = true // track manually set keys.
297
298       if (opt.alias) self.alias(key, opt.alias)
299
300       var demand = opt.demand || opt.required || opt.require
301
302       if (demand) {
303         self.demand(key, demand)
304       } if ('config' in opt) {
305         self.config(key, opt.configParser)
306       } if ('default' in opt) {
307         self.default(key, opt.default)
308       } if ('nargs' in opt) {
309         self.nargs(key, opt.nargs)
310       } if ('choices' in opt) {
311         self.choices(key, opt.choices)
312       } if ('group' in opt) {
313         self.group(key, opt.group)
314       } if (opt.boolean || opt.type === 'boolean') {
315         self.boolean(key)
316         if (opt.alias) self.boolean(opt.alias)
317       } if (opt.array || opt.type === 'array') {
318         self.array(key)
319         if (opt.alias) self.array(opt.alias)
320       } if (opt.string || opt.type === 'string') {
321         self.string(key)
322         if (opt.alias) self.string(opt.alias)
323       } if (opt.count || opt.type === 'count') {
324         self.count(key)
325       } if (opt.defaultDescription) {
326         options.defaultDescription[key] = opt.defaultDescription
327       }
328
329       var desc = opt.describe || opt.description || opt.desc
330       if (desc) {
331         self.describe(key, desc)
332       }
333
334       if (opt.requiresArg) {
335         self.requiresArg(key)
336       }
337     }
338
339     return self
340   }
341   self.getOptions = function () {
342     return options
343   }
344
345   var groups = {}
346   self.group = function (opts, groupName) {
347     var seen = {}
348     groups[groupName] = (groups[groupName] || []).concat(opts).filter(function (key) {
349       if (seen[key]) return false
350       return (seen[key] = true)
351     })
352     return self
353   }
354   self.getGroups = function () {
355     return groups
356   }
357
358   // as long as options.envPrefix is not undefined,
359   // parser will apply env vars matching prefix to argv
360   self.env = function (prefix) {
361     if (prefix === false) options.envPrefix = undefined
362     else options.envPrefix = prefix || ''
363     return self
364   }
365
366   self.wrap = function (cols) {
367     usage.wrap(cols)
368     return self
369   }
370
371   var strict = false
372   self.strict = function () {
373     strict = true
374     return self
375   }
376   self.getStrict = function () {
377     return strict
378   }
379
380   self.showHelp = function (level) {
381     if (!self.parsed) parseArgs(processArgs) // run parser, if it has not already been executed.
382     usage.showHelp(level)
383     return self
384   }
385
386   var versionOpt = null
387   self.version = function (ver, opt, msg) {
388     versionOpt = opt || 'version'
389     usage.version(ver)
390     self.boolean(versionOpt)
391     self.describe(versionOpt, msg || usage.deferY18nLookup('Show version number'))
392     return self
393   }
394
395   var helpOpt = null
396   self.addHelpOpt = function (opt, msg) {
397     helpOpt = opt
398     self.boolean(opt)
399     self.describe(opt, msg || usage.deferY18nLookup('Show help'))
400     return self
401   }
402
403   self.showHelpOnFail = function (enabled, message) {
404     usage.showHelpOnFail(enabled, message)
405     return self
406   }
407
408   var exitProcess = true
409   self.exitProcess = function (enabled) {
410     if (typeof enabled !== 'boolean') {
411       enabled = true
412     }
413     exitProcess = enabled
414     return self
415   }
416   self.getExitProcess = function () {
417     return exitProcess
418   }
419
420   self.help = function () {
421     if (arguments.length > 0) return self.addHelpOpt.apply(self, arguments)
422
423     if (!self.parsed) parseArgs(processArgs) // run parser, if it has not already been executed.
424
425     return usage.help()
426   }
427
428   var completionCommand = null
429   self.completion = function (cmd, desc, fn) {
430     // a function to execute when generating
431     // completions can be provided as the second
432     // or third argument to completion.
433     if (typeof desc === 'function') {
434       fn = desc
435       desc = null
436     }
437
438     // register the completion command.
439     completionCommand = cmd || 'completion'
440     if (!desc && desc !== false) {
441       desc = 'generate bash completion script'
442     }
443     self.command(completionCommand, desc)
444
445     // a function can be provided
446     if (fn) completion.registerFunction(fn)
447
448     return self
449   }
450
451   self.showCompletionScript = function ($0) {
452     $0 = $0 || self.$0
453     console.log(completion.generateCompletionScript($0))
454     return self
455   }
456
457   self.locale = function (locale) {
458     if (arguments.length === 0) {
459       guessLocale()
460       return y18n.getLocale()
461     }
462     detectLocale = false
463     y18n.setLocale(locale)
464     return self
465   }
466
467   self.updateStrings = self.updateLocale = function (obj) {
468     detectLocale = false
469     y18n.updateLocale(obj)
470     return self
471   }
472
473   var detectLocale = true
474   self.detectLocale = function (detect) {
475     detectLocale = detect
476     return self
477   }
478   self.getDetectLocale = function () {
479     return detectLocale
480   }
481
482   self.getUsageInstance = function () {
483     return usage
484   }
485
486   self.getValidationInstance = function () {
487     return validation
488   }
489
490   self.terminalWidth = function () {
491     return require('window-size').width
492   }
493
494   Object.defineProperty(self, 'argv', {
495     get: function () {
496       var args = null
497
498       try {
499         args = parseArgs(processArgs)
500       } catch (err) {
501         usage.fail(err.message)
502       }
503
504       return args
505     },
506     enumerable: true
507   })
508
509   function parseArgs (args) {
510     args = normalizeArgs(args)
511
512     var parsed = Parser(args, options, y18n)
513     var argv = parsed.argv
514     var aliases = parsed.aliases
515
516     argv.$0 = self.$0
517
518     self.parsed = parsed
519
520     guessLocale() // guess locale lazily, so that it can be turned off in chain.
521
522     // while building up the argv object, there
523     // are two passes through the parser. If completion
524     // is being performed short-circuit on the first pass.
525     if (completionCommand &&
526       (process.argv.join(' ')).indexOf(completion.completionKey) !== -1 &&
527       !argv[completion.completionKey]) {
528       return argv
529     }
530
531     // if there's a handler associated with a
532     // command defer processing to it.
533     var handlerKeys = Object.keys(self.getCommandHandlers())
534     for (var i = 0, command; (command = handlerKeys[i]) !== undefined; i++) {
535       if (~argv._.indexOf(command)) {
536         runCommand(command, self, argv)
537         return self.argv
538       }
539     }
540
541     // generate a completion script for adding to ~/.bashrc.
542     if (completionCommand && ~argv._.indexOf(completionCommand) && !argv[completion.completionKey]) {
543       self.showCompletionScript()
544       if (exitProcess) {
545         process.exit(0)
546       }
547     }
548
549     // we must run completions first, a user might
550     // want to complete the --help or --version option.
551     if (completion.completionKey in argv) {
552       // we allow for asynchronous completions,
553       // e.g., loading in a list of commands from an API.
554       completion.getCompletion(function (completions) {
555         ;(completions || []).forEach(function (completion) {
556           console.log(completion)
557         })
558
559         if (exitProcess) {
560           process.exit(0)
561         }
562       })
563       return
564     }
565
566     var helpOrVersion = false
567     Object.keys(argv).forEach(function (key) {
568       if (key === helpOpt && argv[key]) {
569         helpOrVersion = true
570         self.showHelp('log')
571         if (exitProcess) {
572           process.exit(0)
573         }
574       } else if (key === versionOpt && argv[key]) {
575         helpOrVersion = true
576         usage.showVersion()
577         if (exitProcess) {
578           process.exit(0)
579         }
580       }
581     })
582
583     // If the help or version options where used and exitProcess is false,
584     // we won't run validations
585     if (!helpOrVersion) {
586       if (parsed.error) throw parsed.error
587
588       // if we're executed via bash completion, don't
589       // bother with validation.
590       if (!argv[completion.completionKey]) {
591         validation.nonOptionCount(argv)
592         validation.missingArgumentValue(argv)
593         validation.requiredArguments(argv)
594         if (strict) validation.unknownArguments(argv, aliases)
595         validation.customChecks(argv, aliases)
596         validation.limitedChoices(argv)
597         validation.implications(argv)
598       }
599     }
600
601     setPlaceholderKeys(argv)
602
603     return argv
604   }
605
606   function guessLocale () {
607     if (!detectLocale) return
608
609     try {
610       var osLocale = require('os-locale')
611       self.locale(osLocale.sync({ spawn: false }))
612     } catch (err) {
613       // if we explode looking up locale just noop
614       // we'll keep using the default language 'en'.
615     }
616   }
617
618   function runCommand (command, yargs, argv) {
619     setPlaceholderKeys(argv)
620     yargs.getCommandHandlers()[command](yargs.reset(), argv)
621   }
622
623   function setPlaceholderKeys (argv) {
624     Object.keys(options.key).forEach(function (key) {
625       // don't set placeholder keys for dot
626       // notation options 'foo.bar'.
627       if (~key.indexOf('.')) return
628       if (typeof argv[key] === 'undefined') argv[key] = undefined
629     })
630   }
631
632   function normalizeArgs (args) {
633     if (typeof args === 'string') {
634       return tokenizeArgString(args)
635     }
636     return args
637   }
638
639   singletonify(self)
640   return self
641 }
642
643 // rebase an absolute path to a relative one with respect to a base directory
644 // exported for tests
645 exports.rebase = rebase
646 function rebase (base, dir) {
647   return path.relative(base, dir)
648 }
649
650 /*  Hack an instance of Argv with process.argv into Argv
651     so people can do
652     require('yargs')(['--beeble=1','-z','zizzle']).argv
653     to parse a list of args and
654     require('yargs').argv
655     to get a parsed version of process.argv.
656 */
657 function singletonify (inst) {
658   Object.keys(inst).forEach(function (key) {
659     if (key === 'argv') {
660       Argv.__defineGetter__(key, inst.__lookupGetter__(key))
661     } else {
662       Argv[key] = typeof inst[key] === 'function' ? inst[key].bind(inst) : inst[key]
663     }
664   })
665 }