Bug:Fix file validation issue
[vnfsdk/refrepo.git] / vnfmarket / src / main / webapp / vnfmarket / node_modules / yargs / lib / parser.js
1 // fancy-pants parsing of argv, originally forked
2 // from minimist: https://www.npmjs.com/package/minimist
3 var camelCase = require('camelcase'),
4   path = require('path')
5
6 function increment (orig) {
7   return orig !== undefined ? orig + 1 : 0
8 }
9
10 module.exports = function (args, opts) {
11   if (!opts) opts = {}
12   var flags = { arrays: {}, bools: {}, strings: {}, counts: {}, normalize: {}, configs: {} }
13
14   ;[].concat(opts['array']).filter(Boolean).forEach(function (key) {
15     flags.arrays[key] = true
16   })
17
18   ;[].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
19     flags.bools[key] = true
20   })
21
22   ;[].concat(opts.string).filter(Boolean).forEach(function (key) {
23     flags.strings[key] = true
24   })
25
26   ;[].concat(opts.count).filter(Boolean).forEach(function (key) {
27     flags.counts[key] = true
28   })
29
30   ;[].concat(opts.normalize).filter(Boolean).forEach(function (key) {
31     flags.normalize[key] = true
32   })
33
34   ;[].concat(opts.config).filter(Boolean).forEach(function (key) {
35     flags.configs[key] = true
36   })
37
38   var aliases = {},
39   newAliases = {}
40
41   extendAliases(opts.key)
42   extendAliases(opts.alias)
43
44   var defaults = opts['default'] || {}
45   Object.keys(defaults).forEach(function (key) {
46     if (/-/.test(key) && !opts.alias[key]) {
47       aliases[key] = aliases[key] || []
48     }
49     (aliases[key] || []).forEach(function (alias) {
50       defaults[alias] = defaults[key]
51     })
52   })
53
54   var argv = { _: [] }
55
56   Object.keys(flags.bools).forEach(function (key) {
57     setArg(key, !(key in defaults) ? false : defaults[key])
58   })
59
60   var notFlags = []
61   if (args.indexOf('--') !== -1) {
62     notFlags = args.slice(args.indexOf('--') + 1)
63     args = args.slice(0, args.indexOf('--'))
64   }
65
66   for (var i = 0; i < args.length; i++) {
67     var arg = args[i],
68       broken,
69       key,
70       letters,
71       m,
72       next,
73       value
74
75     // -- seperated by =
76     if (arg.match(/^--.+=/)) {
77       // Using [\s\S] instead of . because js doesn't support the
78       // 'dotall' regex modifier. See:
79       // http://stackoverflow.com/a/1068308/13216
80       m = arg.match(/^--([^=]+)=([\s\S]*)$/)
81
82       // nargs format = '--f=monkey washing cat'
83       if (checkAllAliases(m[1], opts.narg)) {
84         args.splice(i + 1, m[1], m[2])
85         i = eatNargs(i, m[1], args)
86       // arrays format = '--f=a b c'
87       } else if (checkAllAliases(m[1], flags.arrays) && args.length > i + 1) {
88         args.splice(i + 1, m[1], m[2])
89         i = eatArray(i, m[1], args)
90       } else {
91         setArg(m[1], m[2])
92       }
93     } else if (arg.match(/^--no-.+/)) {
94       key = arg.match(/^--no-(.+)/)[1]
95       setArg(key, false)
96
97     // -- seperated by space.
98     } else if (arg.match(/^--.+/)) {
99       key = arg.match(/^--(.+)/)[1]
100
101       // nargs format = '--foo a b c'
102       if (checkAllAliases(key, opts.narg)) {
103         i = eatNargs(i, key, args)
104       // array format = '--foo a b c'
105       } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
106         i = eatArray(i, key, args)
107       } else {
108         next = args[i + 1]
109
110         if (next !== undefined && !next.match(/^-/)
111         && !checkAllAliases(key, flags.bools)
112         && !checkAllAliases(key, flags.counts)) {
113           setArg(key, next)
114           i++
115         } else if (/^(true|false)$/.test(next)) {
116           setArg(key, next)
117           i++
118         } else {
119           setArg(key, defaultForType(guessType(key, flags)))
120         }
121       }
122
123     // dot-notation flag seperated by '='.
124     } else if (arg.match(/^-.\..+=/)) {
125       m = arg.match(/^-([^=]+)=([\s\S]*)$/)
126       setArg(m[1], m[2])
127
128     // dot-notation flag seperated by space.
129     } else if (arg.match(/^-.\..+/)) {
130       next = args[i + 1]
131       key = arg.match(/^-(.\..+)/)[1]
132
133       if (next !== undefined && !next.match(/^-/)
134         && !checkAllAliases(key, flags.bools)
135         && !checkAllAliases(key, flags.counts)) {
136         setArg(key, next)
137         i++
138       } else {
139         setArg(key, defaultForType(guessType(key, flags)))
140       }
141     } else if (arg.match(/^-[^-]+/)) {
142       letters = arg.slice(1, -1).split('')
143       broken = false
144
145       for (var j = 0; j < letters.length; j++) {
146         next = arg.slice(j + 2)
147
148         if (letters[j + 1] && letters[j + 1] === '=') {
149           value = arg.slice(j + 3)
150           key = letters[j]
151
152           // nargs format = '-f=monkey washing cat'
153           if (checkAllAliases(letters[j], opts.narg)) {
154             args.splice(i + 1, 0, value)
155             i = eatNargs(i, key, args)
156           // array format = '-f=a b c'
157           } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
158             args.splice(i + 1, 0, value)
159             i = eatArray(i, key, args)
160           } else {
161             setArg(key, value)
162           }
163
164           broken = true
165           break
166         }
167
168         if (next === '-') {
169           setArg(letters[j], next)
170           continue
171         }
172
173         if (/[A-Za-z]/.test(letters[j])
174         && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
175           setArg(letters[j], next)
176           broken = true
177           break
178         }
179
180         if (letters[j + 1] && letters[j + 1].match(/\W/)) {
181           setArg(letters[j], arg.slice(j + 2))
182           broken = true
183           break
184         } else {
185           setArg(letters[j], defaultForType(guessType(letters[j], flags)))
186         }
187       }
188
189       key = arg.slice(-1)[0]
190
191       if (!broken && key !== '-') {
192         // nargs format = '-f a b c'
193         if (checkAllAliases(key, opts.narg)) {
194           i = eatNargs(i, key, args)
195         // array format = '-f a b c'
196         } else if (checkAllAliases(key, flags.arrays) && args.length > i + 1) {
197           i = eatArray(i, key, args)
198         } else {
199           if (args[i + 1] && !/^(-|--)[^-]/.test(args[i + 1])
200           && !checkAllAliases(key, flags.bools)
201           && !checkAllAliases(key, flags.counts)) {
202             setArg(key, args[i + 1])
203             i++
204           } else if (args[i + 1] && /true|false/.test(args[i + 1])) {
205             setArg(key, args[i + 1])
206             i++
207           } else {
208             setArg(key, defaultForType(guessType(key, flags)))
209           }
210         }
211       }
212     } else {
213       argv._.push(
214         flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
215       )
216     }
217   }
218
219   setConfig(argv)
220   applyDefaultsAndAliases(argv, aliases, defaults)
221
222   Object.keys(flags.counts).forEach(function (key) {
223     setArg(key, defaults[key])
224   })
225
226   notFlags.forEach(function (key) {
227     argv._.push(key)
228   })
229
230   // how many arguments should we consume, based
231   // on the nargs option?
232   function eatNargs (i, key, args) {
233     var toEat = checkAllAliases(key, opts.narg)
234
235     if (args.length - (i + 1) < toEat) throw Error('not enough arguments following: ' + key)
236
237     for (var ii = i + 1; ii < (toEat + i + 1); ii++) {
238       setArg(key, args[ii])
239     }
240
241     return (i + toEat)
242   }
243
244   // if an option is an array, eat all non-hyphenated arguments
245   // following it... YUM!
246   // e.g., --foo apple banana cat becomes ["apple", "banana", "cat"]
247   function eatArray (i, key, args) {
248     for (var ii = i + 1; ii < args.length; ii++) {
249       if (/^-/.test(args[ii])) break
250       i = ii
251       setArg(key, args[ii])
252     }
253
254     return i
255   }
256
257   function setArg (key, val) {
258     // handle parsing boolean arguments --foo=true --bar false.
259     if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {
260       if (typeof val === 'string') val = val === 'true'
261     }
262
263     if (/-/.test(key) && !(aliases[key] && aliases[key].length)) {
264       var c = camelCase(key)
265       aliases[key] = [c]
266       newAliases[c] = true
267     }
268
269     var value = !checkAllAliases(key, flags.strings) && isNumber(val) ? Number(val) : val
270
271     if (checkAllAliases(key, flags.counts)) {
272       value = increment
273     }
274
275     var splitKey = key.split('.')
276     setKey(argv, splitKey, value)
277
278     ;(aliases[splitKey[0]] || []).forEach(function (x) {
279       x = x.split('.')
280
281       // handle populating dot notation for both
282       // the key and its aliases.
283       if (splitKey.length > 1) {
284         var a = [].concat(splitKey)
285         a.shift() // nuke the old key.
286         x = x.concat(a)
287       }
288
289       setKey(argv, x, value)
290     })
291
292     var keys = [key].concat(aliases[key] || [])
293     for (var i = 0, l = keys.length; i < l; i++) {
294       if (flags.normalize[keys[i]]) {
295         keys.forEach(function (key) {
296           argv.__defineSetter__(key, function (v) {
297             val = path.normalize(v)
298           })
299
300           argv.__defineGetter__(key, function () {
301             return typeof val === 'string' ?
302             path.normalize(val) : val
303           })
304         })
305         break
306       }
307     }
308   }
309
310   // set args from config.json file, this should be
311   // applied last so that defaults can be applied.
312   function setConfig (argv) {
313     var configLookup = {}
314
315     // expand defaults/aliases, in-case any happen to reference
316     // the config.json file.
317     applyDefaultsAndAliases(configLookup, aliases, defaults)
318
319     Object.keys(flags.configs).forEach(function (configKey) {
320       var configPath = argv[configKey] || configLookup[configKey]
321       if (configPath) {
322         try {
323           var config = require(path.resolve(process.cwd(), configPath))
324
325           Object.keys(config).forEach(function (key) {
326             // setting arguments via CLI takes precedence over
327             // values within the config file.
328             if (argv[key] === undefined) {
329               delete argv[key]
330               setArg(key, config[key])
331             }
332           })
333         } catch (ex) {
334           throw Error('invalid json config file: ' + configPath)
335         }
336       }
337     })
338   }
339
340   function applyDefaultsAndAliases (obj, aliases, defaults) {
341     Object.keys(defaults).forEach(function (key) {
342       if (!hasKey(obj, key.split('.'))) {
343         setKey(obj, key.split('.'), defaults[key])
344
345         ;(aliases[key] || []).forEach(function (x) {
346           setKey(obj, x.split('.'), defaults[key])
347         })
348       }
349     })
350   }
351
352   function hasKey (obj, keys) {
353     var o = obj
354     keys.slice(0, -1).forEach(function (key) {
355       o = (o[key] || {})
356     })
357
358     var key = keys[keys.length - 1]
359     return key in o
360   }
361
362   function setKey (obj, keys, value) {
363     var o = obj
364     keys.slice(0, -1).forEach(function (key) {
365       if (o[key] === undefined) o[key] = {}
366       o = o[key]
367     })
368
369     var key = keys[keys.length - 1]
370     if (value === increment) {
371       o[key] = increment(o[key])
372     } else if (o[key] === undefined && checkAllAliases(key, flags.arrays)) {
373       o[key] = Array.isArray(value) ? value : [value]
374     } else if (o[key] === undefined || typeof o[key] === 'boolean') {
375       o[key] = value
376     } else if (Array.isArray(o[key])) {
377       o[key].push(value)
378     } else {
379       o[key] = [ o[key], value ]
380     }
381   }
382
383   // extend the aliases list with inferred aliases.
384   function extendAliases (obj) {
385     Object.keys(obj || {}).forEach(function (key) {
386       aliases[key] = [].concat(opts.alias[key] || [])
387       // For "--option-name", also set argv.optionName
388       aliases[key].concat(key).forEach(function (x) {
389         if (/-/.test(x)) {
390           var c = camelCase(x)
391           aliases[key].push(c)
392           newAliases[c] = true
393         }
394       })
395       aliases[key].forEach(function (x) {
396         aliases[x] = [key].concat(aliases[key].filter(function (y) {
397           return x !== y
398         }))
399       })
400     })
401   }
402
403   // check if a flag is set for any of a key's aliases.
404   function checkAllAliases (key, flag) {
405     var isSet = false,
406     toCheck = [].concat(aliases[key] || [], key)
407
408     toCheck.forEach(function (key) {
409       if (flag[key]) isSet = flag[key]
410     })
411
412     return isSet
413   }
414
415   // return a default value, given the type of a flag.,
416   // e.g., key of type 'string' will default to '', rather than 'true'.
417   function defaultForType (type) {
418     var def = {
419       boolean: true,
420       string: '',
421       array: []
422     }
423
424     return def[type]
425   }
426
427   // given a flag, enforce a default type.
428   function guessType (key, flags) {
429     var type = 'boolean'
430
431     if (flags.strings && flags.strings[key]) type = 'string'
432     else if (flags.arrays && flags.arrays[key]) type = 'array'
433
434     return type
435   }
436
437   function isNumber (x) {
438     if (typeof x === 'number') return true
439     if (/^0x[0-9a-f]+$/i.test(x)) return true
440     return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x)
441   }
442
443   return {
444     argv: argv,
445     aliases: aliases,
446     newAliases: newAliases
447   }
448 }