diff --git a/lib/access.js b/lib/access.js index e11934af43ebc..3bc21119033f5 100644 --- a/lib/access.js +++ b/lib/access.js @@ -3,7 +3,6 @@ const path = require('path') const libaccess = require('libnpmaccess') const readPackageJson = require('read-package-json-fast') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const usageUtil = require('./utils/usage.js') const getIdentity = require('./utils/get-identity.js') @@ -157,7 +156,7 @@ class Access { const pkgs = await libaccess.lsPackages(owner, opts) // TODO - print these out nicely (breaking change) - output(JSON.stringify(pkgs, null, 2)) + this.npm.output(JSON.stringify(pkgs, null, 2)) } get ['ls-collaborators'] () { @@ -169,7 +168,7 @@ class Access { const collabs = await libaccess.lsCollaborators(pkgName, usr, opts) // TODO - print these out nicely (breaking change) - output(JSON.stringify(collabs, null, 2)) + this.npm.output(JSON.stringify(collabs, null, 2)) } async edit () { diff --git a/lib/adduser.js b/lib/adduser.js index dac0f5a46840d..45d602fd2c844 100644 --- a/lib/adduser.js +++ b/lib/adduser.js @@ -1,5 +1,4 @@ const log = require('npmlog') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') const replaceInfo = require('./utils/replace-info.js') const authTypes = { @@ -49,7 +48,7 @@ class AddUser { scope, }) - output(message) + this.npm.output(message) } getRegistry ({ scope, registry }) { diff --git a/lib/audit.js b/lib/audit.js index dfa01cb2709fa..b8c85605dba43 100644 --- a/lib/audit.js +++ b/lib/audit.js @@ -1,6 +1,5 @@ const Arborist = require('@npmcli/arborist') const auditReport = require('npm-audit-report') -const output = require('./utils/output.js') const reifyFinish = require('./utils/reify-finish.js') const auditError = require('./utils/audit-error.js') const usageUtil = require('./utils/usage.js') @@ -57,7 +56,7 @@ class Audit { reporter, }) process.exitCode = process.exitCode || result.exitCode - output(result.report) + this.npm.output(result.report) } } } diff --git a/lib/bin.js b/lib/bin.js index 11490c41cbcc5..f540cc57c8cd7 100644 --- a/lib/bin.js +++ b/lib/bin.js @@ -1,4 +1,3 @@ -const output = require('./utils/output.js') const envPath = require('./utils/path.js') const usageUtil = require('./utils/usage.js') @@ -18,7 +17,7 @@ class Bin { async bin (args) { const b = this.npm.bin - output(b) + this.npm.output(b) if (this.npm.flatOptions.global && !envPath.includes(b)) console.error('(not in PATH env variable)') } diff --git a/lib/cache.js b/lib/cache.js index 8469559764fb3..3ca99fd2562e3 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,7 +1,6 @@ const cacache = require('cacache') const { promisify } = require('util') const log = require('npmlog') -const output = require('./utils/output.js') const pacote = require('pacote') const path = require('path') const rimraf = promisify(require('rimraf')) @@ -116,13 +115,13 @@ with --force.`) ? `~${cache.substr(process.env.HOME.length)}` : cache const stats = await cacache.verify(cache) - output(`Cache verified and compressed (${prefix})`) - output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`) - stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`) - stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) - stats.missingContent && output(`Missing content: ${stats.missingContent}`) - output(`Index entries: ${stats.totalEntries}`) - output(`Finished in ${stats.runTime.total / 1000}s`) + this.npm.output(`Cache verified and compressed (${prefix})`) + this.npm.output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`) + stats.badContentCount && this.npm.output(`Corrupted content removed: ${stats.badContentCount}`) + stats.reclaimedCount && this.npm.output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) + stats.missingContent && this.npm.output(`Missing content: ${stats.missingContent}`) + this.npm.output(`Index entries: ${stats.totalEntries}`) + this.npm.output(`Finished in ${stats.runTime.total / 1000}s`) } } diff --git a/lib/completion.js b/lib/completion.js index 4c37e6ef354ef..5baf17665800d 100644 --- a/lib/completion.js +++ b/lib/completion.js @@ -39,7 +39,6 @@ const configNames = Object.keys(types) const shorthandNames = Object.keys(shorthands) const allConfs = configNames.concat(shorthandNames) const isWindowsShell = require('./utils/is-windows-shell.js') -const output = require('./utils/output.js') const fileExists = require('./utils/file-exists.js') const usageUtil = require('./utils/usage.js') @@ -131,14 +130,14 @@ class Completion { if (partialWords.slice(0, -1).indexOf('--') === -1) { if (word.charAt(0) === '-') - return wrap(opts, configCompl(opts)) + return this.wrap(opts, configCompl(opts)) if (words[w - 1] && words[w - 1].charAt(0) === '-' && !isFlag(words[w - 1])) { // awaiting a value for a non-bool config. // don't even try to do this for now - return wrap(opts, configValueCompl(opts)) + return this.wrap(opts, configValueCompl(opts)) } } @@ -152,7 +151,7 @@ class Completion { // check if there's a command already. const cmd = parsed.argv.remain[1] if (!cmd) - return wrap(opts, cmdCompl(opts)) + return this.wrap(opts, cmdCompl(opts)) Object.keys(parsed).forEach(k => this.npm.config.set(k, parsed[k])) @@ -162,9 +161,29 @@ class Completion { const impl = this.npm.commands[cmd] if (impl && impl.completion) { const comps = await impl.completion(opts) - return wrap(opts, comps) + return this.wrap(opts, comps) } } + + // The command should respond with an array. Loop over that, + // wrapping quotes around any that have spaces, and writing + // them to stdout. + // If any of the items are arrays, then join them with a space. + // Ie, returning ['a', 'b c', ['d', 'e']] would allow it to expand + // to: 'a', 'b c', or 'd' 'e' + wrap (opts, compls) { + if (!Array.isArray(compls)) + compls = compls ? [compls] : [] + + compls = compls.map(c => + Array.isArray(c) ? c.map(escape).join(' ') : escape(c)) + + if (opts.partialWord) + compls = compls.filter(c => c.startsWith(opts.partialWord)) + + if (compls.length > 0) + this.npm.output(compls.join('\n')) + } } const dumpScript = async () => { @@ -214,26 +233,6 @@ const unescape = w => w.charAt(0) === '\'' ? w.replace(/^'|'$/g, '') const escape = w => !/\s+/.test(w) ? w : '\'' + w + '\'' -// The command should respond with an array. Loop over that, -// wrapping quotes around any that have spaces, and writing -// them to stdout. -// If any of the items are arrays, then join them with a space. -// Ie, returning ['a', 'b c', ['d', 'e']] would allow it to expand -// to: 'a', 'b c', or 'd' 'e' -const wrap = (opts, compls) => { - if (!Array.isArray(compls)) - compls = compls ? [compls] : [] - - compls = compls.map(c => - Array.isArray(c) ? c.map(escape).join(' ') : escape(c)) - - if (opts.partialWord) - compls = compls.filter(c => c.startsWith(opts.partialWord)) - - if (compls.length > 0) - output(compls.join('\n')) -} - // the current word has a dash. Return the config names, // with the same number of dashes as the current word has. const configCompl = opts => { diff --git a/lib/config.js b/lib/config.js index 2805db9b80ec7..7009f46016d23 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,6 +1,5 @@ const { defaults, types } = require('./utils/config.js') const usageUtil = require('./utils/usage.js') -const output = require('./utils/output.js') const mkdirp = require('mkdirp-infer-owner') const { dirname } = require('path') @@ -142,7 +141,7 @@ class Config { const pref = keys.length > 1 ? `${key}=` : '' out.push(pref + this.npm.config.get(key)) } - output(out.join('\n')) + this.npm.output(out.join('\n')) } async del (keys) { @@ -241,7 +240,7 @@ ${defData} ) } - output(msg.join('\n').trim()) + this.npm.output(msg.join('\n').trim()) } async listJson () { @@ -252,7 +251,7 @@ ${defData} publicConf[key] = this.npm.config.get(key) } - output(JSON.stringify(publicConf, null, 2)) + this.npm.output(JSON.stringify(publicConf, null, 2)) } usageError () { diff --git a/lib/diff.js b/lib/diff.js index 859e6f76feeef..ed36a30673c43 100644 --- a/lib/diff.js +++ b/lib/diff.js @@ -9,7 +9,6 @@ const pacote = require('pacote') const pickManifest = require('npm-pick-manifest') const usageUtil = require('./utils/usage.js') -const output = require('./utils/output.js') const readLocalPkg = require('./utils/read-local-package.js') class Diff { @@ -55,7 +54,7 @@ class Diff { diffFiles: args, where: this.where, }) - return output(res) + return this.npm.output(res) } async retrieveSpecs ([a, b]) { diff --git a/lib/dist-tag.js b/lib/dist-tag.js index 171a88c527e5d..4b7e2602043be 100644 --- a/lib/dist-tag.js +++ b/lib/dist-tag.js @@ -3,7 +3,6 @@ const npa = require('npm-package-arg') const regFetch = require('npm-registry-fetch') const semver = require('semver') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const readLocalPkgName = require('./utils/read-local-package.js') const usageUtil = require('./utils/usage.js') @@ -91,7 +90,7 @@ class DistTag { spec, } await otplease(reqOpts, reqOpts => regFetch(url, reqOpts)) - output(`+${t}: ${spec.name}@${version}`) + this.npm.output(`+${t}: ${spec.name}@${version}`) } async remove (spec, tag, opts) { @@ -116,7 +115,7 @@ class DistTag { spec, } await otplease(reqOpts, reqOpts => regFetch(url, reqOpts)) - output(`-${tag}: ${spec.name}@${version}`) + this.npm.output(`-${tag}: ${spec.name}@${version}`) } async list (spec, opts) { @@ -133,7 +132,7 @@ class DistTag { const tags = await this.fetchTags(spec, opts) const msg = Object.keys(tags).map(k => `${k}: ${tags[k]}`).sort().join('\n') - output(msg) + this.npm.output(msg) return tags } catch (err) { log.error('dist-tag ls', "Couldn't get dist-tag data for", spec) diff --git a/lib/doctor.js b/lib/doctor.js index 81860004e344e..63619d0cf5377 100644 --- a/lib/doctor.js +++ b/lib/doctor.js @@ -10,7 +10,6 @@ const semver = require('semver') const { promisify } = require('util') const ansiTrim = require('./utils/ansi-trim.js') const isWindows = require('./utils/is-windows.js') -const output = require('./utils/output.js') const ping = require('./utils/ping.js') const usageUtil = require('./utils/usage.js') const { defaults: { registry: defaultRegistry } } = require('./utils/config.js') @@ -111,7 +110,7 @@ class Doctor { const silent = this.npm.log.levels[this.npm.log.level] > this.npm.log.levels.error if (!silent) { - output(table(outTable, tableOpts)) + this.npm.output(table(outTable, tableOpts)) if (!allOk) console.error('') } diff --git a/lib/exec.js b/lib/exec.js index d1db49128587e..69c3cfe75c2cc 100644 --- a/lib/exec.js +++ b/lib/exec.js @@ -1,4 +1,3 @@ -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') const { promisify } = require('util') const read = promisify(require('read')) @@ -224,7 +223,7 @@ class Exec { if (process.stdin.isTTY) { if (ciDetect()) return this.npm.log.warn('exec', 'Interactive mode disabled in CI environment') - output(`\nEntering npm script environment\nType 'exit' or ^D when finished\n`) + this.npm.output(`\nEntering npm script environment\nType 'exit' or ^D when finished\n`) } } return await runScript({ diff --git a/lib/explain.js b/lib/explain.js index 01541040ef649..f46d3b5072637 100644 --- a/lib/explain.js +++ b/lib/explain.js @@ -1,7 +1,6 @@ const usageUtil = require('./utils/usage.js') const { explainNode } = require('./utils/explain-dep.js') const completion = require('./utils/completion/installed-deep.js') -const output = require('./utils/output.js') const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') const semver = require('semver') @@ -59,9 +58,9 @@ class Explain { } if (this.npm.flatOptions.json) - output(JSON.stringify(expls, null, 2)) + this.npm.output(JSON.stringify(expls, null, 2)) else { - output(expls.map(expl => { + this.npm.output(expls.map(expl => { return explainNode(expl, Infinity, this.npm.color) }).join('\n\n')) } diff --git a/lib/explore.js b/lib/explore.js index fdfe6e1bcf7c8..e09e867406e1d 100644 --- a/lib/explore.js +++ b/lib/explore.js @@ -5,7 +5,6 @@ const rpj = require('read-package-json-fast') const runScript = require('@npmcli/run-script') const { join, resolve, relative } = require('path') const completion = require('./utils/completion/installed-shallow.js') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') class Explore { @@ -54,7 +53,7 @@ class Explore { } if (!args.length) - output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`) + this.npm.output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`) this.npm.log.disableProgress() try { return await runScript({ diff --git a/lib/fund.js b/lib/fund.js index 1e9724266401f..826c3170e7e8a 100644 --- a/lib/fund.js +++ b/lib/fund.js @@ -12,7 +12,6 @@ const { } = require('libnpmfund') const completion = require('./utils/completion/installed-deep.js') -const output = require('./utils/output.js') const openUrl = require('./utils/open-url.js') const usageUtil = require('./utils/usage.js') @@ -85,7 +84,7 @@ class Fund { ? this.printJSON : this.printHuman - output( + this.npm.output( print( getFundingInfo(tree), opts @@ -206,9 +205,9 @@ class Fund { validSources.forEach(({ type, url }, i) => { const typePrefix = type ? `${type} funding` : 'Funding' const msg = `${typePrefix} available at the following URL` - output(`${i + 1}: ${msg}: ${url}`) + this.npm.output(`${i + 1}: ${msg}: ${url}`) }) - output('Run `npm fund [<@scope>/] --which=1`, for example, to open the first funding URL listed in that package') + this.npm.output('Run `npm fund [<@scope>/] --which=1`, for example, to open the first funding URL listed in that package') } else { const noFundingError = new Error(`No valid funding method available for: ${spec}`) noFundingError.code = 'ENOFUND' diff --git a/lib/help-search.js b/lib/help-search.js index ed2bc23b9109d..9648e3b1478d5 100644 --- a/lib/help-search.js +++ b/lib/help-search.js @@ -1,7 +1,6 @@ const fs = require('fs') const path = require('path') const color = require('ansicolors') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') const npmUsage = require('./utils/npm-usage.js') const { promisify } = require('util') @@ -44,8 +43,8 @@ class HelpSearch { if (!formatted.trim()) npmUsage(this.npm, false) else { - output(formatted) - output(didYouMean(args[0], cmdList)) + this.npm.output(formatted) + this.npm.output(didYouMean(args[0], cmdList)) } } diff --git a/lib/help.js b/lib/help.js index d7897326f3118..ef7e3bfd03214 100644 --- a/lib/help.js +++ b/lib/help.js @@ -4,7 +4,6 @@ const path = require('path') const log = require('npmlog') const openUrl = require('./utils/open-url.js') const glob = require('glob') -const output = require('./utils/output.js') const usage = require('./utils/usage.js') @@ -70,7 +69,7 @@ class Help { this.npm.commands[section].usage) { this.npm.config.set('loglevel', 'silent') log.level = 'silent' - output(this.npm.commands[section].usage) + this.npm.output(this.npm.commands[section].usage) return } diff --git a/lib/hook.js b/lib/hook.js index 312f542d7cff6..a6f04d6532e50 100644 --- a/lib/hook.js +++ b/lib/hook.js @@ -1,5 +1,4 @@ const hookApi = require('libnpmhook') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const relativeDate = require('tiny-relative-date') const Table = require('cli-table3') @@ -44,12 +43,12 @@ class Hook { async add (pkg, uri, secret, opts) { const hook = await hookApi.add(pkg, uri, secret, opts) if (opts.json) - output(JSON.stringify(hook, null, 2)) + this.npm.output(JSON.stringify(hook, null, 2)) else if (opts.parseable) { - output(Object.keys(hook).join('\t')) - output(Object.keys(hook).map(k => hook[k]).join('\t')) + this.npm.output(Object.keys(hook).join('\t')) + this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`+ ${this.hookName(hook)} ${ + this.npm.output(`+ ${this.hookName(hook)} ${ opts.unicode ? ' ➜ ' : ' -> ' } ${hook.endpoint}`) } @@ -58,19 +57,19 @@ class Hook { async ls (pkg, opts) { const hooks = await hookApi.ls({ ...opts, package: pkg }) if (opts.json) - output(JSON.stringify(hooks, null, 2)) + this.npm.output(JSON.stringify(hooks, null, 2)) else if (opts.parseable) { - output(Object.keys(hooks[0]).join('\t')) + this.npm.output(Object.keys(hooks[0]).join('\t')) hooks.forEach(hook => { - output(Object.keys(hook).map(k => hook[k]).join('\t')) + this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) }) } else if (!hooks.length) - output("You don't have any hooks configured yet.") + this.npm.output("You don't have any hooks configured yet.") else if (!opts.silent && opts.loglevel !== 'silent') { if (hooks.length === 1) - output('You have one hook configured.') + this.npm.output('You have one hook configured.') else - output(`You have ${hooks.length} hooks configured.`) + this.npm.output(`You have ${hooks.length} hooks configured.`) const table = new Table({ head: ['id', 'target', 'endpoint'] }) hooks.forEach((hook) => { @@ -90,19 +89,19 @@ class Hook { } else table.push([{ colSpan: 2, content: 'never triggered' }]) }) - output(table.toString()) + this.npm.output(table.toString()) } } async rm (id, opts) { const hook = await hookApi.rm(id, opts) if (opts.json) - output(JSON.stringify(hook, null, 2)) + this.npm.output(JSON.stringify(hook, null, 2)) else if (opts.parseable) { - output(Object.keys(hook).join('\t')) - output(Object.keys(hook).map(k => hook[k]).join('\t')) + this.npm.output(Object.keys(hook).join('\t')) + this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`- ${this.hookName(hook)} ${ + this.npm.output(`- ${this.hookName(hook)} ${ opts.unicode ? ' ✘ ' : ' X ' } ${hook.endpoint}`) } @@ -111,12 +110,12 @@ class Hook { async update (id, uri, secret, opts) { const hook = await hookApi.update(id, uri, secret, opts) if (opts.json) - output(JSON.stringify(hook, null, 2)) + this.npm.output(JSON.stringify(hook, null, 2)) else if (opts.parseable) { - output(Object.keys(hook).join('\t')) - output(Object.keys(hook).map(k => hook[k]).join('\t')) + this.npm.output(Object.keys(hook).join('\t')) + this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') { - output(`+ ${this.hookName(hook)} ${ + this.npm.output(`+ ${this.hookName(hook)} ${ opts.unicode ? ' ➜ ' : ' -> ' } ${hook.endpoint}`) } diff --git a/lib/init.js b/lib/init.js index af97a9614e368..3f9abbcdd354d 100644 --- a/lib/init.js +++ b/lib/init.js @@ -2,7 +2,6 @@ const initJson = require('init-package-json') const npa = require('npm-package-arg') const usageUtil = require('./utils/usage.js') -const output = require('./utils/output.js') class Init { constructor (npm) { @@ -61,7 +60,7 @@ class Init { this.npm.log.disableProgress() const initFile = this.npm.config.get('init-module') if (!this.npm.flatOptions.yes && !this.npm.flatOptions.force) { - output([ + this.npm.output([ 'This utility will walk you through creating a package.json file.', 'It only covers the most common items, and tries to guess sensible defaults.', '', diff --git a/lib/ls.js b/lib/ls.js index 359fe21e6f8cc..b94684401e6f6 100644 --- a/lib/ls.js +++ b/lib/ls.js @@ -9,7 +9,6 @@ const npa = require('npm-package-arg') const usageUtil = require('./utils/usage.js') const completion = require('./utils/completion/installed-deep.js') -const output = require('./utils/output.js') const _depth = Symbol('depth') const _dedupe = Symbol('dedupe') @@ -147,7 +146,7 @@ class LS { const [rootError] = tree.errors.filter(e => e.code === 'EJSONPARSE' && e.path === resolve(path, 'package.json')) - output( + this.npm.output( json ? jsonOutput({ path, problems, result, rootError, seenItems }) : parseable diff --git a/lib/npm.js b/lib/npm.js index 1f8c785e755c4..0534e630606e4 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -282,6 +282,13 @@ const npm = module.exports = new class extends EventEmitter { } return resolve(this.config.get('tmp'), this[_tmpFolder]) } + + // output to stdout in a progress bar compatible way + output (...msg) { + this.log.clearProgress() + console.log(...msg) + this.log.showProgress() + } }() // now load everything required by the class methods diff --git a/lib/org.js b/lib/org.js index 054e1833dba4b..2a08941a83f3a 100644 --- a/lib/org.js +++ b/lib/org.js @@ -1,6 +1,5 @@ const liborg = require('libnpmorg') const usageUtil = require('./utils/usage.js') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const Table = require('cli-table3') @@ -72,17 +71,17 @@ class Org { return liborg.set(org, user, role, opts).then(memDeets => { if (opts.json) - output(JSON.stringify(memDeets, null, 2)) + this.npm.output(JSON.stringify(memDeets, null, 2)) else if (opts.parseable) { - output(['org', 'orgsize', 'user', 'role'].join('\t')) - output([ + this.npm.output(['org', 'orgsize', 'user', 'role'].join('\t')) + this.npm.output([ memDeets.org.name, memDeets.org.size, memDeets.user, memDeets.role, ].join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') - output(`Added ${memDeets.user} as ${memDeets.role} to ${memDeets.org.name}. You now have ${memDeets.org.size} member${memDeets.org.size === 1 ? '' : 's'} in this org.`) + this.npm.output(`Added ${memDeets.user} as ${memDeets.role} to ${memDeets.org.name}. You now have ${memDeets.org.size} member${memDeets.org.size === 1 ? '' : 's'} in this org.`) return memDeets }) @@ -102,17 +101,17 @@ class Org { org = org.replace(/^[~@]?/, '') const userCount = Object.keys(roster).length if (opts.json) { - output(JSON.stringify({ + this.npm.output(JSON.stringify({ user, org, userCount, deleted: true, })) } else if (opts.parseable) { - output(['user', 'org', 'userCount', 'deleted'].join('\t')) - output([user, org, userCount, true].join('\t')) + this.npm.output(['user', 'org', 'userCount', 'deleted'].join('\t')) + this.npm.output([user, org, userCount, true].join('\t')) } else if (!opts.silent && opts.loglevel !== 'silent') - output(`Successfully removed ${user} from ${org}. You now have ${userCount} member${userCount === 1 ? '' : 's'} in this org.`) + this.npm.output(`Successfully removed ${user} from ${org}. You now have ${userCount} member${userCount === 1 ? '' : 's'} in this org.`) }) } @@ -129,18 +128,18 @@ class Org { roster = newRoster } if (opts.json) - output(JSON.stringify(roster, null, 2)) + this.npm.output(JSON.stringify(roster, null, 2)) else if (opts.parseable) { - output(['user', 'role'].join('\t')) + this.npm.output(['user', 'role'].join('\t')) Object.keys(roster).forEach(user => { - output([user, roster[user]].join('\t')) + this.npm.output([user, roster[user]].join('\t')) }) } else if (!opts.silent && opts.loglevel !== 'silent') { const table = new Table({ head: ['user', 'role'] }) Object.keys(roster).sort().forEach(user => { table.push([user, roster[user]]) }) - output(table.toString()) + this.npm.output(table.toString()) } }) } diff --git a/lib/outdated.js b/lib/outdated.js index fc6967faf60fe..be5820870411c 100644 --- a/lib/outdated.js +++ b/lib/outdated.js @@ -9,7 +9,6 @@ const pickManifest = require('npm-pick-manifest') const Arborist = require('@npmcli/arborist') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') const ansiTrim = require('./utils/ansi-trim.js') @@ -75,9 +74,9 @@ class Outdated { // display results if (this.opts.json) - output(this.makeJSON(outdated)) + this.npm.output(this.makeJSON(outdated)) else if (this.opts.parseable) - output(this.makeParseable(outdated)) + this.npm.output(this.makeParseable(outdated)) else { const outList = outdated.map(x => this.makePretty(x)) const outHead = ['Package', @@ -99,7 +98,7 @@ class Outdated { align: ['l', 'r', 'r', 'r', 'l'], stringLength: s => ansiTrim(s).length, } - output(table(outTable, tableOpts)) + this.npm.output(table(outTable, tableOpts)) } } diff --git a/lib/owner.js b/lib/owner.js index 6cb9904880dc2..cd387e94d9eaf 100644 --- a/lib/owner.js +++ b/lib/owner.js @@ -3,7 +3,6 @@ const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') const pacote = require('pacote') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const readLocalPkg = require('./utils/read-local-package.js') const usageUtil = require('./utils/usage.js') @@ -89,9 +88,9 @@ class Owner { const packumentOpts = { ...opts, fullMetadata: true } const { maintainers } = await pacote.packument(spec, packumentOpts) if (!maintainers || !maintainers.length) - output('no admin found') + this.npm.output('no admin found') else - output(maintainers.map(o => `${o.name} <${o.email}>`).join('\n')) + this.npm.output(maintainers.map(o => `${o.name} <${o.email}>`).join('\n')) return maintainers } catch (err) { @@ -114,7 +113,8 @@ class Owner { log.verbose('owner add', '%s to %s', user, pkg) const spec = npa(pkg) - return putOwners(spec, user, opts, validateAddOwner) + return this.putOwners(spec, user, opts, + (newOwner, owners) => this.validateAddOwner(newOwner, owners)) } async rm (user, pkg, opts) { @@ -131,109 +131,111 @@ class Owner { log.verbose('owner rm', '%s from %s', user, pkg) const spec = npa(pkg) - return putOwners(spec, user, opts, validateRmOwner) + return this.putOwners(spec, user, opts, + (rmOwner, owners) => this.validateRmOwner(rmOwner, owners)) } -} -module.exports = Owner -const validateAddOwner = (newOwner, owners) => { - owners = owners || [] - for (const o of owners) { - if (o.name === newOwner.name) { - log.info( - 'owner add', - 'Already a package owner: ' + o.name + ' <' + o.email + '>' - ) - return false - } - } - return [ - ...owners, - newOwner, - ] -} - -const validateRmOwner = (rmOwner, owners) => { - let found = false - const m = owners.filter(function (o) { - var match = (o.name === rmOwner.name) - found = found || match - return !match - }) - - if (!found) { - log.info('owner rm', 'Not a package owner: ' + rmOwner.name) - return false - } + async putOwners (spec, user, opts, validation) { + const uri = `/-/user/org.couchdb.user:${encodeURIComponent(user)}` + let u = '' - if (!m.length) { - throw Object.assign( - new Error( - 'Cannot remove all owners of a package. Add someone else first.' - ), - { code: 'EOWNERRM' } - ) - } + try { + u = await npmFetch.json(uri, opts) + } catch (err) { + log.error('owner mutate', `Error getting user data for ${user}`) + throw err + } - return m -} + if (user && (!u || !u.name || u.error)) { + throw Object.assign( + new Error( + "Couldn't get user data for " + user + ': ' + JSON.stringify(u) + ), + { code: 'EOWNERUSER' } + ) + } -const putOwners = async (spec, user, opts, validation) => { - const uri = `/-/user/org.couchdb.user:${encodeURIComponent(user)}` - let u = '' + // normalize user data + u = { name: u.name, email: u.email } - try { - u = await npmFetch.json(uri, opts) - } catch (err) { - log.error('owner mutate', `Error getting user data for ${user}`) - throw err - } + const data = await pacote.packument(spec, { ...opts, fullMetadata: true }) - if (user && (!u || !u.name || u.error)) { - throw Object.assign( - new Error( - "Couldn't get user data for " + user + ': ' + JSON.stringify(u) - ), - { code: 'EOWNERUSER' } - ) - } + // save the number of maintainers before validation for comparison + const before = data.maintainers ? data.maintainers.length : 0 - // normalize user data - u = { name: u.name, email: u.email } + const m = validation(u, data.maintainers) + if (!m) + return // invalid owners - const data = await pacote.packument(spec, { ...opts, fullMetadata: true }) + const body = { + _id: data._id, + _rev: data._rev, + maintainers: m, + } + const dataPath = `/${spec.escapedName}/-rev/${encodeURIComponent(data._rev)}` + const res = await otplease(opts, opts => { + return npmFetch.json(dataPath, { + ...opts, + method: 'PUT', + body, + spec, + }) + }) - // save the number of maintainers before validation for comparison - const before = data.maintainers ? data.maintainers.length : 0 + if (!res.error) { + if (m.length < before) + this.npm.output(`- ${user} (${spec.name})`) + else + this.npm.output(`+ ${user} (${spec.name})`) + } else { + throw Object.assign( + new Error('Failed to update package: ' + JSON.stringify(res)), + { code: 'EOWNERMUTATE' } + ) + } + return res + } + + validateAddOwner (newOwner, owners) { + owners = owners || [] + for (const o of owners) { + if (o.name === newOwner.name) { + log.info( + 'owner add', + 'Already a package owner: ' + o.name + ' <' + o.email + '>' + ) + return false + } + } + return [ + ...owners, + newOwner, + ] + } + + validateRmOwner (rmOwner, owners) { + let found = false + const m = owners.filter(function (o) { + var match = (o.name === rmOwner.name) + found = found || match + return !match + }) + + if (!found) { + log.info('owner rm', 'Not a package owner: ' + rmOwner.name) + return false + } - const m = validation(u, data.maintainers) - if (!m) - return // invalid owners + if (!m.length) { + throw Object.assign( + new Error( + 'Cannot remove all owners of a package. Add someone else first.' + ), + { code: 'EOWNERRM' } + ) + } - const body = { - _id: data._id, - _rev: data._rev, - maintainers: m, - } - const dataPath = `/${spec.escapedName}/-rev/${encodeURIComponent(data._rev)}` - const res = await otplease(opts, opts => - npmFetch.json(dataPath, { - ...opts, - method: 'PUT', - body, - spec, - })) - - if (!res.error) { - if (m.length < before) - output(`- ${user} (${spec.name})`) - else - output(`+ ${user} (${spec.name})`) - } else { - throw Object.assign( - new Error('Failed to update package: ' + JSON.stringify(res)), - { code: 'EOWNERMUTATE' } - ) + return m } - return res } +module.exports = Owner diff --git a/lib/pack.js b/lib/pack.js index cf1e77f48ee69..7ffe3138ed55f 100644 --- a/lib/pack.js +++ b/lib/pack.js @@ -7,7 +7,6 @@ const npa = require('npm-package-arg') const { getContents, logTar } = require('./utils/tar.js') const writeFile = util.promisify(require('fs').writeFile) -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') @@ -49,7 +48,7 @@ class Pack { for (const tar of tarballs) { logTar(tar, { log, unicode }) - output(tar.filename.replace(/^@/, '').replace(/\//, '-')) + this.npm.output(tar.filename.replace(/^@/, '').replace(/\//, '-')) } } } diff --git a/lib/ping.js b/lib/ping.js index e43f0640f212b..3643fe3b621aa 100644 --- a/lib/ping.js +++ b/lib/ping.js @@ -1,5 +1,4 @@ const log = require('npmlog') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') const pingUtil = require('./utils/ping.js') @@ -24,7 +23,7 @@ class Ping { const time = Date.now() - start log.notice('PONG', `${time / 1000}ms`) if (this.npm.flatOptions.json) { - output(JSON.stringify({ + this.npm.output(JSON.stringify({ registry: this.npm.flatOptions.registry, time, details, diff --git a/lib/prefix.js b/lib/prefix.js index e46f9c4cdd94a..8ec5ab9efcf78 100644 --- a/lib/prefix.js +++ b/lib/prefix.js @@ -1,4 +1,3 @@ -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') class Prefix { @@ -16,7 +15,7 @@ class Prefix { } async prefix (args) { - return output(this.npm.prefix) + return this.npm.output(this.npm.prefix) } } module.exports = Prefix diff --git a/lib/profile.js b/lib/profile.js index dab99092b0a0f..a0a8606014da4 100644 --- a/lib/profile.js +++ b/lib/profile.js @@ -7,7 +7,6 @@ const qrcodeTerminal = require('qrcode-terminal') const Table = require('cli-table3') const otplease = require('./utils/otplease.js') -const output = require('./utils/output.js') const pulseTillDone = require('./utils/pulse-till-done.js') const readUserInfo = require('./utils/read-user-info.js') const usageUtil = require('./utils/usage.js') @@ -116,7 +115,7 @@ class Profile { delete info.cidr_whitelist if (conf.json) { - output(JSON.stringify(info, null, 2)) + this.npm.output(JSON.stringify(info, null, 2)) return } @@ -145,21 +144,21 @@ class Profile { .filter((arg) => arg.trim() !== '') .map((arg) => cleaned[arg]) .join('\t') - output(values) + this.npm.output(values) } else { if (conf.parseable) { for (const key of Object.keys(info)) { if (key === 'tfa') - output(`${key}\t${cleaned[tfa]}`) + this.npm.output(`${key}\t${cleaned[tfa]}`) else - output(`${key}\t${info[key]}`) + this.npm.output(`${key}\t${info[key]}`) } } else { const table = new Table() for (const key of Object.keys(cleaned)) table.push({ [ansistyles.bright(key)]: cleaned[key] }) - output(table.toString()) + this.npm.output(table.toString()) } } } @@ -215,13 +214,13 @@ class Profile { const result = await otplease(conf, conf => npmProfile.set(newUser, conf)) if (conf.json) - output(JSON.stringify({ [prop]: result[prop] }, null, 2)) + this.npm.output(JSON.stringify({ [prop]: result[prop] }, null, 2)) else if (conf.parseable) - output(prop + '\t' + result[prop]) + this.npm.output(prop + '\t' + result[prop]) else if (result[prop] != null) - output('Set', prop, 'to', result[prop]) + this.npm.output('Set', prop, 'to', result[prop]) else - output('Set', prop) + this.npm.output('Set', prop) } async enable2fa (args) { @@ -327,7 +326,7 @@ class Profile { ) if (challenge.tfa === null) { - output('Two factor authentication mode changed to: ' + mode) + this.npm.output('Two factor authentication mode changed to: ' + mode) return } @@ -344,7 +343,7 @@ class Profile { const secret = otpauth.searchParams.get('secret') const code = await qrcode(challenge.tfa) - output( + this.npm.output( 'Scan into your authenticator app:\n' + code + '\n Or enter code:', secret ) @@ -355,17 +354,17 @@ class Profile { const result = await npmProfile.set({ tfa: [interactiveOTP] }, conf) - output( + this.npm.output( '2FA successfully enabled. Below are your recovery codes, ' + 'please print these out.' ) - output( + this.npm.output( 'You will need these to recover access to your account ' + 'if you lose your authentication device.' ) for (const tfaCode of result.tfa) - output('\t' + tfaCode) + this.npm.output('\t' + tfaCode) } async disable2fa (args) { @@ -373,7 +372,7 @@ class Profile { const info = await pulseTillDone.withPromise(npmProfile.get(conf)) if (!info.tfa || info.tfa.pending) { - output('Two factor authentication not enabled.') + this.npm.output('Two factor authentication not enabled.') return } @@ -391,11 +390,11 @@ class Profile { }, conf)) if (conf.json) - output(JSON.stringify({ tfa: false }, null, 2)) + this.npm.output(JSON.stringify({ tfa: false }, null, 2)) else if (conf.parseable) - output('tfa\tfalse') + this.npm.output('tfa\tfalse') else - output('Two factor authentication disabled.') + this.npm.output('Two factor authentication disabled.') } } module.exports = Profile diff --git a/lib/publish.js b/lib/publish.js index c8e82c44c5a3c..b0bf922138ce3 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -9,7 +9,6 @@ const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') const { flatten } = require('./utils/flat-options.js') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const usageUtil = require('./utils/usage.js') const { getContents, logTar } = require('./utils/tar.js') @@ -115,9 +114,9 @@ class Publish { const silent = log.level === 'silent' if (!silent && json) - output(JSON.stringify(pkgContents, null, 2)) + this.npm.output(JSON.stringify(pkgContents, null, 2)) else if (!silent) - output(`+ ${pkgContents.id}`) + this.npm.output(`+ ${pkgContents.id}`) return pkgContents } diff --git a/lib/rebuild.js b/lib/rebuild.js index 1091b01589389..ffbdebc21fa27 100644 --- a/lib/rebuild.js +++ b/lib/rebuild.js @@ -3,7 +3,6 @@ const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') const semver = require('semver') const usageUtil = require('./utils/usage.js') -const output = require('./utils/output.js') const completion = require('./utils/completion/installed-deep.js') class Rebuild { @@ -52,7 +51,7 @@ class Rebuild { } else await arb.rebuild() - output('rebuilt dependencies successfully') + this.npm.output('rebuilt dependencies successfully') } isNode (specs, node) { diff --git a/lib/root.js b/lib/root.js index 8e5ac63d7b9b8..7c3fa2bbb3544 100644 --- a/lib/root.js +++ b/lib/root.js @@ -1,4 +1,3 @@ -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') class Root { @@ -16,7 +15,7 @@ class Root { } async root () { - output(this.npm.dir) + this.npm.output(this.npm.dir) } } module.exports = Root diff --git a/lib/run-script.js b/lib/run-script.js index cdfd88f10f7b8..dc822668d0318 100644 --- a/lib/run-script.js +++ b/lib/run-script.js @@ -2,7 +2,6 @@ const runScript = require('@npmcli/run-script') const { isServerPackage } = runScript const readJson = require('read-package-json-fast') const { resolve } = require('path') -const output = require('./utils/output.js') const log = require('npmlog') const usageUtil = require('./utils/usage.js') const didYouMean = require('./utils/did-you-mean.js') @@ -117,13 +116,13 @@ class RunScript { return allScripts if (this.npm.flatOptions.json) { - output(JSON.stringify(scripts, null, 2)) + this.npm.output(JSON.stringify(scripts, null, 2)) return allScripts } if (this.npm.flatOptions.parseable) { for (const [script, cmd] of Object.entries(scripts)) - output(`${script}:${cmd}`) + this.npm.output(`${script}:${cmd}`) return allScripts } @@ -138,18 +137,18 @@ class RunScript { } if (cmds.length) - output(`Lifecycle scripts included in ${name}:`) + this.npm.output(`Lifecycle scripts included in ${name}:`) for (const script of cmds) - output(prefix + script + indent + scripts[script]) + this.npm.output(prefix + script + indent + scripts[script]) if (!cmds.length && runScripts.length) - output(`Scripts available in ${name} via \`npm run-script\`:`) + this.npm.output(`Scripts available in ${name} via \`npm run-script\`:`) else if (runScripts.length) - output('\navailable via `npm run-script`:') + this.npm.output('\navailable via `npm run-script`:') for (const script of runScripts) - output(prefix + script + indent + scripts[script]) + this.npm.output(prefix + script + indent + scripts[script]) return allScripts } diff --git a/lib/search.js b/lib/search.js index e0922b9846cdb..35e3eeb0e552c 100644 --- a/lib/search.js +++ b/lib/search.js @@ -5,7 +5,6 @@ const log = require('npmlog') const formatPackageStream = require('./search/format-package-stream.js') const packageFilter = require('./search/package-filter.js') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') function prepareIncludes (args) { @@ -83,12 +82,12 @@ class Search { p.on('data', chunk => { if (!anyOutput) anyOutput = true - output(chunk.toString('utf8')) + this.npm.output(chunk.toString('utf8')) }) await p.promise() if (!anyOutput && !opts.json && !opts.parseable) - output('No matches found for ' + (args.map(JSON.stringify).join(' '))) + this.npm.output('No matches found for ' + (args.map(JSON.stringify).join(' '))) log.silly('search', 'search completed') log.clearProgress() diff --git a/lib/star.js b/lib/star.js index b39d23b2c1170..073c93a898eaf 100644 --- a/lib/star.js +++ b/lib/star.js @@ -2,7 +2,6 @@ const fetch = require('npm-registry-fetch') const log = require('npmlog') const npa = require('npm-package-arg') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') const getIdentity = require('./utils/get-identity') @@ -73,7 +72,7 @@ class Star { body, }) - output(show + ' ' + pkg.name) + this.npm.output(show + ' ' + pkg.name) log.verbose('star', data) return data } diff --git a/lib/stars.js b/lib/stars.js index fe280705b4b5c..e0a6a0003ecc3 100644 --- a/lib/stars.js +++ b/lib/stars.js @@ -1,7 +1,6 @@ const log = require('npmlog') const fetch = require('npm-registry-fetch') -const output = require('./utils/output.js') const getIdentity = require('./utils/get-identity.js') const usageUtil = require('./utils/usage.js') @@ -36,7 +35,7 @@ class Stars { log.warn('stars', 'user has not starred any packages') for (const row of rows) - output(row.value) + this.npm.output(row.value) } } module.exports = Stars diff --git a/lib/team.js b/lib/team.js index 4947739a045c4..3ba2c023dbaef 100644 --- a/lib/team.js +++ b/lib/team.js @@ -1,7 +1,6 @@ const columns = require('cli-columns') const libteam = require('libnpmteam') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const usageUtil = require('./utils/usage.js') @@ -66,82 +65,82 @@ class Team { async create (entity, opts) { await libteam.create(entity, opts) if (opts.json) { - output(JSON.stringify({ + this.npm.output(JSON.stringify({ created: true, team: entity, })) } else if (opts.parseable) - output(`${entity}\tcreated`) + this.npm.output(`${entity}\tcreated`) else if (!opts.silent && opts.loglevel !== 'silent') - output(`+@${entity}`) + this.npm.output(`+@${entity}`) } async destroy (entity, opts) { await libteam.destroy(entity, opts) if (opts.json) { - output(JSON.stringify({ + this.npm.output(JSON.stringify({ deleted: true, team: entity, })) } else if (opts.parseable) - output(`${entity}\tdeleted`) + this.npm.output(`${entity}\tdeleted`) else if (!opts.silent && opts.loglevel !== 'silent') - output(`-@${entity}`) + this.npm.output(`-@${entity}`) } async add (entity, user, opts) { await libteam.add(user, entity, opts) if (opts.json) { - output(JSON.stringify({ + this.npm.output(JSON.stringify({ added: true, team: entity, user, })) } else if (opts.parseable) - output(`${user}\t${entity}\tadded`) + this.npm.output(`${user}\t${entity}\tadded`) else if (!opts.silent && opts.loglevel !== 'silent') - output(`${user} added to @${entity}`) + this.npm.output(`${user} added to @${entity}`) } async rm (entity, user, opts) { await libteam.rm(user, entity, opts) if (opts.json) { - output(JSON.stringify({ + this.npm.output(JSON.stringify({ removed: true, team: entity, user, })) } else if (opts.parseable) - output(`${user}\t${entity}\tremoved`) + this.npm.output(`${user}\t${entity}\tremoved`) else if (!opts.silent && opts.loglevel !== 'silent') - output(`${user} removed from @${entity}`) + this.npm.output(`${user} removed from @${entity}`) } async listUsers (entity, opts) { const users = (await libteam.lsUsers(entity, opts)).sort() if (opts.json) - output(JSON.stringify(users, null, 2)) + this.npm.output(JSON.stringify(users, null, 2)) else if (opts.parseable) - output(users.join('\n')) + this.npm.output(users.join('\n')) else if (!opts.silent && opts.loglevel !== 'silent') { const plural = users.length === 1 ? '' : 's' const more = users.length === 0 ? '' : ':\n' - output(`\n@${entity} has ${users.length} user${plural}${more}`) - output(columns(users, { padding: 1 })) + this.npm.output(`\n@${entity} has ${users.length} user${plural}${more}`) + this.npm.output(columns(users, { padding: 1 })) } } async listTeams (entity, opts) { const teams = (await libteam.lsTeams(entity, opts)).sort() if (opts.json) - output(JSON.stringify(teams, null, 2)) + this.npm.output(JSON.stringify(teams, null, 2)) else if (opts.parseable) - output(teams.join('\n')) + this.npm.output(teams.join('\n')) else if (!opts.silent && opts.loglevel !== 'silent') { const plural = teams.length === 1 ? '' : 's' const more = teams.length === 0 ? '' : ':\n' - output(`\n@${entity} has ${teams.length} team${plural}${more}`) - output(columns(teams.map(t => `@${t}`), { padding: 1 })) + this.npm.output(`\n@${entity} has ${teams.length} team${plural}${more}`) + this.npm.output(columns(teams.map(t => `@${t}`), { padding: 1 })) } } } diff --git a/lib/token.js b/lib/token.js index ad6d5c6fcb82c..ad634c0b00772 100644 --- a/lib/token.js +++ b/lib/token.js @@ -5,7 +5,6 @@ const log = require('npmlog') const profile = require('npm-profile') const otplease = require('./utils/otplease.js') -const output = require('./utils/output.js') const pulseTillDone = require('./utils/pulse-till-done.js') const readUserInfo = require('./utils/read-user-info.js') const usageUtil = require('./utils/usage.js') @@ -64,12 +63,12 @@ class Token { log.info('token', 'getting list') const tokens = await pulseTillDone.withPromise(profile.listTokens(conf)) if (conf.json) { - output(JSON.stringify(tokens, null, 2)) + this.npm.output(JSON.stringify(tokens, null, 2)) return } else if (conf.parseable) { - output(['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t')) + this.npm.output(['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t')) tokens.forEach((token) => { - output([ + this.npm.output([ token.key, token.token, token.created, @@ -95,7 +94,7 @@ class Token { token.cidr_whitelist ? token.cidr_whitelist.join(', ') : '', ]) }) - output(table.toString()) + this.npm.output(table.toString()) } async rm (args) { @@ -127,11 +126,11 @@ class Token { }) })) if (conf.json) - output(JSON.stringify(toRemove)) + this.npm.output(JSON.stringify(toRemove)) else if (conf.parseable) - output(toRemove.join('\t')) + this.npm.output(toRemove.join('\t')) else - output('Removed ' + toRemove.length + ' token' + (toRemove.length !== 1 ? 's' : '')) + this.npm.output('Removed ' + toRemove.length + ' token' + (toRemove.length !== 1 ? 's' : '')) } async create (args) { @@ -149,14 +148,14 @@ class Token { delete result.key delete result.updated if (conf.json) - output(JSON.stringify(result)) + this.npm.output(JSON.stringify(result)) else if (conf.parseable) - Object.keys(result).forEach((k) => output(k + '\t' + result[k])) + Object.keys(result).forEach((k) => this.npm.output(k + '\t' + result[k])) else { const table = new Table() for (const k of Object.keys(result)) table.push({ [ansistyles.bright(k)]: String(result[k]) }) - output(table.toString()) + this.npm.output(table.toString()) } }) } diff --git a/lib/unpublish.js b/lib/unpublish.js index 34751da4a5909..acba6ea521191 100644 --- a/lib/unpublish.js +++ b/lib/unpublish.js @@ -8,7 +8,6 @@ const libunpub = require('libnpmpublish').unpublish const readJson = util.promisify(require('read-package-json')) const usageUtil = require('./utils/usage.js') -const output = require('./utils/output.js') const otplease = require('./utils/otplease.js') const getIdentity = require('./utils/get-identity.js') @@ -107,7 +106,7 @@ class Unpublish { } if (!silent && loglevel !== 'silent') - output(`- ${pkgName}${pkgVersion}`) + this.npm.output(`- ${pkgName}${pkgVersion}`) } } module.exports = Unpublish diff --git a/lib/utils/audit-error.js b/lib/utils/audit-error.js index ae0749ff6f0be..c58c1d16e6885 100644 --- a/lib/utils/audit-error.js +++ b/lib/utils/audit-error.js @@ -3,7 +3,6 @@ // prints a JSON version of the error if it's --json // returns 'true' if there was an error, false otherwise -const output = require('./output.js') const auditError = (npm, report) => { if (!report || !report.error) return false @@ -18,7 +17,7 @@ const auditError = (npm, report) => { const { body: errBody } = error const body = Buffer.isBuffer(errBody) ? errBody.toString() : errBody if (npm.flatOptions.json) { - output(JSON.stringify({ + npm.output(JSON.stringify({ message: error.message, method: error.method, uri: error.uri, @@ -27,7 +26,7 @@ const auditError = (npm, report) => { body, }, null, 2)) } else - output(body) + npm.output(body) throw 'audit endpoint returned an error' } diff --git a/lib/utils/npm-usage.js b/lib/utils/npm-usage.js index 220f8037f164d..b77bca7bec1a8 100644 --- a/lib/utils/npm-usage.js +++ b/lib/utils/npm-usage.js @@ -1,6 +1,5 @@ const didYouMean = require('./did-you-mean.js') const { dirname } = require('path') -const output = require('./output.js') const { cmdList } = require('./cmd-list') module.exports = (npm, valid = true) => { @@ -8,7 +7,7 @@ module.exports = (npm, valid = true) => { const usesBrowser = npm.config.get('viewer') === 'browser' ? ' (in a browser)' : '' npm.log.level = 'silent' - output(` + npm.output(` Usage: npm npm install install all the dependencies in your project @@ -34,7 +33,7 @@ npm@${npm.version} ${dirname(dirname(__dirname))} `) if (npm.argv.length >= 1) - output(didYouMean(npm.argv[0], cmdList)) + npm.output(didYouMean(npm.argv[0], cmdList)) if (!valid) process.exitCode = 1 diff --git a/lib/utils/open-url.js b/lib/utils/open-url.js index 1fe456bd050be..41fac33ec66e9 100644 --- a/lib/utils/open-url.js +++ b/lib/utils/open-url.js @@ -1,4 +1,3 @@ -const output = require('./output.js') const opener = require('opener') const { URL } = require('url') @@ -16,7 +15,7 @@ const open = async (npm, url, errMsg) => { }, null, 2) : `${errMsg}:\n ${url}\n` - output(alternateMsg) + npm.output(alternateMsg) } if (browser === false) { diff --git a/lib/utils/output.js b/lib/utils/output.js deleted file mode 100644 index 2d1549859ac0d..0000000000000 --- a/lib/utils/output.js +++ /dev/null @@ -1,7 +0,0 @@ -const log = require('npmlog') -// output to stdout in a progress bar compatible way -module.exports = (...msg) => { - log.clearProgress() - console.log(...msg) - log.showProgress() -} diff --git a/lib/utils/reify-output.js b/lib/utils/reify-output.js index 216f0e902e90a..ddad32121e8b4 100644 --- a/lib/utils/reify-output.js +++ b/lib/utils/reify-output.js @@ -10,7 +10,6 @@ // run `npm audit fix` to fix them, or `npm audit` for details const log = require('npmlog') -const output = require('./output.js') const { depth } = require('treeverse') const ms = require('ms') const auditReport = require('npm-audit-report') @@ -72,10 +71,10 @@ const reifyOutput = (npm, arb) => { summary.audit = npm.command === 'audit' ? auditReport : auditReport.toJSON().metadata } - output(JSON.stringify(summary, 0, 2)) + npm.output(JSON.stringify(summary, 0, 2)) } else { packagesChangedMessage(npm, summary) - packagesFundingMessage(summary) + packagesFundingMessage(npm, summary) printAuditReport(npm, auditReport) } } @@ -98,7 +97,7 @@ const printAuditReport = (npm, report) => { auditLevel, }) process.exitCode = process.exitCode || res.exitCode - output('\n' + res.report) + npm.output('\n' + res.report) } const packagesChangedMessage = (npm, { added, removed, changed, audited }) => { @@ -136,18 +135,18 @@ const packagesChangedMessage = (npm, { added, removed, changed, audited }) => { msg.push(`audited ${audited} package${audited === 1 ? '' : 's'}`) msg.push(` in ${ms(Date.now() - npm.started)}`) - output(msg.join('')) + npm.output(msg.join('')) } -const packagesFundingMessage = ({ funding }) => { +const packagesFundingMessage = (npm, { funding }) => { if (!funding) return - output('') + npm.output('') const pkg = funding === 1 ? 'package' : 'packages' const is = funding === 1 ? 'is' : 'are' - output(`${funding} ${pkg} ${is} looking for funding`) - output(' run `npm fund` for details') + npm.output(`${funding} ${pkg} ${is} looking for funding`) + npm.output(' run `npm fund` for details') } module.exports = reifyOutput diff --git a/lib/version.js b/lib/version.js index 1ba834f5d711b..a7c0c1955d536 100644 --- a/lib/version.js +++ b/lib/version.js @@ -1,5 +1,4 @@ const libversion = require('libnpmversion') -const output = require('./utils/output.js') const usageUtil = require('./utils/usage.js') class Version { @@ -56,7 +55,7 @@ class Version { ...this.npm.flatOptions, path: this.npm.prefix, }) - return output(`${prefix}${version}`) + return this.npm.output(`${prefix}${version}`) } async list () { @@ -78,9 +77,9 @@ class Version { results[key] = version if (this.npm.flatOptions.json) - output(JSON.stringify(results, null, 2)) + this.npm.output(JSON.stringify(results, null, 2)) else - output(results) + this.npm.output(results) } } module.exports = Version diff --git a/lib/whoami.js b/lib/whoami.js index 39184ed9c581c..7ce877104c185 100644 --- a/lib/whoami.js +++ b/lib/whoami.js @@ -1,4 +1,3 @@ -const output = require('./utils/output.js') const getIdentity = require('./utils/get-identity.js') const usageUtil = require('./utils/usage.js') @@ -23,7 +22,7 @@ class Whoami { async whoami (args) { const opts = this.npm.flatOptions const username = await getIdentity(this.npm, opts) - output(opts.json ? JSON.stringify(username) : username) + this.npm.output(opts.json ? JSON.stringify(username) : username) } } module.exports = Whoami diff --git a/node_modules/.gitignore b/node_modules/.gitignore index df322e6a05cb4..6ffd61bf29c27 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -353,6 +353,7 @@ package-lock.json /unist-util-stringify-position /unist-util-visit /unist-util-visit-parents +/universalify /util-promisify /v8-compile-cache /vfile diff --git a/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js b/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js index 17b42f81bb39a..412d6ce8b7119 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js +++ b/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js @@ -431,11 +431,13 @@ module.exports = cls => class IdealTreeBuilder extends cls { // ie, doing `foo@bar` we just return foo // but if it's a url or git, we don't know the name until we // fetch it and look in its manifest. - return Promise.all(add.map(rawSpec => - this[_retrieveSpecName](npa(rawSpec)) + return Promise.all(add.map(rawSpec => { + // We do NOT provide the path here, because user-additions need + // to be resolved relative to the CWD the user is in. + return this[_retrieveSpecName](npa(rawSpec)) .then(add => this[_updateFilePath](add)) .then(add => this[_followSymlinkPath](add)) - )).then(add => { + })).then(add => { this[_resolvedAdd] = add // now add is a list of spec objects with names. // find a home for each of them! diff --git a/node_modules/@npmcli/arborist/lib/arborist/reify.js b/node_modules/@npmcli/arborist/lib/arborist/reify.js index c3ea1b43bbc76..803fb9782f07c 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/reify.js +++ b/node_modules/@npmcli/arborist/lib/arborist/reify.js @@ -6,6 +6,7 @@ const rpj = require('read-package-json-fast') const { updateDepSpec } = require('../dep-spec.js') const AuditReport = require('../audit-report.js') const {subset} = require('semver') +const npa = require('npm-package-arg') const {dirname, resolve, relative} = require('path') const {depth: dfwalk} = require('treeverse') @@ -881,11 +882,17 @@ module.exports = cls => class Reifier extends cls { process.emit('time', 'reify:save') + // resolvedAdd is the list of user add requests, but with names added + // to things like git repos and tarball file/urls. However, if the + // user requested 'foo@', and we have a foo@file:../foo, then we should + // end up saving the spec we actually used, not whatever they gave us. if (this[_resolvedAdd]) { const root = this.idealTree const pkg = root.package - for (const req of this[_resolvedAdd]) { - const {name, rawSpec, subSpec} = req + for (const { name } of this[_resolvedAdd]) { + const req = npa(root.edgesOut.get(name).spec, root.realpath) + const {rawSpec, subSpec} = req + const spec = subSpec ? subSpec.rawSpec : rawSpec const child = root.children.get(name) @@ -910,6 +917,15 @@ module.exports = cls => class Reifier extends cls { const save = h.https && h.auth ? `git+${h.https(opt)}` : h.shortcut(opt) updateDepSpec(pkg, name, save) + } else if (req.type === 'directory' || req.type === 'file') { + // save the relative path in package.json + // Normally saveSpec is updated with the proper relative + // path already, but it's possible to specify a full absolute + // path initially, in which case we can end up with the wrong + // thing, so just get the ultimate fetchSpec and relativize it. + const p = req.fetchSpec.replace(/^file:/, '') + const rel = relpath(root.realpath, p) + updateDepSpec(pkg, name, `file:${rel}`) } else updateDepSpec(pkg, name, req.saveSpec) } diff --git a/node_modules/@npmcli/arborist/package.json b/node_modules/@npmcli/arborist/package.json index 268f0e72a92d5..35623f90c44ed 100644 --- a/node_modules/@npmcli/arborist/package.json +++ b/node_modules/@npmcli/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "2.2.6", + "version": "2.2.7", "description": "Manage node_modules trees", "dependencies": { "@npmcli/installed-package-contents": "^1.0.7", diff --git a/node_modules/@npmcli/run-script/lib/make-spawn-args.js b/node_modules/@npmcli/run-script/lib/make-spawn-args.js index 4c38b9401ddf0..8ee24c06daf7b 100644 --- a/node_modules/@npmcli/run-script/lib/make-spawn-args.js +++ b/node_modules/@npmcli/run-script/lib/make-spawn-args.js @@ -3,24 +3,6 @@ const isWindows = require('./is-windows.js') const setPATH = require('./set-path.js') const {resolve} = require('path') const npm_config_node_gyp = require.resolve('node-gyp/bin/node-gyp.js') -const { quoteForShell, ShellString, ShellStringText, ShellStringUnquoted } = require('puka') - -const escapeCmd = cmd => { - const result = [] - const parsed = ShellString.sh([cmd]) - for (const child of parsed.children) { - if (child instanceof ShellStringText) { - const children = child.contents.filter(segment => segment !== null).map(segment => quoteForShell(segment, false, isWindows && 'win32')) - result.push(...children) - } else if (child instanceof ShellStringUnquoted) { - result.push(child.value) - } else { - result.push(isWindows ? '&' : ';') - } - } - - return result.join('') -} const makeSpawnArgs = options => { const { @@ -34,7 +16,7 @@ const makeSpawnArgs = options => { } = options const isCmd = /(?:^|\\)cmd(?:\.exe)?$/i.test(scriptShell) - const args = isCmd ? ['/d', '/s', '/c', escapeCmd(cmd)] : ['-c', cmd] + const args = isCmd ? ['/d', '/s', '/c', cmd] : ['-c', cmd] const spawnOpts = { env: setPATH(path, { diff --git a/node_modules/@npmcli/run-script/package.json b/node_modules/@npmcli/run-script/package.json index 9df5b31178747..7e0e5255de410 100644 --- a/node_modules/@npmcli/run-script/package.json +++ b/node_modules/@npmcli/run-script/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/run-script", - "version": "1.8.3", + "version": "1.8.4", "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)", "author": "Isaac Z. Schlueter (https://izs.me)", "license": "ISC", @@ -32,7 +32,6 @@ "@npmcli/promise-spawn": "^1.3.2", "infer-owner": "^1.0.4", "node-gyp": "^7.1.0", - "puka": "^1.0.1", "read-package-json-fast": "^2.0.1" }, "files": [ diff --git a/node_modules/byte-size/LICENSE b/node_modules/byte-size/LICENSE index d9e1e9d6918a4..5699dfbe51830 100644 --- a/node_modules/byte-size/LICENSE +++ b/node_modules/byte-size/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-20 Lloyd Brookes <75pound@gmail.com> +Copyright (c) 2014-21 Lloyd Brookes <75pound@gmail.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/node_modules/byte-size/README.hbs b/node_modules/byte-size/README.hbs index 5b677f2a98870..8d0b32f3e5fdc 100644 --- a/node_modules/byte-size/README.hbs +++ b/node_modules/byte-size/README.hbs @@ -159,6 +159,6 @@ Old browser (adds `window.byteSize`): * * * -© 2014-20 Lloyd Brookes \<75pound@gmail.com\>. +© 2014-21 Lloyd Brookes \<75pound@gmail.com\>. Isomorphic test suite by [test-runner](https://github.com/test-runner-js/test-runner) and [web-runner](https://github.com/test-runner-js/web-runner). Documented by [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown). diff --git a/node_modules/byte-size/README.md b/node_modules/byte-size/README.md index 71f47b1e49b3c..955f707b77007 100644 --- a/node_modules/byte-size/README.md +++ b/node_modules/byte-size/README.md @@ -193,6 +193,6 @@ Old browser (adds `window.byteSize`): * * * -© 2014-20 Lloyd Brookes \<75pound@gmail.com\>. +© 2014-21 Lloyd Brookes \<75pound@gmail.com\>. Isomorphic test suite by [test-runner](https://github.com/test-runner-js/test-runner) and [web-runner](https://github.com/test-runner-js/web-runner). Documented by [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown). diff --git a/node_modules/byte-size/dist/index.js b/node_modules/byte-size/dist/index.js index 78129d8b02d21..dd1debda59abd 100644 --- a/node_modules/byte-size/dist/index.js +++ b/node_modules/byte-size/dist/index.js @@ -1,7 +1,7 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global = global || self, global.byteSize = factory()); + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.byteSize = factory()); }(this, (function () { 'use strict'; /** diff --git a/node_modules/byte-size/package.json b/node_modules/byte-size/package.json index e69b7e5f53ae2..b5f454592da10 100644 --- a/node_modules/byte-size/package.json +++ b/node_modules/byte-size/package.json @@ -8,7 +8,7 @@ "url": "http://repejota.com" } ], - "version": "7.0.0", + "version": "7.0.1", "main": "dist/index.js", "license": "MIT", "engines": { @@ -39,12 +39,12 @@ "dist": "rollup -f umd -n byteSize -o dist/index.js index.mjs" }, "devDependencies": { - "@test-runner/web": "^0.3.4", + "@test-runner/web": "^0.3.5", "coveralls": "^3.1.0", "esm-runner": "^0.3.4", "isomorphic-assert": "^0.1.1", - "jsdoc-to-markdown": "^5.0.3", - "rollup": "^2.10.9", + "jsdoc-to-markdown": "^7.0.0", + "rollup": "^2.40.0", "test-object-model": "^0.6.1" }, "standard": { diff --git a/node_modules/libnpmdiff/README.md b/node_modules/libnpmdiff/README.md index d1cf53fc6c5c7..bc260ad15ce12 100644 --- a/node_modules/libnpmdiff/README.md +++ b/node_modules/libnpmdiff/README.md @@ -86,7 +86,7 @@ Fetches the registry tarballs and compare files between a spec `a` and spec `b`. - `diffSrcPrefix `: Prefix to be used in the filenames from `a`. Defaults to `a/`. - `diffDstPrefix `: Prefix to be used in the filenames from `b`. Defaults to `b/`. - `diffText `: Should treat all files as text and try to print diff for binary files. Defaults to `false`. -- ...`cache`, `registry` and other common options accepted by [pacote](https://github.com/npm/pacote#options) +- ...`cache`, `registry`, `where` and other common options accepted by [pacote](https://github.com/npm/pacote#options) Returns a `Promise` that fullfils with a `String` containing the resulting patch diffs. diff --git a/node_modules/libnpmdiff/index.js b/node_modules/libnpmdiff/index.js index 0bfc8734ef639..73dc3ee64e3ce 100644 --- a/node_modules/libnpmdiff/index.js +++ b/node_modules/libnpmdiff/index.js @@ -1,6 +1,7 @@ const pacote = require('pacote') const formatDiff = require('./lib/format-diff.js') +const getTarball = require('./lib/tarball.js') const untar = require('./lib/untar.js') const argsError = () => @@ -25,8 +26,8 @@ const diff = async (specs, opts = {}) => { // fetches tarball using pacote const [a, b] = await Promise.all([ - pacote.tarball(aManifest._resolved, opts), - pacote.tarball(bManifest._resolved, opts), + getTarball(aManifest, opts), + getTarball(bManifest, opts), ]) // read all files diff --git a/node_modules/libnpmdiff/lib/tarball.js b/node_modules/libnpmdiff/lib/tarball.js new file mode 100644 index 0000000000000..0c8fb177a3885 --- /dev/null +++ b/node_modules/libnpmdiff/lib/tarball.js @@ -0,0 +1,33 @@ +const { relative } = require('path') + +const npa = require('npm-package-arg') +const pkgContents = require('@npmcli/installed-package-contents') +const pacote = require('pacote') +const { tarCreateOptions } = pacote.DirFetcher +const tar = require('tar') + +// returns a simplified tarball when reading files from node_modules folder, +// thus avoiding running the prepare scripts and the extra logic from packlist +const nodeModulesTarball = (manifest, opts) => + pkgContents({ path: manifest._resolved, depth: 1 }) + .then(files => + files.map(file => relative(manifest._resolved, file)) + ) + .then(files => + tar.c(tarCreateOptions(manifest), files).concat() + ) + +const tarball = (manifest, opts) => { + const resolved = manifest._resolved + const where = opts.where || process.cwd() + + const fromNodeModules = npa(resolved).type === 'directory' + && /node_modules[\\/](@[^\\/]+\/)?[^\\/]+[\\/]?$/.test(relative(where, resolved)) + + if (fromNodeModules) + return nodeModulesTarball(manifest, opts) + + return pacote.tarball(manifest._resolved, opts) +} + +module.exports = tarball diff --git a/node_modules/libnpmdiff/package.json b/node_modules/libnpmdiff/package.json index fab4293e9374e..aa13954c63010 100644 --- a/node_modules/libnpmdiff/package.json +++ b/node_modules/libnpmdiff/package.json @@ -1,6 +1,6 @@ { "name": "libnpmdiff", - "version": "2.0.3", + "version": "2.0.4", "description": "The registry diff", "repository": "https://github.com/npm/libnpmdiff", "files": [ @@ -55,10 +55,12 @@ }, "dependencies": { "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", "binary-extensions": "^2.2.0", "diff": "^5.0.0", "minimatch": "^3.0.4", - "pacote": "^11.2.3", + "npm-package-arg": "^8.1.1", + "pacote": "^11.3.0", "tar": "^6.1.0" } } diff --git a/node_modules/pacote/README.md b/node_modules/pacote/README.md index 619e0ec44e8f6..2328c0a4a55dc 100644 --- a/node_modules/pacote/README.md +++ b/node_modules/pacote/README.md @@ -168,6 +168,18 @@ resolved, and other properties, as they are determined. times (even just to validate the cache) for a given packument, since it is unlikely to change in the span of a single command. + +### Advanced API + +Each different type of fetcher is exposed for more advanced usage such as +using helper methods from this classes: + +* `DirFetcher` +* `FileFetcher` +* `GitFetcher` +* `RegistryFetcher` +* `RemoteFetcher` + ## Extracted File Modes Files are extracted with a mode matching the following formula: diff --git a/node_modules/pacote/lib/dir.js b/node_modules/pacote/lib/dir.js index 4a89348b9290c..0d3a00d95ae7c 100644 --- a/node_modules/pacote/lib/dir.js +++ b/node_modules/pacote/lib/dir.js @@ -4,11 +4,10 @@ const cacache = require('cacache') const Minipass = require('minipass') const { promisify } = require('util') const readPackageJson = require('read-package-json-fast') -const isPackageBin = require('./util/is-package-bin.js') +const tarCreateOptions = require('./util/tar-create-options.js') const packlist = require('npm-packlist') const tar = require('tar') const _prepareDir = Symbol('_prepareDir') -const _tarcOpts = Symbol('_tarcOpts') const { resolve } = require('path') const runScript = require('@npmcli/run-script') @@ -21,6 +20,11 @@ class DirFetcher extends Fetcher { this.resolved = this.spec.fetchSpec } + // exposes tarCreateOptions as public API + static tarCreateOptions (manifest) { + return tarCreateOptions(manifest) + } + get types () { return ['directory'] } @@ -65,35 +69,12 @@ class DirFetcher extends Fetcher { // pipe to the stream, and proxy errors the chain. this[_prepareDir]() .then(() => packlist({ path: this.resolved })) - .then(files => tar.c(this[_tarcOpts](), files) + .then(files => tar.c(tarCreateOptions(this.package), files) .on('error', er => stream.emit('error', er)).pipe(stream)) .catch(er => stream.emit('error', er)) return stream } - [_tarcOpts] () { - return { - cwd: this.resolved, - prefix: 'package/', - portable: true, - gzip: true, - - // ensure that package bins are always executable - // Note that npm-packlist is already filtering out - // anything that is not a regular file, ignored by - // .npmignore or package.json "files", etc. - filter: (path, stat) => { - if (isPackageBin(this.package, path)) - stat.mode |= 0o111 - return true - }, - - // Provide a specific date in the 1980s for the benefit of zip, - // which is confounded by files dated at the Unix epoch 0. - mtime: new Date('1985-10-26T08:15:00.000Z'), - } - } - manifest () { if (this.package) return Promise.resolve(this.package) diff --git a/node_modules/pacote/lib/index.js b/node_modules/pacote/lib/index.js index 546ba960baa2e..cbcbd7c92d15f 100644 --- a/node_modules/pacote/lib/index.js +++ b/node_modules/pacote/lib/index.js @@ -1,5 +1,16 @@ const { get } = require('./fetcher.js') +const GitFetcher = require('./git.js') +const RegistryFetcher = require('./registry.js') +const FileFetcher = require('./file.js') +const DirFetcher = require('./dir.js') +const RemoteFetcher = require('./remote.js') + module.exports = { + GitFetcher, + RegistryFetcher, + FileFetcher, + DirFetcher, + RemoteFetcher, resolve: (spec, opts) => get(spec, opts).resolve(), extract: (spec, dest, opts) => get(spec, opts).extract(dest), manifest: (spec, opts) => get(spec, opts).manifest(), diff --git a/node_modules/pacote/lib/util/tar-create-options.js b/node_modules/pacote/lib/util/tar-create-options.js new file mode 100644 index 0000000000000..e8abbe175b262 --- /dev/null +++ b/node_modules/pacote/lib/util/tar-create-options.js @@ -0,0 +1,24 @@ +const isPackageBin = require('./is-package-bin.js') + +const tarCreateOptions = manifest => ({ + cwd: manifest._resolved, + prefix: 'package/', + portable: true, + gzip: true, + + // ensure that package bins are always executable + // Note that npm-packlist is already filtering out + // anything that is not a regular file, ignored by + // .npmignore or package.json "files", etc. + filter: (path, stat) => { + if (isPackageBin(manifest, path)) + stat.mode |= 0o111 + return true + }, + + // Provide a specific date in the 1980s for the benefit of zip, + // which is confounded by files dated at the Unix epoch 0. + mtime: new Date('1985-10-26T08:15:00.000Z'), +}) + +module.exports = tarCreateOptions diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index a1668056f9794..dca67f3e8876a 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "11.2.7", + "version": "11.3.0", "description": "JavaScript package downloader", "author": "Isaac Z. Schlueter (https://izs.me)", "bin": { diff --git a/node_modules/puka/CHANGELOG.md b/node_modules/puka/CHANGELOG.md deleted file mode 100644 index 781b81295a4a7..0000000000000 --- a/node_modules/puka/CHANGELOG.md +++ /dev/null @@ -1,31 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [1.0.1](https://gitlab.com/rhendric/puka/-/compare/v1.0.0...v1.0.1) - 2020-05-16 - -### Fixed - -- Add more carets to win32 command arguments ([45965ca](https://gitlab.com/rhendric/puka/-/commit/45965ca60fcc518082e0b085d8e81f3f3279ffb4)) - - As previously documented and implemented, Puka assumed that all programs - are batch files for the purpose of multi-escaping commands that appear - in pipelines. However, regardless of whether a command is in a pipeline, - one extra layer of escaping is needed if the command invokes a batch - file, which Puka was not producing. This only applies to the arguments - to the command, not to the batch file path, nor to paths used in - redirects. (The property-based spawn test which was supposed to catch - such oversights missed this one because it was invoking the Node.js - executable directly, not, as recommended in the documentation, a batch - file.) - - Going forward, the caveats described in the documentation continue to - apply: if you are running programs on Windows with Puka, make sure they - are batch files, or you may find arguments are being escaped with too - many carets. As the documentation says, if this causes problems for you, - please open an issue so we can work out the details of what a good - workaround looks like. - -## [1.0.0](https://gitlab.com/rhendric/puka/-/tags/v1.0.0) - 2017-09-29 diff --git a/node_modules/puka/LICENSE.txt b/node_modules/puka/LICENSE.txt deleted file mode 100644 index 0141196a59337..0000000000000 --- a/node_modules/puka/LICENSE.txt +++ /dev/null @@ -1,18 +0,0 @@ -Copyright 2017 Ryan Hendrickson - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/puka/README.md b/node_modules/puka/README.md deleted file mode 100644 index 2670f742b3677..0000000000000 --- a/node_modules/puka/README.md +++ /dev/null @@ -1,411 +0,0 @@ -# Puka - -[![GitLab CI pipeline status](https://gitlab.com/rhendric/puka/badges/master/pipeline.svg)](https://gitlab.com/rhendric/puka/commits/master) [![AppVeyor build status](https://img.shields.io/appveyor/ci/rhendric/puka.svg?label=windows%20tests)](https://ci.appveyor.com/project/rhendric/puka) [![Codecov status](https://img.shields.io/codecov/c/gl/rhendric/puka.svg)](https://codecov.io/gl/rhendric/puka) - -Puka is a cross-platform library for safely passing strings through shells. - -#### Contents - -- [Introduction](#introduction) - - [Why would I use Puka?](#why-would-i-use-puka) - - [How do I use Puka?](#how-do-i-use-puka) - - [What's the catch?](#whats-the-catch) -- [API Documentation](#api-documentation) - - [Basic API](#basic-api) - - [sh](#sh) - - [unquoted](#unquoted) - - [Advanced API](#advanced-api) - - [quoteForShell](#quoteforshell) - - [quoteForCmd](#quoteforcmd) - - [quoteForSh](#quoteforsh) - - [ShellString](#shellstring) - - [Secret API](#secret-api) -- [The sh DSL](#the-sh-dsl) - - [Syntax](#syntax) - - [Semantics](#semantics) - - [Types of placeholders](#types-of-placeholders) - -## Introduction - -### Why would I use Puka? - -When launching a child process from Node, you have a choice between launching -directly from the operating system (as with [child_process.spawn](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options), -if you don't use the `{ shell: true }` option), and running the command through -a shell (as with [child_process.exec](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)). -Using a shell gives you more power, such as the ability to chain multiple -commands together or use redirection, but you have to construct your command as -a single string instead of using an array of arguments. And doing that can be -buggy (if not dangerous) if you don't take care to quote any arguments -correctly for the shell you're targeting, _and_ the quoting has to be done -differently on Windows and non-Windows shells. - -Puka solves that problem by giving you a simple and platform-agnostic way to -build shell commands with arguments that pass through your shell unaltered and -with no unsafe side effects, **whether you are running on Windows or a -Unix-based OS**. - -### How do I use Puka? - -Puka gives you an `sh` function intended for tagging -[template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals), -which quotes (if necessary) any values interpolated into the template. A simple -example: - -```javascript -const { sh } = require('puka'); -const { execSync } = require('child_process'); - -const arg = 'file with spaces.txt'; -execSync(sh`some-command ${arg}`); -``` - -But Puka supports more than this! See [the `sh` DSL documentation](#the-sh-dsl) -for a detailed description of all the features currently supported. - -### What's the catch? - -Here are the ones I know about: - -Puka does _not_ ensure that the actual commands you're running are -cross-platform. If you're running npm programs, you generally won't have a -problem with that, but if you want to run ``sh`cat file` `` on Windows, you'll -need to depend on something like -[cash-cat](https://www.npmjs.com/package/cash-cat). - -I searched for days for a way to quote or escape line breaks in arguments to -`cmd.exe`, but couldn't find one (regular `^`-prepending and quotation marks -don't seem to cut it). If you know of a way that works, please [open an -issue](https://gitlab.com/rhendric/puka/issues/new) to tell me about it! Until -then, any line break characters (`\r` or `\n`) in values being interpolated by -`sh` will cause an error to be thrown on Windows only. - -Also on Windows, you may notice quoting mistakes if you run commands that -involve invoking a native executable (not a batch file ending in `.cmd` or -`.bat`). Unfortunately, batch files require some extra escaping on Windows, and -Puka assumes all programs are batch files because npm creates batch file shims -for programs it installs (and, if you care about cross-platform, you'll be -using npm programs in your commands). If this causes problems for you, please -[open an issue](https://gitlab.com/rhendric/puka/issues/new); if your situation -is specific enough, there may be workarounds or improvements to Puka to be -found. - -## API Documentation - -### Basic API - - - - -#### sh - -A string template tag for safely constructing cross-platform shell commands. - -An `sh` template is not actually treated as a literal string to be -interpolated; instead, it is a tiny DSL designed to make working with shell -strings safe, simple, and straightforward. To get started quickly, see the -examples below. [More detailed documentation][1] is available -further down. - -##### Examples - -```javascript -const title = '"this" & "that"'; -sh`script --title=${title}`; // => "script '--title=\"this\" & \"that\"'" -// Note: these examples show results for non-Windows platforms. -// On Windows, the above would instead be -// 'script ^^^"--title=\\^^^"this\\^^^" ^^^& \\^^^"that\\^^^"^^^"'. - -const names = ['file1', 'file 2']; -sh`rimraf ${names}.txt`; // => "rimraf file1.txt 'file 2.txt'" - -const cmd1 = ['cat', 'file 1.txt', 'file 2.txt']; -const cmd2 = ['use-input', '-abc']; -sh`${cmd1}|${cmd2}`; // => "cat 'file 1.txt' 'file 2.txt'|use-input -abc" -``` - -Returns **[String][2]** a string formatted for the platform Node is currently -running on. - -#### unquoted - -This function permits raw strings to be interpolated into a `sh` template. - -**IMPORTANT**: If you're using Puka due to security concerns, make sure you -don't pass any untrusted content to `unquoted`. This may be obvious, but -stray punctuation in an `unquoted` section can compromise the safety of the -entire shell command. - -##### Parameters - -- `value` any value (it will be treated as a string) - -##### Examples - -```javascript -const both = true; -sh`foo ${unquoted(both ? '&&' : '||')} bar`; // => 'foo && bar' -``` - -### Advanced API - -If these functions make life easier for you, go ahead and use them; they -are just as well supported as the above. But if you aren't certain you -need them, you probably don't. - - -#### quoteForShell - -Quotes a string for injecting into a shell command. - -This function is exposed for some hypothetical case when the `sh` DSL simply -won't do; `sh` is expected to be the more convenient option almost always. -Compare: - -```javascript -console.log('cmd' + args.map(a => ' ' + quoteForShell(a)).join('')); -console.log(sh`cmd ${args}`); // same as above - -console.log('cmd' + args.map(a => ' ' + quoteForShell(a, true)).join('')); -console.log(sh`cmd "${args}"`); // same as above -``` - -Additionally, on Windows, `sh` checks the entire command string for pipes, -which subtly change how arguments need to be quoted. If your commands may -involve pipes, you are strongly encouraged to use `sh` and not try to roll -your own with `quoteForShell`. - -##### Parameters - -- `text` **[String][2]** to be quoted -- `forceQuote` **[Boolean][3]?** whether to always add quotes even if the string - is already safe. Defaults to `false`. -- `platform` **[String][2]?** a value that `process.platform` might take: - `'win32'`, `'linux'`, etc.; determines how the string is to be formatted. - When omitted, effectively the same as `process.platform`. - -Returns **[String][2]** a string that is safe for the current (or specified) -platform. - -#### quoteForCmd - -A Windows-specific version of [quoteForShell][4]. - -##### Parameters - -- `text` **[String][2]** to be quoted -- `forceQuote` **[Boolean][3]?** whether to always add quotes even if the string - is already safe. Defaults to `false`. - -#### quoteForSh - -A Unix-specific version of [quoteForShell][4]. - -##### Parameters - -- `text` **[String][2]** to be quoted -- `forceQuote` **[Boolean][3]?** whether to always add quotes even if the string - is already safe. Defaults to `false`. - -#### ShellString - -A ShellString represents a shell command after it has been interpolated, but -before it has been formatted for a particular platform. ShellStrings are -useful if you want to prepare a command for a different platform than the -current one, for instance. - -To create a ShellString, use `ShellString.sh` the same way you would use -top-level `sh`. - -##### toString - -A method to format a ShellString into a regular String formatted for a -particular platform. - -###### Parameters - -- `platform` **[String][2]?** a value that `process.platform` might take: - `'win32'`, `'linux'`, etc.; determines how the string is to be formatted. - When omitted, effectively the same as `process.platform`. - -Returns **[String][2]** - -##### sh - -`ShellString.sh` is a template tag just like `sh`; the only difference is -that this function returns a ShellString which has not yet been formatted -into a String. - -Returns **[ShellString][5]** - -### Secret API - -Some internals of string formatting have been exposed for the ambitious and -brave souls who want to try to extend Puka to handle more shells or custom -interpolated values. This ‘secret’ API is partially documented in the code -but not here, and the semantic versioning guarantees on this API are bumped -down by one level: in other words, minor version releases of Puka can change -the secret API in backward-incompatible ways, and patch releases can add or -deprecate functionality. - -If it's not even documented in the code, use at your own risk—no semver -guarantees apply. - - -[1]: #the-sh-dsl - -[2]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String - -[3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean - -[4]: #quoteforshell - -[5]: #shellstring - -## The sh DSL - -### Syntax - -An `sh` template comprises words, separated by whitespace. Words can contain: - -- text, which is composed of any characters that are not whitespace, single or - double quotes, or any of the special characters - ``# $ & ( ) ; < > \ ` |``; -- quotations, which are matching single or double quotes surrounding any - characters other than the delimiting quote; and -- placeholders, using the standard JavaScript template syntax (`${}`). - (Placeholders may also appear inside quotations.) - -The special characters ``# $ & ( ) ; < > \ ` |``, if unquoted, form their own -words. - -Redirect operators (`<`, `>`, `>>`, `2>`, etc.) receive their own special -handling, as do semicolons. Other than these two exceptions, no attempt is made -to understand any more sophisticated features of shell syntax. - -Standard JavaScript escape sequences, such as `\t`, are honored in the template -literal, and are treated equivalently to the characters they represent. There -is no further mechanism for escaping within the `sh` DSL itself; in particular, -if you want to put quotes inside quotes, you have to use interpolation, like -this: - -```javascript -sh`echo "${'single = \', double = "'}"` // => "echo 'single = '\\'', double = \"'" -``` - -### Semantics - -Words that do not contain placeholders are emitted mostly verbatim to the -output string. Quotations are formatted in the expected style for the target -platform (single quotes for Unix, double quotes for Windows) regardless of the -quotes used in the template literal—as with JavaScript, single and double quotes -are interchangeable, except for the requirement to pair like with like. Unquoted -semicolons are translated to ampersands on Windows; all other special characters -(as enumerated above), when unquoted, are passed as-is to the output for the -shell to interpret. - -Puka may still quote words not containing the above special characters, if they -contain characters that need quoting on the target platform. For example, on -Windows, the character `%` is used for variable interpolation in `cmd.exe`, and -Puka quotes it on on that platform even if it appears unquoted in the template -literal. Consequently, there is no need to be paranoid about quoting anything -that doesn't look alphanumeric inside a `sh` template literal, for fear of being -burned on a different operating system; anything that matches the definition of -‘text’ above will never need manual quoting. - -#### Types of placeholders - -##### Strings - -If a word contains a string placeholder, then the value of the placeholder is -interpolated into the word and the entire word, if necessary, is quoted. If -the placeholder occurs within quotes, no further quoting is performed: - -```javascript -sh`script --file="${'herp derp'}.txt"`; // => "script --file='herp derp.txt'" -``` - -This behavior can be exploited to force consistent quoting, if desired; but -both of the examples below are safe on all platforms: - -```javascript -const words = ['oneword', 'two words']; -sh`minimal ${words[0]}`; // => "minimal oneword" -sh`minimal ${words[1]}`; // => "minimal 'two words'" -sh`consistent '${words[0]}'`; // => "consistent 'oneword'" -sh`consistent '${words[1]}'`; // => "consistent 'two words'" -``` - -##### Arrays and iterables - -If a word contains a placeholder for an array (or other iterable object), then -the entire word is repeated once for each value in the array, separated by -spaces. If the array is empty, then the word is not emitted at all, and neither -is any leading whitespace. - -```javascript -const files = ['foo', 'bar']; -sh`script ${files}`; // => "script foo bar" -sh`script --file=${files}`; // => "script --file=foo --file=bar" -sh`script --file=${[]}`; // => "script" -``` - -Note that, since special characters are their own words, the pipe operator here -is not repeated: - -```javascript -const cmd = ['script', 'foo', 'bar']; -sh`${cmd}|another-script`; // => "script foo bar|another-script" -``` - -Multiple arrays in the same word generate a Cartesian product: - -```javascript -const names = ['foo', 'bar'], exts = ['log', 'txt']; -// Same word -sh`... ${names}.${exts}`; // => "... foo.log foo.txt bar.log bar.txt" -sh`... "${names} ${exts}"`; // => "... 'foo log' 'foo txt' 'bar log' 'bar txt'" - -// Not the same word (extra space just for emphasis): -sh`... ${names} ${exts}`; // => "... foo bar log txt" -sh`... ${names};${exts}`; // => "... foo bar;log txt" -``` - -Finally, if a placeholder appears in the object of a redirect operator, the -entire redirect is repeated as necessary: - -```javascript -sh`script > ${['foo', 'bar']}.txt`; // => "script > foo.txt > bar.txt" -sh`script > ${[]}.txt`; // => "script" -``` - -##### unquoted - -The `unquoted` function returns a value that will skip being quoted when used -in a placeholder, alone or in an array. - -```javascript -const cmd = 'script < input.txt'; -const fields = ['foo', 'bar']; -sh`${unquoted(cmd)} | json ${fields}`; // => "script < input.txt | json foo bar" -``` - -##### ShellString - -If `ShellString.sh` is used to construct an unformatted ShellString, that value -can be used in a placeholder to insert the contents of the ShellString into the -outer template literal. This is safer than using `unquoted` as in the previous -example, but `unquoted` can be used when all you have is a string from another -(trusted!) source. - -```javascript -const url = 'http://example.com/data.json?x=1&y=2'; -const curl = ShellString.sh`curl -L ${url}`; -const fields = ['foo', 'bar']; -sh`${curl} | json ${fields}`; // => "curl -L 'http://example.com/data.json?x=1&y=2' | json foo bar" -``` - -##### Anything else - -... is treated like a string—namely, a value `x` is equivalent to `'' + x`, if -not in one of the above categories. diff --git a/node_modules/puka/index.js b/node_modules/puka/index.js deleted file mode 100644 index b69e47d7639db..0000000000000 --- a/node_modules/puka/index.js +++ /dev/null @@ -1,804 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -/** - * Key a method on your object with this symbol and you can get special - * formatting for that value! See ShellStringText, ShellStringUnquoted, or - * shellStringSemicolon for examples. - * @ignore - */ -const formatSymbol = Symbol('format'); -/** - * This symbol is for implementing advanced behaviors like the need for extra - * carets in Windows shell strings that use pipes. If present, it's called in - * an earlier phase than formatSymbol, and is passed a mutable context that can - * be read during the format phase to influence formatting. - * @ignore - */ -const preformatSymbol = Symbol('preformat'); - -// When minimum Node version becomes 6, replace calls to sticky with /.../y and -// inline execFrom. -let stickySupported = true; -try { - new RegExp('', 'y'); -} catch (e) { - stickySupported = false; -} -const sticky = stickySupported ? source => new RegExp(source, 'y') : source => new RegExp(`^(?:${source})`); -const execFrom = stickySupported ? (re, haystack, index) => (re.lastIndex = index, re.exec(haystack)) : (re, haystack, index) => re.exec(haystack.substr(index)); - -function quoteForCmd(text, forceQuote) { - let caretDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; - // See the below blog post for an explanation of this function and - // quoteForWin32: - // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/ - if (!text.length) { - return '""'; - } - if (/[\n\r]/.test(text)) { - throw new Error("Line breaks can't be quoted on Windows"); - } - const caretEscape = /["%]/.test(text); - text = quoteForWin32(text, forceQuote || !caretEscape && /[&()<>^|]/.test(text)); - if (caretEscape) { - // See Win32Context for explanation of what caretDepth is for. - do { - text = text.replace(/[\t "%&()<>^|]/g, '^$&'); - } while (caretDepth--); - } - return text; -} -const quoteForWin32 = (text, forceQuote) => forceQuote || /[\t "]/.test(text) ? `"${text.replace(/\\+(?=$|")/g, '$&$&').replace(/"/g, '\\"')}"` : text; -const cmdMetaChars = /[\t\n\r "%&()<>^|]/; -class Win32Context { - constructor() { - this.currentScope = newScope(null); - this.scopesByObject = new Map(); - this.argDetectState = 0; - this.argSet = new Set(); - } - read(text) { - // When cmd.exe executes a batch file, or pipes to or from one, it spawns a - // second copy of itself to run the inner command. This necessitates - // doubling up on carets so that escaped characters survive both cmd.exe - // invocations. See: - // https://stackoverflow.com/questions/8192318/why-does-delayed-expansion-fail-when-inside-a-piped-block-of-code#8194279 - // https://ss64.com/nt/syntax-redirection.html - // - // Parentheses can create an additional subshell, requiring additional - // escaping... it's a mess. - // - // So here's what we do about it: we read all unquoted text in a shell - // string and put it through this tiny parser that looks for pipes, - // sequence operators (&, &&, ||), redirects, and parentheses. This can't - // be part of the main Puka parsing, because it can be affected by - // `unquoted(...)` values provided at evaluation time. - // - // Then, after associating each thing that needs to be quoted with a scope - // (via `mark()`), and identifying whether or not it's an argument to a - // command, we can determine the depth of caret escaping required in each - // scope and pass it (via `Formatter::quote()`) to `quoteForCmd()`. - // - // See also `ShellStringText`, which holds the logic for the previous - // paragraph. - const length = text.length; - for (let pos = 0, match; pos < length;) { - while (match = execFrom(reUnimportant, text, pos)) { - if (match[2] == null) { - // (not whitespace) - if (match[1] != null) { - // (>&) - this.argDetectState = this.argDetectState === 0 ? ADS_FLAG_INITIAL_REDIRECT : 0; - } else if (this.argDetectState !== ADS_FLAG_ARGS) { - this.argDetectState |= ADS_FLAG_WORD; - } - } else { - // (whitespace) - if ((this.argDetectState & ADS_FLAG_WORD) !== 0) { - this.argDetectState = ADS_FLAG_ARGS & ~this.argDetectState >> 1; - } - } - pos += match[0].length; - } - if (pos >= length) break; - if (match = execFrom(reSeqOp, text, pos)) { - this.seq(); - pos += match[0].length; - } else { - const char = text.charCodeAt(pos); - if (char === CARET) { - pos += 2; - } else if (char === QUOTE) { - // If you were foolish enough to leave a dangling quotation mark in - // an unquoted span... you're likely to have bigger problems than - // incorrect escaping. So we just do the simplest thing of looking for - // the end quote only in this piece of text. - pos += execFrom(reNotQuote, text, pos + 1)[0].length + 2; - } else { - if (char === OPEN_PAREN) { - this.enterScope(); - } else if (char === CLOSE_PAREN) { - this.exitScope(); - } else if (char === PIPE) { - this.pipe(); - } else { - // (char === '<' or '>') - this.argDetectState = this.argDetectState === 0 ? ADS_FLAG_INITIAL_REDIRECT : 0; - } - pos++; - } - } - } - } - enterScope() { - this.currentScope = newScope(this.currentScope); - this.argDetectState = 0; - } - exitScope() { - this.currentScope = this.currentScope.parent || (this.currentScope.parent = newScope(null)); - this.argDetectState = ADS_FLAG_ARGS; - } - seq() { - // | binds tighter than sequence operators, so the latter create new sibling - // scopes for future |s to mutate. - this.currentScope = newScope(this.currentScope.parent); - this.argDetectState = 0; - } - pipe() { - this.currentScope.depthDelta = 1; - this.argDetectState = 0; - } - mark(obj) { - this.scopesByObject.set(obj, this.currentScope); - if (this.argDetectState === ADS_FLAG_ARGS) { - this.argSet.add(obj); - } else { - this.argDetectState |= ADS_FLAG_WORD; - } - } - at(obj) { - const scope = this.scopesByObject.get(obj); - return { - depth: getDepth(scope), - isArgument: this.argSet.has(obj), - isNative: scope.isNative - }; - } -} -// These flags span the Win32Context's argument detection state machine. WORD -// is set when the context is inside a word that is not an argument (meaning it -// is either the first word in the command, or it is the object of a redirect). -// ARGS is set when the context has reached the arguments of a command. -// INITIAL_REDIRECT tracks the edge case when a redirect occurs before the -// first word of the command (if this flag is set, reaching the end of a word -// should take the state machine back to 0 instead of setting ADS_FLAG_ARGS). -const ADS_FLAG_WORD = 0x1; -const ADS_FLAG_ARGS = 0x2; -const ADS_FLAG_INITIAL_REDIRECT = 0x4; -const getDepth = scope => scope === null ? 0 : scope.depth !== -1 ? scope.depth : scope.depth = getDepth(scope.parent) + scope.depthDelta; -const newScope = parent => ({ - parent, - depthDelta: 0, - depth: -1, - isNative: false -}); -const CARET = '^'.charCodeAt(); -const QUOTE = '"'.charCodeAt(); -const OPEN_PAREN = '('.charCodeAt(); -const CLOSE_PAREN = ')'.charCodeAt(); -const PIPE = '|'.charCodeAt(); -const reNotQuote = sticky('[^"]*'); -const reSeqOp = sticky('&&?|\\|\\|'); -const reUnimportant = sticky('(\\d*>&)|[^\\s"$&()<>^|]+|(\\s+)'); - -const quoteForSh = (text, forceQuote) => text.length ? forceQuote || shMetaChars.test(text) ? `'${text.replace(/'/g, "'\\''")}'`.replace(/^(?:'')+(?!$)/, '').replace(/\\'''/g, "\\'") : text : "''"; -const shMetaChars = /[\t\n\r "#$&'()*;<>?\\`|~]/; - -/** - * To get a Formatter, call `Formatter.for`. - * - * To create a new Formatter, pass an object to `Formatter.declare`. - * - * To set the global default Formatter, assign to `Formatter.default`. - * - * @class - * @property {Formatter} default - The Formatter to be used when no platform - * is provided—for example, when creating strings with `sh`. - * @ignore - */ -function Formatter() {} -Object.assign(Formatter, -/** @lends Formatter */ -{ - /** - * Gets a Formatter that has been declared for the provided platform, or - * the base `'sh'` formatter if there is no Formatter specific to this - * platform, or the Formatter for the current platform if no specific platform - * is provided. - */ - for(platform) { - return platform == null ? Formatter.default || (Formatter.default = Formatter.for(process.platform)) : Formatter._registry.get(platform) || Formatter._registry.get('sh'); - }, - /** - * Creates a new Formatter or mutates the properties on an existing - * Formatter. The `platform` key on the provided properties object determines - * when the Formatter is retrieved. - */ - declare(props) { - const platform = props && props.platform || 'sh'; - const existingFormatter = Formatter._registry.get(platform); - const formatter = Object.assign(existingFormatter || new Formatter(), props); - formatter.emptyString === void 0 && (formatter.emptyString = formatter.quote('', true)); - existingFormatter || Formatter._registry.set(formatter.platform, formatter); - }, - _registry: new Map(), - prototype: { - platform: 'sh', - quote: quoteForSh, - metaChars: shMetaChars, - hasExtraMetaChars: false, - statementSeparator: ';', - createContext() { - return defaultContext; - } - } -}); -const defaultContext = { - at() {} -}; -Formatter.declare(); -Formatter.declare({ - platform: 'win32', - quote(text, forceQuote, opts) { - const caretDepth = opts ? (opts.depth || 0) + (opts.isArgument && !opts.isNative ? 1 : 0) : 0; - return quoteForCmd(text, forceQuote, caretDepth); - }, - metaChars: cmdMetaChars, - hasExtraMetaChars: true, - statementSeparator: '&', - createContext(root) { - const context = new this.Context(); - root[preformatSymbol](context); - return context; - }, - Context: Win32Context -}); - -const isObject = any => any === Object(any); -function memoize(f) { - const cache = new WeakMap(); - return arg => { - let result = cache.get(arg); - if (result === void 0) { - result = f(arg); - cache.set(arg, result); - } - return result; - }; -} - -/** - * Represents a contiguous span of text that may or must be quoted. The contents - * may already contain quoted segments, which will always be quoted. If unquoted - * segments also require quoting, the entire span will be quoted together. - * @ignore - */ -class ShellStringText { - constructor(contents, untested) { - this.contents = contents; - this.untested = untested; - } - [formatSymbol](formatter, context) { - const unformattedContents = this.contents; - const length = unformattedContents.length; - const contents = new Array(length); - for (let i = 0; i < length; i++) { - const c = unformattedContents[i]; - contents[i] = isObject(c) && formatSymbol in c ? c[formatSymbol](formatter) : c; - } - for (let unquoted = true, i = 0; i < length; i++) { - const content = contents[i]; - if (content === null) { - unquoted = !unquoted; - } else { - if (unquoted && (formatter.hasExtraMetaChars || this.untested && this.untested.has(i)) && formatter.metaChars.test(content)) { - return formatter.quote(contents.join(''), false, context.at(this)); - } - } - } - const parts = []; - for (let quoted = null, i = 0; i < length; i++) { - const content = contents[i]; - if (content === null) { - quoted = quoted ? (parts.push(formatter.quote(quoted.join(''), true, context.at(this))), null) : []; - } else { - (quoted || parts).push(content); - } - } - const result = parts.join(''); - return result.length ? result : formatter.emptyString; - } - [preformatSymbol](context) { - context.mark(this); - } -} - -/** - * Represents a contiguous span of text that will not be quoted. - * @ignore - */ -class ShellStringUnquoted { - constructor(value) { - this.value = value; - } - [formatSymbol]() { - return this.value; - } - [preformatSymbol](context) { - context.read(this.value); - } -} - -/** - * Represents a semicolon... or an ampersand, on Windows. - * @ignore - */ -const shellStringSemicolon = { - [formatSymbol](formatter) { - return formatter.statementSeparator; - }, - [preformatSymbol](context) { - context.seq(); - } -}; - -const PLACEHOLDER = {}; -const parse = memoize(templateSpans => { - // These are the token types our DSL can recognize. Their values won't escape - // this function. - const TOKEN_TEXT = 0; - const TOKEN_QUOTE = 1; - const TOKEN_SEMI = 2; - const TOKEN_UNQUOTED = 3; - const TOKEN_SPACE = 4; - const TOKEN_REDIRECT = 5; - const result = []; - let placeholderCount = 0; - let prefix = null; - let onlyPrefixOnce = false; - let contents = []; - let quote = 0; - const lastSpan = templateSpans.length - 1; - for (let spanIndex = 0; spanIndex <= lastSpan; spanIndex++) { - const templateSpan = templateSpans[spanIndex]; - const posEnd = templateSpan.length; - let tokenStart = 0; - if (spanIndex) { - placeholderCount++; - contents.push(PLACEHOLDER); - } - // For each span, we first do a recognizing pass in which we use regular - // expressions to identify the positions of tokens in the text, and then - // a second pass that actually splits the text into the minimum number of - // substrings necessary. - const recognized = []; // [type1, index1, type2, index2...] - let firstWordBreak = -1; - let lastWordBreak = -1; - { - let pos = 0, - match; - while (pos < posEnd) { - if (quote) { - if (match = execFrom(quote === CHAR_SQUO ? reQuotation1 : reQuotation2, templateSpan, pos)) { - recognized.push(TOKEN_TEXT, pos); - pos += match[0].length; - } - if (pos < posEnd) { - recognized.push(TOKEN_QUOTE, pos++); - quote = 0; - } - } else { - if (match = execFrom(reRedirectOrSpace, templateSpan, pos)) { - firstWordBreak < 0 && (firstWordBreak = pos); - lastWordBreak = pos; - recognized.push(match[1] ? TOKEN_REDIRECT : TOKEN_SPACE, pos); - pos += match[0].length; - } - if (match = execFrom(reText, templateSpan, pos)) { - const setBreaks = match[1] != null; - setBreaks && firstWordBreak < 0 && (firstWordBreak = pos); - recognized.push(setBreaks ? TOKEN_UNQUOTED : TOKEN_TEXT, pos); - pos += match[0].length; - setBreaks && (lastWordBreak = pos); - } - const char = templateSpan.charCodeAt(pos); - if (char === CHAR_SEMI) { - firstWordBreak < 0 && (firstWordBreak = pos); - recognized.push(TOKEN_SEMI, pos++); - lastWordBreak = pos; - } else if (char === CHAR_SQUO || char === CHAR_DQUO) { - recognized.push(TOKEN_QUOTE, pos++); - quote = char; - } - } - } - } - // Word breaks are only important if they separate words with placeholders, - // so we can ignore the first/last break if this is the first/last span. - spanIndex === 0 && (firstWordBreak = -1); - spanIndex === lastSpan && (lastWordBreak = posEnd); - // Here begins the second pass mentioned above. This loop runs one more - // iteration than there are tokens in recognized, because it handles tokens - // on a one-iteration delay; hence the i <= iEnd instead of i < iEnd. - const iEnd = recognized.length; - for (let i = 0, type = -1; i <= iEnd; i += 2) { - let typeNext = -1, - pos; - if (i === iEnd) { - pos = posEnd; - } else { - typeNext = recognized[i]; - pos = recognized[i + 1]; - // If the next token is space or redirect, but there's another word - // break in this span, then we can handle that token the same way we - // would handle unquoted text because it isn't being attached to a - // placeholder. - typeNext >= TOKEN_SPACE && pos !== lastWordBreak && (typeNext = TOKEN_UNQUOTED); - } - const breakHere = pos === firstWordBreak || pos === lastWordBreak; - if (pos && (breakHere || typeNext !== type)) { - let value = type === TOKEN_QUOTE ? null : type === TOKEN_SEMI ? shellStringSemicolon : templateSpan.substring(tokenStart, pos); - if (type >= TOKEN_SEMI) { - // This branch handles semicolons, unquoted text, spaces, and - // redirects. shellStringSemicolon is already a formatSymbol object; - // the rest need to be wrapped. - type === TOKEN_SEMI || (value = new ShellStringUnquoted(value)); - // We don't need to check placeholderCount here like we do below; - // that's only relevant during the first word break of the span, and - // because this iteration of the loop is processing the token that - // was checked for breaks in the previous iteration, it will have - // already been handled. For the same reason, prefix is guaranteed to - // be null. - if (contents.length) { - result.push(new ShellStringText(contents, null)); - contents = []; - } - // Only spaces and redirects become prefixes, but not if they've been - // rewritten to unquoted above. - if (type >= TOKEN_SPACE) { - prefix = value; - onlyPrefixOnce = type === TOKEN_SPACE; - } else { - result.push(value); - } - } else { - contents.push(value); - } - tokenStart = pos; - } - if (breakHere) { - if (placeholderCount) { - result.push({ - contents, - placeholderCount, - prefix, - onlyPrefixOnce - }); - } else { - // There's no prefix to handle in this branch; a prefix prior to this - // span would mean placeholderCount > 0, and a prefix in this span - // can't be created because spaces and redirects get rewritten to - // unquoted before the last word break. - contents.length && result.push(new ShellStringText(contents, null)); - } - placeholderCount = 0; - prefix = null; - onlyPrefixOnce = false; - contents = []; - } - type = typeNext; - } - } - if (quote) { - throw new SyntaxError(`String is missing a ${String.fromCharCode(quote)} character`); - } - return result; -}); -const CHAR_SEMI = ';'.charCodeAt(); -const CHAR_SQUO = "'".charCodeAt(); -const CHAR_DQUO = '"'.charCodeAt(); -const reQuotation1 = sticky("[^']+"); -const reQuotation2 = sticky('[^"]+'); -const reText = sticky('[^\\s"#$&\'();<>\\\\`|]+|([#$&()\\\\`|]+)'); -const reRedirectOrSpace = sticky('(\\s*\\d*[<>]+\\s*)|\\s+'); - -class BitSet { - constructor() { - this.vector = new Int32Array(1); - } - has(n) { - return (this.vector[n >>> 5] & 1 << n) !== 0; - } - add(n) { - const i = n >>> 5, - requiredLength = i + 1; - let vector = this.vector, - _vector = vector, - length = _vector.length; - if (requiredLength > length) { - while (requiredLength > (length *= 2)); - const oldValues = vector; - vector = new Int32Array(length); - vector.set(oldValues); - this.vector = vector; - } - vector[i] |= 1 << n; - } -} - -function evaluate(template, values) { - values = values.map(toStringishArray); - const children = []; - let valuesStart = 0; - for (let i = 0, iMax = template.length; i < iMax; i++) { - const word = template[i]; - if (formatSymbol in word) { - children.push(word); - continue; - } - const contents = word.contents, - placeholderCount = word.placeholderCount, - prefix = word.prefix, - onlyPrefixOnce = word.onlyPrefixOnce; - const kMax = contents.length; - const valuesEnd = valuesStart + placeholderCount; - const tuples = cartesianProduct(values, valuesStart, valuesEnd); - valuesStart = valuesEnd; - for (let j = 0, jMax = tuples.length; j < jMax; j++) { - const needSpace = j > 0; - const tuple = tuples[j]; - (needSpace || prefix) && children.push(needSpace && (onlyPrefixOnce || !prefix) ? unquotedSpace : prefix); - let interpolatedContents = []; - let untested = null; - let quoting = false; - let tupleIndex = 0; - for (let k = 0; k < kMax; k++) { - const content = contents[k]; - if (content === PLACEHOLDER) { - const value = tuple[tupleIndex++]; - if (quoting) { - interpolatedContents.push(value); - } else { - if (isObject(value) && formatSymbol in value) { - if (interpolatedContents.length) { - children.push(new ShellStringText(interpolatedContents, untested)); - interpolatedContents = []; - untested = null; - } - children.push(value); - } else { - (untested || (untested = new BitSet())).add(interpolatedContents.length); - interpolatedContents.push(value); - } - } - } else { - interpolatedContents.push(content); - content === null && (quoting = !quoting); - } - } - if (interpolatedContents.length) { - children.push(new ShellStringText(interpolatedContents, untested)); - } - } - } - return children; -} -const primToStringish = value => value == null ? '' + value : value; -function toStringishArray(value) { - let array; - switch (true) { - default: - if (isObject(value)) { - if (Array.isArray(value)) { - array = value; - break; - } - if (Symbol.iterator in value) { - array = Array.from(value); - break; - } - } - array = [value]; - } - return array.map(primToStringish); -} -function cartesianProduct(arrs, start, end) { - const size = end - start; - let resultLength = 1; - for (let i = start; i < end; i++) { - resultLength *= arrs[i].length; - } - if (resultLength > 1e6) { - throw new RangeError("Far too many elements to interpolate"); - } - const result = new Array(resultLength); - const indices = new Array(size).fill(0); - for (let i = 0; i < resultLength; i++) { - const value = result[i] = new Array(size); - for (let j = 0; j < size; j++) { - value[j] = arrs[j + start][indices[j]]; - } - for (let j = size - 1; j >= 0; j--) { - if (++indices[j] < arrs[j + start].length) break; - indices[j] = 0; - } - } - return result; -} -const unquotedSpace = new ShellStringUnquoted(' '); - -/** - * A ShellString represents a shell command after it has been interpolated, but - * before it has been formatted for a particular platform. ShellStrings are - * useful if you want to prepare a command for a different platform than the - * current one, for instance. - * - * To create a ShellString, use `ShellString.sh` the same way you would use - * top-level `sh`. - */ -class ShellString { - /** @hideconstructor */ - constructor(children) { - this.children = children; - } - /** - * `ShellString.sh` is a template tag just like `sh`; the only difference is - * that this function returns a ShellString which has not yet been formatted - * into a String. - * @returns {ShellString} - * @function sh - * @static - * @memberof ShellString - */ - static sh(templateSpans) { - for (var _len = arguments.length, values = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - values[_key - 1] = arguments[_key]; - } - return new ShellString(evaluate(parse(templateSpans), values)); - } - /** - * A method to format a ShellString into a regular String formatted for a - * particular platform. - * - * @param {String} [platform] a value that `process.platform` might take: - * `'win32'`, `'linux'`, etc.; determines how the string is to be formatted. - * When omitted, effectively the same as `process.platform`. - * @returns {String} - */ - toString(platform) { - return this[formatSymbol](Formatter.for(platform)); - } - [formatSymbol](formatter) { - let context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : formatter.createContext(this); - return this.children.map(child => child[formatSymbol](formatter, context)).join(''); - } - [preformatSymbol](context) { - const children = this.children; - for (let i = 0, iMax = children.length; i < iMax; i++) { - const child = children[i]; - if (preformatSymbol in child) { - child[preformatSymbol](context); - } - } - } -} - -/** - * A Windows-specific version of {@link quoteForShell}. - * @param {String} text to be quoted - * @param {Boolean} [forceQuote] whether to always add quotes even if the string - * is already safe. Defaults to `false`. - */ - -/** - * A Unix-specific version of {@link quoteForShell}. - * @param {String} text to be quoted - * @param {Boolean} [forceQuote] whether to always add quotes even if the string - * is already safe. Defaults to `false`. - */ - -/** - * Quotes a string for injecting into a shell command. - * - * This function is exposed for some hypothetical case when the `sh` DSL simply - * won't do; `sh` is expected to be the more convenient option almost always. - * Compare: - * - * ```javascript - * console.log('cmd' + args.map(a => ' ' + quoteForShell(a)).join('')); - * console.log(sh`cmd ${args}`); // same as above - * - * console.log('cmd' + args.map(a => ' ' + quoteForShell(a, true)).join('')); - * console.log(sh`cmd "${args}"`); // same as above - * ``` - * - * Additionally, on Windows, `sh` checks the entire command string for pipes, - * which subtly change how arguments need to be quoted. If your commands may - * involve pipes, you are strongly encouraged to use `sh` and not try to roll - * your own with `quoteForShell`. - * - * @param {String} text to be quoted - * @param {Boolean} [forceQuote] whether to always add quotes even if the string - * is already safe. Defaults to `false`. - * @param {String} [platform] a value that `process.platform` might take: - * `'win32'`, `'linux'`, etc.; determines how the string is to be formatted. - * When omitted, effectively the same as `process.platform`. - * - * @returns {String} a string that is safe for the current (or specified) - * platform. - */ -function quoteForShell(text, forceQuote, platform) { - return Formatter.for(platform).quote(text, forceQuote); -} - -/** - * A string template tag for safely constructing cross-platform shell commands. - * - * An `sh` template is not actually treated as a literal string to be - * interpolated; instead, it is a tiny DSL designed to make working with shell - * strings safe, simple, and straightforward. To get started quickly, see the - * examples below. {@link #the-sh-dsl More detailed documentation} is available - * further down. - * - * @name sh - * @example - * const title = '"this" & "that"'; - * sh`script --title=${title}`; // => "script '--title=\"this\" & \"that\"'" - * // Note: these examples show results for non-Windows platforms. - * // On Windows, the above would instead be - * // 'script ^^^"--title=\\^^^"this\\^^^" ^^^& \\^^^"that\\^^^"^^^"'. - * - * const names = ['file1', 'file 2']; - * sh`rimraf ${names}.txt`; // => "rimraf file1.txt 'file 2.txt'" - * - * const cmd1 = ['cat', 'file 1.txt', 'file 2.txt']; - * const cmd2 = ['use-input', '-abc']; - * sh`${cmd1}|${cmd2}`; // => "cat 'file 1.txt' 'file 2.txt'|use-input -abc" - * - * @returns {String} - a string formatted for the platform Node is currently - * running on. - */ -const sh = function () { - return ShellString.sh.apply(ShellString, arguments).toString(); -}; - -/** - * This function permits raw strings to be interpolated into a `sh` template. - * - * **IMPORTANT**: If you're using Puka due to security concerns, make sure you - * don't pass any untrusted content to `unquoted`. This may be obvious, but - * stray punctuation in an `unquoted` section can compromise the safety of the - * entire shell command. - * - * @param value - any value (it will be treated as a string) - * - * @example - * const both = true; - * sh`foo ${unquoted(both ? '&&' : '||')} bar`; // => 'foo && bar' - */ -const unquoted = value => new ShellStringUnquoted(value); - -exports.Formatter = Formatter; -exports.ShellString = ShellString; -exports.ShellStringText = ShellStringText; -exports.ShellStringUnquoted = ShellStringUnquoted; -exports.quoteForCmd = quoteForCmd; -exports.quoteForSh = quoteForSh; -exports.quoteForShell = quoteForShell; -exports.sh = sh; -exports.shellStringSemicolon = shellStringSemicolon; -exports.formatSymbol = formatSymbol; -exports.preformatSymbol = preformatSymbol; -exports.unquoted = unquoted; diff --git a/node_modules/puka/package.json b/node_modules/puka/package.json deleted file mode 100644 index 41798dc2493b8..0000000000000 --- a/node_modules/puka/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "puka", - "version": "1.0.1", - "description": "A cross-platform library for safely passing strings through shells", - "keywords": [ - "args", - "arguments", - "cmd", - "command", - "command-line", - "cross-platform", - "escape", - "escaping", - "exec", - "linux", - "mac", - "macos", - "osx", - "quote", - "quoting", - "sh", - "shell", - "spawn", - "unix", - "win", - "win32", - "windows" - ], - "homepage": "https://gitlab.com/rhendric/puka", - "bugs": "https://gitlab.com/rhendric/puka/issues", - "license": "MIT", - "author": "Ryan Hendrickson ", - "repository": "gitlab:rhendric/puka", - "dependencies": {}, - "engines": { - "node": ">=4" - } -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9ab2710988952..a12e8e5cf1397 100644 --- a/package-lock.json +++ b/package-lock.json @@ -209,7 +209,6 @@ "promise-retry", "promzard", "psl", - "puka", "punycode", "qs", "read-cmd-shim", @@ -252,15 +251,15 @@ ], "license": "Artistic-2.0", "dependencies": { - "@npmcli/arborist": "^2.2.6", + "@npmcli/arborist": "^2.2.7", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^1.2.9", - "@npmcli/run-script": "^1.8.3", + "@npmcli/run-script": "^1.8.4", "abbrev": "~1.1.1", "ansicolors": "~0.3.2", "ansistyles": "~0.1.3", "archy": "~1.0.0", - "byte-size": "^7.0.0", + "byte-size": "^7.0.1", "cacache": "^15.0.5", "chalk": "^4.1.0", "chownr": "^2.0.0", @@ -276,7 +275,7 @@ "json-parse-even-better-errors": "^2.3.1", "leven": "^3.1.0", "libnpmaccess": "^4.0.1", - "libnpmdiff": "^2.0.3", + "libnpmdiff": "^2.0.4", "libnpmfund": "^1.0.2", "libnpmhook": "^6.0.1", "libnpmorg": "^2.0.1", @@ -301,7 +300,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.2.7", + "pacote": "^11.3.0", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", @@ -812,9 +811,9 @@ } }, "node_modules/@npmcli/arborist": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.2.6.tgz", - "integrity": "sha512-dLWPjMeUTrlIJG+f4j3cOMZ24vJ1GQmZm7QixXeOnx3XCo7reWqzjDZfQvPE21FPUuz25EGoRw+MSHzc7OlxAA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.2.7.tgz", + "integrity": "sha512-NulX/tVu45PIXO4DSNpVQkLrN94OjzAUxgLQ7Vsdb1macSmklJwQF0+4jBgC2riMpdWJP+IiFsxg1k9T9RoRRg==", "inBundle": true, "dependencies": { "@npmcli/installed-package-contents": "^1.0.7", @@ -977,16 +976,15 @@ } }, "node_modules/@npmcli/run-script": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.3.tgz", - "integrity": "sha512-ELPGWAVU/xyU+A+H3pEPj0QOvYwLTX71RArXcClFzeiyJ/b/McsZ+d0QxpznvfFtZzxGN/gz/1cvlqICR4/suQ==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.4.tgz", + "integrity": "sha512-Yd9HXTtF1JGDXZw0+SOn+mWLYS0e7bHBHVC/2C8yqs4wUrs/k8rwBSinD7rfk+3WG/MFGRZKxjyoD34Pch2E/A==", "inBundle": true, "dependencies": { "@npmcli/node-gyp": "^1.0.2", "@npmcli/promise-spawn": "^1.3.2", "infer-owner": "^1.0.4", "node-gyp": "^7.1.0", - "puka": "^1.0.1", "read-package-json-fast": "^2.0.1" } }, @@ -1575,9 +1573,9 @@ "inBundle": true }, "node_modules/byte-size": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-7.0.0.tgz", - "integrity": "sha512-NNiBxKgxybMBtWdmvx7ZITJi4ZG+CYUgwOSZTfqB1qogkRHrhbQE/R2r5Fh94X+InN5MCYz6SvB/ejHMj/HbsQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz", + "integrity": "sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==", "inBundle": true, "engines": { "node": ">=10" @@ -2548,13 +2546,13 @@ } }, "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "dependencies": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1" }, @@ -2563,12 +2561,21 @@ "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=4.0" + "node": ">=6.0" }, "optionalDependencies": { "source-map": "~0.6.1" } }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/escodegen/node_modules/levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -3719,12 +3726,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-raw/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/hast-util-to-parse5": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz", @@ -4566,36 +4567,36 @@ "inBundle": true }, "node_modules/jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.0.tgz", + "integrity": "sha512-QxZH0nmDTnTTVI0YDm4RUlaUPl5dcyn62G5TMDNfMmTW+J1u1v9gCR8WR+WZ6UghAa7nKJjDOFaI00eMMWvJFQ==", "dev": true, "dependencies": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.5", + "acorn": "^8.0.5", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", - "cssstyle": "^2.2.0", + "cssstyle": "^2.3.0", "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", + "decimal.js": "^10.2.1", "domexception": "^2.0.1", - "escodegen": "^1.14.1", + "escodegen": "^2.0.0", "html-encoding-sniffer": "^2.0.1", "is-potential-custom-element-name": "^1.0.0", "nwsapi": "^2.2.0", - "parse5": "5.1.1", + "parse5": "6.0.1", "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "request-promise-native": "^1.0.9", + "saxes": "^5.0.1", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^2.0.0", "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.0.0", - "ws": "^7.2.3", + "ws": "^7.4.4", "xml-name-validator": "^3.0.0" }, "engines": { @@ -4610,6 +4611,18 @@ } } }, + "node_modules/jsdom/node_modules/acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -4768,16 +4781,18 @@ } }, "node_modules/libnpmdiff": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/libnpmdiff/-/libnpmdiff-2.0.3.tgz", - "integrity": "sha512-BgVvJCjd+EGY3Ifb3+gWkZwMjn6kYMtruT88XXOrJCWyjnG5aRdFv3lKuJx5JdU5ku08G5LlY8tOZdfRn72m7w==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/libnpmdiff/-/libnpmdiff-2.0.4.tgz", + "integrity": "sha512-q3zWePOJLHwsLEUjZw3Kyu/MJMYfl4tWCg78Vl6QGSfm4aXBUSVzMzjJ6jGiyarsT4d+1NH4B1gxfs62/+y9iQ==", "inBundle": true, "dependencies": { "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", "binary-extensions": "^2.2.0", "diff": "^5.0.0", "minimatch": "^3.0.4", - "pacote": "^11.2.3", + "npm-package-arg": "^8.1.1", + "pacote": "^11.3.0", "tar": "^6.1.0" }, "engines": { @@ -5972,9 +5987,9 @@ } }, "node_modules/pacote": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.7.tgz", - "integrity": "sha512-ogxPor11v/rnU9ukwLlI2dPx22q9iob1+yZyqSwerKsOvBMhU9e+SJHtxY4y2N0MRH4/5jGsGiRLsZeJWyM4dQ==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.0.tgz", + "integrity": "sha512-cygprcGpEVqvDzpuPMkGVXW/ooc2ibpoosuJ4YHcUXozDs9VJP7Vha+41pYppG2MVNis4t1BB8IygIBh7vVr2Q==", "inBundle": true, "dependencies": { "@npmcli/git": "^2.0.1", @@ -6058,9 +6073,9 @@ } }, "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, "node_modules/path-exists": { @@ -6294,15 +6309,6 @@ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "inBundle": true }, - "node_modules/puka": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/puka/-/puka-1.0.1.tgz", - "integrity": "sha512-ssjRZxBd7BT3dte1RR3VoeT2cT/ODH8x+h0rUF1rMqB0srHYf48stSDWfiYakTp5UBZMxroZhB2+ExLDHm7W3g==", - "inBundle": true, - "engines": { - "node": ">=4" - } - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -9600,28 +9606,19 @@ } }, "node_modules/tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", "dev": true, "dependencies": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" }, "engines": { "node": ">=6" } }, - "node_modules/tough-cookie/node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/tr46": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", @@ -9947,6 +9944,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -10264,9 +10270,9 @@ } }, "node_modules/ws": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", - "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", "dev": true, "engines": { "node": ">=8.3.0" @@ -10944,9 +10950,9 @@ "dev": true }, "@npmcli/arborist": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.2.6.tgz", - "integrity": "sha512-dLWPjMeUTrlIJG+f4j3cOMZ24vJ1GQmZm7QixXeOnx3XCo7reWqzjDZfQvPE21FPUuz25EGoRw+MSHzc7OlxAA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.2.7.tgz", + "integrity": "sha512-NulX/tVu45PIXO4DSNpVQkLrN94OjzAUxgLQ7Vsdb1macSmklJwQF0+4jBgC2riMpdWJP+IiFsxg1k9T9RoRRg==", "requires": { "@npmcli/installed-package-contents": "^1.0.7", "@npmcli/map-workspaces": "^1.0.2", @@ -11076,15 +11082,14 @@ } }, "@npmcli/run-script": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.3.tgz", - "integrity": "sha512-ELPGWAVU/xyU+A+H3pEPj0QOvYwLTX71RArXcClFzeiyJ/b/McsZ+d0QxpznvfFtZzxGN/gz/1cvlqICR4/suQ==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.4.tgz", + "integrity": "sha512-Yd9HXTtF1JGDXZw0+SOn+mWLYS0e7bHBHVC/2C8yqs4wUrs/k8rwBSinD7rfk+3WG/MFGRZKxjyoD34Pch2E/A==", "requires": { "@npmcli/node-gyp": "^1.0.2", "@npmcli/promise-spawn": "^1.3.2", "infer-owner": "^1.0.4", "node-gyp": "^7.1.0", - "puka": "^1.0.1", "read-package-json-fast": "^2.0.1" } }, @@ -11530,9 +11535,9 @@ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" }, "byte-size": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-7.0.0.tgz", - "integrity": "sha512-NNiBxKgxybMBtWdmvx7ZITJi4ZG+CYUgwOSZTfqB1qogkRHrhbQE/R2r5Fh94X+InN5MCYz6SvB/ejHMj/HbsQ==" + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-7.0.1.tgz", + "integrity": "sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==" }, "cacache": { "version": "15.0.5", @@ -12253,18 +12258,24 @@ "dev": true }, "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" }, "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -13146,14 +13157,6 @@ "web-namespaces": "^1.0.0", "xtend": "^4.0.0", "zwitch": "^1.0.0" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - } } }, "hast-util-to-parse5": { @@ -13749,37 +13752,45 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.0.tgz", + "integrity": "sha512-QxZH0nmDTnTTVI0YDm4RUlaUPl5dcyn62G5TMDNfMmTW+J1u1v9gCR8WR+WZ6UghAa7nKJjDOFaI00eMMWvJFQ==", "dev": true, "requires": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.5", + "acorn": "^8.0.5", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", - "cssstyle": "^2.2.0", + "cssstyle": "^2.3.0", "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", + "decimal.js": "^10.2.1", "domexception": "^2.0.1", - "escodegen": "^1.14.1", + "escodegen": "^2.0.0", "html-encoding-sniffer": "^2.0.1", "is-potential-custom-element-name": "^1.0.0", "nwsapi": "^2.2.0", - "parse5": "5.1.1", + "parse5": "6.0.1", "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "request-promise-native": "^1.0.9", + "saxes": "^5.0.1", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^2.0.0", "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.0.0", - "ws": "^7.2.3", + "ws": "^7.4.4", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", + "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==", + "dev": true + } } }, "jsesc": { @@ -13899,15 +13910,17 @@ } }, "libnpmdiff": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/libnpmdiff/-/libnpmdiff-2.0.3.tgz", - "integrity": "sha512-BgVvJCjd+EGY3Ifb3+gWkZwMjn6kYMtruT88XXOrJCWyjnG5aRdFv3lKuJx5JdU5ku08G5LlY8tOZdfRn72m7w==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/libnpmdiff/-/libnpmdiff-2.0.4.tgz", + "integrity": "sha512-q3zWePOJLHwsLEUjZw3Kyu/MJMYfl4tWCg78Vl6QGSfm4aXBUSVzMzjJ6jGiyarsT4d+1NH4B1gxfs62/+y9iQ==", "requires": { "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", "binary-extensions": "^2.2.0", "diff": "^5.0.0", "minimatch": "^3.0.4", - "pacote": "^11.2.3", + "npm-package-arg": "^8.1.1", + "pacote": "^11.3.0", "tar": "^6.1.0" } }, @@ -14802,9 +14815,9 @@ } }, "pacote": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.7.tgz", - "integrity": "sha512-ogxPor11v/rnU9ukwLlI2dPx22q9iob1+yZyqSwerKsOvBMhU9e+SJHtxY4y2N0MRH4/5jGsGiRLsZeJWyM4dQ==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.0.tgz", + "integrity": "sha512-cygprcGpEVqvDzpuPMkGVXW/ooc2ibpoosuJ4YHcUXozDs9VJP7Vha+41pYppG2MVNis4t1BB8IygIBh7vVr2Q==", "requires": { "@npmcli/git": "^2.0.1", "@npmcli/installed-package-contents": "^1.0.6", @@ -14870,9 +14883,9 @@ } }, "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, "path-exists": { @@ -15044,11 +15057,6 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" }, - "puka": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/puka/-/puka-1.0.1.tgz", - "integrity": "sha512-ssjRZxBd7BT3dte1RR3VoeT2cT/ODH8x+h0rUF1rMqB0srHYf48stSDWfiYakTp5UBZMxroZhB2+ExLDHm7W3g==" - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -17422,22 +17430,14 @@ } }, "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", "dev": true, "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "dependencies": { - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - } + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" } }, "tr46": { @@ -17675,6 +17675,12 @@ "unist-util-is": "^4.0.0" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -17932,9 +17938,9 @@ } }, "ws": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz", - "integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index f4d34f98abd6c..940cc1922c14a 100644 --- a/package.json +++ b/package.json @@ -42,15 +42,15 @@ "./package.json": "./package.json" }, "dependencies": { - "@npmcli/arborist": "^2.2.6", + "@npmcli/arborist": "^2.2.7", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^1.2.9", - "@npmcli/run-script": "^1.8.3", + "@npmcli/run-script": "^1.8.4", "abbrev": "~1.1.1", "ansicolors": "~0.3.2", "ansistyles": "~0.1.3", "archy": "~1.0.0", - "byte-size": "^7.0.0", + "byte-size": "^7.0.1", "cacache": "^15.0.5", "chalk": "^4.1.0", "chownr": "^2.0.0", @@ -66,7 +66,7 @@ "json-parse-even-better-errors": "^2.3.1", "leven": "^3.1.0", "libnpmaccess": "^4.0.1", - "libnpmdiff": "^2.0.3", + "libnpmdiff": "^2.0.4", "libnpmfund": "^1.0.2", "libnpmhook": "^6.0.1", "libnpmorg": "^2.0.1", @@ -91,7 +91,7 @@ "npm-user-validate": "^1.0.1", "npmlog": "~4.1.2", "opener": "^1.5.2", - "pacote": "^11.2.7", + "pacote": "^11.3.0", "parse-conflict-json": "^1.1.1", "qrcode-terminal": "^0.12.0", "read": "~1.0.7", diff --git a/tap-snapshots/test-lib-profile.js-TAP.test.js b/tap-snapshots/test-lib-profile.js-TAP.test.js index bb838ad92c97d..58975515162f6 100644 --- a/tap-snapshots/test-lib-profile.js-TAP.test.js +++ b/tap-snapshots/test-lib-profile.js-TAP.test.js @@ -9,7 +9,11 @@ exports[`test/lib/profile.js TAP enable-2fa from token and set otp, retries on p Scan into your authenticator app: qrcode Or enter code: -12342FA successfully enabled. Below are your recovery codes, please print these out.You will need these to recover access to your account if you lose your authentication device. 123456 789101 +1234 +2FA successfully enabled. Below are your recovery codes, please print these out. +You will need these to recover access to your account if you lose your authentication device. + 123456 + 789101 ` exports[`test/lib/profile.js TAP profile get --parseable > should output parseable result value 1`] = ` @@ -29,7 +33,17 @@ foo foo@github.com (verified) https://github.com/npm ` exports[`test/lib/profile.js TAP profile get no args --parseable > should output all profile info as parseable result 1`] = ` -tfa auth-and-writesname fooemail foo@github.comemail_verified truecreated 2015-02-26T01:26:37.384Zupdated 2020-08-12T16:19:35.326Zfullname Foo Barhomepage https://github.comfreenode foobartwitter https://twitter.com/npmjsgithub https://github.com/npm +tfa auth-and-writes +name foo +email foo@github.com +email_verified true +created 2015-02-26T01:26:37.384Z +updated 2020-08-12T16:19:35.326Z +fullname Foo Bar +homepage https://github.com +freenode foobar +twitter https://twitter.com/npmjs +github https://github.com/npm ` exports[`test/lib/profile.js TAP profile get no args default output > should output table with contents 1`] = ` diff --git a/test/lib/access.js b/test/lib/access.js index 3a732ad0aac37..8134c1d9116d2 100644 --- a/test/lib/access.js +++ b/test/lib/access.js @@ -3,6 +3,10 @@ const requireInject = require('require-inject') const Access = require('../../lib/access.js') +const npm = { + output: () => null, +} + test('completion', t => { const access = new Access({ flatOptions: {} }) const testComp = (argv, expect) => { @@ -457,9 +461,8 @@ test('npm access ls-packages with no team', (t) => { }, }, '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), - '../../lib/utils/output.js': () => null, }) - const access = new Access({}) + const access = new Access(npm) access.exec([ 'ls-packages', ], (err) => { @@ -477,9 +480,8 @@ test('access ls-packages on team', (t) => { return {} }, }, - '../../lib/utils/output.js': () => null, }) - const access = new Access({}) + const access = new Access(npm) access.exec([ 'ls-packages', 'myorg:myteam', @@ -503,9 +505,8 @@ test('access ls-collaborators on current', (t) => { return {} }, }, - '../../lib/utils/output.js': () => null, }) - const access = new Access({ prefix }) + const access = new Access({ prefix, ...npm }) access.exec([ 'ls-collaborators', ], (err) => { @@ -523,9 +524,8 @@ test('access ls-collaborators on spec', (t) => { return {} }, }, - '../../lib/utils/output.js': () => null, }) - const access = new Access({}) + const access = new Access(npm) access.exec([ 'ls-collaborators', 'yargs', diff --git a/test/lib/adduser.js b/test/lib/adduser.js index 32fd97c1bd46d..106cd429e37a6 100644 --- a/test/lib/adduser.js +++ b/test/lib/adduser.js @@ -61,6 +61,9 @@ const npm = { }, setCredentialsByURI, }, + output: msg => { + result = msg + }, } const AddUser = requireInject('../../lib/adduser.js', { @@ -70,9 +73,6 @@ const AddUser = requireInject('../../lib/adduser.js', { registryOutput = msg }, }, - '../../lib/utils/output.js': msg => { - result = msg - }, '../../lib/auth/legacy.js': authDummy, }) diff --git a/test/lib/audit.js b/test/lib/audit.js index 6fd9c8a2c9b8f..d291ef87948c9 100644 --- a/test/lib/audit.js +++ b/test/lib/audit.js @@ -14,6 +14,9 @@ t.test('should audit using Arborist', t => { flatOptions: { json: false, }, + output: () => { + OUTPUT_CALLED = true + }, } const Audit = requireInject('../../lib/audit.js', { 'npm-audit-report': () => { @@ -37,9 +40,6 @@ t.test('should audit using Arborist', t => { REIFY_FINISH_CALLED = true }, - '../../lib/utils/output.js': () => { - OUTPUT_CALLED = true - }, }) const audit = new Audit(npm) @@ -70,6 +70,7 @@ t.test('should audit - json', t => { flatOptions: { json: true, }, + output: () => {}, } const Audit = requireInject('../../lib/audit.js', { @@ -83,7 +84,6 @@ t.test('should audit - json', t => { } }, '../../lib/utils/reify-output.js': () => {}, - '../../lib/utils/output.js': () => {}, }) const audit = new Audit(npm) @@ -107,6 +107,9 @@ t.test('report endpoint error', t => { log: { warn: (...warning) => LOGS.push(warning), }, + output: (...msg) => { + OUTPUT.push(msg) + }, } const Audit = requireInject('../../lib/audit.js', { 'npm-audit-report': () => { @@ -130,9 +133,6 @@ t.test('report endpoint error', t => { } }, '../../lib/utils/reify-output.js': () => {}, - '../../lib/utils/output.js': (...msg) => { - OUTPUT.push(msg) - }, }) const audit = new Audit(npm) diff --git a/test/lib/bin.js b/test/lib/bin.js index e96eb91af9708..512fa8d0267b9 100644 --- a/test/lib/bin.js +++ b/test/lib/bin.js @@ -5,13 +5,16 @@ test('bin', (t) => { t.plan(3) const dir = '/bin/dir' - const Bin = requireInject('../../lib/bin.js', { - '../../lib/utils/output.js': (output) => { + const Bin = require('../../lib/bin.js') + + const npm = { + bin: dir, + flatOptions: { global: false }, + output: (output) => { t.equal(output, dir, 'prints the correct directory') }, - }) - - const bin = new Bin({ bin: dir, flatOptions: { global: false } }) + } + const bin = new Bin(npm) bin.exec([], (err) => { t.ifError(err, 'npm bin') @@ -33,12 +36,16 @@ test('bin -g', (t) => { const Bin = requireInject('../../lib/bin.js', { '../../lib/utils/path.js': [dir], - '../../lib/utils/output.js': (output) => { - t.equal(output, dir, 'prints the correct directory') - }, }) - const bin = new Bin({ bin: dir, flatOptions: { global: true } }) + const npm = { + bin: dir, + flatOptions: { global: true }, + output: (output) => { + t.equal(output, dir, 'prints the correct directory') + }, + } + const bin = new Bin(npm) bin.exec([], (err) => { t.ifError(err, 'npm bin') @@ -60,11 +67,15 @@ test('bin -g (not in path)', (t) => { const Bin = requireInject('../../lib/bin.js', { '../../lib/utils/path.js': ['/not/my/dir'], - '../../lib/utils/output.js': (output) => { + }) + const npm = { + bin: dir, + flatOptions: { global: true }, + output: (output) => { t.equal(output, dir, 'prints the correct directory') }, - }) - const bin = new Bin({ bin: dir, flatOptions: { global: true } }) + } + const bin = new Bin(npm) bin.exec([], (err) => { t.ifError(err, 'npm bin') diff --git a/test/lib/cache.js b/test/lib/cache.js index 67499f37e9f30..5c2588f34ecba 100644 --- a/test/lib/cache.js +++ b/test/lib/cache.js @@ -8,9 +8,14 @@ const flatOptions = { force: false, } +let outputOutput = [] + const npm = { flatOptions, cache: '/fake/path', + output: (msg) => { + outputOutput.push(msg) + }, } let rimrafPath = '' @@ -41,11 +46,6 @@ const pacote = { }, } -let outputOutput = [] -const output = (msg) => { - outputOutput.push(msg) -} - const cacacheVerifyStats = { keptSize: 100, verifiedContent: 1, @@ -63,7 +63,6 @@ const Cache = requireInject('../../lib/cache.js', { npmlog, pacote, rimraf, - '../../lib/utils/output.js': output, '../../lib/utils/usage.js': usageUtil, }) diff --git a/test/lib/completion.js b/test/lib/completion.js index 89e8134ebb303..708f138251d19 100644 --- a/test/lib/completion.js +++ b/test/lib/completion.js @@ -46,6 +46,9 @@ const npm = { }, }, }, + output: (line) => { + output.push(line) + }, } const cmdList = { @@ -80,9 +83,6 @@ const Completion = requireInject('../../lib/completion.js', { '../../lib/utils/config.js': config, '../../lib/utils/deref-command.js': deref, '../../lib/utils/is-windows-shell.js': false, - '../../lib/utils/output.js': (line) => { - output.push(line) - }, }) const completion = new Completion(npm) diff --git a/test/lib/config.js b/test/lib/config.js index c2420aefb4a00..48934ba4e74d2 100644 --- a/test/lib/config.js +++ b/test/lib/config.js @@ -62,15 +62,15 @@ const npm = { return true }, }, + output: msg => { + result = msg + }, } const usageUtil = () => 'usage instructions' const mocks = { '../../lib/utils/config.js': { defaults, types }, - '../../lib/utils/output.js': msg => { - result = msg - }, '../../lib/utils/usage.js': usageUtil, } diff --git a/test/lib/diff.js b/test/lib/diff.js index 2af3bd69bc2e5..9f58505dca6ad 100644 --- a/test/lib/diff.js +++ b/test/lib/diff.js @@ -23,12 +23,12 @@ const npm = { get prefix () { return this.flatOptions.prefix }, + output: noop, } const mocks = { npmlog: { info: noop, verbose: noop }, libnpmdiff: (...args) => libnpmdiff(...args), 'npm-registry-fetch': async () => ({}), - '../../lib/utils/output.js': noop, '../../lib/utils/read-local-package.js': async () => rlp(), '../../lib/utils/usage.js': () => 'usage instructions', } diff --git a/test/lib/dist-tag.js b/test/lib/dist-tag.js index b761fb103cda8..a3c05bb2b3a15 100644 --- a/test/lib/dist-tag.js +++ b/test/lib/dist-tag.js @@ -58,9 +58,6 @@ const DistTag = requireInject('../../lib/dist-tag.js', { get 'npm-registry-fetch' () { return npmRegistryFetchMock }, - '../../lib/utils/output.js': msg => { - result = msg - }, }) const distTag = new DistTag({ @@ -70,6 +67,9 @@ const distTag = new DistTag({ return _flatOptions[key] }, }, + output: msg => { + result = msg + }, }) test('ls in current package', (t) => { diff --git a/test/lib/doctor.js b/test/lib/doctor.js index eaa7ad72df8a5..56bbdf974491d 100644 --- a/test/lib/doctor.js +++ b/test/lib/doctor.js @@ -104,6 +104,9 @@ const npm = { }, }, version: '7.1.0', + output: (data) => { + output.push(data) + }, } let latestNpm = npm.version @@ -123,9 +126,6 @@ const cacache = { const Doctor = requireInject('../../lib/doctor.js', { '../../lib/utils/is-windows.js': false, '../../lib/utils/ping.js': ping, - '../../lib/utils/output.js': (data) => { - output.push(data) - }, cacache, pacote, 'make-fetch-happen': fetch, @@ -285,9 +285,6 @@ test('node versions', t => { const WinDoctor = requireInject('../../lib/doctor.js', { '../../lib/utils/is-windows.js': true, '../../lib/utils/ping.js': ping, - '../../lib/utils/output.js': (data) => { - output.push(data) - }, cacache, pacote, 'make-fetch-happen': fetch, @@ -566,9 +563,6 @@ test('node versions', t => { const Doctor = requireInject('../../lib/doctor.js', { '../../lib/utils/is-windows.js': false, '../../lib/utils/ping.js': ping, - '../../lib/utils/output.js': (data) => { - output.push(data) - }, cacache, pacote, 'make-fetch-happen': fetch, diff --git a/test/lib/exec.js b/test/lib/exec.js index 4dc7f31cc31f4..eb9fef6a61da2 100644 --- a/test/lib/exec.js +++ b/test/lib/exec.js @@ -55,6 +55,7 @@ const npm = { LOG_WARN.push(args) }, }, + output, } const RUN_SCRIPTS = [] @@ -93,7 +94,6 @@ const mocks = { pacote, read, 'mkdirp-infer-owner': mkdirp, - '../../lib/utils/output.js': output, } const Exec = requireInject('../../lib/exec.js', mocks) const exec = new Exec(npm) diff --git a/test/lib/explain.js b/test/lib/explain.js index 22bfb8639ecff..2e82928d89d19 100644 --- a/test/lib/explain.js +++ b/test/lib/explain.js @@ -4,15 +4,15 @@ const npm = { prefix: null, color: true, flatOptions: {}, + output: (...args) => { + OUTPUT.push(args) + }, } const { resolve } = require('path') const OUTPUT = [] const Explain = requireInject('../../lib/explain.js', { - '../../lib/utils/output.js': (...args) => { - OUTPUT.push(args) - }, // keep the snapshots pared down a bit, since this has its own tests. '../../lib/utils/explain-dep.js': { diff --git a/test/lib/explore.js b/test/lib/explore.js index 6f1f3bb47f240..af16444ca8f71 100644 --- a/test/lib/explore.js +++ b/test/lib/explore.js @@ -55,9 +55,6 @@ const getExplore = (windows) => { }, 'read-package-json-fast': mockRPJ, '@npmcli/run-script': mockRunScript, - '../../lib/utils/output.js': out => { - output.push(out) - }, }) const npm = { dir: windows ? 'c:\\npm\\dir' : '/npm/dir', @@ -69,6 +66,9 @@ const getExplore = (windows) => { flatOptions: { shell: 'shell-command', }, + output: out => { + output.push(out) + }, } return new Explore(npm) } diff --git a/test/lib/fund.js b/test/lib/fund.js index 831d76f151bb7..2ae604a653632 100644 --- a/test/lib/fund.js +++ b/test/lib/fund.js @@ -202,9 +202,6 @@ const openUrl = async (npm, url, msg) => { } const Fund = requireInject('../../lib/fund.js', { '../../lib/utils/open-url.js': openUrl, - '../../lib/utils/output.js': msg => { - result += msg + '\n' - }, pacote: { manifest: (arg) => arg.name === 'ntl' ? Promise.resolve({ @@ -218,6 +215,9 @@ const fund = new Fund({ get prefix () { return _flatOptions.prefix }, + output: msg => { + result += msg + '\n' + }, }) test('fund with no package containing funding', t => { diff --git a/test/lib/help-search.js b/test/lib/help-search.js index 8b1ecd46eb774..6228f5ca97b3b 100644 --- a/test/lib/help-search.js +++ b/test/lib/help-search.js @@ -21,6 +21,7 @@ const npm = { return cb(npmHelpErr) }, }, + output, } let npmUsageArg = null @@ -45,7 +46,6 @@ const glob = (p, cb) => const HelpSearch = requireInject('../../lib/help-search.js', { '../../lib/utils/npm-usage.js': npmUsage, - '../../lib/utils/output.js': output, glob, }) const helpSearch = new HelpSearch(npm) diff --git a/test/lib/help.js b/test/lib/help.js index addbe4dcc1f9b..ae2f7e99dafa8 100644 --- a/test/lib/help.js +++ b/test/lib/help.js @@ -14,6 +14,7 @@ const npmConfig = { } let helpSearchArgs = null +const OUTPUT = [] const npm = { config: { get: (key) => npmConfig[key], @@ -34,11 +35,9 @@ const npm = { }, }, deref: (cmd) => {}, -} - -const OUTPUT = [] -const output = (msg) => { - OUTPUT.push(msg) + output: msg => { + OUTPUT.push(msg) + }, } const globDefaults = [ @@ -74,7 +73,6 @@ const openUrl = async (npm, url, msg) => { const Help = requireInject('../../lib/help.js', { '../../lib/utils/npm-usage.js': npmUsage, '../../lib/utils/open-url.js': openUrl, - '../../lib/utils/output.js': output, child_process: { spawn, }, diff --git a/test/lib/hook.js b/test/lib/hook.js index 923f86e81ddf3..3e012d94ee74f 100644 --- a/test/lib/hook.js +++ b/test/lib/hook.js @@ -1,6 +1,7 @@ const { test } = require('tap') const requireInject = require('require-inject') +const output = [] const npm = { flatOptions: { json: false, @@ -9,6 +10,9 @@ const npm = { loglevel: 'info', unicode: false, }, + output: (msg) => { + output.push(msg) + }, } const pkgTypes = { @@ -51,12 +55,8 @@ const libnpmhook = { }, } -const output = [] const Hook = requireInject('../../lib/hook.js', { '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - '../../lib/utils/output.js': (msg) => { - output.push(msg) - }, libnpmhook, }) const hook = new Hook(npm) diff --git a/test/lib/init.js b/test/lib/init.js index db5411ba76bf8..8b9f32e156e3d 100644 --- a/test/lib/init.js +++ b/test/lib/init.js @@ -14,13 +14,13 @@ const npm = { config: { set () {} }, flatOptions: {}, log: npmLog, + output: (...msg) => { + result += msg.join('\n') + }, } const mocks = { 'init-package-json': (dir, initFile, config, cb) => cb(null, 'data'), '../../lib/utils/usage.js': () => 'usage instructions', - '../../lib/utils/output.js': (...msg) => { - result += msg.join('\n') - }, } const Init = requireInject('../../lib/init.js', mocks) const init = new Init(npm) diff --git a/test/lib/ls.js b/test/lib/ls.js index bd81776d5f3df..bcbd3413563dd 100644 --- a/test/lib/ls.js +++ b/test/lib/ls.js @@ -1,8 +1,6 @@ -const { resolve } = require('path') - const t = require('tap') -const requireInject = require('require-inject') +const { resolve } = require('path') const { utimesSync } = require('fs') const touchHiddenPackageLock = prefix => { const later = new Date(Date.now() + 10000) @@ -106,11 +104,7 @@ const _flatOptions = { }, production: false, } -const LS = requireInject('../../lib/ls.js', { - '../../lib/utils/output.js': msg => { - result = msg - }, -}) +const LS = require('../../lib/ls.js') const ls = new LS({ flatOptions: _flatOptions, limit: { @@ -127,6 +121,9 @@ const ls = new LS({ return _flatOptions[key] }, }, + output: msg => { + result = msg + }, }) const redactCwd = res => diff --git a/test/lib/org.js b/test/lib/org.js index d21df85d64312..4ffbf0af411a6 100644 --- a/test/lib/org.js +++ b/test/lib/org.js @@ -2,6 +2,7 @@ const { test } = require('tap') const requireInject = require('require-inject') const ansiTrim = require('../../lib/utils/ansi-trim.js') +const output = [] const npm = { flatOptions: { json: false, @@ -9,10 +10,11 @@ const npm = { silent: false, loglevel: 'info', }, + output: (msg) => { + output.push(msg) + }, } -const output = [] - let orgSize = 1 let orgSetArgs = null let orgRmArgs = null @@ -41,9 +43,6 @@ const libnpmorg = { const Org = requireInject('../../lib/org.js', { '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), - '../../lib/utils/output.js': (msg) => { - output.push(msg) - }, libnpmorg, }) const org = new Org(npm) diff --git a/test/lib/outdated.js b/test/lib/outdated.js index aa8a1bcb6b3a5..02952971b69f9 100644 --- a/test/lib/outdated.js +++ b/test/lib/outdated.js @@ -68,17 +68,8 @@ const packument = spec => { } let logs -const cleanLogs = (done) => { - logs = '' - const fn = (...args) => { - logs += '\n' - args.map(el => { - logs += el - return logs - }) - } - console.log = fn - done() +const output = (msg) => { + logs = `${logs}\n${msg}` } const globalDir = t.testdir({ @@ -102,10 +93,14 @@ const outdated = (dir, opts) => { prefix: dir, globalDir: `${globalDir}/node_modules`, flatOptions: opts, + output, }) } -t.beforeEach(cleanLogs) +t.beforeEach((done) => { + logs = '' + done() +}) const redactCwd = (path) => { const normalizePath = p => p diff --git a/test/lib/owner.js b/test/lib/owner.js index 4f8f430886b7e..14753689f9384 100644 --- a/test/lib/owner.js +++ b/test/lib/owner.js @@ -6,7 +6,12 @@ let readLocalPkgResponse = null const noop = () => null -const npm = { flatOptions: {} } +const npm = { + flatOptions: {}, + output: (msg) => { + result = result ? `${result}\n${msg}` : msg + }, +} const npmFetch = { json: noop } const npmlog = { error: noop, info: noop, verbose: noop } const pacote = { packument: noop } @@ -15,9 +20,6 @@ const mocks = { npmlog, 'npm-registry-fetch': npmFetch, pacote, - '../../lib/utils/output.js': (...msg) => { - result += msg.join('\n') - }, '../../lib/utils/otplease.js': async (opts, fn) => fn({ otp: '123456', opts }), '../../lib/utils/read-local-package.js': async () => readLocalPkgResponse, '../../lib/utils/usage.js': () => 'usage instructions', diff --git a/test/lib/pack.js b/test/lib/pack.js index 73a19baa3ef73..ce319be76ba3f 100644 --- a/test/lib/pack.js +++ b/test/lib/pack.js @@ -18,7 +18,6 @@ t.afterEach(cb => { t.test('should pack current directory with no arguments', (t) => { const Pack = requireInject('../../lib/pack.js', { - '../../lib/utils/output.js': output, libnpmpack, npmlog: { notice: () => {}, @@ -32,6 +31,7 @@ t.test('should pack current directory with no arguments', (t) => { json: false, dryRun: false, }, + output, }) pack.exec([], er => { @@ -53,7 +53,6 @@ t.test('should pack given directory', (t) => { }) const Pack = requireInject('../../lib/pack.js', { - '../../lib/utils/output.js': output, libnpmpack, npmlog: { notice: () => {}, @@ -67,6 +66,7 @@ t.test('should pack given directory', (t) => { json: true, dryRun: true, }, + output, }) pack.exec([testDir], er => { @@ -88,7 +88,6 @@ t.test('should pack given directory for scoped package', (t) => { }) const Pack = requireInject('../../lib/pack.js', { - '../../lib/utils/output.js': output, libnpmpack, npmlog: { notice: () => {}, @@ -102,6 +101,7 @@ t.test('should pack given directory for scoped package', (t) => { json: true, dryRun: true, }, + output, }) return pack.exec([testDir], er => { @@ -116,7 +116,6 @@ t.test('should pack given directory for scoped package', (t) => { t.test('should log pack contents', (t) => { const Pack = requireInject('../../lib/pack.js', { - '../../lib/utils/output.js': output, '../../lib/utils/tar.js': { ...require('../../lib/utils/tar.js'), logTar: () => { @@ -136,6 +135,7 @@ t.test('should log pack contents', (t) => { json: false, dryRun: false, }, + output, }) pack.exec([], er => { diff --git a/test/lib/ping.js b/test/lib/ping.js index cf47530749b33..f3563036f71fd 100644 --- a/test/lib/ping.js +++ b/test/lib/ping.js @@ -81,12 +81,6 @@ test('pings and returns json', (t) => { t.equal(spec, flatOptions, 'passes flatOptions') return details }, - '../../lib/utils/output.js': function (spec) { - const parsed = JSON.parse(spec) - t.equal(parsed.registry, flatOptions.registry, 'returns the correct registry url') - t.match(parsed.details, details, 'prints returned details') - t.type(parsed.time, 'number', 'returns time as a number') - }, npmlog: { notice: (type, spec) => { ++noticeCalls @@ -100,7 +94,15 @@ test('pings and returns json', (t) => { }, }, }) - const ping = new Ping({ flatOptions }) + const ping = new Ping({ + flatOptions, + output: function (spec) { + const parsed = JSON.parse(spec) + t.equal(parsed.registry, flatOptions.registry, 'returns the correct registry url') + t.match(parsed.details, details, 'prints returned details') + t.type(parsed.time, 'number', 'returns time as a number') + }, + }) ping.exec([], (err) => { t.equal(noticeCalls, 2, 'should have logged 2 lines') diff --git a/test/lib/prefix.js b/test/lib/prefix.js index dfb50f174f5db..5eb7ddb934d93 100644 --- a/test/lib/prefix.js +++ b/test/lib/prefix.js @@ -1,16 +1,16 @@ -const { test } = require('tap') -const requireInject = require('require-inject') +const t = require('tap') -test('prefix', (t) => { +t.test('prefix', (t) => { t.plan(3) const dir = '/prefix/dir' - const Prefix = requireInject('../../lib/prefix.js', { - '../../lib/utils/output.js': (output) => { + const Prefix = require('../../lib/prefix.js') + const prefix = new Prefix({ + prefix: dir, + output: (output) => { t.equal(output, dir, 'prints the correct directory') }, }) - const prefix = new Prefix({ prefix: dir }) prefix.exec([], (err) => { t.ifError(err, 'npm prefix') diff --git a/test/lib/profile.js b/test/lib/profile.js index 743ba2d6872e1..d1be93b0cbb62 100644 --- a/test/lib/profile.js +++ b/test/lib/profile.js @@ -8,7 +8,13 @@ const flatOptions = { parseable: false, registry: 'https://registry.npmjs.org/', } -const npm = { config: {}, flatOptions: { ...flatOptions }} +const npm = { + config: {}, + flatOptions: { ...flatOptions }, + output: (...msg) => { + result = result ? `${result}\n${msg.join('\n')}` : msg.join('\n') + }, +} const mocks = { ansistyles: { bright: a => a }, npmlog: { @@ -32,9 +38,6 @@ const mocks = { .join('\n') } }, - '../../lib/utils/output.js': (...msg) => { - result += msg.join('\n') - }, '../../lib/utils/pulse-till-done.js': { withPromise: async a => a, }, diff --git a/test/lib/publish.js b/test/lib/publish.js index 0e857fafddfe2..6337a1fcf0b2a 100644 --- a/test/lib/publish.js +++ b/test/lib/publish.js @@ -134,9 +134,6 @@ t.test('if loglevel=info and json, should not output package contents', (t) => { log.level = 'info' const Publish = requireInject('../../lib/publish.js', { - '../../lib/utils/output.js': () => { - t.pass('output is called') - }, '../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', @@ -162,6 +159,9 @@ t.test('if loglevel=info and json, should not output package contents', (t) => { return { token: 'some.registry.token' } }, }, + output: () => { + t.pass('output is called') + }, }) publish.exec([testDir], (er) => { @@ -184,9 +184,6 @@ t.test('if loglevel=silent and dry-run, should not output package contents or pu log.level = 'silent' const Publish = requireInject('../../lib/publish.js', { - '../../lib/utils/output.js': () => { - throw new Error('should not output in dry run mode') - }, '../../lib/utils/tar.js': { getContents: () => ({ id: 'someid', @@ -211,6 +208,9 @@ t.test('if loglevel=silent and dry-run, should not output package contents or pu throw new Error('should not call getCredentialsByURI in dry run') }, }, + output: () => { + throw new Error('should not output in dry run mode') + }, }) publish.exec([testDir], (er) => { @@ -241,9 +241,6 @@ t.test('if loglevel=info and dry-run, should not publish, should log package con t.pass('logTar is called') }, }, - '../../lib/utils/output.js': () => { - t.pass('output fn is called') - }, libnpmpublish: { publish: () => { throw new Error('should not call libnpmpublish in dry run') @@ -258,7 +255,11 @@ t.test('if loglevel=info and dry-run, should not publish, should log package con ...config, getCredentialsByURI: () => { throw new Error('should not call getCredentialsByURI in dry run') - }}, + }, + }, + output: () => { + t.pass('output fn is called') + }, }) publish.exec([testDir], (er) => { diff --git a/test/lib/rebuild.js b/test/lib/rebuild.js index ee081c087f07f..1eb45e0d1d7bd 100644 --- a/test/lib/rebuild.js +++ b/test/lib/rebuild.js @@ -1,7 +1,6 @@ const fs = require('fs') const { resolve } = require('path') const t = require('tap') -const requireInject = require('require-inject') let result = '' @@ -11,15 +10,11 @@ const npm = { global: false, }, prefix: '', -} -const mocks = { - '../../lib/utils/output.js': (...msg) => { + output: (...msg) => { result += msg.join('\n') }, - '../../lib/utils/usage.js': () => 'usage instructions', } - -const Rebuild = requireInject('../../lib/rebuild.js', mocks) +const Rebuild = require('../../lib/rebuild.js') const rebuild = new Rebuild(npm) t.afterEach(cb => { diff --git a/test/lib/root.js b/test/lib/root.js index e8ccc1106d772..4a1aefa02dcea 100644 --- a/test/lib/root.js +++ b/test/lib/root.js @@ -1,16 +1,16 @@ -const { test } = require('tap') -const requireInject = require('require-inject') +const t = require('tap') -test('root', (t) => { +t.test('root', (t) => { t.plan(3) const dir = '/root/dir' - const Root = requireInject('../../lib/root.js', { - '../../lib/utils/output.js': (output) => { + const Root = require('../../lib/root.js') + const root = new Root({ + dir, + output: (output) => { t.equal(output, dir, 'prints the correct directory') }, }) - const root = new Root({ dir }) root.exec([], (err) => { t.ifError(err, 'npm root') diff --git a/test/lib/run-script.js b/test/lib/run-script.js index 43592d3243466..0566daf2341f4 100644 --- a/test/lib/run-script.js +++ b/test/lib/run-script.js @@ -18,6 +18,7 @@ const npm = { npm.config.settings[k] = v }, }, + output: (...msg) => output.push(msg), } const output = [] @@ -40,7 +41,6 @@ const getRS = windows => { }), npmlog, '../../lib/utils/is-windows-shell.js': windows, - '../../lib/utils/output.js': (...msg) => output.push(msg), }) return new RunScript(npm) } diff --git a/test/lib/search.js b/test/lib/search.js index 59c59f3b96e27..ea7ec4ca7c19e 100644 --- a/test/lib/search.js +++ b/test/lib/search.js @@ -12,7 +12,12 @@ const flatOptions = { opts: '', }, } -const npm = { flatOptions: { ...flatOptions } } +const npm = { + flatOptions: { ...flatOptions }, + output: (...msg) => { + result += msg.join('\n') + }, +} const npmlog = { silly () {}, clearProgress () {}, @@ -23,9 +28,6 @@ const libnpmsearch = { const mocks = { npmlog, libnpmsearch, - '../../lib/utils/output.js': (...msg) => { - result += msg.join('\n') - }, '../../lib/utils/usage.js': () => 'usage instructions', // '../../lib/search/format-package-stream.js': a => a, } diff --git a/test/lib/star.js b/test/lib/star.js index 64efd9ef8c7ed..774fabe3924c4 100644 --- a/test/lib/star.js +++ b/test/lib/star.js @@ -4,15 +4,18 @@ const t = require('tap') let result = '' const noop = () => null -const npm = { config: { get () {} }, flatOptions: { unicode: false } } +const npm = { + config: { get () {} }, + flatOptions: { unicode: false }, + output: (...msg) => { + result += msg.join('\n') + }, +} const npmFetch = { json: noop } const npmlog = { error: noop, info: noop, verbose: noop } const mocks = { npmlog, 'npm-registry-fetch': npmFetch, - '../../lib/utils/output.js': (...msg) => { - result += msg.join('\n') - }, '../../lib/utils/get-identity.js': async () => 'foo', '../../lib/utils/usage.js': () => 'usage instructions', } diff --git a/test/lib/stars.js b/test/lib/stars.js index 383b5adf42677..b242a883ad90f 100644 --- a/test/lib/stars.js +++ b/test/lib/stars.js @@ -4,15 +4,18 @@ const t = require('tap') let result = '' const noop = () => null -const npm = { config: { get () {} }, flatOptions: {} } +const npm = { + config: { get () {} }, + flatOptions: {}, + output: (...msg) => { + result = [result, ...msg].join('\n') + }, +} const npmFetch = { json: noop } const npmlog = { warn: noop } const mocks = { npmlog, 'npm-registry-fetch': npmFetch, - '../../lib/utils/output.js': (...msg) => { - result = [result, ...msg].join('\n') - }, '../../lib/utils/get-identity.js': async () => 'foo', '../../lib/utils/usage.js': () => 'usage instructions', } diff --git a/test/lib/team.js b/test/lib/team.js index a264597258d5a..458f8ee6700ce 100644 --- a/test/lib/team.js +++ b/test/lib/team.js @@ -10,13 +10,15 @@ const libnpmteam = { async lsUsers () {}, async rm () {}, } -const npm = { flatOptions: {} } +const npm = { + flatOptions: {}, + output: (...msg) => { + result += msg.join('\n') + }, +} const mocks = { libnpmteam, 'cli-columns': a => a.join(' '), - '../../lib/utils/output.js': (...msg) => { - result += msg.join('\n') - }, '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), '../../lib/utils/usage.js': () => 'usage instructions', } diff --git a/test/lib/token.js b/test/lib/token.js index 412d2746befd4..3ca44ab5c90c6 100644 --- a/test/lib/token.js +++ b/test/lib/token.js @@ -7,9 +7,11 @@ const mocks = { log: {}, readUserInfo: {}, } +const npm = { + output: (...args) => mocks.output(...args), +} const Token = requireInject('../../lib/token.js', { - '../../lib/utils/output.js': (...args) => mocks.output(...args), '../../lib/utils/otplease.js': (opts, fn) => { return Promise.resolve().then(() => fn(opts)) }, @@ -17,11 +19,14 @@ const Token = requireInject('../../lib/token.js', { 'npm-profile': mocks.profile, npmlog: mocks.log, }) -const token = new Token({}) + +const token = new Token(npm) const tokenWithMocks = (mockRequests) => { for (const mod in mockRequests) { - if (mod !== 'npm') { + if (mod === 'npm') + mockRequests.npm = { ...npm, ...mockRequests.npm } + else { if (typeof mockRequests[mod] === 'function') mocks[mod] = mockRequests[mod] else { @@ -44,7 +49,7 @@ const tokenWithMocks = (mockRequests) => { } } - const token = new Token(mockRequests.npm || {}) + const token = new Token(mockRequests.npm || npm) return [token, reset] } diff --git a/test/lib/unpublish.js b/test/lib/unpublish.js index 80a879cb6e6df..b1255b94a8fe4 100644 --- a/test/lib/unpublish.js +++ b/test/lib/unpublish.js @@ -10,6 +10,9 @@ const npm = { silent: false, loglevel: 'silly', }, + output: (...msg) => { + result += msg.join('\n') + }, } const mocks = { npmlog: { silly () {}, verbose () {} }, @@ -18,9 +21,6 @@ const mocks = { 'npm-package-arg': noop, 'npm-registry-fetch': { json: noop }, 'read-package-json': cb => cb(), - '../../lib/utils/output.js': (...msg) => { - result += msg.join('\n') - }, '../../lib/utils/otplease.js': async (opts, fn) => fn(opts), '../../lib/utils/usage.js': () => 'usage instructions', '../../lib/utils/get-identity.js': async () => 'foo', diff --git a/test/lib/utils/audit-error.js b/test/lib/utils/audit-error.js index ea7c84373e9f3..d236f4f9e9eaf 100644 --- a/test/lib/utils/audit-error.js +++ b/test/lib/utils/audit-error.js @@ -1,20 +1,18 @@ const t = require('tap') -const requireInject = require('require-inject') const LOGS = [] +const OUTPUT = [] +const output = (...msg) => OUTPUT.push(msg) +const auditError = require('../../../lib/utils/audit-error.js') + const npm = { command: null, flatOptions: {}, log: { warn: (...msg) => LOGS.push(msg), }, + output, } -const OUTPUT = [] -const output = (...msg) => OUTPUT.push(msg) -const auditError = requireInject('../../../lib/utils/audit-error.js', { - '../../../lib/utils/output.js': output, -}) - t.afterEach(cb => { npm.flatOptions = {} OUTPUT.length = 0 diff --git a/test/lib/utils/npm-usage.js b/test/lib/utils/npm-usage.js index dbbde947ce5ed..fbc453811ec2f 100644 --- a/test/lib/utils/npm-usage.js +++ b/test/lib/utils/npm-usage.js @@ -3,10 +3,10 @@ const t = require('tap') const OUTPUT = [] const output = (...msg) => OUTPUT.push(msg) const requireInject = require('require-inject') -const usage = requireInject('../../../lib/utils/npm-usage.js', { - '../../../lib/utils/output.js': output, -}) +const usage = require('../../../lib/utils/npm-usage.js') + const npm = requireInject('../../../lib/npm.js') +npm.output = output t.test('usage', t => { t.afterEach((cb) => { diff --git a/test/lib/utils/open-url.js b/test/lib/utils/open-url.js index e8ab8f15a14a8..781b70d3e8d31 100644 --- a/test/lib/utils/open-url.js +++ b/test/lib/utils/open-url.js @@ -1,6 +1,8 @@ const { test } = require('tap') const requireInject = require('require-inject') +const OUTPUT = [] +const output = (...args) => OUTPUT.push(args) const npm = { _config: { json: false, @@ -12,11 +14,9 @@ const npm = { npm._config[k] = v }, }, + output, } -const OUTPUT = [] -const output = (...args) => OUTPUT.push(args) - let openerUrl = null let openerOpts = null let openerResult = null @@ -27,7 +27,6 @@ const opener = (url, opts, cb) => { } const openUrl = requireInject('../../../lib/utils/open-url.js', { - '../../../lib/utils/output.js': output, opener, }) diff --git a/test/lib/utils/output.js b/test/lib/utils/output.js deleted file mode 100644 index 72871187d889a..0000000000000 --- a/test/lib/utils/output.js +++ /dev/null @@ -1,8 +0,0 @@ -const t = require('tap') -const logs = [] -console.log = (...msg) => logs.push(msg) -const output = require('../../../lib/utils/output.js') -output('hello', 'world') -output('hello') -output('world') -t.strictSame(logs, [['hello', 'world'], ['hello'], ['world']]) diff --git a/test/lib/utils/reify-output.js b/test/lib/utils/reify-output.js index e41eabcb896e9..e4f58b4668e05 100644 --- a/test/lib/utils/reify-output.js +++ b/test/lib/utils/reify-output.js @@ -1,5 +1,4 @@ const t = require('tap') -const requireInject = require('require-inject') const log = require('npmlog') log.level = 'warn' @@ -13,22 +12,13 @@ const npm = { started: Date.now(), flatOptions: settings, } -const getReifyOutput = tester => - requireInject( - '../../../lib/utils/reify-output.js', - { - '../../../lib/utils/output.js': tester, - } - ) - +const reifyOutput = require('../../../lib/utils/reify-output.js') t.test('missing info', (t) => { t.plan(1) - const reifyOutput = getReifyOutput( - out => t.doesNotHave( - out, - 'looking for funding', - 'should not print fund message if missing info' - ) + npm.output = out => t.doesNotHave( + out, + 'looking for funding', + 'should not print fund message if missing info' ) reifyOutput(npm, { @@ -43,12 +33,10 @@ t.test('missing info', (t) => { t.test('even more missing info', t => { t.plan(1) - const reifyOutput = getReifyOutput( - out => t.doesNotHave( - out, - 'looking for funding', - 'should not print fund message if missing info' - ) + npm.output = out => t.doesNotHave( + out, + 'looking for funding', + 'should not print fund message if missing info' ) reifyOutput(npm, { @@ -60,17 +48,15 @@ t.test('even more missing info', t => { t.test('single package', (t) => { t.plan(1) - const reifyOutput = getReifyOutput( - out => { - if (out.endsWith('looking for funding')) { - t.match( - out, - '1 package is looking for funding', - 'should print single package message' - ) - } + npm.output = out => { + if (out.endsWith('looking for funding')) { + t.match( + out, + '1 package is looking for funding', + 'should print single package message' + ) } - ) + } reifyOutput(npm, { // a report with an error is the same as no report at all, if @@ -110,12 +96,10 @@ t.test('no message when funding config is false', (t) => { settings.fund = true }) settings.fund = false - const reifyOutput = getReifyOutput( - out => { - if (out.endsWith('looking for funding')) - t.fail('should not print funding info', { actual: out }) - } - ) + npm.output = out => { + if (out.endsWith('looking for funding')) + t.fail('should not print funding info', { actual: out }) + } reifyOutput(npm, { actualTree: { @@ -147,17 +131,15 @@ t.test('no message when funding config is false', (t) => { t.test('print appropriate message for many packages', (t) => { t.plan(1) - const reifyOutput = getReifyOutput( - out => { - if (out.endsWith('looking for funding')) { - t.match( - out, - '3 packages are looking for funding', - 'should print single package message' - ) - } + npm.output = out => { + if (out.endsWith('looking for funding')) { + t.match( + out, + '3 packages are looking for funding', + 'should print single package message' + ) } - ) + } reifyOutput(npm, { actualTree: { @@ -206,9 +188,9 @@ t.test('print appropriate message for many packages', (t) => { }) t.test('no output when silent', t => { - const reifyOutput = getReifyOutput(out => { + npm.output = out => { t.fail('should not get output when silent', { actual: out }) - }) + } t.teardown(() => log.level = 'warn') log.level = 'silent' reifyOutput(npm, { @@ -235,9 +217,9 @@ t.test('no output when silent', t => { t.test('packages changed message', t => { const output = [] - const reifyOutput = getReifyOutput(out => { + npm.output = out => { output.push(out) - }) + } // return a test function that builds up the mock and snapshots output const testCase = (t, added, removed, changed, audited, json, command) => { @@ -311,9 +293,7 @@ t.test('packages changed message', t => { t.test('added packages should be looked up within returned tree', t => { t.test('has added pkg in inventory', t => { t.plan(1) - const reifyOutput = getReifyOutput( - out => t.matchSnapshot(out) - ) + npm.output = out => t.matchSnapshot(out) reifyOutput(npm, { actualTree: { @@ -332,9 +312,7 @@ t.test('added packages should be looked up within returned tree', t => { t.test('missing added pkg in inventory', t => { t.plan(1) - const reifyOutput = getReifyOutput( - out => t.matchSnapshot(out) - ) + npm.output = out => t.matchSnapshot(out) reifyOutput(npm, { actualTree: { diff --git a/test/lib/version.js b/test/lib/version.js index e0e07f5172efe..a8fcd831fb5c3 100644 --- a/test/lib/version.js +++ b/test/lib/version.js @@ -11,14 +11,13 @@ const npm = { }, prefix: '', version: '1.0.0', -} -const mocks = { - libnpmversion: noop, - '../../lib/utils/output.js': (...msg) => { + output: (...msg) => { for (const m of msg) result.push(m) }, - '../../lib/utils/usage.js': () => 'usage instructions', +} +const mocks = { + libnpmversion: noop, } const Version = requireInject('../../lib/version.js', mocks) @@ -65,7 +64,7 @@ t.test('too many args', t => { version.exec(['foo', 'bar'], err => { t.match( err, - 'usage instructions', + 'npm version', 'should throw usage instructions error' ) diff --git a/test/lib/whoami.js b/test/lib/whoami.js index 3d9618ffa7150..1a1ecd25742e1 100644 --- a/test/lib/whoami.js +++ b/test/lib/whoami.js @@ -5,11 +5,13 @@ test('whoami', (t) => { t.plan(3) const Whoami = requireInject('../../lib/whoami.js', { '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), - '../../lib/utils/output.js': (output) => { + }) + const whoami = new Whoami({ + flatOptions: {}, + output: (output) => { t.equal(output, 'foo', 'should output the username') }, }) - const whoami = new Whoami({ flatOptions: {} }) whoami.exec([], (err) => { t.ifError(err, 'npm whoami') @@ -21,11 +23,13 @@ test('whoami json', (t) => { t.plan(3) const Whoami = requireInject('../../lib/whoami.js', { '../../lib/utils/get-identity.js': () => Promise.resolve('foo'), - '../../lib/utils/output.js': (output) => { + }) + const whoami = new Whoami({ + flatOptions: { json: true }, + output: (output) => { t.equal(output, '"foo"', 'should output the username as json') }, }) - const whoami = new Whoami({ flatOptions: { json: true } }) whoami.exec([], (err) => { t.ifError(err, 'npm whoami')