source: trip-planner-front/node_modules/yargs-parser/index.js@ 571e0df

Last change on this file since 571e0df was e29cc2e, checked in by Ema <ema_spirova@…>, 3 years ago

primeNG components

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