11cb0ef41Sopenharmony_ciconst { mkdir, readFile, writeFile } = require('fs/promises')
21cb0ef41Sopenharmony_ciconst { dirname, resolve } = require('path')
31cb0ef41Sopenharmony_ciconst { spawn } = require('child_process')
41cb0ef41Sopenharmony_ciconst { EOL } = require('os')
51cb0ef41Sopenharmony_ciconst ini = require('ini')
61cb0ef41Sopenharmony_ciconst localeCompare = require('@isaacs/string-locale-compare')('en')
71cb0ef41Sopenharmony_ciconst pkgJson = require('@npmcli/package-json')
81cb0ef41Sopenharmony_ciconst { defaults, definitions } = require('@npmcli/config/lib/definitions')
91cb0ef41Sopenharmony_ciconst log = require('../utils/log-shim.js')
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci// These are the configs that we can nerf-dart. Not all of them currently even
121cb0ef41Sopenharmony_ci// *have* config definitions so we have to explicitly validate them here
131cb0ef41Sopenharmony_ciconst nerfDarts = [
141cb0ef41Sopenharmony_ci  '_auth',
151cb0ef41Sopenharmony_ci  '_authToken',
161cb0ef41Sopenharmony_ci  'username',
171cb0ef41Sopenharmony_ci  '_password',
181cb0ef41Sopenharmony_ci  'email',
191cb0ef41Sopenharmony_ci  'certfile',
201cb0ef41Sopenharmony_ci  'keyfile',
211cb0ef41Sopenharmony_ci]
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci// take an array of `[key, value, k2=v2, k3, v3, ...]` and turn into
241cb0ef41Sopenharmony_ci// { key: value, k2: v2, k3: v3 }
251cb0ef41Sopenharmony_ciconst keyValues = args => {
261cb0ef41Sopenharmony_ci  const kv = {}
271cb0ef41Sopenharmony_ci  for (let i = 0; i < args.length; i++) {
281cb0ef41Sopenharmony_ci    const arg = args[i].split('=')
291cb0ef41Sopenharmony_ci    const key = arg.shift()
301cb0ef41Sopenharmony_ci    const val = arg.length ? arg.join('=')
311cb0ef41Sopenharmony_ci      : i < args.length - 1 ? args[++i]
321cb0ef41Sopenharmony_ci      : ''
331cb0ef41Sopenharmony_ci    kv[key.trim()] = val.trim()
341cb0ef41Sopenharmony_ci  }
351cb0ef41Sopenharmony_ci  return kv
361cb0ef41Sopenharmony_ci}
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ciconst publicVar = k => {
391cb0ef41Sopenharmony_ci  // _password
401cb0ef41Sopenharmony_ci  if (k.startsWith('_')) {
411cb0ef41Sopenharmony_ci    return false
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci  // //localhost:8080/:_password
441cb0ef41Sopenharmony_ci  if (k.startsWith('//') && k.includes(':_')) {
451cb0ef41Sopenharmony_ci    return false
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci  return true
481cb0ef41Sopenharmony_ci}
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ciconst BaseCommand = require('../base-command.js')
511cb0ef41Sopenharmony_ciclass Config extends BaseCommand {
521cb0ef41Sopenharmony_ci  static description = 'Manage the npm configuration files'
531cb0ef41Sopenharmony_ci  static name = 'config'
541cb0ef41Sopenharmony_ci  static usage = [
551cb0ef41Sopenharmony_ci    'set <key>=<value> [<key>=<value> ...]',
561cb0ef41Sopenharmony_ci    'get [<key> [<key> ...]]',
571cb0ef41Sopenharmony_ci    'delete <key> [<key> ...]',
581cb0ef41Sopenharmony_ci    'list [--json]',
591cb0ef41Sopenharmony_ci    'edit',
601cb0ef41Sopenharmony_ci    'fix',
611cb0ef41Sopenharmony_ci  ]
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  static params = [
641cb0ef41Sopenharmony_ci    'json',
651cb0ef41Sopenharmony_ci    'global',
661cb0ef41Sopenharmony_ci    'editor',
671cb0ef41Sopenharmony_ci    'location',
681cb0ef41Sopenharmony_ci    'long',
691cb0ef41Sopenharmony_ci  ]
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  static ignoreImplicitWorkspace = false
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  static skipConfigValidation = true
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  static async completion (opts) {
761cb0ef41Sopenharmony_ci    const argv = opts.conf.argv.remain
771cb0ef41Sopenharmony_ci    if (argv[1] !== 'config') {
781cb0ef41Sopenharmony_ci      argv.unshift('config')
791cb0ef41Sopenharmony_ci    }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    if (argv.length === 2) {
821cb0ef41Sopenharmony_ci      const cmds = ['get', 'set', 'delete', 'ls', 'rm', 'edit', 'fix']
831cb0ef41Sopenharmony_ci      if (opts.partialWord !== 'l') {
841cb0ef41Sopenharmony_ci        cmds.push('list')
851cb0ef41Sopenharmony_ci      }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci      return cmds
881cb0ef41Sopenharmony_ci    }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    const action = argv[2]
911cb0ef41Sopenharmony_ci    switch (action) {
921cb0ef41Sopenharmony_ci      case 'set':
931cb0ef41Sopenharmony_ci        // todo: complete with valid values, if possible.
941cb0ef41Sopenharmony_ci        if (argv.length > 3) {
951cb0ef41Sopenharmony_ci          return []
961cb0ef41Sopenharmony_ci        }
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci        // fallthrough
991cb0ef41Sopenharmony_ci        /* eslint no-fallthrough:0 */
1001cb0ef41Sopenharmony_ci      case 'get':
1011cb0ef41Sopenharmony_ci      case 'delete':
1021cb0ef41Sopenharmony_ci      case 'rm':
1031cb0ef41Sopenharmony_ci        return Object.keys(definitions)
1041cb0ef41Sopenharmony_ci      case 'edit':
1051cb0ef41Sopenharmony_ci      case 'list':
1061cb0ef41Sopenharmony_ci      case 'ls':
1071cb0ef41Sopenharmony_ci      case 'fix':
1081cb0ef41Sopenharmony_ci      default:
1091cb0ef41Sopenharmony_ci        return []
1101cb0ef41Sopenharmony_ci    }
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  async exec ([action, ...args]) {
1141cb0ef41Sopenharmony_ci    log.disableProgress()
1151cb0ef41Sopenharmony_ci    try {
1161cb0ef41Sopenharmony_ci      switch (action) {
1171cb0ef41Sopenharmony_ci        case 'set':
1181cb0ef41Sopenharmony_ci          await this.set(args)
1191cb0ef41Sopenharmony_ci          break
1201cb0ef41Sopenharmony_ci        case 'get':
1211cb0ef41Sopenharmony_ci          await this.get(args)
1221cb0ef41Sopenharmony_ci          break
1231cb0ef41Sopenharmony_ci        case 'delete':
1241cb0ef41Sopenharmony_ci        case 'rm':
1251cb0ef41Sopenharmony_ci        case 'del':
1261cb0ef41Sopenharmony_ci          await this.del(args)
1271cb0ef41Sopenharmony_ci          break
1281cb0ef41Sopenharmony_ci        case 'list':
1291cb0ef41Sopenharmony_ci        case 'ls':
1301cb0ef41Sopenharmony_ci          await (this.npm.flatOptions.json ? this.listJson() : this.list())
1311cb0ef41Sopenharmony_ci          break
1321cb0ef41Sopenharmony_ci        case 'edit':
1331cb0ef41Sopenharmony_ci          await this.edit()
1341cb0ef41Sopenharmony_ci          break
1351cb0ef41Sopenharmony_ci        case 'fix':
1361cb0ef41Sopenharmony_ci          await this.fix()
1371cb0ef41Sopenharmony_ci          break
1381cb0ef41Sopenharmony_ci        default:
1391cb0ef41Sopenharmony_ci          throw this.usageError()
1401cb0ef41Sopenharmony_ci      }
1411cb0ef41Sopenharmony_ci    } finally {
1421cb0ef41Sopenharmony_ci      log.enableProgress()
1431cb0ef41Sopenharmony_ci    }
1441cb0ef41Sopenharmony_ci  }
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  async set (args) {
1471cb0ef41Sopenharmony_ci    if (!args.length) {
1481cb0ef41Sopenharmony_ci      throw this.usageError()
1491cb0ef41Sopenharmony_ci    }
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci    const where = this.npm.flatOptions.location
1521cb0ef41Sopenharmony_ci    for (const [key, val] of Object.entries(keyValues(args))) {
1531cb0ef41Sopenharmony_ci      log.info('config', 'set %j %j', key, val)
1541cb0ef41Sopenharmony_ci      const baseKey = key.split(':').pop()
1551cb0ef41Sopenharmony_ci      if (!this.npm.config.definitions[baseKey] && !nerfDarts.includes(baseKey)) {
1561cb0ef41Sopenharmony_ci        throw new Error(`\`${baseKey}\` is not a valid npm option`)
1571cb0ef41Sopenharmony_ci      }
1581cb0ef41Sopenharmony_ci      const deprecated = this.npm.config.definitions[baseKey]?.deprecated
1591cb0ef41Sopenharmony_ci      if (deprecated) {
1601cb0ef41Sopenharmony_ci        throw new Error(
1611cb0ef41Sopenharmony_ci          `The \`${baseKey}\` option is deprecated, and can not be set in this way${deprecated}`
1621cb0ef41Sopenharmony_ci        )
1631cb0ef41Sopenharmony_ci      }
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci      if (val === '') {
1661cb0ef41Sopenharmony_ci        this.npm.config.delete(key, where)
1671cb0ef41Sopenharmony_ci      } else {
1681cb0ef41Sopenharmony_ci        this.npm.config.set(key, val, where)
1691cb0ef41Sopenharmony_ci      }
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci      if (!this.npm.config.validate(where)) {
1721cb0ef41Sopenharmony_ci        log.warn('config', 'omitting invalid config values')
1731cb0ef41Sopenharmony_ci      }
1741cb0ef41Sopenharmony_ci    }
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci    await this.npm.config.save(where)
1771cb0ef41Sopenharmony_ci  }
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  async get (keys) {
1801cb0ef41Sopenharmony_ci    if (!keys.length) {
1811cb0ef41Sopenharmony_ci      return this.list()
1821cb0ef41Sopenharmony_ci    }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci    const out = []
1851cb0ef41Sopenharmony_ci    for (const key of keys) {
1861cb0ef41Sopenharmony_ci      if (!publicVar(key)) {
1871cb0ef41Sopenharmony_ci        throw new Error(`The ${key} option is protected, and can not be retrieved in this way`)
1881cb0ef41Sopenharmony_ci      }
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci      const pref = keys.length > 1 ? `${key}=` : ''
1911cb0ef41Sopenharmony_ci      out.push(pref + this.npm.config.get(key))
1921cb0ef41Sopenharmony_ci    }
1931cb0ef41Sopenharmony_ci    this.npm.output(out.join('\n'))
1941cb0ef41Sopenharmony_ci  }
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci  async del (keys) {
1971cb0ef41Sopenharmony_ci    if (!keys.length) {
1981cb0ef41Sopenharmony_ci      throw this.usageError()
1991cb0ef41Sopenharmony_ci    }
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci    const where = this.npm.flatOptions.location
2021cb0ef41Sopenharmony_ci    for (const key of keys) {
2031cb0ef41Sopenharmony_ci      this.npm.config.delete(key, where)
2041cb0ef41Sopenharmony_ci    }
2051cb0ef41Sopenharmony_ci    await this.npm.config.save(where)
2061cb0ef41Sopenharmony_ci  }
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  async edit () {
2091cb0ef41Sopenharmony_ci    const e = this.npm.flatOptions.editor
2101cb0ef41Sopenharmony_ci    const where = this.npm.flatOptions.location
2111cb0ef41Sopenharmony_ci    const file = this.npm.config.data.get(where).source
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci    // save first, just to make sure it's synced up
2141cb0ef41Sopenharmony_ci    // this also removes all the comments from the last time we edited it.
2151cb0ef41Sopenharmony_ci    await this.npm.config.save(where)
2161cb0ef41Sopenharmony_ci
2171cb0ef41Sopenharmony_ci    const data = (
2181cb0ef41Sopenharmony_ci      await readFile(file, 'utf8').catch(() => '')
2191cb0ef41Sopenharmony_ci    ).replace(/\r\n/g, '\n')
2201cb0ef41Sopenharmony_ci    const entries = Object.entries(defaults)
2211cb0ef41Sopenharmony_ci    const defData = entries.reduce((str, [key, val]) => {
2221cb0ef41Sopenharmony_ci      const obj = { [key]: val }
2231cb0ef41Sopenharmony_ci      const i = ini.stringify(obj)
2241cb0ef41Sopenharmony_ci        .replace(/\r\n/g, '\n') // normalizes output from ini.stringify
2251cb0ef41Sopenharmony_ci        .replace(/\n$/m, '')
2261cb0ef41Sopenharmony_ci        .replace(/^/g, '; ')
2271cb0ef41Sopenharmony_ci        .replace(/\n/g, '\n; ')
2281cb0ef41Sopenharmony_ci        .split('\n')
2291cb0ef41Sopenharmony_ci      return str + '\n' + i
2301cb0ef41Sopenharmony_ci    }, '')
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci    const tmpData = `;;;;
2331cb0ef41Sopenharmony_ci; npm ${where}config file: ${file}
2341cb0ef41Sopenharmony_ci; this is a simple ini-formatted file
2351cb0ef41Sopenharmony_ci; lines that start with semi-colons are comments
2361cb0ef41Sopenharmony_ci; run \`npm help 7 config\` for documentation of the various options
2371cb0ef41Sopenharmony_ci;
2381cb0ef41Sopenharmony_ci; Configs like \`@scope:registry\` map a scope to a given registry url.
2391cb0ef41Sopenharmony_ci;
2401cb0ef41Sopenharmony_ci; Configs like \`//<hostname>/:_authToken\` are auth that is restricted
2411cb0ef41Sopenharmony_ci; to the registry host specified.
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci${data.split('\n').sort(localeCompare).join('\n').trim()}
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci;;;;
2461cb0ef41Sopenharmony_ci; all available options shown below with default values
2471cb0ef41Sopenharmony_ci;;;;
2481cb0ef41Sopenharmony_ci
2491cb0ef41Sopenharmony_ci${defData}
2501cb0ef41Sopenharmony_ci`.split('\n').join(EOL)
2511cb0ef41Sopenharmony_ci    await mkdir(dirname(file), { recursive: true })
2521cb0ef41Sopenharmony_ci    await writeFile(file, tmpData, 'utf8')
2531cb0ef41Sopenharmony_ci    await new Promise((res, rej) => {
2541cb0ef41Sopenharmony_ci      const [bin, ...args] = e.split(/\s+/)
2551cb0ef41Sopenharmony_ci      const editor = spawn(bin, [...args, file], { stdio: 'inherit' })
2561cb0ef41Sopenharmony_ci      editor.on('exit', (code) => {
2571cb0ef41Sopenharmony_ci        if (code) {
2581cb0ef41Sopenharmony_ci          return rej(new Error(`editor process exited with code: ${code}`))
2591cb0ef41Sopenharmony_ci        }
2601cb0ef41Sopenharmony_ci        return res()
2611cb0ef41Sopenharmony_ci      })
2621cb0ef41Sopenharmony_ci    })
2631cb0ef41Sopenharmony_ci  }
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci  async fix () {
2661cb0ef41Sopenharmony_ci    let problems
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci    try {
2691cb0ef41Sopenharmony_ci      this.npm.config.validate()
2701cb0ef41Sopenharmony_ci      return // if validate doesn't throw we have nothing to do
2711cb0ef41Sopenharmony_ci    } catch (err) {
2721cb0ef41Sopenharmony_ci      // coverage skipped because we don't need to test rethrowing errors
2731cb0ef41Sopenharmony_ci      // istanbul ignore next
2741cb0ef41Sopenharmony_ci      if (err.code !== 'ERR_INVALID_AUTH') {
2751cb0ef41Sopenharmony_ci        throw err
2761cb0ef41Sopenharmony_ci      }
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci      problems = err.problems
2791cb0ef41Sopenharmony_ci    }
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci    if (!this.npm.config.isDefault('location')) {
2821cb0ef41Sopenharmony_ci      problems = problems.filter((problem) => {
2831cb0ef41Sopenharmony_ci        return problem.where === this.npm.config.get('location')
2841cb0ef41Sopenharmony_ci      })
2851cb0ef41Sopenharmony_ci    }
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_ci    this.npm.config.repair(problems)
2881cb0ef41Sopenharmony_ci    const locations = []
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci    this.npm.output('The following configuration problems have been repaired:\n')
2911cb0ef41Sopenharmony_ci    const summary = problems.map(({ action, from, to, key, where }) => {
2921cb0ef41Sopenharmony_ci      // coverage disabled for else branch because it is intentionally omitted
2931cb0ef41Sopenharmony_ci      // istanbul ignore else
2941cb0ef41Sopenharmony_ci      if (action === 'rename') {
2951cb0ef41Sopenharmony_ci        // we keep track of which configs were modified here so we know what to save later
2961cb0ef41Sopenharmony_ci        locations.push(where)
2971cb0ef41Sopenharmony_ci        return `~ \`${from}\` renamed to \`${to}\` in ${where} config`
2981cb0ef41Sopenharmony_ci      } else if (action === 'delete') {
2991cb0ef41Sopenharmony_ci        locations.push(where)
3001cb0ef41Sopenharmony_ci        return `- \`${key}\` deleted from ${where} config`
3011cb0ef41Sopenharmony_ci      }
3021cb0ef41Sopenharmony_ci    }).join('\n')
3031cb0ef41Sopenharmony_ci    this.npm.output(summary)
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci    return await Promise.all(locations.map((location) => this.npm.config.save(location)))
3061cb0ef41Sopenharmony_ci  }
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci  async list () {
3091cb0ef41Sopenharmony_ci    const msg = []
3101cb0ef41Sopenharmony_ci    // long does not have a flattener
3111cb0ef41Sopenharmony_ci    const long = this.npm.config.get('long')
3121cb0ef41Sopenharmony_ci    for (const [where, { data, source }] of this.npm.config.data.entries()) {
3131cb0ef41Sopenharmony_ci      if (where === 'default' && !long) {
3141cb0ef41Sopenharmony_ci        continue
3151cb0ef41Sopenharmony_ci      }
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ci      const keys = Object.keys(data).sort(localeCompare)
3181cb0ef41Sopenharmony_ci      if (!keys.length) {
3191cb0ef41Sopenharmony_ci        continue
3201cb0ef41Sopenharmony_ci      }
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci      msg.push(`; "${where}" config from ${source}`, '')
3231cb0ef41Sopenharmony_ci      for (const k of keys) {
3241cb0ef41Sopenharmony_ci        const v = publicVar(k) ? JSON.stringify(data[k]) : '(protected)'
3251cb0ef41Sopenharmony_ci        const src = this.npm.config.find(k)
3261cb0ef41Sopenharmony_ci        const overridden = src !== where
3271cb0ef41Sopenharmony_ci        msg.push((overridden ? '; ' : '') +
3281cb0ef41Sopenharmony_ci          `${k} = ${v} ${overridden ? `; overridden by ${src}` : ''}`)
3291cb0ef41Sopenharmony_ci      }
3301cb0ef41Sopenharmony_ci      msg.push('')
3311cb0ef41Sopenharmony_ci    }
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci    if (!long) {
3341cb0ef41Sopenharmony_ci      msg.push(
3351cb0ef41Sopenharmony_ci        `; node bin location = ${process.execPath}`,
3361cb0ef41Sopenharmony_ci        `; node version = ${process.version}`,
3371cb0ef41Sopenharmony_ci        `; npm local prefix = ${this.npm.localPrefix}`,
3381cb0ef41Sopenharmony_ci        `; npm version = ${this.npm.version}`,
3391cb0ef41Sopenharmony_ci        `; cwd = ${process.cwd()}`,
3401cb0ef41Sopenharmony_ci        `; HOME = ${process.env.HOME}`,
3411cb0ef41Sopenharmony_ci        '; Run `npm config ls -l` to show all defaults.'
3421cb0ef41Sopenharmony_ci      )
3431cb0ef41Sopenharmony_ci      msg.push('')
3441cb0ef41Sopenharmony_ci    }
3451cb0ef41Sopenharmony_ci
3461cb0ef41Sopenharmony_ci    if (!this.npm.global) {
3471cb0ef41Sopenharmony_ci      const { content } = await pkgJson.normalize(this.npm.prefix).catch(() => ({ content: {} }))
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci      if (content.publishConfig) {
3501cb0ef41Sopenharmony_ci        const pkgPath = resolve(this.npm.prefix, 'package.json')
3511cb0ef41Sopenharmony_ci        msg.push(`; "publishConfig" from ${pkgPath}`)
3521cb0ef41Sopenharmony_ci        msg.push('; This set of config values will be used at publish-time.', '')
3531cb0ef41Sopenharmony_ci        const pkgKeys = Object.keys(content.publishConfig).sort(localeCompare)
3541cb0ef41Sopenharmony_ci        for (const k of pkgKeys) {
3551cb0ef41Sopenharmony_ci          const v = publicVar(k) ? JSON.stringify(content.publishConfig[k]) : '(protected)'
3561cb0ef41Sopenharmony_ci          msg.push(`${k} = ${v}`)
3571cb0ef41Sopenharmony_ci        }
3581cb0ef41Sopenharmony_ci        msg.push('')
3591cb0ef41Sopenharmony_ci      }
3601cb0ef41Sopenharmony_ci    }
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci    this.npm.output(msg.join('\n').trim())
3631cb0ef41Sopenharmony_ci  }
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  async listJson () {
3661cb0ef41Sopenharmony_ci    const publicConf = {}
3671cb0ef41Sopenharmony_ci    for (const key in this.npm.config.list[0]) {
3681cb0ef41Sopenharmony_ci      if (!publicVar(key)) {
3691cb0ef41Sopenharmony_ci        continue
3701cb0ef41Sopenharmony_ci      }
3711cb0ef41Sopenharmony_ci
3721cb0ef41Sopenharmony_ci      publicConf[key] = this.npm.config.get(key)
3731cb0ef41Sopenharmony_ci    }
3741cb0ef41Sopenharmony_ci    this.npm.output(JSON.stringify(publicConf, null, 2))
3751cb0ef41Sopenharmony_ci  }
3761cb0ef41Sopenharmony_ci}
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_cimodule.exports = Config
379