File Explorer

/proc/4/root/var/lang/lib/node_modules/npm/node_modules/@npmcli/config/lib/definitions

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 /.

definition.js6.5 KB · 256 lines
// class that describes a config key we know about// this keeps us from defining a config key and not// providing a default, description, etc.//// TODO: some kind of categorization system, so we can// say "these are for registry access", "these are for// version resolution" etc. const required = ['type', 'description', 'default', 'key'] const allowed = [  'default',  'defaultDescription',  'deprecated',  'description',  'exclusive',  'flatten',  'hint',  'key',  'short',  'type',  'typeDescription',  'usage',  'envExport',  'alias',  'required',] const {  semver: { type: semver },  Umask: { type: Umask },  url: { type: url },  path: { type: path },} = require('../type-defs.js') class Definition {  constructor (key, def) {    this.key = key    // if it's set falsey, don't export it; otherwise, we do by default    this.envExport = true    Object.assign(this, def)    this.validate()    if (!this.defaultDescription) {      this.defaultDescription = describeValue(this.default)    }    if (!this.typeDescription) {      this.typeDescription = describeType(this.type)    }    // hint is only used for non-boolean values    if (!this.hint) {      if (this.type === Number) {        this.hint = '<number>'      } else {        this.hint = `<${this.key}>`      }    }    if (!this.usage) {      this.usage = describeUsage(this)    }  }   validate () {    for (const req of required) {      if (!Object.prototype.hasOwnProperty.call(this, req)) {        throw new Error(`config lacks ${req}: ${this.key}`)      }    }    if (!this.key) {      throw new Error(`config lacks key: ${this.key}`)    }    for (const field of Object.keys(this)) {      if (!allowed.includes(field)) {        throw new Error(`config defines unknown field ${field}: ${this.key}`)      }    }  }   // a textual description of this config, suitable for help output  describe () {    const description = unindent(this.description)    const noEnvExport = this.envExport      ? ''      : `This value is not exported to the environment for child processes.`    const deprecated = !this.deprecated ? '' : `* DEPRECATED: ${unindent(this.deprecated)}\n`    /* eslint-disable-next-line max-len */    const exclusive = !this.exclusive ? '' : `\nThis config cannot be used with: \`${this.exclusive.join('`, `')}\``    return wrapAll(`#### \`${this.key}\` * Default: ${unindent(this.defaultDescription)}* Type: ${unindent(this.typeDescription)}${deprecated}${description}${exclusive}${noEnvExport}`)  }} const describeUsage = def => {  let key = ''   // Single type  if (!Array.isArray(def.type)) {    if (def.short) {      key = `-${def.short}|`    }     if (def.type === Boolean && def.default !== false) {      key = `${key}--no-${def.key}`    } else {      key = `${key}--${def.key}`    }     if (def.type !== Boolean) {      key = `${key} ${def.hint}`    }     return key  }   key = `--${def.key}`  if (def.short) {    key = `-${def.short}|--${def.key}`  }   // Multiple types  let types = def.type  const multiple = types.includes(Array)  const bool = types.includes(Boolean)   // null type means optional and doesn't currently affect usage output since  // all non-optional params have defaults so we render everything as optional  types = types.filter(t => t !== null && t !== Array && t !== Boolean)   if (!types.length) {    return key  }   let description  if (!types.some(t => typeof t !== 'string')) {    // Specific values, use specifics given    description = `<${types.filter(d => d).join('|')}>`  } else {    // Generic values, use hint    description = def.hint  }   if (bool) {    // Currently none of our multi-type configs with boolean values default to    // false so all their hints should show `--no-`, if we ever add ones that    // default to false we can branch the logic here    key = `--no-${def.key}|${key}`  }   const usage = `${key} ${description}`  if (multiple) {    return `${usage} [${usage} ...]`  } else {    return usage  }} const describeType = type => {  if (Array.isArray(type)) {    const descriptions = type.filter(t => t !== Array).map(t => describeType(t))     // [a] => "a"    // [a, b] => "a or b"    // [a, b, c] => "a, b, or c"    // [a, Array] => "a (can be set multiple times)"    // [a, Array, b] => "a or b (can be set multiple times)"    const last = descriptions.length > 1 ? [descriptions.pop()] : []    const oxford = descriptions.length > 1 ? ', or ' : ' or '    const words = [descriptions.join(', ')].concat(last).join(oxford)    const multiple = type.includes(Array) ? ' (can be set multiple times)' : ''    return `${words}${multiple}`  }   // Note: these are not quite the same as the description printed  // when validation fails.  In that case, we want to give the user  // a bit more information to help them figure out what's wrong.  switch (type) {    case String:      return 'String'    case Number:      return 'Number'    case Umask:      return 'Octal numeric string in range 0000..0777 (0..511)'    case Boolean:      return 'Boolean'    case Date:      return 'Date'    case path:      return 'Path'    case semver:      return 'SemVer string'    case url:      return 'URL'    default:      return describeValue(type)  }} // if it's a string, quote it.  otherwise, just cast to string.const describeValue = val => (typeof val === 'string' ? JSON.stringify(val) : String(val)) const unindent = s => {  // get the first \n followed by a bunch of spaces, and pluck off  // that many spaces from the start of every line.  const match = s.match(/\n +/)  return !match ? s.trim() : s.split(match[0]).join('\n').trim()} const wrap = s => {  const cols = Math.min(Math.max(20, process.stdout.columns) || 80, 80) - 5  return unindent(s)    .split(/[ \n]+/)    .reduce((left, right) => {      const last = left.split('\n').pop()      const join = last.length && last.length + right.length > cols ? '\n' : ' '      return left + join + right    })} const wrapAll = s => {  let inCodeBlock = false  return s    .split('\n\n')    .map(block => {      if (inCodeBlock || block.startsWith('```')) {        inCodeBlock = !block.endsWith('```')        return block      }       if (block.charAt(0) === '*') {        return (          '* ' +          block            .slice(1)            .trim()            .split('\n* ')            .map(li => {              return wrap(li).replace(/\n/g, '\n  ')            })            .join('\n* ')        )      } else {        return wrap(block)      }    })    .join('\n\n')} module.exports = Definition