.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / yargs-parser / index.js
1 var camelCase = require('camelcase')
2 var path = require('path')
3 var tokenizeArgString = require('./lib/tokenize-arg-string')
4 var util = require('util')
5
6 function parse (args, opts) {
7   if (!opts) opts = {}
8   // allow a string argument to be passed in rather
9   // than an argv array.
10   args = tokenizeArgString(args)
11   // aliases might have transitive relationships, normalize this.
12   var aliases = combineAliases(opts.alias || {})
13   var configuration = assign({
14     'short-option-groups': true,
15     'camel-case-expansion': true,
16     'dot-notation': true,
17     'parse-numbers': true,
18     'boolean-negation': true,
19     'negation-prefix': 'no-',
20     'duplicate-arguments-array': true,
21     'flatten-duplicate-arrays': true,
22     'populate--': false,
23     'combine-arrays': false
24   }, opts.configuration)
25   var defaults = opts.default || {}
26   var configObjects = opts.configObjects || []
27   var envPrefix = opts.envPrefix
28   var notFlagsOption = configuration['populate--']
29   var notFlagsArgv = notFlagsOption ? '--' : '_'
30   var newAliases = {}
31   // allow a i18n handler to be passed in, default to a fake one (util.format).
32   var __ = opts.__ || function (str) {
33     return util.format.apply(util, Array.prototype.slice.call(arguments))
34   }
35   var error = null
36   var flags = {
37     aliases: {},
38     arrays: {},
39     bools: {},
40     strings: {},
41     numbers: {},
42     counts: {},
43     normalize: {},
44     configs: {},
45     defaulted: {},
46     nargs: {},
47     coercions: {}
48   }
49   var negative = /^-[0-9]+(\.[0-9]+)?/
50   var negatedBoolean = new RegExp('^--' + configuration['negation-prefix'] + '(.+)')
51
52   ;[].concat(opts.array).filter(Boolean).forEach(function (key) {
53     flags.arrays[key] = true
54   })
55
56   ;[].concat(opts.boolean).filter(Boolean).forEach(function (key) {
57     flags.bools[key] = true
58   })
59
60   ;[].concat(opts.string).filter(Boolean).forEach(function (key) {
61     flags.strings[key] = true
62   })
63
64   ;[].concat(opts.number).filter(Boolean).forEach(function (key) {
65     flags.numbers[key] = true
66   })
67
68   ;[].concat(opts.count).filter(Boolean).forEach(function (key) {
69     flags.counts[key] = true
70   })
71
72   ;[].concat(opts.normalize).filter(Boolean).forEach(function (key) {
73     flags.normalize[key] = true
74   })
75
76   Object.keys(opts.narg || {}).forEach(function (k) {
77     flags.nargs[k] = opts.narg[k]
78   })
79
80   Object.keys(opts.coerce || {}).forEach(function (k) {
81     flags.coercions[k] = opts.coerce[k]
82   })
83
84   if (Array.isArray(opts.config) || typeof opts.config === 'string') {
85     ;[].concat(opts.config).filter(Boolean).forEach(function (key) {
86       flags.configs[key] = true
87     })
88   } else {
89     Object.keys(opts.config || {}).forEach(function (k) {
90       flags.configs[k] = opts.config[k]
91     })
92   }
93
94   // create a lookup table that takes into account all
95   // combinations of aliases: {f: ['foo'], foo: ['f']}
96   extendAliases(opts.key, aliases, opts.default, flags.arrays)
97
98   // apply default values to all aliases.
99   Object.keys(defaults).forEach(function (key) {
100     (flags.aliases[key] || []).forEach(function (alias) {
101       defaults[alias] = defaults[key]
102     })
103   })
104
105   var argv = { _: [] }
106
107   Object.keys(flags.bools).forEach(function (key) {
108     setArg(key, !(key in defaults) ? false : defaults[key])
109     setDefaulted(key)
110   })
111
112   var notFlags = []
113   if (args.indexOf('--') !== -1) {
114     notFlags = args.slice(args.indexOf('--') + 1)
115     args = args.slice(0, args.indexOf('--'))
116   }
117
118   for (var i = 0; i < args.length; i++) {
119     var arg = args[i]
120     var broken
121     var key
122     var letters
123     var m
124     var next
125     var value
126
127     // -- seperated by =
128     if (arg.match(/^--.+=/) || (
129       !configuration['short-option-groups'] && arg.match(/^-.+=/)
130     )) {
131       // Using [\s\S] instead of . because js doesn't support the
132       // 'dotall' regex modifier. See:
133       // http://stackoverflow.com/a/1068308/13216
134       m = arg.match(/^--?([^=]+)=([\s\S]*)$/)
135
136       // nargs format = '--f=monkey washing cat'
137       if (checkAllAliases(m[1], flags.nargs)) {
138         args.splice(i + 1, 0, m[2])
139         i = eatNargs(i, m[1], args)
140       // arrays format = '--f=a b c'
141       } else if (checkAllAliases(m[1], flags.arrays) && args.length > i + 1) {
142         args.splice(i + 1, 0, m[2])
143         i = eatArray(i, m[1], args)
144       } else {
145         setArg(m[1], m[2])
146       }
147     } else if (arg.match(negatedBoolean) && configuration['boolean-negation']) {
148       key = arg.match(negatedBoolean)[1]
149       setArg(key, false)
150
151     // -- seperated by space.
152     } else if (arg.match(/^--.+/) || (
153       !configuration['short-option-groups'] && arg.match(/^-.+/)
154     )) {
155       key = arg.match(/^--?(.+)/)[1]
156
157       // nargs format = '--foo a b c'
158       if (checkAllAliases(key, flags.nargs)) {
159         i = eatNargs(i, key, args)
160       // array format = '--foo a b c'
161       } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
162         i = eatArray(i, key, args)
163       } else {
164         next = args[i + 1]
165
166         if (next !== undefined && (!next.match(/^-/) ||
167           next.match(negative)) &&
168           !checkAllAliases(key, flags.bools) &&
169           !checkAllAliases(key, flags.counts)) {
170           setArg(key, next)
171           i++
172         } else if (/^(true|false)$/.test(next)) {
173           setArg(key, next)
174           i++
175         } else {
176           setArg(key, defaultForType(guessType(key, flags)))
177         }
178       }
179
180     // dot-notation flag seperated by '='.
181     } else if (arg.match(/^-.\..+=/)) {
182       m = arg.match(/^-([^=]+)=([\s\S]*)$/)
183       setArg(m[1], m[2])
184
185     // dot-notation flag seperated by space.
186     } else if (arg.match(/^-.\..+/)) {
187       next = args[i + 1]
188       key = arg.match(/^-(.\..+)/)[1]
189
190       if (next !== undefined && !next.match(/^-/) &&
191         !checkAllAliases(key, flags.bools) &&
192         !checkAllAliases(key, flags.counts)) {
193         setArg(key, next)
194         i++
195       } else {
196         setArg(key, defaultForType(guessType(key, flags)))
197       }
198     } else if (arg.match(/^-[^-]+/) && !arg.match(negative)) {
199       letters = arg.slice(1, -1).split('')
200       broken = false
201
202       for (var j = 0; j < letters.length; j++) {
203         next = arg.slice(j + 2)
204
205         if (letters[j + 1] && letters[j + 1] === '=') {
206           value = arg.slice(j + 3)
207           key = letters[j]
208
209           // nargs format = '-f=monkey washing cat'
210           if (checkAllAliases(key, flags.nargs)) {
211             args.splice(i + 1, 0, value)
212             i = eatNargs(i, key, args)
213           // array format = '-f=a b c'
214           } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
215             args.splice(i + 1, 0, value)
216             i = eatArray(i, key, args)
217           } else {
218             setArg(key, value)
219           }
220
221           broken = true
222           break
223         }
224
225         if (next === '-') {
226           setArg(letters[j], next)
227           continue
228         }
229
230         // current letter is an alphabetic character and next value is a number
231         if (/[A-Za-z]/.test(letters[j]) &&
232           /^-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
233           setArg(letters[j], next)
234           broken = true
235           break
236         }
237
238         if (letters[j + 1] && letters[j + 1].match(/\W/)) {
239           setArg(letters[j], next)
240           broken = true
241           break
242         } else {
243           setArg(letters[j], defaultForType(guessType(letters[j], flags)))
244         }
245       }
246
247       key = arg.slice(-1)[0]
248
249       if (!broken && key !== '-') {
250         // nargs format = '-f a b c'
251         if (checkAllAliases(key, flags.nargs)) {
252           i = eatNargs(i, key, args)
253         // array format = '-f a b c'
254         } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
255           i = eatArray(i, key, args)
256         } else {
257           next = args[i + 1]
258
259           if (next !== undefined && (!/^(-|--)[^-]/.test(next) ||
260             next.match(negative)) &&
261             !checkAllAliases(key, flags.bools) &&
262             !checkAllAliases(key, flags.counts)) {
263             setArg(key, next)
264             i++
265           } else if (/^(true|false)$/.test(next)) {
266             setArg(key, next)
267             i++
268           } else {
269             setArg(key, defaultForType(guessType(key, flags)))
270           }
271         }
272       }
273     } else {
274       argv._.push(maybeCoerceNumber('_', arg))
275     }
276   }
277
278   // order of precedence:
279   // 1. command line arg
280   // 2. value from env var
281   // 3. value from config file
282   // 4. value from config objects
283   // 5. configured default value
284   applyEnvVars(argv, true) // special case: check env vars that point to config file
285   applyEnvVars(argv, false)
286   setConfig(argv)
287   setConfigObjects()
288   applyDefaultsAndAliases(argv, flags.aliases, defaults)
289   applyCoercions(argv)
290
291   // for any counts either not in args or without an explicit default, set to 0
292   Object.keys(flags.counts).forEach(function (key) {
293     if (!hasKey(argv, key.split('.'))) setArg(key, 0)
294   })
295
296   // '--' defaults to undefined.
297   if (notFlagsOption && notFlags.length) argv[notFlagsArgv] = []
298   notFlags.forEach(function (key) {
299     argv[notFlagsArgv].push(key)
300   })
301
302   // how many arguments should we consume, based
303   // on the nargs option?
304   function eatNargs (i, key, args) {
305     var ii
306     const toEat = checkAllAliases(key, flags.nargs)
307
308     // nargs will not consume flag arguments, e.g., -abc, --foo,
309     // and terminates when one is observed.
310     var available = 0
311     for (ii = i + 1; ii < args.length; ii++) {
312       if (!args[ii].match(/^-[^0-9]/)) available++
313       else break
314     }
315
316     if (available < toEat) error = Error(__('Not enough arguments following: %s', key))
317
318     const consumed = Math.min(available, toEat)
319     for (ii = i + 1; ii < (consumed + i + 1); ii++) {
320       setArg(key, args[ii])
321     }
322
323     return (i + consumed)
324   }
325
326   // if an option is an array, eat all non-hyphenated arguments
327   // following it... YUM!
328   // e.g., --foo apple banana cat becomes ["apple", "banana", "cat"]
329   function eatArray (i, key, args) {
330     var start = i + 1
331     var argsToSet = []
332     var multipleArrayFlag = i > 0
333     for (var ii = i + 1; ii < args.length; ii++) {
334       if (/^-/.test(args[ii]) && !negative.test(args[ii])) {
335         if (ii === start) {
336           setArg(key, defaultForType('array'))
337         }
338         multipleArrayFlag = true
339         break
340       }
341       i = ii
342       argsToSet.push(args[ii])
343     }
344     if (multipleArrayFlag) {
345       setArg(key, argsToSet.map(function (arg) {
346         return processValue(key, arg)
347       }))
348     } else {
349       argsToSet.forEach(function (arg) {
350         setArg(key, arg)
351       })
352     }
353
354     return i
355   }
356
357   function setArg (key, val) {
358     unsetDefaulted(key)
359
360     if (/-/.test(key) && configuration['camel-case-expansion']) {
361       addNewAlias(key, camelCase(key))
362     }
363
364     var value = processValue(key, val)
365
366     var splitKey = key.split('.')
367     setKey(argv, splitKey, value)
368
369     // handle populating aliases of the full key
370     if (flags.aliases[key]) {
371       flags.aliases[key].forEach(function (x) {
372         x = x.split('.')
373         setKey(argv, x, value)
374       })
375     }
376
377     // handle populating aliases of the first element of the dot-notation key
378     if (splitKey.length > 1 && configuration['dot-notation']) {
379       ;(flags.aliases[splitKey[0]] || []).forEach(function (x) {
380         x = x.split('.')
381
382         // expand alias with nested objects in key
383         var a = [].concat(splitKey)
384         a.shift() // nuke the old key.
385         x = x.concat(a)
386
387         setKey(argv, x, value)
388       })
389     }
390
391     // Set normalize getter and setter when key is in 'normalize' but isn't an array
392     if (checkAllAliases(key, flags.normalize) && !checkAllAliases(key, flags.arrays)) {
393       var keys = [key].concat(flags.aliases[key] || [])
394       keys.forEach(function (key) {
395         argv.__defineSetter__(key, function (v) {
396           val = path.normalize(v)
397         })
398
399         argv.__defineGetter__(key, function () {
400           return typeof val === 'string' ? path.normalize(val) : val
401         })
402       })
403     }
404   }
405
406   function addNewAlias (key, alias) {
407     if (!(flags.aliases[key] && flags.aliases[key].length)) {
408       flags.aliases[key] = [alias]
409       newAliases[alias] = true
410     }
411     if (!(flags.aliases[alias] && flags.aliases[alias].length)) {
412       addNewAlias(alias, key)
413     }
414   }
415
416   function processValue (key, val) {
417     // handle parsing boolean arguments --foo=true --bar false.
418     if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {
419       if (typeof val === 'string') val = val === 'true'
420     }
421
422     var value = maybeCoerceNumber(key, val)
423
424     // increment a count given as arg (either no value or value parsed as boolean)
425     if (checkAllAliases(key, flags.counts) && (isUndefined(value) || typeof value === 'boolean')) {
426       value = increment
427     }
428
429     // Set normalized value when key is in 'normalize' and in 'arrays'
430     if (checkAllAliases(key, flags.normalize) && checkAllAliases(key, flags.arrays)) {
431       if (Array.isArray(val)) value = val.map(path.normalize)
432       else value = path.normalize(val)
433     }
434     return value
435   }
436
437   function maybeCoerceNumber (key, value) {
438     if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.coercions)) {
439       const shouldCoerceNumber = isNumber(value) && configuration['parse-numbers'] && (
440         Number.isSafeInteger(Math.floor(value))
441       )
442       if (shouldCoerceNumber || (!isUndefined(value) && checkAllAliases(key, flags.numbers))) value = Number(value)
443     }
444     return value
445   }
446
447   // set args from config.json file, this should be
448   // applied last so that defaults can be applied.
449   function setConfig (argv) {
450     var configLookup = {}
451
452     // expand defaults/aliases, in-case any happen to reference
453     // the config.json file.
454     applyDefaultsAndAliases(configLookup, flags.aliases, defaults)
455
456     Object.keys(flags.configs).forEach(function (configKey) {
457       var configPath = argv[configKey] || configLookup[configKey]
458       if (configPath) {
459         try {
460           var config = null
461           var resolvedConfigPath = path.resolve(process.cwd(), configPath)
462
463           if (typeof flags.configs[configKey] === 'function') {
464             try {
465               config = flags.configs[configKey](resolvedConfigPath)
466             } catch (e) {
467               config = e
468             }
469             if (config instanceof Error) {
470               error = config
471               return
472             }
473           } else {
474             config = require(resolvedConfigPath)
475           }
476
477           setConfigObject(config)
478         } catch (ex) {
479           if (argv[configKey]) error = Error(__('Invalid JSON config file: %s', configPath))
480         }
481       }
482     })
483   }
484
485   // set args from config object.
486   // it recursively checks nested objects.
487   function setConfigObject (config, prev) {
488     Object.keys(config).forEach(function (key) {
489       var value = config[key]
490       var fullKey = prev ? prev + '.' + key : key
491
492       // if the value is an inner object and we have dot-notation
493       // enabled, treat inner objects in config the same as
494       // heavily nested dot notations (foo.bar.apple).
495       if (typeof value === 'object' && value !== null && !Array.isArray(value) && configuration['dot-notation']) {
496         // if the value is an object but not an array, check nested object
497         setConfigObject(value, fullKey)
498       } else {
499         // setting arguments via CLI takes precedence over
500         // values within the config file.
501         if (!hasKey(argv, fullKey.split('.')) || (flags.defaulted[fullKey]) || (flags.arrays[fullKey] && configuration['combine-arrays'])) {
502           setArg(fullKey, value)
503         }
504       }
505     })
506   }
507
508   // set all config objects passed in opts
509   function setConfigObjects () {
510     if (typeof configObjects === 'undefined') return
511     configObjects.forEach(function (configObject) {
512       setConfigObject(configObject)
513     })
514   }
515
516   function applyEnvVars (argv, configOnly) {
517     if (typeof envPrefix === 'undefined') return
518
519     var prefix = typeof envPrefix === 'string' ? envPrefix : ''
520     Object.keys(process.env).forEach(function (envVar) {
521       if (prefix === '' || envVar.lastIndexOf(prefix, 0) === 0) {
522         // get array of nested keys and convert them to camel case
523         var keys = envVar.split('__').map(function (key, i) {
524           if (i === 0) {
525             key = key.substring(prefix.length)
526           }
527           return camelCase(key)
528         })
529
530         if (((configOnly && flags.configs[keys.join('.')]) || !configOnly) && (!hasKey(argv, keys) || flags.defaulted[keys.join('.')])) {
531           setArg(keys.join('.'), process.env[envVar])
532         }
533       }
534     })
535   }
536
537   function applyCoercions (argv) {
538     var coerce
539     var applied = {}
540     Object.keys(argv).forEach(function (key) {
541       if (!applied.hasOwnProperty(key)) { // If we haven't already coerced this option via one of its aliases
542         coerce = checkAllAliases(key, flags.coercions)
543         if (typeof coerce === 'function') {
544           try {
545             var value = coerce(argv[key])
546             ;([].concat(flags.aliases[key] || [], key)).forEach(ali => {
547               applied[ali] = argv[ali] = value
548             })
549           } catch (err) {
550             error = err
551           }
552         }
553       }
554     })
555   }
556
557   function applyDefaultsAndAliases (obj, aliases, defaults) {
558     Object.keys(defaults).forEach(function (key) {
559       if (!hasKey(obj, key.split('.'))) {
560         setKey(obj, key.split('.'), defaults[key])
561
562         ;(aliases[key] || []).forEach(function (x) {
563           if (hasKey(obj, x.split('.'))) return
564           setKey(obj, x.split('.'), defaults[key])
565         })
566       }
567     })
568   }
569
570   function hasKey (obj, keys) {
571     var o = obj
572
573     if (!configuration['dot-notation']) keys = [keys.join('.')]
574
575     keys.slice(0, -1).forEach(function (key) {
576       o = (o[key] || {})
577     })
578
579     var key = keys[keys.length - 1]
580
581     if (typeof o !== 'object') return false
582     else return key in o
583   }
584
585   function setKey (obj, keys, value) {
586     var o = obj
587
588     if (!configuration['dot-notation']) keys = [keys.join('.')]
589
590     keys.slice(0, -1).forEach(function (key, index) {
591       if (typeof o === 'object' && o[key] === undefined) {
592         o[key] = {}
593       }
594
595       if (typeof o[key] !== 'object' || Array.isArray(o[key])) {
596         // ensure that o[key] is an array, and that the last item is an empty object.
597         if (Array.isArray(o[key])) {
598           o[key].push({})
599         } else {
600           o[key] = [o[key], {}]
601         }
602
603         // we want to update the empty object at the end of the o[key] array, so set o to that object
604         o = o[key][o[key].length - 1]
605       } else {
606         o = o[key]
607       }
608     })
609
610     var key = keys[keys.length - 1]
611
612     var isTypeArray = checkAllAliases(keys.join('.'), flags.arrays)
613     var isValueArray = Array.isArray(value)
614     var duplicate = configuration['duplicate-arguments-array']
615
616     if (value === increment) {
617       o[key] = increment(o[key])
618     } else if (Array.isArray(o[key])) {
619       if (duplicate && isTypeArray && isValueArray) {
620         o[key] = configuration['flatten-duplicate-arrays'] ? o[key].concat(value) : [o[key]].concat([value])
621       } else if (!duplicate && Boolean(isTypeArray) === Boolean(isValueArray)) {
622         o[key] = value
623       } else {
624         o[key] = o[key].concat([value])
625       }
626     } else if (o[key] === undefined && isTypeArray) {
627       o[key] = isValueArray ? value : [value]
628     } else if (duplicate && !(o[key] === undefined || checkAllAliases(key, flags.bools) || checkAllAliases(keys.join('.'), flags.bools) || checkAllAliases(key, flags.counts))) {
629       o[key] = [ o[key], value ]
630     } else {
631       o[key] = value
632     }
633   }
634
635   // extend the aliases list with inferred aliases.
636   function extendAliases () {
637     Array.prototype.slice.call(arguments).forEach(function (obj) {
638       Object.keys(obj || {}).forEach(function (key) {
639         // short-circuit if we've already added a key
640         // to the aliases array, for example it might
641         // exist in both 'opts.default' and 'opts.key'.
642         if (flags.aliases[key]) return
643
644         flags.aliases[key] = [].concat(aliases[key] || [])
645         // For "--option-name", also set argv.optionName
646         flags.aliases[key].concat(key).forEach(function (x) {
647           if (/-/.test(x) && configuration['camel-case-expansion']) {
648             var c = camelCase(x)
649             if (c !== key && flags.aliases[key].indexOf(c) === -1) {
650               flags.aliases[key].push(c)
651               newAliases[c] = true
652             }
653           }
654         })
655         flags.aliases[key].forEach(function (x) {
656           flags.aliases[x] = [key].concat(flags.aliases[key].filter(function (y) {
657             return x !== y
658           }))
659         })
660       })
661     })
662   }
663
664   // check if a flag is set for any of a key's aliases.
665   function checkAllAliases (key, flag) {
666     var isSet = false
667     var toCheck = [].concat(flags.aliases[key] || [], key)
668
669     toCheck.forEach(function (key) {
670       if (flag[key]) isSet = flag[key]
671     })
672
673     return isSet
674   }
675
676   function setDefaulted (key) {
677     [].concat(flags.aliases[key] || [], key).forEach(function (k) {
678       flags.defaulted[k] = true
679     })
680   }
681
682   function unsetDefaulted (key) {
683     [].concat(flags.aliases[key] || [], key).forEach(function (k) {
684       delete flags.defaulted[k]
685     })
686   }
687
688   // return a default value, given the type of a flag.,
689   // e.g., key of type 'string' will default to '', rather than 'true'.
690   function defaultForType (type) {
691     var def = {
692       boolean: true,
693       string: '',
694       number: undefined,
695       array: []
696     }
697
698     return def[type]
699   }
700
701   // given a flag, enforce a default type.
702   function guessType (key, flags) {
703     var type = 'boolean'
704
705     if (checkAllAliases(key, flags.strings)) type = 'string'
706     else if (checkAllAliases(key, flags.numbers)) type = 'number'
707     else if (checkAllAliases(key, flags.arrays)) type = 'array'
708
709     return type
710   }
711
712   function isNumber (x) {
713     if (typeof x === 'number') return true
714     if (/^0x[0-9a-f]+$/i.test(x)) return true
715     return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x)
716   }
717
718   function isUndefined (num) {
719     return num === undefined
720   }
721
722   return {
723     argv: argv,
724     error: error,
725     aliases: flags.aliases,
726     newAliases: newAliases,
727     configuration: configuration
728   }
729 }
730
731 // if any aliases reference each other, we should
732 // merge them together.
733 function combineAliases (aliases) {
734   var aliasArrays = []
735   var change = true
736   var combined = {}
737
738   // turn alias lookup hash {key: ['alias1', 'alias2']} into
739   // a simple array ['key', 'alias1', 'alias2']
740   Object.keys(aliases).forEach(function (key) {
741     aliasArrays.push(
742       [].concat(aliases[key], key)
743     )
744   })
745
746   // combine arrays until zero changes are
747   // made in an iteration.
748   while (change) {
749     change = false
750     for (var i = 0; i < aliasArrays.length; i++) {
751       for (var ii = i + 1; ii < aliasArrays.length; ii++) {
752         var intersect = aliasArrays[i].filter(function (v) {
753           return aliasArrays[ii].indexOf(v) !== -1
754         })
755
756         if (intersect.length) {
757           aliasArrays[i] = aliasArrays[i].concat(aliasArrays[ii])
758           aliasArrays.splice(ii, 1)
759           change = true
760           break
761         }
762       }
763     }
764   }
765
766   // map arrays back to the hash-lookup (de-dupe while
767   // we're at it).
768   aliasArrays.forEach(function (aliasArray) {
769     aliasArray = aliasArray.filter(function (v, i, self) {
770       return self.indexOf(v) === i
771     })
772     combined[aliasArray.pop()] = aliasArray
773   })
774
775   return combined
776 }
777
778 function assign (defaults, configuration) {
779   var o = {}
780   configuration = configuration || {}
781
782   Object.keys(defaults).forEach(function (k) {
783     o[k] = defaults[k]
784   })
785   Object.keys(configuration).forEach(function (k) {
786     o[k] = configuration[k]
787   })
788
789   return o
790 }
791
792 // this function should only be called when a count is given as an arg
793 // it is NOT called to set a default value
794 // thus we can start the count at 1 instead of 0
795 function increment (orig) {
796   return orig !== undefined ? orig + 1 : 1
797 }
798
799 function Parser (args, opts) {
800   var result = parse(args.slice(), opts)
801
802   return result.argv
803 }
804
805 // parse arguments and return detailed
806 // meta information, aliases, etc.
807 Parser.detailed = function (args, opts) {
808   return parse(args.slice(), opts)
809 }
810
811 module.exports = Parser