From 09526ae9284fc873fd7d123939ab9b3dce0bf9a2 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Fri, 12 Apr 2024 16:13:14 -0700 Subject: [PATCH] feat: do all ouput over proc-log events --- lib/base-command.js | 4 +- lib/cli-entry.js | 10 ++-- lib/commands/access.js | 11 ++-- lib/commands/adduser.js | 4 +- lib/commands/audit.js | 58 ++++++++++---------- lib/commands/cache.js | 22 ++++---- lib/commands/completion.js | 3 +- lib/commands/config.js | 12 ++-- lib/commands/diff.js | 4 +- lib/commands/dist-tag.js | 10 ++-- lib/commands/doctor.js | 4 +- lib/commands/exec.js | 2 - lib/commands/explain.js | 5 +- lib/commands/explore.js | 4 +- lib/commands/fund.js | 7 ++- lib/commands/help-search.js | 11 ++-- lib/commands/help.js | 3 +- lib/commands/hook.js | 39 ++++++------- lib/commands/init.js | 5 +- lib/commands/login.js | 4 +- lib/commands/ls.js | 3 +- lib/commands/org.js | 25 +++++---- lib/commands/outdated.js | 7 ++- lib/commands/owner.js | 10 ++-- lib/commands/pack.js | 6 +- lib/commands/ping.js | 4 +- lib/commands/pkg.js | 5 +- lib/commands/prefix.js | 3 +- lib/commands/profile.js | 38 ++++++------- lib/commands/publish.js | 10 ++-- lib/commands/query.js | 6 +- lib/commands/rebuild.js | 3 +- lib/commands/root.js | 3 +- lib/commands/run-script.js | 22 ++++---- lib/commands/sbom.js | 4 +- lib/commands/search.js | 6 +- lib/commands/star.js | 4 +- lib/commands/stars.js | 4 +- lib/commands/team.js | 41 +++++++------- lib/commands/token.js | 22 ++++---- lib/commands/unpublish.js | 3 +- lib/commands/version.js | 11 ++-- lib/commands/view.js | 64 +++++++++++----------- lib/commands/whoami.js | 3 +- lib/npm.js | 12 ---- lib/utils/audit-error.js | 6 +- lib/utils/display.js | 32 +++++++---- lib/utils/open-url-prompt.js | 5 +- lib/utils/open-url.js | 3 +- lib/utils/reify-output.js | 16 +++--- test/lib/commands/ci.js | 1 - test/lib/commands/pack.js | 44 +++------------ test/lib/commands/publish.js | 50 +++++------------ test/lib/npm.js | 9 --- test/lib/utils/display.js | 8 +-- test/lib/utils/exit-handler.js | 17 +++--- workspaces/arborist/test/arborist/reify.js | 23 ++++---- 57 files changed, 359 insertions(+), 396 deletions(-) diff --git a/lib/base-command.js b/lib/base-command.js index 1efda0fecba54..a5fdadb60870e 100644 --- a/lib/base-command.js +++ b/lib/base-command.js @@ -4,7 +4,7 @@ const { relative } = require('path') const { definitions } = require('@npmcli/config/lib/definitions') const { aliases: cmdAliases } = require('./utils/cmd-list') -const { log } = require('proc-log') +const { log, output } = require('proc-log') class BaseCommand { static workspaces = false @@ -119,7 +119,7 @@ class BaseCommand { const { config } = this.npm if (config.get('usage')) { - return this.npm.output(this.usage) + return output.standard(this.usage) } const hasWsConfig = config.get('workspaces') || config.get('workspace').length diff --git a/lib/cli-entry.js b/lib/cli-entry.js index 3c8fc04ae832c..9a5994aec19a3 100644 --- a/lib/cli-entry.js +++ b/lib/cli-entry.js @@ -18,7 +18,7 @@ module.exports = async (process, validateEngines) => { exitHandler.setNpm(npm) // only log node and npm paths in argv initially since argv can contain sensitive info. a cleaned version will be logged later - const { log } = require('proc-log') + const { log, output } = require('proc-log') log.verbose('cli', process.argv.slice(0, 2).join(' ')) log.info('using', 'npm@%s', npm.version) log.info('using', 'node@%s', process.version) @@ -41,7 +41,7 @@ module.exports = async (process, validateEngines) => { // npm -v if (npm.config.get('version', 'cli')) { - npm.output(npm.version) + output.standard(npm.version) return exitHandler() } @@ -53,7 +53,7 @@ module.exports = async (process, validateEngines) => { cmd = npm.argv.shift() if (!cmd) { - npm.output(npm.usage) + output.standard(npm.usage) process.exitCode = 1 return exitHandler() } @@ -64,8 +64,8 @@ module.exports = async (process, validateEngines) => { if (err.code === 'EUNKNOWNCOMMAND') { const didYouMean = require('./utils/did-you-mean.js') const suggestions = await didYouMean(npm.localPrefix, cmd) - npm.output(`Unknown command: "${cmd}"${suggestions}\n`) - npm.output('To see a list of supported npm commands, run:\n npm help') + output.standard(`Unknown command: "${cmd}"${suggestions}\n`) + output.standard('To see a list of supported npm commands, run:\n npm help') process.exitCode = 1 return exitHandler() } diff --git a/lib/commands/access.js b/lib/commands/access.js index 4594241b402b7..20565e274398e 100644 --- a/lib/commands/access.js +++ b/lib/commands/access.js @@ -1,5 +1,6 @@ const libnpmaccess = require('libnpmaccess') const npa = require('npm-package-arg') +const { output } = require('proc-log') const pkgJson = require('@npmcli/package-json') const localeCompare = require('@isaacs/string-locale-compare')('en') @@ -197,7 +198,7 @@ class Access extends BaseCommand { } #output (items, limiter) { - const output = {} + const outputs = {} const lookup = { __proto__: null, read: 'read-only', @@ -205,14 +206,14 @@ class Access extends BaseCommand { } for (const item in items) { const val = items[item] - output[item] = lookup[val] || val + outputs[item] = lookup[val] || val } if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify(output, null, 2)) + output.standard(JSON.stringify(outputs, null, 2)) } else { - for (const item of Object.keys(output).sort(localeCompare)) { + for (const item of Object.keys(outputs).sort(localeCompare)) { if (!limiter || limiter === item) { - this.npm.output(`${item}: ${output[item]}`) + output.standard(`${item}: ${outputs[item]}`) } } } diff --git a/lib/commands/adduser.js b/lib/commands/adduser.js index 2ac4b7d3db4db..842819f2bf44b 100644 --- a/lib/commands/adduser.js +++ b/lib/commands/adduser.js @@ -1,4 +1,4 @@ -const { log } = require('proc-log') +const { log, output } = require('proc-log') const { redactLog: replaceInfo } = require('@npmcli/redact') const auth = require('../utils/auth.js') @@ -44,7 +44,7 @@ class AddUser extends BaseCommand { await this.npm.config.save('user') - this.npm.output(message) + output.standard(message) } } module.exports = AddUser diff --git a/lib/commands/audit.js b/lib/commands/audit.js index fd99459d1febd..0ec4eec44a77e 100644 --- a/lib/commands/audit.js +++ b/lib/commands/audit.js @@ -8,7 +8,7 @@ const tufClient = require('@sigstore/tuf') const ArboristWorkspaceCmd = require('../arborist-cmd.js') const auditError = require('../utils/audit-error.js') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const reifyFinish = require('../utils/reify-finish.js') const sortAlphabetically = (a, b) => localeCompare(a.name, b.name) @@ -65,7 +65,7 @@ class VerifySignatures { } if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify({ + output.standard(JSON.stringify({ invalid, missing, }, null, 2)) @@ -77,91 +77,91 @@ class VerifySignatures { const auditedPlural = this.auditedWithKeysCount > 1 ? 's' : '' const timing = `audited ${this.auditedWithKeysCount} package${auditedPlural} in ` + `${Math.floor(Number(elapsed) / 1e9)}s` - this.npm.output(timing) - this.npm.output('') + output.standard(timing) + output.standard('') const verifiedBold = this.npm.chalk.bold('verified') if (this.verifiedSignatureCount) { if (this.verifiedSignatureCount === 1) { /* eslint-disable-next-line max-len */ - this.npm.output(`${this.verifiedSignatureCount} package has a ${verifiedBold} registry signature`) + output.standard(`${this.verifiedSignatureCount} package has a ${verifiedBold} registry signature`) } else { /* eslint-disable-next-line max-len */ - this.npm.output(`${this.verifiedSignatureCount} packages have ${verifiedBold} registry signatures`) + output.standard(`${this.verifiedSignatureCount} packages have ${verifiedBold} registry signatures`) } - this.npm.output('') + output.standard('') } if (this.verifiedAttestationCount) { if (this.verifiedAttestationCount === 1) { /* eslint-disable-next-line max-len */ - this.npm.output(`${this.verifiedAttestationCount} package has a ${verifiedBold} attestation`) + output.standard(`${this.verifiedAttestationCount} package has a ${verifiedBold} attestation`) } else { /* eslint-disable-next-line max-len */ - this.npm.output(`${this.verifiedAttestationCount} packages have ${verifiedBold} attestations`) + output.standard(`${this.verifiedAttestationCount} packages have ${verifiedBold} attestations`) } - this.npm.output('') + output.standard('') } if (missing.length) { const missingClr = this.npm.chalk.bold(this.npm.chalk.red('missing')) if (missing.length === 1) { /* eslint-disable-next-line max-len */ - this.npm.output(`1 package has a ${missingClr} registry signature but the registry is providing signing keys:`) + output.standard(`1 package has a ${missingClr} registry signature but the registry is providing signing keys:`) } else { /* eslint-disable-next-line max-len */ - this.npm.output(`${missing.length} packages have ${missingClr} registry signatures but the registry is providing signing keys:`) + output.standard(`${missing.length} packages have ${missingClr} registry signatures but the registry is providing signing keys:`) } - this.npm.output('') + output.standard('') missing.map(m => - this.npm.output(`${this.npm.chalk.red(`${m.name}@${m.version}`)} (${m.registry})`) + output.standard(`${this.npm.chalk.red(`${m.name}@${m.version}`)} (${m.registry})`) ) } if (invalid.length) { if (missing.length) { - this.npm.output('') + output.standard('') } const invalidClr = this.npm.chalk.bold(this.npm.chalk.red('invalid')) // We can have either invalid signatures or invalid provenance const invalidSignatures = this.invalid.filter(i => i.code === 'EINTEGRITYSIGNATURE') if (invalidSignatures.length) { if (invalidSignatures.length === 1) { - this.npm.output(`1 package has an ${invalidClr} registry signature:`) + output.standard(`1 package has an ${invalidClr} registry signature:`) } else { /* eslint-disable-next-line max-len */ - this.npm.output(`${invalidSignatures.length} packages have ${invalidClr} registry signatures:`) + output.standard(`${invalidSignatures.length} packages have ${invalidClr} registry signatures:`) } - this.npm.output('') + output.standard('') invalidSignatures.map(i => - this.npm.output(`${this.npm.chalk.red(`${i.name}@${i.version}`)} (${i.registry})`) + output.standard(`${this.npm.chalk.red(`${i.name}@${i.version}`)} (${i.registry})`) ) - this.npm.output('') + output.standard('') } const invalidAttestations = this.invalid.filter(i => i.code === 'EATTESTATIONVERIFY') if (invalidAttestations.length) { if (invalidAttestations.length === 1) { - this.npm.output(`1 package has an ${invalidClr} attestation:`) + output.standard(`1 package has an ${invalidClr} attestation:`) } else { /* eslint-disable-next-line max-len */ - this.npm.output(`${invalidAttestations.length} packages have ${invalidClr} attestations:`) + output.standard(`${invalidAttestations.length} packages have ${invalidClr} attestations:`) } - this.npm.output('') + output.standard('') invalidAttestations.map(i => - this.npm.output(`${this.npm.chalk.red(`${i.name}@${i.version}`)} (${i.registry})`) + output.standard(`${this.npm.chalk.red(`${i.name}@${i.version}`)} (${i.registry})`) ) - this.npm.output('') + output.standard('') } if (invalid.length === 1) { /* eslint-disable-next-line max-len */ - this.npm.output(`Someone might have tampered with this package since it was published on the registry!`) + output.standard(`Someone might have tampered with this package since it was published on the registry!`) } else { /* eslint-disable-next-line max-len */ - this.npm.output(`Someone might have tampered with these packages since they were published on the registry!`) + output.standard(`Someone might have tampered with these packages since they were published on the registry!`) } - this.npm.output('') + output.standard('') } } @@ -463,7 +463,7 @@ class Audit extends ArboristWorkspaceCmd { chalk: this.npm.chalk, }) process.exitCode = process.exitCode || result.exitCode - this.npm.output(result.report) + output.standard(result.report) } } diff --git a/lib/commands/cache.js b/lib/commands/cache.js index b6ab75a6265be..8e9b33b3d1a49 100644 --- a/lib/commands/cache.js +++ b/lib/commands/cache.js @@ -7,7 +7,7 @@ const BaseCommand = require('../base-command.js') const npa = require('npm-package-arg') const jsonParse = require('json-parse-even-better-errors') const localeCompare = require('@isaacs/string-locale-compare')('en') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const searchCachePackage = async (path, parsed, cacheKeys) => { /* eslint-disable-next-line max-len */ @@ -135,7 +135,7 @@ class Cache extends BaseCommand { log.warn(`Not Found: ${key}`) break } - this.npm.output(`Deleted: ${key}`) + output.standard(`Deleted: ${key}`) await cacache.rm.entry(cachePath, key) // XXX this could leave other entries without content! await cacache.rm.content(cachePath, entry.integrity) @@ -170,20 +170,20 @@ class Cache extends BaseCommand { ? `~${cache.slice(process.env.HOME.length)}` : cache const stats = await cacache.verify(cache) - this.npm.output(`Cache verified and compressed (${prefix})`) - this.npm.output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`) + output.standard(`Cache verified and compressed (${prefix})`) + output.standard(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`) if (stats.badContentCount) { - this.npm.output(`Corrupted content removed: ${stats.badContentCount}`) + output.standard(`Corrupted content removed: ${stats.badContentCount}`) } if (stats.reclaimedCount) { /* eslint-disable-next-line max-len */ - this.npm.output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) + output.standard(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`) } if (stats.missingContent) { - this.npm.output(`Missing content: ${stats.missingContent}`) + output.standard(`Missing content: ${stats.missingContent}`) } - this.npm.output(`Index entries: ${stats.totalEntries}`) - this.npm.output(`Finished in ${stats.runTime.total / 1000}s`) + output.standard(`Index entries: ${stats.totalEntries}`) + output.standard(`Finished in ${stats.runTime.total / 1000}s`) } // npm cache ls [--package ...] @@ -203,10 +203,10 @@ class Cache extends BaseCommand { results.add(key) } } - [...results].sort(localeCompare).forEach(key => this.npm.output(key)) + [...results].sort(localeCompare).forEach(key => output.standard(key)) return } - cacheKeys.sort(localeCompare).forEach(key => this.npm.output(key)) + cacheKeys.sort(localeCompare).forEach(key => output.standard(key)) } } diff --git a/lib/commands/completion.js b/lib/commands/completion.js index 59113c50560bc..677d7fa2ec3fe 100644 --- a/lib/commands/completion.js +++ b/lib/commands/completion.js @@ -32,6 +32,7 @@ const fs = require('fs/promises') const nopt = require('nopt') const { resolve } = require('path') +const { output } = require('proc-log') const Npm = require('../npm.js') const { definitions, shorthands } = require('@npmcli/config/lib/definitions') @@ -185,7 +186,7 @@ class Completion extends BaseCommand { } if (compls.length > 0) { - this.npm.output(compls.join('\n')) + output.standard(compls.join('\n')) } } } diff --git a/lib/commands/config.js b/lib/commands/config.js index fcd21cc1f8d51..b1273120cf9ee 100644 --- a/lib/commands/config.js +++ b/lib/commands/config.js @@ -6,7 +6,7 @@ const ini = require('ini') const localeCompare = require('@isaacs/string-locale-compare')('en') const pkgJson = require('@npmcli/package-json') const { defaults, definitions } = require('@npmcli/config/lib/definitions') -const { log } = require('proc-log') +const { log, output } = require('proc-log') // These are the configs that we can nerf-dart. Not all of them currently even // *have* config definitions so we have to explicitly validate them here @@ -185,7 +185,7 @@ class Config extends BaseCommand { const pref = keys.length > 1 ? `${key}=` : '' out.push(pref + this.npm.config.get(key)) } - this.npm.output(out.join('\n')) + output.standard(out.join('\n')) } async del (keys) { @@ -282,7 +282,7 @@ ${defData} this.npm.config.repair(problems) const locations = [] - this.npm.output('The following configuration problems have been repaired:\n') + output.standard('The following configuration problems have been repaired:\n') const summary = problems.map(({ action, from, to, key, where }) => { // coverage disabled for else branch because it is intentionally omitted // istanbul ignore else @@ -295,7 +295,7 @@ ${defData} return `- \`${key}\` deleted from ${where} config` } }).join('\n') - this.npm.output(summary) + output.standard(summary) return await Promise.all(locations.map((location) => this.npm.config.save(location))) } @@ -354,7 +354,7 @@ ${defData} } } - this.npm.output(msg.join('\n').trim()) + output.standard(msg.join('\n').trim()) } async listJson () { @@ -366,7 +366,7 @@ ${defData} publicConf[key] = this.npm.config.get(key) } - this.npm.output(JSON.stringify(publicConf, null, 2)) + output.standard(JSON.stringify(publicConf, null, 2)) } } diff --git a/lib/commands/diff.js b/lib/commands/diff.js index bdd72e4dec99a..e188a38505867 100644 --- a/lib/commands/diff.js +++ b/lib/commands/diff.js @@ -4,7 +4,7 @@ const libnpmdiff = require('libnpmdiff') const npa = require('npm-package-arg') const pacote = require('pacote') const pickManifest = require('npm-pick-manifest') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') @@ -64,7 +64,7 @@ class Diff extends BaseCommand { diffFiles: args, where: this.top, }) - return this.npm.output(res) + return output.standard(res) } async execWorkspaces (args) { diff --git a/lib/commands/dist-tag.js b/lib/commands/dist-tag.js index c6b795c57b70c..741890fc9cec7 100644 --- a/lib/commands/dist-tag.js +++ b/lib/commands/dist-tag.js @@ -1,7 +1,7 @@ const npa = require('npm-package-arg') const regFetch = require('npm-registry-fetch') const semver = require('semver') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const otplease = require('../utils/otplease.js') const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') @@ -120,7 +120,7 @@ class DistTag extends BaseCommand { spec, } await otplease(this.npm, reqOpts, o => regFetch(url, o)) - this.npm.output(`+${t}: ${spec.name}@${version}`) + output.standard(`+${t}: ${spec.name}@${version}`) } async remove (spec, tag, opts) { @@ -146,7 +146,7 @@ class DistTag extends BaseCommand { spec, } await otplease(this.npm, reqOpts, o => regFetch(url, o)) - this.npm.output(`-${tag}: ${spec.name}@${version}`) + output.standard(`-${tag}: ${spec.name}@${version}`) } async list (spec, opts) { @@ -167,7 +167,7 @@ class DistTag extends BaseCommand { const tags = await this.fetchTags(spec, opts) const msg = Object.keys(tags).map(k => `${k}: ${tags[k]}`).sort().join('\n') - this.npm.output(msg) + output.standard(msg) return tags } catch (err) { log.error('dist-tag ls', "Couldn't get dist-tag data for", spec) @@ -180,7 +180,7 @@ class DistTag extends BaseCommand { for (const name of this.workspaceNames) { try { - this.npm.output(`${name}:`) + output.standard(`${name}:`) await this.list(npa(name), this.npm.flatOptions) } catch (err) { // set the exitCode directly, but ignore the error diff --git a/lib/commands/doctor.js b/lib/commands/doctor.js index fc1eb42efc587..e3177f7a45544 100644 --- a/lib/commands/doctor.js +++ b/lib/commands/doctor.js @@ -7,7 +7,7 @@ const pacote = require('pacote') const { resolve } = require('path') const semver = require('semver') const { promisify } = require('util') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const ping = require('../utils/ping.js') const { defaults } = require('@npmcli/config/lib/definitions') const lstat = promisify(fs.lstat) @@ -374,7 +374,7 @@ class Doctor extends BaseCommand { colWidths: [this.#checkWidth, 6], }) t.push(row) - this.npm.output(t.toString()) + output.standard(t.toString()) } actions (params) { diff --git a/lib/commands/exec.js b/lib/commands/exec.js index d532eca107c6c..f181bbb2ef6fe 100644 --- a/lib/commands/exec.js +++ b/lib/commands/exec.js @@ -65,7 +65,6 @@ class Exec extends BaseCommand { globalDir, chalk, } = this.npm - const output = this.npm.output.bind(this.npm) const scriptShell = this.npm.config.get('script-shell') || undefined const packages = this.npm.config.get('package') const yes = this.npm.config.get('yes') @@ -93,7 +92,6 @@ class Exec extends BaseCommand { globalPath, localBin, locationMsg, - output, packages, path, runPath, diff --git a/lib/commands/explain.js b/lib/commands/explain.js index 403274db68dfa..98ef356bfc1b3 100644 --- a/lib/commands/explain.js +++ b/lib/commands/explain.js @@ -3,6 +3,7 @@ const npa = require('npm-package-arg') const semver = require('semver') const { relative, resolve } = require('path') const validName = require('validate-npm-package-name') +const { output } = require('proc-log') const ArboristWorkspaceCmd = require('../arborist-cmd.js') class Explain extends ArboristWorkspaceCmd { @@ -75,9 +76,9 @@ class Explain extends ArboristWorkspaceCmd { } if (this.npm.flatOptions.json) { - this.npm.output(JSON.stringify(expls, null, 2)) + output.standard(JSON.stringify(expls, null, 2)) } else { - this.npm.output(expls.map(expl => { + output.standard(expls.map(expl => { return explainNode(expl, Infinity, this.npm.chalk) }).join('\n\n')) } diff --git a/lib/commands/explore.js b/lib/commands/explore.js index c24565b5c0c42..ef4743e62197d 100644 --- a/lib/commands/explore.js +++ b/lib/commands/explore.js @@ -4,7 +4,7 @@ const pkgJson = require('@npmcli/package-json') const runScript = require('@npmcli/run-script') const { join, relative } = require('path') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const completion = require('../utils/completion/installed-shallow.js') const BaseCommand = require('../base-command.js') @@ -50,7 +50,7 @@ class Explore extends BaseCommand { } if (!args.length) { - this.npm.output(`\nExploring ${path}\nType 'exit' or ^D when finished\n`) + output.standard(`\nExploring ${path}\nType 'exit' or ^D when finished\n`) } return runScript({ diff --git a/lib/commands/fund.js b/lib/commands/fund.js index 2804d36cd5603..aa8c7b17b48b6 100644 --- a/lib/commands/fund.js +++ b/lib/commands/fund.js @@ -1,6 +1,7 @@ const archy = require('archy') const pacote = require('pacote') const semver = require('semver') +const { output } = require('proc-log') const npa = require('npm-package-arg') const { depth } = require('treeverse') const { readTree: getFundingInfo, normalizeFunding, isValidFunding } = require('libnpmfund') @@ -85,9 +86,9 @@ class Fund extends ArboristWorkspaceCmd { }) if (this.npm.config.get('json')) { - this.npm.output(this.printJSON(fundingInfo)) + output.standard(this.printJSON(fundingInfo)) } else { - this.npm.output(this.printHuman(fundingInfo)) + output.standard(this.printHuman(fundingInfo)) } } @@ -212,7 +213,7 @@ class Fund extends ArboristWorkspaceCmd { if (fundingSourceNumber) { ambiguousUrlMsg.unshift(`--which=${fundingSourceNumber} is not a valid index`) } - this.npm.output(ambiguousUrlMsg.join('\n')) + output.standard(ambiguousUrlMsg.join('\n')) } urlMessage (source) { diff --git a/lib/commands/help-search.js b/lib/commands/help-search.js index 273807c7469af..c3719d48f2f5a 100644 --- a/lib/commands/help-search.js +++ b/lib/commands/help-search.js @@ -1,6 +1,7 @@ const { readFile } = require('fs/promises') const path = require('path') const { glob } = require('glob') +const { output } = require('proc-log') const BaseCommand = require('../base-command.js') const globify = pattern => pattern.split('\\').join('/') @@ -24,9 +25,9 @@ class HelpSearch extends BaseCommand { const results = await this.searchFiles(args, data, files) const formatted = this.formatResults(args, results) if (!formatted.trim()) { - this.npm.output(`No matches in help for: ${args.join(' ')}\n`) + output.standard(`No matches in help for: ${args.join(' ')}\n`) } else { - this.npm.output(formatted) + output.standard(formatted) } } @@ -140,7 +141,7 @@ class HelpSearch extends BaseCommand { formatResults (args, results) { const cols = Math.min(process.stdout.columns || Infinity, 80) + 1 - const output = results.map(res => { + const formattedOutput = results.map(res => { const out = [res.cmd] const r = Object.keys(res.hits) .map(k => `${k}:${res.hits[k]}`) @@ -183,10 +184,10 @@ class HelpSearch extends BaseCommand { const finalOut = results.length && !this.npm.config.get('long') ? 'Top hits for ' + (args.map(JSON.stringify).join(' ')) + '\n' + '—'.repeat(cols - 1) + '\n' + - output + '\n' + + formattedOutput + '\n' + '—'.repeat(cols - 1) + '\n' + '(run with -l or --long to see more context)' - : output + : formattedOutput return finalOut.trim() } diff --git a/lib/commands/help.js b/lib/commands/help.js index 39c580f9a6871..1f51713a8d051 100644 --- a/lib/commands/help.js +++ b/lib/commands/help.js @@ -2,6 +2,7 @@ const spawn = require('@npmcli/promise-spawn') const path = require('path') const openUrl = require('../utils/open-url.js') const { glob } = require('glob') +const { output } = require('proc-log') const localeCompare = require('@isaacs/string-locale-compare')('en') const { deref } = require('../utils/cmd-list.js') @@ -50,7 +51,7 @@ class Help extends BaseCommand { const manSearch = /^\d+$/.test(args[0]) ? `man${args.shift()}` : 'man*' if (!args.length) { - return this.npm.output(this.npm.usage) + return output.standard(this.npm.usage) } // npm help foo bar baz: search topics diff --git a/lib/commands/hook.js b/lib/commands/hook.js index b0f52a801f571..5e6b593cccfd6 100644 --- a/lib/commands/hook.js +++ b/lib/commands/hook.js @@ -2,6 +2,7 @@ const hookApi = require('libnpmhook') const otplease = require('../utils/otplease.js') const relativeDate = require('tiny-relative-date') const Table = require('cli-table3') +const { output } = require('proc-log') const BaseCommand = require('../base-command.js') class Hook extends BaseCommand { @@ -40,31 +41,31 @@ class Hook extends BaseCommand { async add (pkg, uri, secret, opts) { const hook = await hookApi.add(pkg, uri, secret, opts) if (opts.json) { - this.npm.output(JSON.stringify(hook, null, 2)) + output.standard(JSON.stringify(hook, null, 2)) } else if (opts.parseable) { - this.npm.output(Object.keys(hook).join('\t')) - this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) + output.standard(Object.keys(hook).join('\t')) + output.standard(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!this.npm.silent) { - this.npm.output(`+ ${this.hookName(hook)} ${opts.unicode ? ' ➜ ' : ' -> '} ${hook.endpoint}`) + output.standard(`+ ${this.hookName(hook)} ${opts.unicode ? ' ➜ ' : ' -> '} ${hook.endpoint}`) } } async ls (pkg, opts) { const hooks = await hookApi.ls({ ...opts, package: pkg }) if (opts.json) { - this.npm.output(JSON.stringify(hooks, null, 2)) + output.standard(JSON.stringify(hooks, null, 2)) } else if (opts.parseable) { - this.npm.output(Object.keys(hooks[0]).join('\t')) + output.standard(Object.keys(hooks[0]).join('\t')) hooks.forEach(hook => { - this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) + output.standard(Object.keys(hook).map(k => hook[k]).join('\t')) }) } else if (!hooks.length) { - this.npm.output("You don't have any hooks configured yet.") + output.standard("You don't have any hooks configured yet.") } else if (!this.npm.silent) { if (hooks.length === 1) { - this.npm.output('You have one hook configured.') + output.standard('You have one hook configured.') } else { - this.npm.output(`You have ${hooks.length} hooks configured.`) + output.standard(`You have ${hooks.length} hooks configured.`) } const table = new Table({ head: ['id', 'target', 'endpoint'] }) @@ -86,31 +87,31 @@ class Hook extends BaseCommand { table.push([{ colSpan: 2, content: 'never triggered' }]) } }) - this.npm.output(table.toString()) + output.standard(table.toString()) } } async rm (id, opts) { const hook = await hookApi.rm(id, opts) if (opts.json) { - this.npm.output(JSON.stringify(hook, null, 2)) + output.standard(JSON.stringify(hook, null, 2)) } else if (opts.parseable) { - this.npm.output(Object.keys(hook).join('\t')) - this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) + output.standard(Object.keys(hook).join('\t')) + output.standard(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!this.npm.silent) { - this.npm.output(`- ${this.hookName(hook)} ${opts.unicode ? ' ✘ ' : ' X '} ${hook.endpoint}`) + output.standard(`- ${this.hookName(hook)} ${opts.unicode ? ' ✘ ' : ' X '} ${hook.endpoint}`) } } async update (id, uri, secret, opts) { const hook = await hookApi.update(id, uri, secret, opts) if (opts.json) { - this.npm.output(JSON.stringify(hook, null, 2)) + output.standard(JSON.stringify(hook, null, 2)) } else if (opts.parseable) { - this.npm.output(Object.keys(hook).join('\t')) - this.npm.output(Object.keys(hook).map(k => hook[k]).join('\t')) + output.standard(Object.keys(hook).join('\t')) + output.standard(Object.keys(hook).map(k => hook[k]).join('\t')) } else if (!this.npm.silent) { - this.npm.output(`+ ${this.hookName(hook)} ${opts.unicode ? ' ➜ ' : ' -> '} ${hook.endpoint}`) + output.standard(`+ ${this.hookName(hook)} ${opts.unicode ? ' ➜ ' : ' -> '} ${hook.endpoint}`) } } diff --git a/lib/commands/init.js b/lib/commands/init.js index d3d2efd60589d..d45dbaa1fa0d7 100644 --- a/lib/commands/init.js +++ b/lib/commands/init.js @@ -6,7 +6,7 @@ const npa = require('npm-package-arg') const libexec = require('libnpmexec') const mapWorkspaces = require('@npmcli/map-workspaces') const PackageJson = require('@npmcli/package-json') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const updateWorkspaces = require('../workspaces/update-workspaces.js') const posixPath = p => p.split('\\').join('/') @@ -130,7 +130,6 @@ class Init extends BaseCommand { globalBin, chalk, } = this.npm - const output = this.npm.output.bind(this.npm) const runPath = path const scriptShell = this.npm.config.get('script-shell') || undefined const yes = this.npm.config.get('yes') @@ -154,7 +153,7 @@ class Init extends BaseCommand { const initFile = this.npm.config.get('init-module') if (!this.npm.config.get('yes') && !this.npm.config.get('force')) { - this.npm.output([ + output.standard([ '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/commands/login.js b/lib/commands/login.js index 87e598debcd31..d38aec51289cc 100644 --- a/lib/commands/login.js +++ b/lib/commands/login.js @@ -1,4 +1,4 @@ -const { log } = require('proc-log') +const { log, output } = require('proc-log') const { redactLog: replaceInfo } = require('@npmcli/redact') const auth = require('../utils/auth.js') @@ -44,7 +44,7 @@ class Login extends BaseCommand { await this.npm.config.save('user') - this.npm.output(message) + output.standard(message) } } module.exports = Login diff --git a/lib/commands/ls.js b/lib/commands/ls.js index aef3be2828a5a..ff954dec49cc7 100644 --- a/lib/commands/ls.js +++ b/lib/commands/ls.js @@ -4,6 +4,7 @@ const relativePrefix = `.${sep}` const archy = require('archy') const { breadth } = require('treeverse') const npa = require('npm-package-arg') +const { output } = require('proc-log') const _depth = Symbol('depth') const _dedupe = Symbol('dedupe') @@ -176,7 +177,7 @@ class LS extends ArboristWorkspaceCmd { const [rootError] = tree.errors.filter(e => e.code === 'EJSONPARSE' && e.path === resolve(path, 'package.json')) - this.npm.outputBuffer( + output.buffer( json ? jsonOutput({ path, problems, result, rootError, seenItems }) : parseable ? parseableOutput({ seenNodes, global, long }) : humanOutput({ chalk, result, seenItems, unicode }) diff --git a/lib/commands/org.js b/lib/commands/org.js index 1f32d41ff7306..8881ded70f638 100644 --- a/lib/commands/org.js +++ b/lib/commands/org.js @@ -2,6 +2,7 @@ const liborg = require('libnpmorg') const otplease = require('../utils/otplease.js') const Table = require('cli-table3') const BaseCommand = require('../base-command.js') +const { output } = require('proc-log') class Org extends BaseCommand { static description = 'Manage orgs' @@ -68,14 +69,14 @@ class Org extends BaseCommand { const memDeets = await liborg.set(org, user, role, opts) if (opts.json) { - this.npm.output(JSON.stringify(memDeets, null, 2)) + output.standard(JSON.stringify(memDeets, null, 2)) } else if (opts.parseable) { - this.npm.output(['org', 'orgsize', 'user', 'role'].join('\t')) - this.npm.output( + output.standard(['org', 'orgsize', 'user', 'role'].join('\t')) + output.standard( [memDeets.org.name, memDeets.org.size, memDeets.user, memDeets.role].join('\t') ) } else if (!this.npm.silent) { - this.npm.output( + output.standard( `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.` @@ -100,7 +101,7 @@ class Org extends BaseCommand { org = org.replace(/^[~@]?/, '') const userCount = Object.keys(roster).length if (opts.json) { - this.npm.output( + output.standard( JSON.stringify({ user, org, @@ -109,10 +110,10 @@ class Org extends BaseCommand { }) ) } else if (opts.parseable) { - this.npm.output(['user', 'org', 'userCount', 'deleted'].join('\t')) - this.npm.output([user, org, userCount, true].join('\t')) + output.standard(['user', 'org', 'userCount', 'deleted'].join('\t')) + output.standard([user, org, userCount, true].join('\t')) } else if (!this.npm.silent) { - this.npm.output( + output.standard( `Successfully removed ${user} from ${org}. You now have ${userCount} member${ userCount === 1 ? '' : 's' } in this org.` @@ -135,11 +136,11 @@ class Org extends BaseCommand { roster = newRoster } if (opts.json) { - this.npm.output(JSON.stringify(roster, null, 2)) + output.standard(JSON.stringify(roster, null, 2)) } else if (opts.parseable) { - this.npm.output(['user', 'role'].join('\t')) + output.standard(['user', 'role'].join('\t')) Object.keys(roster).forEach(u => { - this.npm.output([u, roster[u]].join('\t')) + output.standard([u, roster[u]].join('\t')) }) } else if (!this.npm.silent) { const table = new Table({ head: ['user', 'role'] }) @@ -148,7 +149,7 @@ class Org extends BaseCommand { .forEach(u => { table.push([u, roster[u]]) }) - this.npm.output(table.toString()) + output.standard(table.toString()) } } } diff --git a/lib/commands/outdated.js b/lib/commands/outdated.js index 27b29b314b745..a75afe18e6d93 100644 --- a/lib/commands/outdated.js +++ b/lib/commands/outdated.js @@ -4,6 +4,7 @@ const pacote = require('pacote') const table = require('text-table') const npa = require('npm-package-arg') const pickManifest = require('npm-pick-manifest') +const { output } = require('proc-log') const localeCompare = require('@isaacs/string-locale-compare')('en') const ArboristWorkspaceCmd = require('../arborist-cmd.js') @@ -83,9 +84,9 @@ class Outdated extends ArboristWorkspaceCmd { // display results if (this.npm.config.get('json')) { - this.npm.output(this.makeJSON(outdated)) + output.standard(this.makeJSON(outdated)) } else if (this.npm.config.get('parseable')) { - this.npm.output(this.makeParseable(outdated)) + output.standard(this.makeParseable(outdated)) } else { const outList = outdated.map(x => this.makePretty(x)) const outHead = ['Package', @@ -107,7 +108,7 @@ class Outdated extends ArboristWorkspaceCmd { align: ['l', 'r', 'r', 'r', 'l'], stringLength: s => stripVTControlCharacters(s).length, } - this.npm.output(table(outTable, tableOpts)) + output.standard(table(outTable, tableOpts)) } } diff --git a/lib/commands/owner.js b/lib/commands/owner.js index ccb85fae91f55..cfd40df2151e6 100644 --- a/lib/commands/owner.js +++ b/lib/commands/owner.js @@ -1,7 +1,7 @@ const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') const pacote = require('pacote') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const otplease = require('../utils/otplease.js') const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') @@ -115,9 +115,9 @@ class Owner extends BaseCommand { const packumentOpts = { ...this.npm.flatOptions, fullMetadata: true, preferOnline: true } const { maintainers } = await pacote.packument(spec, packumentOpts) if (!maintainers || !maintainers.length) { - this.npm.output('no admin found') + output.standard('no admin found') } else { - this.npm.output(maintainers.map(m => `${m.name} <${m.email}>`).join('\n')) + output.standard(maintainers.map(m => `${m.name} <${m.email}>`).join('\n')) } } catch (err) { log.error('owner ls', "Couldn't get owner data", redact(pkg)) @@ -216,9 +216,9 @@ class Owner extends BaseCommand { }) }) if (addOrRm === 'add') { - this.npm.output(`+ ${user} (${spec.name})`) + output.standard(`+ ${user} (${spec.name})`) } else { - this.npm.output(`- ${user} (${spec.name})`) + output.standard(`- ${user} (${spec.name})`) } return res } catch (err) { diff --git a/lib/commands/pack.js b/lib/commands/pack.js index b482c54dc7ac4..463329235d417 100644 --- a/lib/commands/pack.js +++ b/lib/commands/pack.js @@ -1,7 +1,7 @@ const pacote = require('pacote') const libpack = require('libnpmpack') const npa = require('npm-package-arg') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const { getContents, logTar } = require('../utils/tar.js') const BaseCommand = require('../base-command.js') @@ -58,13 +58,13 @@ class Pack extends BaseCommand { } if (json) { - this.npm.output(JSON.stringify(tarballs, null, 2)) + output.standard(JSON.stringify(tarballs, null, 2)) return } for (const tar of tarballs) { logTar(tar, { unicode }) - this.npm.output(tar.filename.replace(/^@/, '').replace(/\//, '-')) + output.standard(tar.filename.replace(/^@/, '').replace(/\//, '-')) } } diff --git a/lib/commands/ping.js b/lib/commands/ping.js index a16278fc3e130..3ae4ed80a22cb 100644 --- a/lib/commands/ping.js +++ b/lib/commands/ping.js @@ -1,5 +1,5 @@ const { redact } = require('@npmcli/redact') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const pingUtil = require('../utils/ping.js') const BaseCommand = require('../base-command.js') @@ -16,7 +16,7 @@ class Ping extends BaseCommand { const time = Date.now() - start log.notice('PONG', `${time}ms`) if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify({ + output.standard(JSON.stringify({ registry: cleanRegistry, time, details, diff --git a/lib/commands/pkg.js b/lib/commands/pkg.js index 49a66823cca99..26e60fec48786 100644 --- a/lib/commands/pkg.js +++ b/lib/commands/pkg.js @@ -1,3 +1,4 @@ +const { output } = require('proc-log') const PackageJson = require('@npmcli/package-json') const BaseCommand = require('../base-command.js') const Queryable = require('../utils/queryable.js') @@ -62,7 +63,7 @@ class Pkg extends BaseCommand { } // when running in workspaces names, make sure to key by workspace // name the results of each value retrieved in each ws - this.npm.output(JSON.stringify(result, null, 2)) + output.standard(JSON.stringify(result, null, 2)) } async get (args) { @@ -85,7 +86,7 @@ class Pkg extends BaseCommand { // only outputs if not running with workspaces config // execWorkspaces will handle the output otherwise if (!this.workspaces) { - this.npm.output(JSON.stringify(result, null, 2)) + output.standard(JSON.stringify(result, null, 2)) } return result diff --git a/lib/commands/prefix.js b/lib/commands/prefix.js index 264b819fc7692..6c3d6f886f12c 100644 --- a/lib/commands/prefix.js +++ b/lib/commands/prefix.js @@ -1,3 +1,4 @@ +const { output } = require('proc-log') const BaseCommand = require('../base-command.js') class Prefix extends BaseCommand { @@ -7,7 +8,7 @@ class Prefix extends BaseCommand { static usage = ['[-g]'] async exec (args) { - return this.npm.output(this.npm.prefix) + return output.standard(this.npm.prefix) } } module.exports = Prefix diff --git a/lib/commands/profile.js b/lib/commands/profile.js index 5ef0d0dbe7c57..98a8dcd050ee9 100644 --- a/lib/commands/profile.js +++ b/lib/commands/profile.js @@ -1,6 +1,6 @@ const inspect = require('util').inspect const { URL } = require('url') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const npmProfile = require('npm-profile') const qrcodeTerminal = require('qrcode-terminal') const Table = require('cli-table3') @@ -110,7 +110,7 @@ class Profile extends BaseCommand { } if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify(info, null, 2)) + output.standard(JSON.stringify(info, null, 2)) return } @@ -142,14 +142,14 @@ class Profile extends BaseCommand { .filter((arg) => arg.trim() !== '') .map((arg) => cleaned[arg]) .join('\t') - this.npm.output(values) + output.standard(values) } else { if (this.npm.config.get('parseable')) { for (const key of Object.keys(info)) { if (key === 'tfa') { - this.npm.output(`${key}\t${cleaned[tfa]}`) + output.standard(`${key}\t${cleaned[tfa]}`) } else { - this.npm.output(`${key}\t${info[key]}`) + output.standard(`${key}\t${info[key]}`) } } } else { @@ -158,7 +158,7 @@ class Profile extends BaseCommand { table.push({ [this.npm.chalk.bold(key)]: cleaned[key] }) } - this.npm.output(table.toString()) + output.standard(table.toString()) } } } @@ -216,13 +216,13 @@ class Profile extends BaseCommand { const result = await otplease(this.npm, conf, c => npmProfile.set(newUser, c)) if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify({ [prop]: result[prop] }, null, 2)) + output.standard(JSON.stringify({ [prop]: result[prop] }, null, 2)) } else if (this.npm.config.get('parseable')) { - this.npm.output(prop + '\t' + result[prop]) + output.standard(prop + '\t' + result[prop]) } else if (result[prop] != null) { - this.npm.output('Set', prop, 'to', result[prop]) + output.standard('Set', prop, 'to', result[prop]) } else { - this.npm.output('Set', prop) + output.standard('Set', prop) } } @@ -320,7 +320,7 @@ class Profile extends BaseCommand { const challenge = await npmProfile.set(info, conf) if (challenge.tfa === null) { - this.npm.output('Two factor authentication mode changed to: ' + mode) + output.standard('Two factor authentication mode changed to: ' + mode) return } @@ -337,7 +337,7 @@ class Profile extends BaseCommand { const secret = otpauth.searchParams.get('secret') const code = await qrcode(challenge.tfa) - this.npm.output( + output.standard( 'Scan into your authenticator app:\n' + code + '\n Or enter code:', secret ) @@ -348,17 +348,17 @@ class Profile extends BaseCommand { const result = await npmProfile.set({ tfa: [interactiveOTP] }, conf) - this.npm.output( + output.standard( '2FA successfully enabled. Below are your recovery codes, ' + 'please print these out.' ) - this.npm.output( + output.standard( 'You will need these to recover access to your account ' + 'if you lose your authentication device.' ) for (const tfaCode of result.tfa) { - this.npm.output('\t' + tfaCode) + output.standard('\t' + tfaCode) } } @@ -367,7 +367,7 @@ class Profile extends BaseCommand { const info = await npmProfile.get(conf) if (!info.tfa || info.tfa.pending) { - this.npm.output('Two factor authentication not enabled.') + output.standard('Two factor authentication not enabled.') return } @@ -383,11 +383,11 @@ class Profile extends BaseCommand { await npmProfile.set({ tfa: { password: password, mode: 'disable' } }, conf) if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify({ tfa: false }, null, 2)) + output.standard(JSON.stringify({ tfa: false }, null, 2)) } else if (this.npm.config.get('parseable')) { - this.npm.output('tfa\tfalse') + output.standard('tfa\tfalse') } else { - this.npm.output('Two factor authentication disabled.') + output.standard('Two factor authentication disabled.') } } } diff --git a/lib/commands/publish.js b/lib/commands/publish.js index 94a36d8d41212..8758422f5e9a7 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -1,4 +1,4 @@ -const { log } = require('proc-log') +const { log, output } = require('proc-log') const semver = require('semver') const pack = require('libnpmpack') const libpub = require('libnpmpublish').publish @@ -142,9 +142,9 @@ class Publish extends BaseCommand { if (!this.suppressOutput) { if (!silent && json) { - this.npm.output(JSON.stringify(pkgContents, null, 2)) + output.standard(JSON.stringify(pkgContents, null, 2)) } else if (!silent) { - this.npm.output(`+ ${pkgContents.id}`) + output.standard(`+ ${pkgContents.id}`) } } @@ -181,14 +181,14 @@ class Publish extends BaseCommand { // This needs to be in-line w/ the rest of the output that non-JSON // publish generates if (!silent && !json) { - this.npm.output(`+ ${pkgContents.id}`) + output.standard(`+ ${pkgContents.id}`) } else { results[name] = pkgContents } } if (!silent && json) { - this.npm.output(JSON.stringify(results, null, 2)) + output.standard(JSON.stringify(results, null, 2)) } } diff --git a/lib/commands/query.js b/lib/commands/query.js index 6bee73d1ba2ad..319d3ee0cc293 100644 --- a/lib/commands/query.js +++ b/lib/commands/query.js @@ -2,7 +2,7 @@ const { resolve } = require('path') const BaseCommand = require('../base-command.js') -const { log } = require('proc-log') +const { log, output } = require('proc-log') class QuerySelectorItem { constructor (node) { @@ -83,7 +83,7 @@ class Query extends BaseCommand { this.buildResponse(items) this.checkExpected(this.#response.length) - this.npm.output(this.parsedResponse) + output.standard(this.parsedResponse) } async execWorkspaces (args) { @@ -107,7 +107,7 @@ class Query extends BaseCommand { this.buildResponse(items) } this.checkExpected(this.#response.length) - this.npm.output(this.parsedResponse) + output.standard(this.parsedResponse) } // builds a normalized inventory diff --git a/lib/commands/rebuild.js b/lib/commands/rebuild.js index 8af96f725555c..8858edd1da349 100644 --- a/lib/commands/rebuild.js +++ b/lib/commands/rebuild.js @@ -1,4 +1,5 @@ const { resolve } = require('path') +const { output } = require('proc-log') const npa = require('npm-package-arg') const semver = require('semver') @@ -56,7 +57,7 @@ class Rebuild extends ArboristWorkspaceCmd { await arb.rebuild() } - this.npm.output('rebuilt dependencies successfully') + output.standard('rebuilt dependencies successfully') } isNode (specs, node) { diff --git a/lib/commands/root.js b/lib/commands/root.js index 7749c602456b7..f1f9579d103fd 100644 --- a/lib/commands/root.js +++ b/lib/commands/root.js @@ -1,3 +1,4 @@ +const { output } = require('proc-log') const BaseCommand = require('../base-command.js') class Root extends BaseCommand { static description = 'Display npm root' @@ -5,7 +6,7 @@ class Root extends BaseCommand { static params = ['global'] async exec () { - this.npm.output(this.npm.dir) + output.standard(this.npm.dir) } } module.exports = Root diff --git a/lib/commands/run-script.js b/lib/commands/run-script.js index 2a7142a881941..d86f9b7326e3b 100644 --- a/lib/commands/run-script.js +++ b/lib/commands/run-script.js @@ -1,7 +1,7 @@ const runScript = require('@npmcli/run-script') const { isServerPackage } = runScript const pkgJson = require('@npmcli/package-json') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const didYouMean = require('../utils/did-you-mean.js') const { isWindowsShell } = require('../utils/is-windows.js') @@ -135,13 +135,13 @@ class RunScript extends BaseCommand { } if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify(scripts, null, 2)) + output.standard(JSON.stringify(scripts, null, 2)) return allScripts } if (this.npm.config.get('parseable')) { for (const [script, cmd] of Object.entries(scripts)) { - this.npm.output(`${script}:${cmd}`) + output.standard(`${script}:${cmd}`) } return allScripts @@ -158,7 +158,7 @@ class RunScript extends BaseCommand { const colorize = this.npm.chalk if (cmds.length) { - this.npm.output( + output.standard( `${colorize.reset(colorize.bold('Lifecycle scripts'))} included in ${colorize.green( pkgid )}:` @@ -166,24 +166,24 @@ class RunScript extends BaseCommand { } for (const script of cmds) { - this.npm.output(prefix + script + indent + colorize.dim(scripts[script])) + output.standard(prefix + script + indent + colorize.dim(scripts[script])) } if (!cmds.length && runScripts.length) { - this.npm.output( + output.standard( `${colorize.bold('Scripts')} available in ${colorize.green(pkgid)} via \`${colorize.blue( 'npm run-script' )}\`:` ) } else if (runScripts.length) { - this.npm.output(`\navailable via \`${colorize.blue('npm run-script')}\`:`) + output.standard(`\navailable via \`${colorize.blue('npm run-script')}\`:`) } for (const script of runScripts) { - this.npm.output(prefix + script + indent + colorize.dim(scripts[script])) + output.standard(prefix + script + indent + colorize.dim(scripts[script])) } - this.npm.output('') + output.standard('') return allScripts } @@ -220,7 +220,7 @@ class RunScript extends BaseCommand { const { content: { scripts, name } } = await pkgJson.normalize(workspacePath) res[name] = { ...scripts } } - this.npm.output(JSON.stringify(res, null, 2)) + output.standard(JSON.stringify(res, null, 2)) return } @@ -228,7 +228,7 @@ class RunScript extends BaseCommand { for (const workspacePath of this.workspacePaths) { const { content: { scripts, name } } = await pkgJson.normalize(workspacePath) for (const [script, cmd] of Object.entries(scripts || {})) { - this.npm.output(`${name}:${script}:${cmd}`) + output.standard(`${name}:${script}:${cmd}`) } } return diff --git a/lib/commands/sbom.js b/lib/commands/sbom.js index aea94099ef3b9..4b20bf5ea1f76 100644 --- a/lib/commands/sbom.js +++ b/lib/commands/sbom.js @@ -2,7 +2,7 @@ const localeCompare = require('@isaacs/string-locale-compare')('en') const BaseCommand = require('../base-command.js') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const { cyclonedxOutput } = require('../utils/sbom-cyclonedx.js') const { spdxOutput } = require('../utils/sbom-spdx.js') @@ -86,7 +86,7 @@ class SBOM extends BaseCommand { items .sort((a, b) => localeCompare(a.location, b.location)) ) - this.npm.output(this.#parsedResponse) + output.standard(this.#parsedResponse) } async execWorkspaces (args) { diff --git a/lib/commands/search.js b/lib/commands/search.js index d1db948b34ba9..4a69c77a256e7 100644 --- a/lib/commands/search.js +++ b/lib/commands/search.js @@ -1,7 +1,7 @@ const { Minipass } = require('minipass') const Pipeline = require('minipass-pipeline') const libSearch = require('libnpmsearch') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const formatSearchStream = require('../utils/format-search-stream.js') @@ -99,12 +99,12 @@ class Search extends BaseCommand { if (!anyOutput) { anyOutput = true } - this.npm.output(chunk.toString('utf8')) + output.standard(chunk.toString('utf8')) }) await p.promise() if (!anyOutput && !this.npm.config.get('json') && !this.npm.config.get('parseable')) { - this.npm.output('No matches found for ' + (args.map(JSON.stringify).join(' '))) + output.standard('No matches found for ' + (args.map(JSON.stringify).join(' '))) } log.silly('search', 'search completed') diff --git a/lib/commands/star.js b/lib/commands/star.js index 54ebdb535865d..39165d8c3d8dc 100644 --- a/lib/commands/star.js +++ b/lib/commands/star.js @@ -1,6 +1,6 @@ const fetch = require('npm-registry-fetch') const npa = require('npm-package-arg') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const getIdentity = require('../utils/get-identity') const BaseCommand = require('../base-command.js') @@ -62,7 +62,7 @@ class Star extends BaseCommand { body, }) - this.npm.output(show + ' ' + pkg.name) + output.standard(show + ' ' + pkg.name) log.verbose('star', data) return data } diff --git a/lib/commands/stars.js b/lib/commands/stars.js index f4a8321692f93..1d92d97d7760a 100644 --- a/lib/commands/stars.js +++ b/lib/commands/stars.js @@ -1,5 +1,5 @@ const fetch = require('npm-registry-fetch') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const getIdentity = require('../utils/get-identity.js') const BaseCommand = require('../base-command.js') @@ -25,7 +25,7 @@ class Stars extends BaseCommand { } for (const row of rows) { - this.npm.output(row.value) + output.standard(row.value) } } catch (err) { if (err.code === 'ENEEDAUTH') { diff --git a/lib/commands/team.js b/lib/commands/team.js index 3c6cf305a6e5f..4ffaa5ff86ab9 100644 --- a/lib/commands/team.js +++ b/lib/commands/team.js @@ -1,5 +1,6 @@ const columns = require('cli-columns') const libteam = require('libnpmteam') +const { output } = require('proc-log') const otplease = require('../utils/otplease.js') @@ -68,86 +69,86 @@ class Team extends BaseCommand { async create (entity, opts) { await libteam.create(entity, opts) if (opts.json) { - this.npm.output(JSON.stringify({ + output.standard(JSON.stringify({ created: true, team: entity, })) } else if (opts.parseable) { - this.npm.output(`${entity}\tcreated`) + output.standard(`${entity}\tcreated`) } else if (!this.npm.silent) { - this.npm.output(`+@${entity}`) + output.standard(`+@${entity}`) } } async destroy (entity, opts) { await libteam.destroy(entity, opts) if (opts.json) { - this.npm.output(JSON.stringify({ + output.standard(JSON.stringify({ deleted: true, team: entity, })) } else if (opts.parseable) { - this.npm.output(`${entity}\tdeleted`) + output.standard(`${entity}\tdeleted`) } else if (!this.npm.silent) { - this.npm.output(`-@${entity}`) + output.standard(`-@${entity}`) } } async add (entity, user, opts) { await libteam.add(user, entity, opts) if (opts.json) { - this.npm.output(JSON.stringify({ + output.standard(JSON.stringify({ added: true, team: entity, user, })) } else if (opts.parseable) { - this.npm.output(`${user}\t${entity}\tadded`) + output.standard(`${user}\t${entity}\tadded`) } else if (!this.npm.silent) { - this.npm.output(`${user} added to @${entity}`) + output.standard(`${user} added to @${entity}`) } } async rm (entity, user, opts) { await libteam.rm(user, entity, opts) if (opts.json) { - this.npm.output(JSON.stringify({ + output.standard(JSON.stringify({ removed: true, team: entity, user, })) } else if (opts.parseable) { - this.npm.output(`${user}\t${entity}\tremoved`) + output.standard(`${user}\t${entity}\tremoved`) } else if (!this.npm.silent) { - this.npm.output(`${user} removed from @${entity}`) + output.standard(`${user} removed from @${entity}`) } } async listUsers (entity, opts) { const users = (await libteam.lsUsers(entity, opts)).sort() if (opts.json) { - this.npm.output(JSON.stringify(users, null, 2)) + output.standard(JSON.stringify(users, null, 2)) } else if (opts.parseable) { - this.npm.output(users.join('\n')) + output.standard(users.join('\n')) } else if (!this.npm.silent) { const plural = users.length === 1 ? '' : 's' const more = users.length === 0 ? '' : ':\n' - this.npm.output(`\n@${entity} has ${users.length} user${plural}${more}`) - this.npm.output(columns(users, { padding: 1 })) + output.standard(`\n@${entity} has ${users.length} user${plural}${more}`) + output.standard(columns(users, { padding: 1 })) } } async listTeams (entity, opts) { const teams = (await libteam.lsTeams(entity, opts)).sort() if (opts.json) { - this.npm.output(JSON.stringify(teams, null, 2)) + output.standard(JSON.stringify(teams, null, 2)) } else if (opts.parseable) { - this.npm.output(teams.join('\n')) + output.standard(teams.join('\n')) } else if (!this.npm.silent) { const plural = teams.length === 1 ? '' : 's' const more = teams.length === 0 ? '' : ':\n' - this.npm.output(`\n@${entity} has ${teams.length} team${plural}${more}`) - this.npm.output(columns(teams.map(t => `@${t}`), { padding: 1 })) + output.standard(`\n@${entity} has ${teams.length} team${plural}${more}`) + output.standard(columns(teams.map(t => `@${t}`), { padding: 1 })) } } } diff --git a/lib/commands/token.js b/lib/commands/token.js index d87949fd77af5..ba842f9747948 100644 --- a/lib/commands/token.js +++ b/lib/commands/token.js @@ -1,5 +1,5 @@ const Table = require('cli-table3') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const profile = require('npm-profile') const otplease = require('../utils/otplease.js') @@ -51,12 +51,12 @@ class Token extends BaseCommand { log.info('token', 'getting list') const tokens = profile.listTokens(conf) if (conf.json) { - this.npm.output(JSON.stringify(tokens, null, 2)) + output.standard(JSON.stringify(tokens, null, 2)) return } else if (conf.parseable) { - this.npm.output(['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t')) + output.standard(['key', 'token', 'created', 'readonly', 'CIDR whitelist'].join('\t')) tokens.forEach(token => { - this.npm.output( + output.standard( [ token.key, token.token, @@ -83,7 +83,7 @@ class Token extends BaseCommand { token.cidr_whitelist ? token.cidr_whitelist.join(', ') : '', ]) }) - this.npm.output(table.toString()) + output.standard(table.toString()) } async rm (args) { @@ -119,11 +119,11 @@ class Token extends BaseCommand { }) ) if (conf.json) { - this.npm.output(JSON.stringify(toRemove)) + output.standard(JSON.stringify(toRemove)) } else if (conf.parseable) { - this.npm.output(toRemove.join('\t')) + output.standard(toRemove.join('\t')) } else { - this.npm.output('Removed ' + toRemove.length + ' token' + (toRemove.length !== 1 ? 's' : '')) + output.standard('Removed ' + toRemove.length + ' token' + (toRemove.length !== 1 ? 's' : '')) } } @@ -143,15 +143,15 @@ class Token extends BaseCommand { delete result.key delete result.updated if (conf.json) { - this.npm.output(JSON.stringify(result)) + output.standard(JSON.stringify(result)) } else if (conf.parseable) { - Object.keys(result).forEach(k => this.npm.output(k + '\t' + result[k])) + Object.keys(result).forEach(k => output.standard(k + '\t' + result[k])) } else { const table = new Table() for (const k of Object.keys(result)) { table.push({ [this.npm.chalk.bold(k)]: String(result[k]) }) } - this.npm.output(table.toString()) + output.standard(table.toString()) } } diff --git a/lib/commands/unpublish.js b/lib/commands/unpublish.js index bf02d96712825..095b07e870c5e 100644 --- a/lib/commands/unpublish.js +++ b/lib/commands/unpublish.js @@ -2,6 +2,7 @@ const libaccess = require('libnpmaccess') const libunpub = require('libnpmpublish').unpublish const npa = require('npm-package-arg') const pacote = require('pacote') +const { output } = require('proc-log') const pkgJson = require('@npmcli/package-json') const { flatten } = require('@npmcli/config/lib/definitions') @@ -161,7 +162,7 @@ class Unpublish extends BaseCommand { await otplease(this.npm, opts, o => libunpub(spec, o)) } if (!silent) { - this.npm.output(`- ${spec.name}${pkgVersion}`) + output.standard(`- ${spec.name}${pkgVersion}`) } } diff --git a/lib/commands/version.js b/lib/commands/version.js index 029a6fdd3101e..9776b70240519 100644 --- a/lib/commands/version.js +++ b/lib/commands/version.js @@ -1,6 +1,7 @@ const libnpmversion = require('libnpmversion') const { resolve } = require('path') const { promisify } = require('util') +const { output } = require('proc-log') const readFile = promisify(require('fs').readFile) const updateWorkspaces = require('../workspaces/update-workspaces.js') @@ -78,7 +79,7 @@ class Version extends BaseCommand { ...this.npm.flatOptions, path: this.npm.prefix, }) - return this.npm.output(`${prefix}${version}`) + return output.standard(`${prefix}${version}`) } async changeWorkspaces (args) { @@ -86,14 +87,14 @@ class Version extends BaseCommand { await this.setWorkspaces() const updatedWorkspaces = [] for (const [name, path] of this.workspaces) { - this.npm.output(name) + output.standard(name) const version = await libnpmversion(args[0], { ...this.npm.flatOptions, 'git-tag-version': false, path, }) updatedWorkspaces.push(name) - this.npm.output(`${prefix}${version}`) + output.standard(`${prefix}${version}`) } return this.update(updatedWorkspaces) } @@ -115,9 +116,9 @@ class Version extends BaseCommand { } if (this.npm.config.get('json')) { - this.npm.output(JSON.stringify(results, null, 2)) + output.standard(JSON.stringify(results, null, 2)) } else { - this.npm.output(results) + output.standard(results) } } diff --git a/lib/commands/view.js b/lib/commands/view.js index 25a45ab016758..9fb0f8add1ca7 100644 --- a/lib/commands/view.js +++ b/lib/commands/view.js @@ -1,7 +1,7 @@ const columns = require('cli-columns') const fs = require('fs') const jsonParse = require('json-parse-even-better-errors') -const { log } = require('proc-log') +const { log, output } = require('proc-log') const npa = require('npm-package-arg') const { resolve } = require('path') const formatBytes = require('../utils/format-bytes.js') @@ -118,7 +118,7 @@ class View extends BaseCommand { const msg = await this.jsonData(reducedData, pckmnt._id) if (msg !== '') { - this.npm.output(msg) + output.standard(msg) } } } @@ -157,10 +157,10 @@ class View extends BaseCommand { if (wholePackument) { data.map((v) => this.prettyView(pckmnt, v[Object.keys(v)[0]][''])) } else { - this.npm.output(`${name}:`) + output.standard(`${name}:`) const msg = await this.jsonData(reducedData, pckmnt._id) if (msg !== '') { - this.npm.output(msg) + output.standard(msg) } } } else { @@ -171,7 +171,7 @@ class View extends BaseCommand { } } if (Object.keys(results).length > 0) { - this.npm.output(JSON.stringify(results, null, 2)) + output.standard(JSON.stringify(results, null, 2)) } } @@ -374,61 +374,61 @@ class View extends BaseCommand { info.license = chalk.green(info.license) } - this.npm.output('') - this.npm.output( + output.standard('') + output.standard( chalk.underline.bold(`${info.name}@${info.version}`) + ' | ' + info.license + ' | deps: ' + (info.deps.length ? chalk.cyan(info.deps.length) : chalk.green('none')) + ' | versions: ' + info.versions ) - info.description && this.npm.output(info.description) + info.description && output.standard(info.description) if (info.repo || info.site) { - info.site && this.npm.output(chalk.cyan(info.site)) + info.site && output.standard(chalk.cyan(info.site)) } const warningSign = unicode ? ' ⚠️ ' : '!!' - info.deprecated && this.npm.output( + info.deprecated && output.standard( `\n${chalk.bold.red('DEPRECATED')}${ warningSign } - ${info.deprecated}` ) if (info.keywords.length) { - this.npm.output('') - this.npm.output(`keywords: ${chalk.yellow(info.keywords.join(', '))}`) + output.standard('') + output.standard(`keywords: ${chalk.yellow(info.keywords.join(', '))}`) } if (info.bins.length) { - this.npm.output('') - this.npm.output(`bin: ${chalk.yellow(info.bins.join(', '))}`) + output.standard('') + output.standard(`bin: ${chalk.yellow(info.bins.join(', '))}`) } - this.npm.output('') - this.npm.output('dist') - this.npm.output(`.tarball: ${info.tarball}`) - this.npm.output(`.shasum: ${info.shasum}`) - info.integrity && this.npm.output(`.integrity: ${info.integrity}`) - info.unpackedSize && this.npm.output(`.unpackedSize: ${info.unpackedSize}`) + output.standard('') + output.standard('dist') + output.standard(`.tarball: ${info.tarball}`) + output.standard(`.shasum: ${info.shasum}`) + info.integrity && output.standard(`.integrity: ${info.integrity}`) + info.unpackedSize && output.standard(`.unpackedSize: ${info.unpackedSize}`) const maxDeps = 24 if (info.deps.length) { - this.npm.output('') - this.npm.output('dependencies:') - this.npm.output(columns(info.deps.slice(0, maxDeps), { padding: 1 })) + output.standard('') + output.standard('dependencies:') + output.standard(columns(info.deps.slice(0, maxDeps), { padding: 1 })) if (info.deps.length > maxDeps) { - this.npm.output(`(...and ${info.deps.length - maxDeps} more.)`) + output.standard(`(...and ${info.deps.length - maxDeps} more.)`) } } if (info.maintainers && info.maintainers.length) { - this.npm.output('') - this.npm.output('maintainers:') - info.maintainers.forEach((u) => this.npm.output(`- ${u}`)) + output.standard('') + output.standard('maintainers:') + info.maintainers.forEach((u) => output.standard(`- ${u}`)) } - this.npm.output('') - this.npm.output('dist-tags:') - this.npm.output(columns(info.tags)) + output.standard('') + output.standard('dist-tags:') + output.standard(columns(info.tags)) if (info.publisher || info.modified) { let publishInfo = 'published' @@ -438,8 +438,8 @@ class View extends BaseCommand { if (info.publisher) { publishInfo += ` by ${info.publisher}` } - this.npm.output('') - this.npm.output(publishInfo) + output.standard('') + output.standard(publishInfo) } } } diff --git a/lib/commands/whoami.js b/lib/commands/whoami.js index 154cc870391ba..e05993abdd5bf 100644 --- a/lib/commands/whoami.js +++ b/lib/commands/whoami.js @@ -1,3 +1,4 @@ +const { output } = require('proc-log') const getIdentity = require('../utils/get-identity.js') const BaseCommand = require('../base-command.js') @@ -8,7 +9,7 @@ class Whoami extends BaseCommand { async exec (args) { const username = await getIdentity(this.npm, { ...this.npm.flatOptions }) - this.npm.output( + output.standard( this.npm.config.get('json') ? JSON.stringify(username) : username ) } diff --git a/lib/npm.js b/lib/npm.js index e19f41a844ec5..a4668fee99813 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -444,18 +444,6 @@ class Npm { this.#display.forceLog(...args) } - output (...args) { - this.#display.output(...args) - } - - outputError (...args) { - this.#display.outputError(...args) - } - - outputBuffer (arg) { - this.#display.outputBuffer(arg) - } - flushOutput (jsonError) { this.#display.flushOutput(jsonError) } diff --git a/lib/utils/audit-error.js b/lib/utils/audit-error.js index de3a026553dfc..10aec7592b03c 100644 --- a/lib/utils/audit-error.js +++ b/lib/utils/audit-error.js @@ -1,4 +1,4 @@ -const { log } = require('proc-log') +const { log, output } = require('proc-log') const { redactLog: replaceInfo } = require('@npmcli/redact') // print an error or just nothing if the audit report has an error @@ -22,7 +22,7 @@ const auditError = (npm, report) => { const { body: errBody } = error const body = Buffer.isBuffer(errBody) ? errBody.toString() : errBody if (npm.flatOptions.json) { - npm.output(JSON.stringify({ + output.standard(JSON.stringify({ message: error.message, method: error.method, uri: replaceInfo(error.uri), @@ -31,7 +31,7 @@ const auditError = (npm, report) => { body, }, null, 2)) } else { - npm.output(body) + output.standard(body) } throw 'audit endpoint returned an error' diff --git a/lib/utils/display.js b/lib/utils/display.js index 311844d9bd6e5..8e5a2046b7ca5 100644 --- a/lib/utils/display.js +++ b/lib/utils/display.js @@ -110,10 +110,12 @@ class Display { this.#stdout = setBlocking(stdout) this.#stderr = setBlocking(stderr) process.on('log', this.#logHandler) + process.on('output', this.#outputHandler) } off () { process.off('log', this.#logHandler) + process.off('output', this.#outputHandler) this.#logBuffer.length = 0 if (this.#progress) { this.#progress.stop() @@ -148,17 +150,25 @@ class Display { this.#logHandler({ level, force: true }, ...args) } - output (...args) { - // TODO: make this respect silent option - this.#stdout.write(format(...args)) - } + #outputHandler = (level, ...args) => { + if (level === 'standard') { + this.#stdout.write(format(...args)) + return + } - outputError (...args) { - this.#stderr.write(format(...args)) - } + /* istanbul ignore next - not implemented yet */ + if (level === 'error') { + this.#stderr.write(format(...args)) + return + } + + if (level === 'buffer') { + this.#outputBuffer.push(args[0]) + return + } - outputBuffer (item) { - this.#outputBuffer.push(item) + /* istanbul ignore next - just to catch accidental errors */ + log.verbose('display', `Unknown output event ${level}`) } flushOutput (jsonError) { @@ -168,9 +178,9 @@ class Display { if (this.#json) { const output = this.#outputBuffer.reduce((a, i) => ({ ...a, ...safeJsonParse(i) }), {}) - this.output(JSON.stringify({ ...output, ...jsonError }, null, 2)) + this.#stdout.write(format(JSON.stringify({ ...output, ...jsonError }, null, 2))) } else { - this.#outputBuffer.forEach((item) => this.output(item)) + this.#outputBuffer.forEach((item) => this.#stdout.write(format(item))) } this.#outputBuffer.length = 0 diff --git a/lib/utils/open-url-prompt.js b/lib/utils/open-url-prompt.js index 71a68c253c050..261cf370da6bd 100644 --- a/lib/utils/open-url-prompt.js +++ b/lib/utils/open-url-prompt.js @@ -1,4 +1,5 @@ const readline = require('readline') +const { output } = require('proc-log') const open = require('./open-url.js') function print (npm, title, url) { @@ -6,7 +7,7 @@ function print (npm, title, url) { const message = json ? JSON.stringify({ title, url }) : `${title}:\n${url}` - npm.output(message) + output.standard(message) } // Prompt to open URL in browser if possible @@ -48,7 +49,7 @@ const promptOpen = async (npm, url, title, prompt, emitter) => { rl.close() // clear the prompt line - npm.output('') + output.standard('') resolve(false) }) diff --git a/lib/utils/open-url.js b/lib/utils/open-url.js index 77bb1d03d8e16..46b7abc731fa1 100644 --- a/lib/utils/open-url.js +++ b/lib/utils/open-url.js @@ -1,4 +1,5 @@ const promiseSpawn = require('@npmcli/promise-spawn') +const { output } = require('proc-log') const { URL } = require('url') @@ -16,7 +17,7 @@ const open = async (npm, url, errMsg, isFile) => { }, null, 2) : `${errMsg}:\n ${url}\n` - npm.output(alternateMsg) + output.standard(alternateMsg) } if (browser === false) { diff --git a/lib/utils/reify-output.js b/lib/utils/reify-output.js index 58cf76dda7837..40f1722f246e9 100644 --- a/lib/utils/reify-output.js +++ b/lib/utils/reify-output.js @@ -9,7 +9,7 @@ // found 37 vulnerabilities (5 low, 7 moderate, 25 high) // run `npm audit fix` to fix them, or `npm audit` for details -const { log } = require('proc-log') +const { log, output } = require('proc-log') const { depth } = require('treeverse') const ms = require('ms') const npmAuditReport = require('npm-audit-report') @@ -99,7 +99,7 @@ const reifyOutput = (npm, arb) => { }) if (diffTable) { - npm.output('\n' + diffTable.toString()) + output.standard('\n' + diffTable.toString()) } } @@ -115,7 +115,7 @@ const reifyOutput = (npm, arb) => { summary.audit = npm.command === 'audit' ? auditReport : auditReport.toJSON().metadata } - npm.output(JSON.stringify(summary, null, 2)) + output.standard(JSON.stringify(summary, null, 2)) } else { packagesChangedMessage(npm, summary) packagesFundingMessage(npm, summary) @@ -134,7 +134,7 @@ const printAuditReport = (npm, report) => { if (!res || !res.report) { return } - npm.output(`\n${res.report}`) + output.standard(`\n${res.report}`) } const getAuditReport = (npm, report) => { @@ -206,7 +206,7 @@ const packagesChangedMessage = (npm, { added, removed, changed, audited }) => { } msg.push(` in ${ms(Date.now() - npm.started)}`) - npm.output(msg.join('')) + output.standard(msg.join('')) } const packagesFundingMessage = (npm, { funding }) => { @@ -214,11 +214,11 @@ const packagesFundingMessage = (npm, { funding }) => { return } - npm.output('') + output.standard('') const pkg = funding === 1 ? 'package' : 'packages' const is = funding === 1 ? 'is' : 'are' - npm.output(`${funding} ${pkg} ${is} looking for funding`) - npm.output(' run `npm fund` for details') + output.standard(`${funding} ${pkg} ${is} looking for funding`) + output.standard(' run `npm fund` for details') } module.exports = reifyOutput diff --git a/test/lib/commands/ci.js b/test/lib/commands/ci.js index 681ccad7d87a7..6ab9662fc8be5 100644 --- a/test/lib/commands/ci.js +++ b/test/lib/commands/ci.js @@ -164,7 +164,6 @@ t.test('lifecycle scripts', async t => { }, mocks: { '@npmcli/run-script': (opts) => { - t.ok(opts.banner) scripts.push(opts.event) }, }, diff --git a/test/lib/commands/pack.js b/test/lib/commands/pack.js index 93d4da22d31c2..067e84a0980e0 100644 --- a/test/lib/commands/pack.js +++ b/test/lib/commands/pack.js @@ -121,28 +121,17 @@ t.test('foreground-scripts defaults to true', async t => { config: { 'dry-run': true }, }) - /* eslint no-console: 0 */ - // TODO: replace this with `const results = t.intercept(console, 'log')` - const log = console.log - t.teardown(() => { - console.log = log - }) - const caughtLogs = [] - console.log = (...args) => { - caughtLogs.push(args) - } - // end TODO - await npm.exec('pack', []) const filename = 'test-fg-scripts-0.0.0.tgz' - t.same( - caughtLogs, + t.strictSame( + outputs, [ - ['\n> test-fg-scripts@0.0.0 prepack\n> echo prepack!\n'], - ['\n> test-fg-scripts@0.0.0 postpack\n> echo postpack!\n'], + '\n> test-fg-scripts@0.0.0 prepack\n> echo prepack!\n', + '\n> test-fg-scripts@0.0.0 postpack\n> echo postpack!\n', + filename, ], - 'prepack and postpack log to stdout') - t.strictSame(outputs, [filename]) + 'prepack and postpack log to stdout' + ) t.matchSnapshot(logs.notice, 'logs pack contents') t.throws(() => fs.statSync(path.resolve(npm.prefix, filename))) }) @@ -163,25 +152,10 @@ t.test('foreground-scripts can still be set to false', async t => { config: { 'dry-run': true, 'foreground-scripts': false }, }) - /* eslint no-console: 0 */ - // TODO: replace this with `const results = t.intercept(console, 'log')` - const log = console.log - t.teardown(() => { - console.log = log - }) - const caughtLogs = [] - console.log = (...args) => { - caughtLogs.push(args) - } - // end TODO - await npm.exec('pack', []) const filename = 'test-fg-scripts-0.0.0.tgz' - t.same( - caughtLogs, - [], - 'prepack and postpack do not log to stdout') - t.strictSame(outputs, [filename]) + + t.strictSame(outputs, [filename], 'prepack and postpack do not log to stdout') t.matchSnapshot(logs.notice, 'logs pack contents') t.throws(() => fs.statSync(path.resolve(npm.prefix, filename))) }) diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index 751cd97d8acf6..ed35bdeeedd05 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -83,6 +83,7 @@ t.test('re-loads publishConfig.registry if added during script process', async t const { joinedOutput, npm } = await loadMockNpm(t, { config: { [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token', + 'foreground-scripts': false, }, prefixDir: { 'package.json': JSON.stringify({ @@ -136,6 +137,7 @@ t.test('prioritize CLI flags over publishConfig', async t => { const { joinedOutput, npm } = await loadMockNpm(t, { config: { [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token', + 'foreground-scripts': false, }, prefixDir: { 'package.json': JSON.stringify({ @@ -220,7 +222,7 @@ t.test('dry-run', async t => { }) t.test('foreground-scripts defaults to true', async t => { - const { joinedOutput, npm, logs } = await loadMockNpm(t, { + const { outputs, npm, logs } = await loadMockNpm(t, { config: { 'dry-run': true, ...auth, @@ -238,33 +240,22 @@ t.test('foreground-scripts defaults to true', async t => { }, }) - /* eslint no-console: 0 */ - // TODO: replace this with `const results = t.intercept(console, 'log')` - const log = console.log - t.teardown(() => { - console.log = log - }) - const caughtLogs = [] - console.log = (...args) => { - caughtLogs.push(args) - } - // end TODO - await npm.exec('publish', []) - t.equal(joinedOutput(), `+ test-fg-scripts@0.0.0`) + t.matchSnapshot(logs.notice) - t.same( - caughtLogs, + t.strictSame( + outputs, [ - ['\n> test-fg-scripts@0.0.0 prepack\n> echo prepack!\n'], - ['\n> test-fg-scripts@0.0.0 postpack\n> echo postpack!\n'], + '\n> test-fg-scripts@0.0.0 prepack\n> echo prepack!\n', + '\n> test-fg-scripts@0.0.0 postpack\n> echo postpack!\n', + `+ test-fg-scripts@0.0.0`, ], 'prepack and postpack log to stdout') }) t.test('foreground-scripts can still be set to false', async t => { - const { joinedOutput, npm, logs } = await loadMockNpm(t, { + const { outputs, npm, logs } = await loadMockNpm(t, { config: { 'dry-run': true, 'foreground-scripts': false, @@ -283,25 +274,13 @@ t.test('foreground-scripts can still be set to false', async t => { }, }) - /* eslint no-console: 0 */ - // TODO: replace this with `const results = t.intercept(console, 'log')` - const log = console.log - t.teardown(() => { - console.log = log - }) - const caughtLogs = [] - console.log = (...args) => { - caughtLogs.push(args) - } - // end TODO - await npm.exec('publish', []) - t.equal(joinedOutput(), `+ test-fg-scripts@0.0.0`) + t.matchSnapshot(logs.notice) - t.same( - caughtLogs, - [], + t.strictSame( + outputs, + [`+ test-fg-scripts@0.0.0`], 'prepack and postpack do not log to stdout') }) @@ -871,6 +850,7 @@ t.test('manifest', async t => { const { npm } = await loadMockNpm(t, { config: { ...auth, + 'foreground-scripts': false, }, chdir: () => root, mocks: { diff --git a/test/lib/npm.js b/test/lib/npm.js index ad776fc65b573..59400ce8da9f1 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -476,15 +476,6 @@ t.test('timings', async t => { } }) -t.test('outputs cleaned messages', async t => { - const { outputs, outputErrors, npm } = await loadMockNpm(t) - npm.output('hello\x00world') - npm.outputError('error\x00world') - - t.match(outputs, ['hello^@world']) - t.match(outputErrors, ['error^@world']) -}) - t.test('aliases and typos', async t => { const { Npm } = await loadMockNpm(t, { init: false }) t.throws(() => Npm.cmd('thisisnotacommand'), { code: 'EUNKNOWNCOMMAND' }) diff --git a/test/lib/utils/display.js b/test/lib/utils/display.js index a10b0dd621e60..ff8328f20d2ec 100644 --- a/test/lib/utils/display.js +++ b/test/lib/utils/display.js @@ -5,7 +5,7 @@ const { inspect } = require('util') const mockDisplay = async (t, { mocks, load } = {}) => { const { Chalk } = await import('chalk') - const { log } = require('proc-log') + const { log, output } = require('proc-log') const logs = mockLogs() const Display = tmock(t, '{LIB}/utils/display', mocks) const display = new Display(logs.streams) @@ -17,7 +17,7 @@ const mockDisplay = async (t, { mocks, load } = {}) => { }) t.teardown(() => display.off()) return { - display, + output, log, ...logs.logs, } @@ -75,7 +75,7 @@ t.test('handles log throwing', async (t) => { }) t.test('Display.clean', async (t) => { - const { display, outputs, clearOutput } = await mockDisplay(t) + const { output, outputs, clearOutput } = await mockDisplay(t) class CustomObj { #inspected @@ -136,7 +136,7 @@ t.test('Display.clean', async (t) => { ] for (const [dirty, clean] of tests) { - display.output(dirty) + output.standard(dirty) t.equal(outputs[0], clean) clearOutput() } diff --git a/test/lib/utils/exit-handler.js b/test/lib/utils/exit-handler.js index 597792da73e63..8e218cb763429 100644 --- a/test/lib/utils/exit-handler.js +++ b/test/lib/utils/exit-handler.js @@ -3,6 +3,7 @@ const fs = require('fs') const fsMiniPass = require('fs-minipass') const { join, resolve } = require('path') const EventEmitter = require('events') +const { output } = require('proc-log') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const mockGlobals = require('@npmcli/mock-globals') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot') @@ -217,7 +218,7 @@ t.test('exit handler called - no npm with error without stack', async (t) => { t.match(errors, [/something happened/]) }) -t.test('console.log output using --json', async (t) => { +t.test('standard output using --json', async (t) => { const { exitHandler, outputs } = await mockExitHandler(t, { config: { json: true }, }) @@ -239,13 +240,13 @@ t.test('console.log output using --json', async (t) => { }) t.test('merges output buffers errors with --json', async (t) => { - const { exitHandler, outputs, npm } = await mockExitHandler(t, { + const { exitHandler, outputs } = await mockExitHandler(t, { config: { json: true }, }) - npm.outputBuffer({ output_data: 1 }) - npm.outputBuffer(JSON.stringify({ more_data: 2 })) - npm.outputBuffer('not json, will be ignored') + output.buffer({ output_data: 1 }) + output.buffer(JSON.stringify({ more_data: 2 })) + output.buffer('not json, will be ignored') await exitHandler(err('Error: EBADTHING Something happened')) @@ -266,10 +267,10 @@ t.test('merges output buffers errors with --json', async (t) => { }) t.test('output buffer without json', async (t) => { - const { exitHandler, outputs, npm, logs } = await mockExitHandler(t) + const { exitHandler, outputs, logs } = await mockExitHandler(t) - npm.outputBuffer('output_data') - npm.outputBuffer('more_data') + output.buffer('output_data') + output.buffer('more_data') await exitHandler(err('Error: EBADTHING Something happened')) diff --git a/workspaces/arborist/test/arborist/reify.js b/workspaces/arborist/test/arborist/reify.js index 46dc367cd3f08..db7df07e46bcd 100644 --- a/workspaces/arborist/test/arborist/reify.js +++ b/workspaces/arborist/test/arborist/reify.js @@ -101,6 +101,16 @@ const warningTracker = () => { } } +const outputTracker = () => { + const list = [] + const onlog = (...msg) => msg[0] === 'standard' && list.push(msg) + process.on('output', onlog) + return () => { + process.removeListener('output', onlog) + return list + } +} + const debugLogTracker = () => { const list = [] mockDebug.log = (...msg) => list.push(msg) @@ -2593,19 +2603,12 @@ t.test('runs dependencies script if tree changes', async (t) => { t.not(fs.existsSync(expectedPath), `did not run ${script}`) } - // take over console.log as run-script is going to print a banner for these because - // they're running in the foreground - const _log = console.log - t.teardown(() => { - console.log = _log - }) - const logs = [] - console.log = (msg) => logs.push(msg) + const outputs = outputTracker() + // reify again, this time adding a new dependency await reify(path, { foregroundScripts: true, add: ['once@^1.4.0'] }) - console.log = _log - t.match(logs, [/predependencies/, /dependencies/, /postdependencies/], 'logged banners') + t.match(outputs(), [/predependencies/, /dependencies/, /postdependencies/], 'logged banners') // files should exist again for (const script of ['predependencies', 'dependencies', 'postdependencies']) {