File Explorer

/proc/self/root/proc/1/task/1/root/node24/lib/node_modules/npm/node_modules/nopt/lib

This explorer reads the filesystem of the server it runs on, so /workspace/user isn't present here. Browsing and the terminal still work against this server's own disk from /.

nopt-lib.js13.9 KB · 515 lines
const abbrev = require('abbrev')const debug = require('./debug')const defaultTypeDefs = require('./type-defs') const hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k) const getType = (k, { types, dynamicTypes }) => {  let hasType = hasOwn(types, k)  let type = types[k]  if (!hasType && typeof dynamicTypes === 'function') {    const matchedType = dynamicTypes(k)    if (matchedType !== undefined) {      type = matchedType      hasType = true    }  }  return [hasType, type]} const isTypeDef = (type, def) => def && type === defconst hasTypeDef = (type, def) => def && type.indexOf(def) !== -1const doesNotHaveTypeDef = (type, def) => def && !hasTypeDef(type, def) function nopt (args, {  types,  shorthands,  typeDefs,  invalidHandler, // opt is configured but its value does not validate against given type  unknownHandler, // opt is not configured  abbrevHandler, // opt is being expanded via abbrev  typeDefault,  dynamicTypes,} = {}) {  debug(types, shorthands, args, typeDefs)   const data = {}  const argv = {    remain: [],    cooked: args,    original: args.slice(0),  }   parse(args, data, argv.remain, {    typeDefs, types, dynamicTypes, shorthands, unknownHandler, abbrevHandler,  })   // now data is full  clean(data, { types, dynamicTypes, typeDefs, invalidHandler, typeDefault })  data.argv = argv   Object.defineProperty(data.argv, 'toString', {    value: function () {      return this.original.map(JSON.stringify).join(' ')    },    enumerable: false,  })   return data} function clean (data, {  types = {},  typeDefs = {},  dynamicTypes,  invalidHandler,  typeDefault,} = {}) {  const StringType = typeDefs.String?.type  const NumberType = typeDefs.Number?.type  const ArrayType = typeDefs.Array?.type  const BooleanType = typeDefs.Boolean?.type  const DateType = typeDefs.Date?.type   const hasTypeDefault = typeof typeDefault !== 'undefined'  if (!hasTypeDefault) {    typeDefault = [false, true, null]    if (StringType) {      typeDefault.push(StringType)    }    if (ArrayType) {      typeDefault.push(ArrayType)    }  }   const remove = {}   Object.keys(data).forEach((k) => {    if (k === 'argv') {      return    }    let val = data[k]    debug('val=%j', val)    const isArray = Array.isArray(val)    let [hasType, rawType] = getType(k, { types, dynamicTypes })    let type = rawType    if (!isArray) {      val = [val]    }    if (!type) {      type = typeDefault    }    if (isTypeDef(type, ArrayType)) {      type = typeDefault.concat(ArrayType)    }    if (!Array.isArray(type)) {      type = [type]    }     debug('val=%j', val)    debug('types=', type)    val = val.map((v) => {      // if it's an unknown value, then parse false/true/null/numbers/dates      if (typeof v === 'string') {        debug('string %j', v)        v = v.trim()        if ((v === 'null' && ~type.indexOf(null))            || (v === 'true' &&               (~type.indexOf(true) || hasTypeDef(type, BooleanType)))            || (v === 'false' &&               (~type.indexOf(false) || hasTypeDef(type, BooleanType)))) {          v = JSON.parse(v)          debug('jsonable %j', v)        } else if (hasTypeDef(type, NumberType) && !isNaN(v)) {          debug('convert to number', v)          v = +v        } else if (hasTypeDef(type, DateType) && !isNaN(Date.parse(v))) {          debug('convert to date', v)          v = new Date(v)        }      }       if (!hasType) {        if (!hasTypeDefault) {          return v        }        // if the default type has been passed in then we want to validate the        // unknown data key instead of bailing out earlier. we also set the raw        // type which is passed to the invalid handler so that it can be        // determined if during validation if it is unknown vs invalid        rawType = typeDefault      }       // allow `--no-blah` to set 'blah' to null if null is allowed      if (v === false && ~type.indexOf(null) &&          !(~type.indexOf(false) || hasTypeDef(type, BooleanType))) {        v = null      }       const d = {}      d[k] = v      debug('prevalidated val', d, v, rawType)      if (!validate(d, k, v, rawType, { typeDefs })) {        if (invalidHandler) {          invalidHandler(k, v, rawType, data)        } else if (invalidHandler !== false) {          debug('invalid: ' + k + '=' + v, rawType)        }        return remove      }      debug('validated v', d, v, rawType)      return d[k]    }).filter((v) => v !== remove)     // if we allow Array specifically, then an empty array is how we    // express 'no value here', not null.  Allow it.    if (!val.length && doesNotHaveTypeDef(type, ArrayType)) {      debug('VAL HAS NO LENGTH, DELETE IT', val, k, type.indexOf(ArrayType))      delete data[k]    } else if (isArray) {      debug(isArray, data[k], val)      data[k] = val    } else {      data[k] = val[0]    }     debug('k=%s val=%j', k, val, data[k])  })} function validate (data, k, val, type, { typeDefs } = {}) {  const ArrayType = typeDefs?.Array?.type  // arrays are lists of types.  if (Array.isArray(type)) {    for (let i = 0, l = type.length; i < l; i++) {      if (isTypeDef(type[i], ArrayType)) {        continue      }      if (validate(data, k, val, type[i], { typeDefs })) {        return true      }    }    delete data[k]    return false  }   // an array of anything?  if (isTypeDef(type, ArrayType)) {    return true  }   // Original comment:  // NaN is poisonous.  Means that something is not allowed.  // New comment: Changing this to an isNaN check breaks a lot of tests.  // Something is being assumed here that is not actually what happens in  // practice.  Fixing it is outside the scope of getting linting to pass in  // this repo. Leaving as-is for now.  /* eslint-disable-next-line no-self-compare */  if (type !== type) {    debug('Poison NaN', k, val, type)    delete data[k]    return false  }   // explicit list of values  if (val === type) {    debug('Explicitly allowed %j', val)    data[k] = val    return true  }   // now go through the list of typeDefs, validate against each one.  let ok = false  const types = Object.keys(typeDefs)  for (let i = 0, l = types.length; i < l; i++) {    debug('test type %j %j %j', k, val, types[i])    const t = typeDefs[types[i]]    if (t && (      (type && type.name && t.type && t.type.name) ?        (type.name === t.type.name) :        (type === t.type)    )) {      const d = {}      ok = t.validate(d, k, val) !== false      val = d[k]      if (ok) {        data[k] = val        break      }    }  }  debug('OK? %j (%j %j %j)', ok, k, val, types[types.length - 1])   if (!ok) {    delete data[k]  }  return ok} function parse (args, data, remain, {  types = {},  typeDefs = {},  shorthands = {},  dynamicTypes,  unknownHandler,  abbrevHandler,} = {}) {  const StringType = typeDefs.String?.type  const NumberType = typeDefs.Number?.type  const ArrayType = typeDefs.Array?.type  const BooleanType = typeDefs.Boolean?.type   debug('parse', args, data, remain)   const abbrevs = abbrev(Object.keys(types))  debug('abbrevs=%j', abbrevs)  const shortAbbr = abbrev(Object.keys(shorthands))   for (let i = 0; i < args.length; i++) {    let arg = args[i]    debug('arg', arg)     if (arg.match(/^-{2,}$/)) {      // done with keys.      // the rest are args.      remain.push.apply(remain, args.slice(i + 1))      args[i] = '--'      break    }    let hadEq = false    if (arg.charAt(0) === '-' && arg.length > 1) {      const at = arg.indexOf('=')      if (at > -1) {        hadEq = true        const v = arg.slice(at + 1)        arg = arg.slice(0, at)        args.splice(i, 1, arg, v)      }       // see if it's a shorthand      // if so, splice and back up to re-parse it.      const shRes = resolveShort(arg, shortAbbr, abbrevs, { shorthands, abbrevHandler })      debug('arg=%j shRes=%j', arg, shRes)      if (shRes) {        args.splice.apply(args, [i, 1].concat(shRes))        if (arg !== shRes[0]) {          i--          continue        }      }      arg = arg.replace(/^-+/, '')      let no = null      while (arg.toLowerCase().indexOf('no-') === 0) {        no = !no        arg = arg.slice(3)      }       // abbrev includes the original full string in its abbrev list      if (abbrevs[arg] && abbrevs[arg] !== arg) {        if (abbrevHandler) {          abbrevHandler(arg, abbrevs[arg])        } else if (abbrevHandler !== false) {          debug(`abbrev: ${arg} -> ${abbrevs[arg]}`)        }        arg = abbrevs[arg]      }       let [hasType, argType] = getType(arg, { types, dynamicTypes })      let isTypeArray = Array.isArray(argType)      if (isTypeArray && argType.length === 1) {        isTypeArray = false        argType = argType[0]      }       let isArray = isTypeDef(argType, ArrayType) ||        isTypeArray && hasTypeDef(argType, ArrayType)       // allow unknown things to be arrays if specified multiple times.      if (!hasType && hasOwn(data, arg)) {        if (!Array.isArray(data[arg])) {          data[arg] = [data[arg]]        }        isArray = true      }       let val      let la = args[i + 1]       const isBool = typeof no === 'boolean' ||        isTypeDef(argType, BooleanType) ||        isTypeArray && hasTypeDef(argType, BooleanType) ||        (typeof argType === 'undefined' && !hadEq) ||        (la === 'false' &&         (argType === null ||          isTypeArray && ~argType.indexOf(null)))       if (typeof argType === 'undefined') {        // la is going to unexpectedly be parsed outside the context of this arg        const hangingLa = !hadEq && la && !la?.startsWith('-') && !['true', 'false'].includes(la)        if (unknownHandler) {          if (hangingLa) {            unknownHandler(arg, la)          } else {            unknownHandler(arg)          }        } else if (unknownHandler !== false) {          debug(`unknown: ${arg}`)          if (hangingLa) {            debug(`unknown: ${la} parsed as normal opt`)          }        }      }       if (isBool) {        // just set and move along        val = !no        // however, also support --bool true or --bool false        if (la === 'true' || la === 'false') {          val = JSON.parse(la)          la = null          if (no) {            val = !val          }          i++        }         // also support "foo":[Boolean, "bar"] and "--foo bar"        if (isTypeArray && la) {          if (~argType.indexOf(la)) {            // an explicit type            val = la            i++          } else if (la === 'null' && ~argType.indexOf(null)) {            // null allowed            val = null            i++          } else if (!la.match(/^-{2,}[^-]/) &&                      !isNaN(la) &&                      hasTypeDef(argType, NumberType)) {            // number            val = +la            i++          } else if (!la.match(/^-[^-]/) && hasTypeDef(argType, StringType)) {            // string            val = la            i++          }        }         if (isArray) {          (data[arg] = data[arg] || []).push(val)        } else {          data[arg] = val        }         continue      }       if (isTypeDef(argType, StringType)) {        if (la === undefined) {          la = ''        } else if (la.match(/^-{1,2}[^-]+/)) {          la = ''          i--        }      }       if (la && la.match(/^-{2,}$/)) {        la = undefined        i--      }       val = la === undefined ? true : la      if (isArray) {        (data[arg] = data[arg] || []).push(val)      } else {        data[arg] = val      }       i++      continue    }    remain.push(arg)  }} const SINGLES = Symbol('singles')const singleCharacters = (arg, shorthands) => {  let singles = shorthands[SINGLES]  if (!singles) {    singles = Object.keys(shorthands).filter((s) => s.length === 1).reduce((l, r) => {      l[r] = true      return l    }, {})    shorthands[SINGLES] = singles    debug('shorthand singles', singles)  }  const chrs = arg.split('').filter((c) => singles[c])  return chrs.join('') === arg ? chrs : null} function resolveShort (arg, ...rest) {  const { abbrevHandler, types = {}, shorthands = {} } = rest.length ? rest.pop() : {}  const shortAbbr = rest[0] ?? abbrev(Object.keys(shorthands))  const abbrevs = rest[1] ?? abbrev(Object.keys(types))   // handle single-char shorthands glommed together, like  // npm ls -glp, but only if there is one dash, and only if  // all of the chars are single-char shorthands, and it's  // not a match to some other abbrev.  arg = arg.replace(/^-+/, '')   // if it's an exact known option, then don't go any further  if (abbrevs[arg] === arg) {    return null  }   // if it's an exact known shortopt, same deal  if (shorthands[arg]) {    // make it an array, if it's a list of words    if (shorthands[arg] && !Array.isArray(shorthands[arg])) {      shorthands[arg] = shorthands[arg].split(/\s+/)    }     return shorthands[arg]  }   // first check to see if this arg is a set of single-char shorthands  const chrs = singleCharacters(arg, shorthands)  if (chrs) {    return chrs.map((c) => shorthands[c]).reduce((l, r) => l.concat(r), [])  }   // if it's an arg abbrev, and not a literal shorthand, then prefer the arg  if (abbrevs[arg] && !shorthands[arg]) {    return null  }   // if it's an abbr for a shorthand, then use that  // exact match has already happened so we don't need to account for that here  if (shortAbbr[arg]) {    if (abbrevHandler) {      abbrevHandler(arg, shortAbbr[arg])    } else if (abbrevHandler !== false) {      debug(`abbrev: ${arg} -> ${shortAbbr[arg]}`)    }    arg = shortAbbr[arg]  }   // make it an array, if it's a list of words  if (shorthands[arg] && !Array.isArray(shorthands[arg])) {    shorthands[arg] = shorthands[arg].split(/\s+/)  }   return shorthands[arg]} module.exports = {  nopt,  clean,  parse,  validate,  resolveShort,  typeDefs: defaultTypeDefs,}