react / react-0.13.3 / examples / basic-commonjs / node_modules / browserify / node_modules / umd / node_modules / uglify-js / node_modules / yargs / lib / parser.js
80759 views// fancy-pants parsing of argv, originally forked1// from minimist: https://www.npmjs.com/package/minimist2var camelCase = require('camelcase'),3fs = require('fs'),4path = require('path');56module.exports = function (args, opts) {7if (!opts) opts = {};8var flags = { arrays: {}, bools : {}, strings : {}, counts: {}, normalize: {}, configs: {} };910[].concat(opts['array']).filter(Boolean).forEach(function (key) {11flags.arrays[key] = true;12});1314[].concat(opts['boolean']).filter(Boolean).forEach(function (key) {15flags.bools[key] = true;16});1718[].concat(opts.string).filter(Boolean).forEach(function (key) {19flags.strings[key] = true;20});2122[].concat(opts.count).filter(Boolean).forEach(function (key) {23flags.counts[key] = true;24});2526[].concat(opts.normalize).filter(Boolean).forEach(function (key) {27flags.normalize[key] = true;28});2930[].concat(opts.config).filter(Boolean).forEach(function (key) {31flags.configs[key] = true;32});3334var aliases = {},35newAliases = {};3637extendAliases(opts.key);38extendAliases(opts.alias);3940var defaults = opts['default'] || {};41Object.keys(defaults).forEach(function (key) {42if (/-/.test(key) && !opts.alias[key]) {43var c = camelCase(key);44aliases[key] = aliases[key] || [];45// don't allow the same key to be added multiple times.46if (aliases[key].indexOf(c) === -1) {47aliases[key] = (aliases[key] || []).concat(c);48newAliases[c] = true;49}50}51(aliases[key] || []).forEach(function (alias) {52defaults[alias] = defaults[key];53});54});5556var argv = { _ : [] };57Object.keys(flags.bools).forEach(function (key) {58setArg(key, !(key in defaults) ? false : defaults[key]);59});6061var notFlags = [];62if (args.indexOf('--') !== -1) {63notFlags = args.slice(args.indexOf('--')+1);64args = args.slice(0, args.indexOf('--'));65}6667for (var i = 0; i < args.length; i++) {68var arg = args[i];6970// -- seperated by =71if (arg.match(/^--.+=/)) {72// Using [\s\S] instead of . because js doesn't support the73// 'dotall' regex modifier. See:74// http://stackoverflow.com/a/1068308/1321675var m = arg.match(/^--([^=]+)=([\s\S]*)$/);76setArg(m[1], m[2]);77}78else if (arg.match(/^--no-.+/)) {79var key = arg.match(/^--no-(.+)/)[1];80setArg(key, false);81}82// -- seperated by space.83else if (arg.match(/^--.+/)) {84var key = arg.match(/^--(.+)/)[1];8586if (checkAllAliases(key, opts.narg)) {87i = eatNargs(i, key, args);88} else {89var next = args[i + 1];9091if (next !== undefined && !next.match(/^-/)92&& !checkAllAliases(key, flags.bools)93&& !checkAllAliases(key, flags.counts)) {94setArg(key, next);95i++;96}97else if (/^(true|false)$/.test(next)) {98setArg(key, next);99i++;100}101else {102setArg(key, defaultForType(guessType(key, flags)));103}104}105}106// dot-notation flag seperated by '='.107else if (arg.match(/^-.\..+=/)) {108var m = arg.match(/^-([^=]+)=([\s\S]*)$/);109setArg(m[1], m[2]);110}111// dot-notation flag seperated by space.112else if (arg.match(/^-.\..+/)) {113var key = arg.match(/^-(.\..+)/)[1];114var next = args[i + 1];115if (next !== undefined && !next.match(/^-/)116&& !checkAllAliases(key, flags.bools)117&& !checkAllAliases(key, flags.counts)) {118setArg(key, next);119i++;120}121else {122setArg(key, defaultForType(guessType(key, flags)));123}124}125else if (arg.match(/^-[^-]+/)) {126var letters = arg.slice(1,-1).split('');127128var broken = false;129for (var j = 0; j < letters.length; j++) {130var next = arg.slice(j+2);131132if (letters[j+1] && letters[j+1] === '=') {133setArg(letters[j], arg.slice(j+3));134broken = true;135break;136}137138if (next === '-') {139setArg(letters[j], next)140continue;141}142if (/[A-Za-z]/.test(letters[j])143&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {144setArg(letters[j], next);145broken = true;146break;147}148if (letters[j+1] && letters[j+1].match(/\W/)) {149setArg(letters[j], arg.slice(j+2));150broken = true;151break;152}153else {154setArg(letters[j], defaultForType(guessType(letters[j], flags)));155}156}157158var key = arg.slice(-1)[0];159160if (!broken && key !== '-') {161if (checkAllAliases(key, opts.narg)) {162i = eatNargs(i, key, args);163} else {164if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])165&& !checkAllAliases(key, flags.bools)166&& !checkAllAliases(key, flags.counts)) {167setArg(key, args[i+1]);168i++;169}170else if (args[i+1] && /true|false/.test(args[i+1])) {171setArg(key, args[i+1]);172i++;173}174else {175setArg(key, defaultForType(guessType(key, flags)));176}177}178}179}180else {181argv._.push(182flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)183);184}185}186187setConfig(argv);188applyDefaultsAndAliases(argv, aliases, defaults);189190Object.keys(flags.counts).forEach(function (key) {191setArg(key, defaults[key]);192});193194notFlags.forEach(function(key) {195argv._.push(key);196});197198// how many arguments should we consume, based199// on the nargs option?200function eatNargs (i, key, args) {201var toEat = checkAllAliases(key, opts.narg);202203if (args.length - (i + 1) < toEat) throw Error('not enough arguments following: ' + key);204205for (var ii = i + 1; ii < (toEat + i + 1); ii++) {206setArg(key, args[ii]);207}208209return (i + toEat);210}211212function setArg (key, val) {213// handle parsing boolean arguments --foo=true --bar false.214if (checkAllAliases(key, flags.bools) || checkAllAliases(key, flags.counts)) {215if (typeof val === 'string') val = val === 'true';216}217218if (/-/.test(key) && !(aliases[key] && aliases[key].length)) {219var c = camelCase(key);220aliases[key] = [c];221newAliases[c] = true;222}223224var value = !checkAllAliases(key, flags.strings) && isNumber(val) ? Number(val) : val;225226if (checkAllAliases(key, flags.counts)) {227value = function(orig) { return orig !== undefined ? orig + 1 : 0; };228}229230var splitKey = key.split('.');231setKey(argv, splitKey, value);232233(aliases[splitKey[0]] || []).forEach(function (x) {234x = x.split('.');235236// handle populating dot notation for both237// the key and its aliases.238if (splitKey.length > 1) {239var a = [].concat(splitKey);240a.shift(); // nuke the old key.241x = x.concat(a);242}243244setKey(argv, x, value);245});246247var keys = [key].concat(aliases[key] || []);248for (var i = 0, l = keys.length; i < l; i++) {249if (flags.normalize[keys[i]]) {250keys.forEach(function(key) {251argv.__defineSetter__(key, function(v) {252val = path.normalize(v);253});254255argv.__defineGetter__(key, function () {256return typeof val === 'string' ?257path.normalize(val) : val;258});259});260break;261}262}263}264265// set args from config.json file, this should be266// applied last so that defaults can be applied.267function setConfig (argv) {268var configLookup = {};269270// expand defaults/aliases, in-case any happen to reference271// the config.json file.272applyDefaultsAndAliases(configLookup, aliases, defaults);273274Object.keys(flags.configs).forEach(function(configKey) {275var configPath = argv[configKey] || configLookup[configKey];276if (configPath) {277try {278var config = JSON.parse(fs.readFileSync(configPath, 'utf8'));279Object.keys(config).forEach(function (key) {280// setting arguments via CLI takes precedence over281// values within the config file.282if (argv[key] === undefined) {283delete argv[key];284setArg(key, config[key]);285}286});287} catch (ex) {288throw Error('invalid json config file: ' + configPath);289}290}291});292}293294function applyDefaultsAndAliases(obj, aliases, defaults) {295Object.keys(defaults).forEach(function (key) {296if (!hasKey(obj, key.split('.'))) {297setKey(obj, key.split('.'), defaults[key]);298299(aliases[key] || []).forEach(function (x) {300setKey(obj, x.split('.'), defaults[key]);301});302}303});304}305306function hasKey (obj, keys) {307var o = obj;308keys.slice(0,-1).forEach(function (key) {309o = (o[key] || {});310});311312var key = keys[keys.length - 1];313return key in o;314}315316function setKey (obj, keys, value) {317var o = obj;318keys.slice(0,-1).forEach(function (key) {319if (o[key] === undefined) o[key] = {};320o = o[key];321});322323var key = keys[keys.length - 1];324if (typeof value === 'function') {325o[key] = value(o[key]);326}327else if (o[key] === undefined && checkAllAliases(key, flags.arrays)) {328o[key] = Array.isArray(value) ? value : [value];329}330else if (o[key] === undefined || typeof o[key] === 'boolean') {331o[key] = value;332}333else if (Array.isArray(o[key])) {334o[key].push(value);335}336else {337o[key] = [ o[key], value ];338}339}340341// extend the aliases list with inferred aliases.342function extendAliases (obj) {343Object.keys(obj || {}).forEach(function(key) {344aliases[key] = [].concat(opts.alias[key] || []);345// For "--option-name", also set argv.optionName346aliases[key].concat(key).forEach(function (x) {347if (/-/.test(x)) {348var c = camelCase(x);349aliases[key].push(c);350newAliases[c] = true;351}352});353aliases[key].forEach(function (x) {354aliases[x] = [key].concat(aliases[key].filter(function (y) {355return x !== y;356}));357});358});359}360361// check if a flag is set for any of a key's aliases.362function checkAllAliases (key, flag) {363var isSet = false,364toCheck = [].concat(aliases[key] || [], key);365366toCheck.forEach(function(key) {367if (flag[key]) isSet = flag[key];368});369370return isSet;371};372373// return a default value, given the type of a flag.,374// e.g., key of type 'string' will default to '', rather than 'true'.375function defaultForType (type) {376var def = {377boolean: true,378string: '',379array: []380};381382return def[type];383}384385// given a flag, enforce a default type.386function guessType (key, flags) {387var type = 'boolean';388389if (flags.strings && flags.strings[key]) type = 'string';390else if (flags.arrays && flags.arrays[key]) type = 'array';391392return type;393}394395function isNumber (x) {396if (typeof x === 'number') return true;397if (/^0x[0-9a-f]+$/i.test(x)) return true;398return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);399}400401return {402argv: argv,403aliases: aliases,404newAliases: newAliases405};406};407408409