"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/yargs/lib/parser.js" (11 Apr 2017, 14691 Bytes) of package /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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