react / wstein / node_modules / jest-cli / node_modules / istanbul / node_modules / nopt / lib / nopt.js
80684 views// info about each config option.12var debug = process.env.DEBUG_NOPT || process.env.NOPT_DEBUG3? function () { console.error.apply(console, arguments) }4: function () {}56var url = require("url")7, path = require("path")8, Stream = require("stream").Stream9, abbrev = require("abbrev")1011module.exports = exports = nopt12exports.clean = clean1314exports.typeDefs =15{ String : { type: String, validate: validateString }16, Boolean : { type: Boolean, validate: validateBoolean }17, url : { type: url, validate: validateUrl }18, Number : { type: Number, validate: validateNumber }19, path : { type: path, validate: validatePath }20, Stream : { type: Stream, validate: validateStream }21, Date : { type: Date, validate: validateDate }22}2324function nopt (types, shorthands, args, slice) {25args = args || process.argv26types = types || {}27shorthands = shorthands || {}28if (typeof slice !== "number") slice = 22930debug(types, shorthands, args, slice)3132args = args.slice(slice)33var data = {}34, key35, remain = []36, cooked = args37, original = args.slice(0)3839parse(args, data, remain, types, shorthands)40// now data is full41clean(data, types, exports.typeDefs)42data.argv = {remain:remain,cooked:cooked,original:original}43Object.defineProperty(data.argv, 'toString', { value: function () {44return this.original.map(JSON.stringify).join(" ")45}, enumerable: false })46return data47}4849function clean (data, types, typeDefs) {50typeDefs = typeDefs || exports.typeDefs51var remove = {}52, typeDefault = [false, true, null, String, Array]5354Object.keys(data).forEach(function (k) {55if (k === "argv") return56var val = data[k]57, isArray = Array.isArray(val)58, type = types[k]59if (!isArray) val = [val]60if (!type) type = typeDefault61if (type === Array) type = typeDefault.concat(Array)62if (!Array.isArray(type)) type = [type]6364debug("val=%j", val)65debug("types=", type)66val = val.map(function (val) {67// if it's an unknown value, then parse false/true/null/numbers/dates68if (typeof val === "string") {69debug("string %j", val)70val = val.trim()71if ((val === "null" && ~type.indexOf(null))72|| (val === "true" &&73(~type.indexOf(true) || ~type.indexOf(Boolean)))74|| (val === "false" &&75(~type.indexOf(false) || ~type.indexOf(Boolean)))) {76val = JSON.parse(val)77debug("jsonable %j", val)78} else if (~type.indexOf(Number) && !isNaN(val)) {79debug("convert to number", val)80val = +val81} else if (~type.indexOf(Date) && !isNaN(Date.parse(val))) {82debug("convert to date", val)83val = new Date(val)84}85}8687if (!types.hasOwnProperty(k)) {88return val89}9091// allow `--no-blah` to set 'blah' to null if null is allowed92if (val === false && ~type.indexOf(null) &&93!(~type.indexOf(false) || ~type.indexOf(Boolean))) {94val = null95}9697var d = {}98d[k] = val99debug("prevalidated val", d, val, types[k])100if (!validate(d, k, val, types[k], typeDefs)) {101if (exports.invalidHandler) {102exports.invalidHandler(k, val, types[k], data)103} else if (exports.invalidHandler !== false) {104debug("invalid: "+k+"="+val, types[k])105}106return remove107}108debug("validated val", d, val, types[k])109return d[k]110}).filter(function (val) { return val !== remove })111112if (!val.length) delete data[k]113else if (isArray) {114debug(isArray, data[k], val)115data[k] = val116} else data[k] = val[0]117118debug("k=%s val=%j", k, val, data[k])119})120}121122function validateString (data, k, val) {123data[k] = String(val)124}125126function validatePath (data, k, val) {127if (val === true) return false128if (val === null) return true129130val = String(val)131var homePattern = process.platform === 'win32' ? /^~(\/|\\)/ : /^~\//132if (val.match(homePattern) && process.env.HOME) {133val = path.resolve(process.env.HOME, val.substr(2))134}135data[k] = path.resolve(String(val))136return true137}138139function validateNumber (data, k, val) {140debug("validate Number %j %j %j", k, val, isNaN(val))141if (isNaN(val)) return false142data[k] = +val143}144145function validateDate (data, k, val) {146debug("validate Date %j %j %j", k, val, Date.parse(val))147var s = Date.parse(val)148if (isNaN(s)) return false149data[k] = new Date(val)150}151152function validateBoolean (data, k, val) {153if (val instanceof Boolean) val = val.valueOf()154else if (typeof val === "string") {155if (!isNaN(val)) val = !!(+val)156else if (val === "null" || val === "false") val = false157else val = true158} else val = !!val159data[k] = val160}161162function validateUrl (data, k, val) {163val = url.parse(String(val))164if (!val.host) return false165data[k] = val.href166}167168function validateStream (data, k, val) {169if (!(val instanceof Stream)) return false170data[k] = val171}172173function validate (data, k, val, type, typeDefs) {174// arrays are lists of types.175if (Array.isArray(type)) {176for (var i = 0, l = type.length; i < l; i ++) {177if (type[i] === Array) continue178if (validate(data, k, val, type[i], typeDefs)) return true179}180delete data[k]181return false182}183184// an array of anything?185if (type === Array) return true186187// NaN is poisonous. Means that something is not allowed.188if (type !== type) {189debug("Poison NaN", k, val, type)190delete data[k]191return false192}193194// explicit list of values195if (val === type) {196debug("Explicitly allowed %j", val)197// if (isArray) (data[k] = data[k] || []).push(val)198// else data[k] = val199data[k] = val200return true201}202203// now go through the list of typeDefs, validate against each one.204var ok = false205, types = Object.keys(typeDefs)206for (var i = 0, l = types.length; i < l; i ++) {207debug("test type %j %j %j", k, val, types[i])208var t = typeDefs[types[i]]209if (t && type === t.type) {210var d = {}211ok = false !== t.validate(d, k, val)212val = d[k]213if (ok) {214// if (isArray) (data[k] = data[k] || []).push(val)215// else data[k] = val216data[k] = val217break218}219}220}221debug("OK? %j (%j %j %j)", ok, k, val, types[i])222223if (!ok) delete data[k]224return ok225}226227function parse (args, data, remain, types, shorthands) {228debug("parse", args, data, remain)229230var key = null231, abbrevs = abbrev(Object.keys(types))232, shortAbbr = abbrev(Object.keys(shorthands))233234for (var i = 0; i < args.length; i ++) {235var arg = args[i]236debug("arg", arg)237238if (arg.match(/^-{2,}$/)) {239// done with keys.240// the rest are args.241remain.push.apply(remain, args.slice(i + 1))242args[i] = "--"243break244}245var hadEq = false246if (arg.charAt(0) === "-" && arg.length > 1) {247if (arg.indexOf("=") !== -1) {248hadEq = true249var v = arg.split("=")250arg = v.shift()251v = v.join("=")252args.splice.apply(args, [i, 1].concat([arg, v]))253}254255// see if it's a shorthand256// if so, splice and back up to re-parse it.257var shRes = resolveShort(arg, shorthands, shortAbbr, abbrevs)258debug("arg=%j shRes=%j", arg, shRes)259if (shRes) {260debug(arg, shRes)261args.splice.apply(args, [i, 1].concat(shRes))262if (arg !== shRes[0]) {263i --264continue265}266}267arg = arg.replace(/^-+/, "")268var no = null269while (arg.toLowerCase().indexOf("no-") === 0) {270no = !no271arg = arg.substr(3)272}273274if (abbrevs[arg]) arg = abbrevs[arg]275276var isArray = types[arg] === Array ||277Array.isArray(types[arg]) && types[arg].indexOf(Array) !== -1278279// allow unknown things to be arrays if specified multiple times.280if (!types.hasOwnProperty(arg) && data.hasOwnProperty(arg)) {281if (!Array.isArray(data[arg]))282data[arg] = [data[arg]]283isArray = true284}285286var val287, la = args[i + 1]288289var isBool = typeof no === 'boolean' ||290types[arg] === Boolean ||291Array.isArray(types[arg]) && types[arg].indexOf(Boolean) !== -1 ||292(typeof types[arg] === 'undefined' && !hadEq) ||293(la === "false" &&294(types[arg] === null ||295Array.isArray(types[arg]) && ~types[arg].indexOf(null)))296297if (isBool) {298// just set and move along299val = !no300// however, also support --bool true or --bool false301if (la === "true" || la === "false") {302val = JSON.parse(la)303la = null304if (no) val = !val305i ++306}307308// also support "foo":[Boolean, "bar"] and "--foo bar"309if (Array.isArray(types[arg]) && la) {310if (~types[arg].indexOf(la)) {311// an explicit type312val = la313i ++314} else if ( la === "null" && ~types[arg].indexOf(null) ) {315// null allowed316val = null317i ++318} else if ( !la.match(/^-{2,}[^-]/) &&319!isNaN(la) &&320~types[arg].indexOf(Number) ) {321// number322val = +la323i ++324} else if ( !la.match(/^-[^-]/) && ~types[arg].indexOf(String) ) {325// string326val = la327i ++328}329}330331if (isArray) (data[arg] = data[arg] || []).push(val)332else data[arg] = val333334continue335}336337if (types[arg] === String && la === undefined)338la = ""339340if (la && la.match(/^-{2,}$/)) {341la = undefined342i --343}344345val = la === undefined ? true : la346if (isArray) (data[arg] = data[arg] || []).push(val)347else data[arg] = val348349i ++350continue351}352remain.push(arg)353}354}355356function resolveShort (arg, shorthands, shortAbbr, abbrevs) {357// handle single-char shorthands glommed together, like358// npm ls -glp, but only if there is one dash, and only if359// all of the chars are single-char shorthands, and it's360// not a match to some other abbrev.361arg = arg.replace(/^-+/, '')362363// if it's an exact known option, then don't go any further364if (abbrevs[arg] === arg)365return null366367// if it's an exact known shortopt, same deal368if (shorthands[arg]) {369// make it an array, if it's a list of words370if (shorthands[arg] && !Array.isArray(shorthands[arg]))371shorthands[arg] = shorthands[arg].split(/\s+/)372373return shorthands[arg]374}375376// first check to see if this arg is a set of single-char shorthands377var singles = shorthands.___singles378if (!singles) {379singles = Object.keys(shorthands).filter(function (s) {380return s.length === 1381}).reduce(function (l,r) {382l[r] = true383return l384}, {})385shorthands.___singles = singles386debug('shorthand singles', singles)387}388389var chrs = arg.split("").filter(function (c) {390return singles[c]391})392393if (chrs.join("") === arg) return chrs.map(function (c) {394return shorthands[c]395}).reduce(function (l, r) {396return l.concat(r)397}, [])398399400// if it's an arg abbrev, and not a literal shorthand, then prefer the arg401if (abbrevs[arg] && !shorthands[arg])402return null403404// if it's an abbr for a shorthand, then use that405if (shortAbbr[arg])406arg = shortAbbr[arg]407408// make it an array, if it's a list of words409if (shorthands[arg] && !Array.isArray(shorthands[arg]))410shorthands[arg] = shorthands[arg].split(/\s+/)411412return shorthands[arg]413}414415416