diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 324a735ade2f2..8d4d4717c86b1 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,16 +1,16 @@ { - ".": "10.6.0", - "workspaces/arborist": "7.5.0", - "workspaces/libnpmaccess": "8.0.4", - "workspaces/libnpmdiff": "6.1.0", - "workspaces/libnpmexec": "8.0.0", - "workspaces/libnpmfund": "5.0.8", - "workspaces/libnpmhook": "10.0.3", - "workspaces/libnpmorg": "6.0.4", - "workspaces/libnpmpack": "7.0.0", - "workspaces/libnpmpublish": "9.0.6", - "workspaces/libnpmsearch": "7.0.3", - "workspaces/libnpmteam": "6.0.3", - "workspaces/libnpmversion": "6.0.0", - "workspaces/config": "8.3.0" + ".": "10.7.0", + "workspaces/arborist": "7.5.1", + "workspaces/libnpmaccess": "8.0.5", + "workspaces/libnpmdiff": "6.1.1", + "workspaces/libnpmexec": "8.1.0", + "workspaces/libnpmfund": "5.0.9", + "workspaces/libnpmhook": "10.0.4", + "workspaces/libnpmorg": "6.0.5", + "workspaces/libnpmpack": "7.0.1", + "workspaces/libnpmpublish": "9.0.7", + "workspaces/libnpmsearch": "7.0.4", + "workspaces/libnpmteam": "6.0.4", + "workspaces/libnpmversion": "6.0.1", + "workspaces/config": "8.3.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index cf11230bc20bd..5399886b3d542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,56 @@ # Changelog +## [10.7.0](https://github.com/npm/cli/compare/v10.6.0...v10.7.0) (2024-04-30) + +### Features + +* [`7e349f4`](https://github.com/npm/cli/commit/7e349f45363bb8dbe1cc803f8b48befc01aae7fd) [#7432](https://github.com/npm/cli/pull/7432) add spinner (#7432) (@lukekarrys) + +### Bug Fixes + +* [`d679ce8`](https://github.com/npm/cli/commit/d679ce80fd9b761b2323777ec5cd84ebc5c164fe) [#7449](https://github.com/npm/cli/pull/7449) linting: no-unused-vars (@wraithgar) +* [`2558283`](https://github.com/npm/cli/commit/25582837b0ebb8c2de2932c04224332b11d0e1d5) [#7450](https://github.com/npm/cli/pull/7450) powershell: fallback to script root if globalPrefix does not exist (#7450) (@lukekarrys) +* [`bc4c342`](https://github.com/npm/cli/commit/bc4c3426c35201baff7230c2b3beee2cf5936296) [#7448](https://github.com/npm/cli/pull/7448) account for registries with no publisher in search (#7448) (@wraithgar) +* [`bcc781a`](https://github.com/npm/cli/commit/bcc781abf10b46aa5b04da996fc4602524be9b0e) [#7439](https://github.com/npm/cli/pull/7439) move run-script banners to stderr when in json mode (#7439) (@lukekarrys) +* [`104fcb5`](https://github.com/npm/cli/commit/104fcb53282653a1c5610a6590afecc207920a6b) [#7438](https://github.com/npm/cli/pull/7438) remove doctor log for each file permission check (#7438) (@lukekarrys) +* [`5230647`](https://github.com/npm/cli/commit/52306473da03123ef5623e9e152e10285c8097f3) [#7422](https://github.com/npm/cli/pull/7422) rewrite powershell scripts to use PSScriptRoot (#7422) (@lukekarrys) +* [`71cbd91`](https://github.com/npm/cli/commit/71cbd91b6f01875a99eeae989ea67489bdd0178d) [#7421](https://github.com/npm/cli/pull/7421) hide banner for exec and explore (#7421) (@lukekarrys) +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Documentation + +* [`1674136`](https://github.com/npm/cli/commit/1674136bc14b0f708bb01f75d65474346c863bd9) [#7441](https://github.com/npm/cli/pull/7441) correct search help output (#7441) (@wraithgar) + +### Dependencies + +* [`80eec03`](https://github.com/npm/cli/commit/80eec03462e5747cb4434d43aff25939826b7850) [#7453](https://github.com/npm/cli/pull/7453) `@npmcli/redact@2.0.0` +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` +* [`a785766`](https://github.com/npm/cli/commit/a785766325141335cde39d43eb631062e32d6605) [#7453](https://github.com/npm/cli/pull/7453) `pacote@18.0.3` +* [`65d76db`](https://github.com/npm/cli/commit/65d76dbd2fb11c83141302500ec4a3f5128ff12f) [#7453](https://github.com/npm/cli/pull/7453) `npm-profile@9.0.2` +* [`cadc0f0`](https://github.com/npm/cli/commit/cadc0f0cad8909755ae8ac72f2dd5802a0d34943) [#7449](https://github.com/npm/cli/pull/7449) hoist production copy of sprintf-js +* [`2cffdfe`](https://github.com/npm/cli/commit/2cffdfef45b9a13d189f5059cc69fc7319620fda) [#7449](https://github.com/npm/cli/pull/7449) `lru-cache@10.2.2` +* [`432efb5`](https://github.com/npm/cli/commit/432efb5ee313ac5bd08642a9cef2b7c52da23ea9) [#7449](https://github.com/npm/cli/pull/7449) `make-fetch-happen@13.0.1` +* [`9da5738`](https://github.com/npm/cli/commit/9da57388ebd5c643c2a95bbf63abc745cad45ccc) [#7437](https://github.com/npm/cli/pull/7437) `@npmcli/run-script@8.1.0` (#7437) +* [`762888a`](https://github.com/npm/cli/commit/762888a3b603704c7c53a94a704b8a7f3edea918) [#7429](https://github.com/npm/cli/pull/7429) update dependencies for workspaces (#7429) +* [workspace](https://github.com/npm/cli/releases/tag/arborist-v7.5.1): `@npmcli/arborist@7.5.1` +* [workspace](https://github.com/npm/cli/releases/tag/config-v8.3.1): `@npmcli/config@8.3.1` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmaccess-v8.0.5): `libnpmaccess@8.0.5` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmdiff-v6.1.1): `libnpmdiff@6.1.1` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmexec-v8.1.0): `libnpmexec@8.1.0` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmfund-v5.0.9): `libnpmfund@5.0.9` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmhook-v10.0.4): `libnpmhook@10.0.4` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmorg-v6.0.5): `libnpmorg@6.0.5` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmpack-v7.0.1): `libnpmpack@7.0.1` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmpublish-v9.0.7): `libnpmpublish@9.0.7` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmsearch-v7.0.4): `libnpmsearch@7.0.4` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmteam-v6.0.4): `libnpmteam@6.0.4` +* [workspace](https://github.com/npm/cli/releases/tag/libnpmversion-v6.0.1): `libnpmversion@6.0.1` + +### Chores + +* [`356c374`](https://github.com/npm/cli/commit/356c374817711845719902184547e1e0ac359b22) [#7453](https://github.com/npm/cli/pull/7453) fix test fixture for new redact behavior (@wraithgar) +* [`2fba4b7`](https://github.com/npm/cli/commit/2fba4b7b6218900fd895daf5218682edeb4253a4) [#7449](https://github.com/npm/cli/pull/7449) update devDependencies in lockfile (@wraithgar) + ## [10.6.0](https://github.com/npm/cli/compare/v10.5.2...v10.6.0) (2024-04-25) ### Features diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 730d8a35ca730..88128ab1ad9ec 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -81,6 +81,7 @@ graph LR; make-fetch-happen-->cacache; make-fetch-happen-->minipass-fetch; make-fetch-happen-->npmcli-agent["@npmcli/agent"]; + make-fetch-happen-->proc-log; make-fetch-happen-->ssri; nopt-->abbrev; normalize-package-data-->hosted-git-info; @@ -132,7 +133,6 @@ graph LR; npm-->pacote; npm-->parse-conflict-json; npm-->proc-log; - npm-->proggy; npm-->read; npm-->semver; npm-->ssri; @@ -428,6 +428,7 @@ graph LR; make-fetch-happen-->minipass; make-fetch-happen-->negotiator; make-fetch-happen-->npmcli-agent["@npmcli/agent"]; + make-fetch-happen-->proc-log; make-fetch-happen-->promise-retry; make-fetch-happen-->ssri; minimatch-->brace-expansion; @@ -527,7 +528,6 @@ graph LR; npm-->pacote; npm-->parse-conflict-json; npm-->proc-log; - npm-->proggy; npm-->qrcode-terminal; npm-->read; npm-->remark-gfm; diff --git a/bin/npm.ps1 b/bin/npm.ps1 index 399e33360e853..04a1fd478ef9d 100644 --- a/bin/npm.ps1 +++ b/bin/npm.ps1 @@ -1,35 +1,32 @@ #!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" +$NODE_EXE="$PSScriptRoot/node.exe" +if (-not (Test-Path $NODE_EXE)) { + $NODE_EXE="$PSScriptRoot/node" } -$ret=0 - -$nodeexe = "node$exe" -$nodebin = $(Get-Command $nodeexe -ErrorAction SilentlyContinue -ErrorVariable F).Source -if ($nodebin -eq $null) { - Write-Host "$nodeexe not found." - exit 1 +if (-not (Test-Path $NODE_EXE)) { + $NODE_EXE="node" } -$nodedir = $(New-Object -ComObject Scripting.FileSystemObject).GetFile("$nodebin").ParentFolder.Path -$npmprefixjs="$nodedir/node_modules/npm/bin/npm-prefix.js" -$npmprefix=(& $nodeexe $npmprefixjs) +$NPM_PREFIX_JS="$PSScriptRoot/node_modules/npm/bin/npm-prefix.js" +$NPM_CLI_JS="$PSScriptRoot/node_modules/npm/bin/npm-cli.js" +$NPM_PREFIX=(& $NODE_EXE $NPM_PREFIX_JS) + if ($LASTEXITCODE -ne 0) { Write-Host "Could not determine Node.js install directory" exit 1 } -$npmprefixclijs="$npmprefix/node_modules/npm/bin/npm-cli.js" + +$NPM_PREFIX_NPM_CLI_JS="$NPM_PREFIX/node_modules/npm/bin/npm-cli.js" +if (Test-Path $NPM_PREFIX_NPM_CLI_JS) { + $NPM_CLI_JS=$NPM_PREFIX_NPM_CLI_JS +} # Support pipeline input if ($MyInvocation.ExpectingInput) { - $input | & $nodeexe $npmprefixclijs $args + $input | & $NODE_EXE $NPM_CLI_JS $args } else { - & $nodeexe $npmprefixclijs $args + & $NODE_EXE $NPM_CLI_JS $args } -$ret=$LASTEXITCODE -exit $ret + +exit $LASTEXITCODE diff --git a/bin/npx-cli.js b/bin/npx-cli.js index 17d96fb26267c..e2e1b87906abe 100755 --- a/bin/npx-cli.js +++ b/bin/npx-cli.js @@ -26,7 +26,7 @@ const removed = new Set([ const { definitions, shorthands } = require('@npmcli/config/lib/definitions') const npmSwitches = Object.entries(definitions) - .filter(([key, { type }]) => type === Boolean || + .filter(([, { type }]) => type === Boolean || (Array.isArray(type) && type.includes(Boolean))) .map(([key]) => key) diff --git a/bin/npx.ps1 b/bin/npx.ps1 index 1d59fc52083d7..28dae51b22ca9 100644 --- a/bin/npx.ps1 +++ b/bin/npx.ps1 @@ -1,35 +1,32 @@ #!/usr/bin/env pwsh -$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent -$exe="" -if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) { - # Fix case when both the Windows and Linux builds of Node - # are installed in the same directory - $exe=".exe" +$NODE_EXE="$PSScriptRoot/node.exe" +if (-not (Test-Path $NODE_EXE)) { + $NODE_EXE="$PSScriptRoot/node" } -$ret=0 - -$nodeexe = "node$exe" -$nodebin = $(Get-Command $nodeexe -ErrorAction SilentlyContinue -ErrorVariable F).Source -if ($nodebin -eq $null) { - Write-Host "$nodeexe not found." - exit 1 +if (-not (Test-Path $NODE_EXE)) { + $NODE_EXE="node" } -$nodedir = $(New-Object -ComObject Scripting.FileSystemObject).GetFile("$nodebin").ParentFolder.Path -$npmprefixjs="$nodedir/node_modules/npm/bin/npm-prefix.js" -$npmprefix=(& $nodeexe $npmprefixjs) +$NPM_PREFIX_JS="$PSScriptRoot/node_modules/npm/bin/npm-prefix.js" +$NPX_CLI_JS="$PSScriptRoot/node_modules/npm/bin/npx-cli.js" +$NPM_PREFIX=(& $NODE_EXE $NPM_PREFIX_JS) + if ($LASTEXITCODE -ne 0) { Write-Host "Could not determine Node.js install directory" exit 1 } -$npmprefixclijs="$npmprefix/node_modules/npm/bin/npx-cli.js" + +$NPM_PREFIX_NPX_CLI_JS="$NPM_PREFIX/node_modules/npm/bin/npx-cli.js" +if (Test-Path $NPM_PREFIX_NPX_CLI_JS) { + $NPX_CLI_JS=$NPM_PREFIX_NPX_CLI_JS +} # Support pipeline input if ($MyInvocation.ExpectingInput) { - $input | & $nodeexe $npmprefixclijs $args + $input | & $NODE_EXE $NPX_CLI_JS $args } else { - & $nodeexe $npmprefixclijs $args + & $NODE_EXE $NPX_CLI_JS $args } -$ret=$LASTEXITCODE -exit $ret + +exit $LASTEXITCODE diff --git a/docs/bin/build.js b/docs/bin/build.js index b94a85cf6f9bc..c25fd76ed7e7f 100644 --- a/docs/bin/build.js +++ b/docs/bin/build.js @@ -16,7 +16,7 @@ const run = require('../lib/build.js') const { paths } = require('../lib/index') run(paths) - .then((res) => console.log(`Wrote ${res.length} files`)) + .then((res) => console.error(`Wrote ${res.length} files`)) .catch((err) => { process.exitCode = 1 console.error(err) diff --git a/docs/lib/index.js b/docs/lib/index.js index 5d4ae7af3457b..5f8501ead27b8 100644 --- a/docs/lib/index.js +++ b/docs/lib/index.js @@ -119,7 +119,7 @@ const replaceConfig = (src, { path }) => { } const allConfig = Object.entries(definitions).sort(sort) - .map(([_, def]) => def.describe()) + .map(([, def]) => def.describe()) .join('\n\n') return src.replace(replacer, allConfig) diff --git a/docs/package.json b/docs/package.json index 95b96ce20ff08..5dd5904cf5636 100644 --- a/docs/package.json +++ b/docs/package.json @@ -16,7 +16,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "docs" }, "devDependencies": { diff --git a/lib/commands/adduser.js b/lib/commands/adduser.js index 5299ebaca41aa..cf64e7a7e7438 100644 --- a/lib/commands/adduser.js +++ b/lib/commands/adduser.js @@ -12,7 +12,7 @@ class AddUser extends BaseCommand { 'auth-type', ] - async exec (args) { + async exec () { const scope = this.npm.config.get('scope') let registry = this.npm.config.get('registry') diff --git a/lib/commands/ci.js b/lib/commands/ci.js index a8b4a845126f5..7e79d7208c9c4 100644 --- a/lib/commands/ci.js +++ b/lib/commands/ci.js @@ -81,7 +81,7 @@ class CI extends ArboristWorkspaceCmd { await time.start('npm-ci:rm', async () => { const path = `${where}/node_modules` // get the list of entries so we can skip the glob for performance - const entries = await fs.readdir(path, null).catch(er => []) + const entries = await fs.readdir(path, null).catch(() => []) return Promise.all(entries.map(f => fs.rm(`${path}/${f}`, { force: true, recursive: true }))) }) diff --git a/lib/commands/completion.js b/lib/commands/completion.js index a4cf1d77c5e3a..9b147d2f5bdac 100644 --- a/lib/commands/completion.js +++ b/lib/commands/completion.js @@ -248,7 +248,7 @@ const configCompl = opts => { // expand with the valid values of various config values. // not yet implemented. -const configValueCompl = opts => [] +const configValueCompl = () => [] // check if the thing is a flag or not. const isFlag = word => { @@ -265,7 +265,7 @@ const isFlag = word => { // complete against the npm commands // if they all resolve to the same thing, just return the thing it already is -const cmdCompl = (opts, npm) => { +const cmdCompl = (opts) => { const allCommands = commands.concat(Object.keys(aliases)) const matches = allCommands.filter(c => c.startsWith(opts.partialWord)) if (!matches.length) { diff --git a/lib/commands/dedupe.js b/lib/commands/dedupe.js index f9785fd66bb49..e07bcd31e894b 100644 --- a/lib/commands/dedupe.js +++ b/lib/commands/dedupe.js @@ -21,7 +21,7 @@ class Dedupe extends ArboristWorkspaceCmd { ...super.params, ] - async exec (args) { + async exec () { if (this.npm.global) { const er = new Error('`npm dedupe` does not work in global mode.') er.code = 'EDEDUPEGLOBAL' diff --git a/lib/commands/diff.js b/lib/commands/diff.js index 6b5adf633acd7..ca8b1237b40c5 100644 --- a/lib/commands/diff.js +++ b/lib/commands/diff.js @@ -78,7 +78,7 @@ class Diff extends BaseCommand { // get the package name from the packument at `path` // throws if no packument is present OR if it does not have `name` attribute - async packageName (path) { + async packageName () { let name try { const { content: pkg } = await pkgJson.normalize(this.prefix) @@ -103,7 +103,7 @@ class Diff extends BaseCommand { // no arguments, defaults to comparing cwd // to its latest published registry version if (!a) { - const pkgName = await this.packageName(this.prefix) + const pkgName = await this.packageName() return [ `${pkgName}@${this.npm.config.get('tag')}`, `file:${this.prefix.replace(/#/g, '%23')}`, diff --git a/lib/commands/doctor.js b/lib/commands/doctor.js index 339dcf15f70f2..c29dd7e0ecb17 100644 --- a/lib/commands/doctor.js +++ b/lib/commands/doctor.js @@ -223,7 +223,6 @@ class Doctor extends BaseCommand { const gid = process.getgid() const files = new Set([root]) for (const f of files) { - log.silly('doctor', 'checkFilesPermission', f.slice(root.length + 1)) const st = await lstat(f).catch(er => { // if it can't be missing, or if it can and the error wasn't that it was missing if (!missingOk || er.code !== 'ENOENT') { @@ -255,7 +254,7 @@ class Doctor extends BaseCommand { } if (st.isDirectory()) { - const entries = await readdir(f).catch(er => { + const entries = await readdir(f).catch(() => { ok = false log.warn('doctor', 'checkFilesPermission', 'error reading directory ' + f) return [] diff --git a/lib/commands/find-dupes.js b/lib/commands/find-dupes.js index 0945089c74b7c..735ac7c4a7ed0 100644 --- a/lib/commands/find-dupes.js +++ b/lib/commands/find-dupes.js @@ -19,7 +19,7 @@ class FindDupes extends ArboristWorkspaceCmd { ...super.params, ] - async exec (args) { + async exec () { this.npm.config.set('dry-run', true) return this.npm.exec('dedupe', []) } diff --git a/lib/commands/help-search.js b/lib/commands/help-search.js index 67d381dd94565..72dd03ac7406e 100644 --- a/lib/commands/help-search.js +++ b/lib/commands/help-search.js @@ -22,7 +22,7 @@ class HelpSearch extends BaseCommand { // preserve glob@8 behavior files = files.sort((a, b) => a.localeCompare(b, 'en')) const data = await this.readFiles(files) - const results = await this.searchFiles(args, data, files) + const results = await this.searchFiles(args, data) const formatted = this.formatResults(args, results) if (!formatted.trim()) { output.standard(`No matches in help for: ${args.join(' ')}\n`) @@ -40,7 +40,7 @@ class HelpSearch extends BaseCommand { return res } - async searchFiles (args, data, files) { + async searchFiles (args, data) { const results = [] for (const [file, content] of Object.entries(data)) { const lowerCase = content.toLowerCase() diff --git a/lib/commands/init.js b/lib/commands/init.js index 1847e19a9560f..205352e86e6ed 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, output } = require('proc-log') +const { log, output, input } = require('proc-log') const updateWorkspaces = require('../utils/update-workspaces.js') const BaseCommand = require('../base-cmd.js') @@ -148,8 +148,6 @@ class Init extends BaseCommand { } async template (path = process.cwd()) { - log.pause() - const initFile = this.npm.config.get('init-module') if (!this.npm.config.get('yes') && !this.npm.config.get('force')) { output.standard([ @@ -167,7 +165,7 @@ class Init extends BaseCommand { } try { - const data = await initJson(path, initFile, this.npm.config) + const data = await input.read(() => initJson(path, initFile, this.npm.config)) log.silly('package data', data) return data } catch (er) { @@ -176,8 +174,6 @@ class Init extends BaseCommand { } else { throw er } - } finally { - log.resume() } } diff --git a/lib/commands/login.js b/lib/commands/login.js index fa82ecaa2c207..630abf9ac8e04 100644 --- a/lib/commands/login.js +++ b/lib/commands/login.js @@ -12,7 +12,7 @@ class Login extends BaseCommand { 'auth-type', ] - async exec (args) { + async exec () { const scope = this.npm.config.get('scope') let registry = this.npm.config.get('registry') diff --git a/lib/commands/logout.js b/lib/commands/logout.js index 39b4b176bf966..dc5a0dfda0e98 100644 --- a/lib/commands/logout.js +++ b/lib/commands/logout.js @@ -11,7 +11,7 @@ class Logout extends BaseCommand { 'scope', ] - async exec (args) { + async exec () { const registry = this.npm.config.get('registry') const scope = this.npm.config.get('scope') const regRef = scope ? `${scope}:registry` : 'registry' diff --git a/lib/commands/outdated.js b/lib/commands/outdated.js index ceef86be950c5..2249808110bbb 100644 --- a/lib/commands/outdated.js +++ b/lib/commands/outdated.js @@ -160,7 +160,7 @@ class Outdated extends ArboristWorkspaceCmd { this.edges.add(edge) } - getWorkspacesEdges (node) { + getWorkspacesEdges () { if (this.npm.global) { return } diff --git a/lib/commands/ping.js b/lib/commands/ping.js index 8ade46ac8f82a..0d057862baa8f 100644 --- a/lib/commands/ping.js +++ b/lib/commands/ping.js @@ -8,7 +8,7 @@ class Ping extends BaseCommand { static params = ['registry'] static name = 'ping' - async exec (args) { + async exec () { const cleanRegistry = redact(this.npm.config.get('registry')) log.notice('PING', cleanRegistry) const start = Date.now() diff --git a/lib/commands/prefix.js b/lib/commands/prefix.js index d1f56cb190bd7..da8702cf91caa 100644 --- a/lib/commands/prefix.js +++ b/lib/commands/prefix.js @@ -7,7 +7,7 @@ class Prefix extends BaseCommand { static params = ['global'] static usage = ['[-g]'] - async exec (args) { + async exec () { return output.standard(this.npm.prefix) } } diff --git a/lib/commands/profile.js b/lib/commands/profile.js index 66bb3d118e6b7..8eae6278549f5 100644 --- a/lib/commands/profile.js +++ b/lib/commands/profile.js @@ -357,7 +357,7 @@ class Profile extends BaseCommand { } } - async disable2fa (args) { + async disable2fa () { const conf = { ...this.npm.flatOptions } const info = await npmProfile.get(conf) diff --git a/lib/commands/publish.js b/lib/commands/publish.js index fba7b7a120953..6bb2dcc6614bb 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -149,7 +149,7 @@ class Publish extends BaseCommand { return pkgContents } - async execWorkspaces (args) { + async execWorkspaces () { // Suppresses JSON output in publish() so we can handle it here this.suppressOutput = true diff --git a/lib/commands/run-script.js b/lib/commands/run-script.js index 0bf517f77efb4..dd00c98fc8b6e 100644 --- a/lib/commands/run-script.js +++ b/lib/commands/run-script.js @@ -24,7 +24,7 @@ class RunScript extends BaseCommand { const argv = opts.conf.argv.remain if (argv.length === 2) { const { content: { scripts = {} } } = await pkgJson.normalize(npm.localPrefix) - .catch(er => ({ content: {} })) + .catch(() => ({ content: {} })) if (opts.isFish) { return Object.keys(scripts).map(s => `${s}\t${scripts[s].slice(0, 30)}`) } @@ -185,7 +185,7 @@ class RunScript extends BaseCommand { return allScripts } - async runWorkspaces (args, filters) { + async runWorkspaces (args) { const res = [] await this.setWorkspaces() @@ -205,7 +205,7 @@ class RunScript extends BaseCommand { } } - async listWorkspaces (args, filters) { + async listWorkspaces (args) { await this.setWorkspaces() if (this.npm.silent) { diff --git a/lib/commands/search.js b/lib/commands/search.js index 93005398480d1..8b6c01e3930d8 100644 --- a/lib/commands/search.js +++ b/lib/commands/search.js @@ -8,7 +8,6 @@ class Search extends BaseCommand { static description = 'Search for packages' static name = 'search' static params = [ - 'long', 'json', 'color', 'parseable', @@ -22,7 +21,7 @@ class Search extends BaseCommand { 'offline', ] - static usage = ['[search terms ...]'] + static usage = [' [ ...]'] async exec (args) { const opts = { diff --git a/lib/commands/token.js b/lib/commands/token.js index aa9bd0fce24f8..24ca21a8e29ce 100644 --- a/lib/commands/token.js +++ b/lib/commands/token.js @@ -125,7 +125,7 @@ class Token extends BaseCommand { } } - async create (args) { + async create () { const json = this.npm.config.get('json') const parseable = this.npm.config.get('parseable') const cidr = this.npm.config.get('cidr') diff --git a/lib/commands/whoami.js b/lib/commands/whoami.js index df749e9db7e91..507adb276c731 100644 --- a/lib/commands/whoami.js +++ b/lib/commands/whoami.js @@ -7,7 +7,7 @@ class Whoami extends BaseCommand { static name = 'whoami' static params = ['registry'] - async exec (args) { + async exec () { const username = await getIdentity(this.npm, { ...this.npm.flatOptions }) output.standard( this.npm.config.get('json') ? JSON.stringify(username) : username diff --git a/lib/npm.js b/lib/npm.js index 84b22f2db5a80..df2297b215da7 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -93,14 +93,7 @@ class Npm { } async load () { - return time.start('npm:load', async () => { - const { exec } = await this.#load() - return { - exec, - command: this.argv.shift(), - args: this.argv, - } - }) + return time.start('npm:load', () => this.#load()) } get loaded () { @@ -165,7 +158,26 @@ class Npm { await time.start('npm:load:configload', () => this.config.load()) + // npm --versions + if (this.config.get('versions', 'cli')) { + this.argv = ['version'] + this.config.set('usage', false, 'cli') + } else { + this.argv = [...this.config.parsedArgv.remain] + } + + // Remove first argv since that is our command as typed + // Note that this might not be the actual name of the command + // due to aliases, etc. But we use the raw form of it later + // in user output so it must be preserved as is. + const commandArg = this.argv.shift() + + // This is the actual name of the command that will be run or + // undefined if deref could not find a match + const command = deref(commandArg) + await this.#display.load({ + command, loglevel: this.config.get('loglevel'), stdoutColor: this.color, stderrColor: this.logColor, @@ -202,9 +214,10 @@ class Npm { // note: this MUST be shorter than the actual argv length, because it // uses the same memory, so node will truncate it if it's too long. + // We time this because setting process.title is slow sometimes but we + // have to do it for security reasons. But still helpful to know how slow it is. time.start('npm:load:setTitle', () => { const { parsedArgv: { cooked, remain } } = this.config - this.argv = remain // Secrets are mostly in configs, so title is set using only the positional args // to keep those from being leaked. We still do a best effort replaceInfo. this.#title = ['npm'].concat(replaceInfo(remain)).join(' ').trim() @@ -244,13 +257,7 @@ class Npm { log.warn('using --force', 'Recommended protections disabled.') } - // npm --versions - if (this.config.get('versions', 'cli')) { - this.argv = ['version'] - this.config.set('usage', false, 'cli') - } - - return { exec: true } + return { exec: true, command: commandArg, args: this.argv } } get isShellout () { diff --git a/lib/utils/auth.js b/lib/utils/auth.js index c38d7cc78e2ce..04ca455ceb526 100644 --- a/lib/utils/auth.js +++ b/lib/utils/auth.js @@ -36,7 +36,7 @@ const adduser = async (npm, { creds, ...opts }) => { // password, it's effectively a login, and if that account has otp you'll // be prompted for it. res = await otplease(npm, opts, (reqOpts) => - profile.adduserCouch(username, email, password, opts) + profile.adduserCouch(username, email, password, reqOpts) ) } diff --git a/lib/utils/display.js b/lib/utils/display.js index 67c745f310415..29a1f7951d506 100644 --- a/lib/utils/display.js +++ b/lib/utils/display.js @@ -1,5 +1,4 @@ -const proggy = require('proggy') -const { log, output, META } = require('proc-log') +const { log, output, input, META } = require('proc-log') const { explain } = require('./explain-eresolve.js') const { formatWithOptions } = require('./format') @@ -119,6 +118,7 @@ class Display { #progress // options + #command #levelIndex #timing #json @@ -136,18 +136,17 @@ class Display { // Handlers are set immediately so they can buffer all events process.on('log', this.#logHandler) process.on('output', this.#outputHandler) + process.on('input', this.#inputHandler) + this.#progress = new Progress({ stream: stderr }) } off () { process.off('log', this.#logHandler) this.#logState.buffer.length = 0 - process.off('output', this.#outputHandler) this.#outputState.buffer.length = 0 - - if (this.#progress) { - this.#progress.stop() - } + process.off('input', this.#inputHandler) + this.#progress.off() } get chalk () { @@ -159,6 +158,7 @@ class Display { } async load ({ + command, heading, json, loglevel, @@ -178,17 +178,14 @@ class Display { // what it knows about the environment to get color support since we already // determined in our definitions that we want to show colors. const level = Math.max(createSupportsColor(null).level, 1) - this.#noColorChalk = new Chalk({ level: 0 }) - this.#stdoutColor = stdoutColor this.#stdoutChalk = stdoutColor ? new Chalk({ level }) : this.#noColorChalk - this.#stderrColor = stderrColor this.#stderrChalk = stderrColor ? new Chalk({ level }) : this.#noColorChalk - this.#logColors = COLOR_PALETTE({ chalk: this.#stderrChalk }) + this.#command = command this.#levelIndex = LEVEL_OPTIONS[loglevel].index this.#timing = timing this.#json = json @@ -198,18 +195,19 @@ class Display { // Emit resume event on the logs which will flush output log.resume() output.flush() - this.#startProgress({ progress, unicode }) + this.#progress.load({ + unicode, + enabled: !!progress && !this.#silent, + }) } // STREAM WRITES // Write formatted and (non-)colorized output to streams - #stdoutWrite (options, ...args) { - this.#stdout.write(formatWithOptions({ colors: this.#stdoutColor, ...options }, ...args)) - } - - #stderrWrite (options, ...args) { - this.#stderr.write(formatWithOptions({ colors: this.#stderrColor, ...options }, ...args)) + #write (stream, options, ...args) { + const colors = stream === this.#stdout ? this.#stdoutColor : this.#stderrColor + const value = formatWithOptions({ colors, ...options }, ...args) + this.#progress.write(() => stream.write(value)) } // HANDLERS @@ -217,81 +215,118 @@ class Display { // Arrow function assigned to a private class field so it can be passed // directly as a listener and still reference "this" #logHandler = withMeta((level, meta, ...args) => { - if (level === log.KEYS.resume) { - this.#logState.buffering = false - this.#logState.buffer.forEach((item) => this.#tryWriteLog(...item)) - this.#logState.buffer.length = 0 - return - } - - if (level === log.KEYS.pause) { - this.#logState.buffering = true - return - } - - if (this.#logState.buffering) { - this.#logState.buffer.push([level, meta, ...args]) - return + switch (level) { + case log.KEYS.resume: + this.#logState.buffering = false + this.#logState.buffer.forEach((item) => this.#tryWriteLog(...item)) + this.#logState.buffer.length = 0 + break + + case log.KEYS.pause: + this.#logState.buffering = true + break + + default: + if (this.#logState.buffering) { + this.#logState.buffer.push([level, meta, ...args]) + } else { + this.#tryWriteLog(level, meta, ...args) + } + break } - - this.#tryWriteLog(level, meta, ...args) }) // Arrow function assigned to a private class field so it can be passed // directly as a listener and still reference "this" #outputHandler = withMeta((level, meta, ...args) => { - if (level === output.KEYS.flush) { - this.#outputState.buffering = false - - if (meta.jsonError && this.#json) { - const json = {} - for (const item of this.#outputState.buffer) { - // index 2 skips the level and meta - Object.assign(json, tryJsonParse(item[2])) + switch (level) { + case output.KEYS.flush: + this.#outputState.buffering = false + if (meta.jsonError && this.#json) { + const json = {} + for (const item of this.#outputState.buffer) { + // index 2 skips the level and meta + Object.assign(json, tryJsonParse(item[2])) + } + this.#writeOutput( + output.KEYS.standard, + meta, + JSON.stringify({ ...json, error: meta.jsonError }, null, 2) + ) + } else { + this.#outputState.buffer.forEach((item) => this.#writeOutput(...item)) } - this.#writeOutput( - output.KEYS.standard, - meta, - JSON.stringify({ ...json, error: meta.jsonError }, null, 2) - ) - } else { - this.#outputState.buffer.forEach((item) => this.#writeOutput(...item)) - } - - this.#outputState.buffer.length = 0 - return - } - - if (level === output.KEYS.buffer) { - this.#outputState.buffer.push([output.KEYS.standard, meta, ...args]) - return - } - - if (this.#outputState.buffering) { - this.#outputState.buffer.push([level, meta, ...args]) - return + this.#outputState.buffer.length = 0 + break + + case output.KEYS.buffer: + this.#outputState.buffer.push([output.KEYS.standard, meta, ...args]) + break + + default: + if (this.#outputState.buffering) { + this.#outputState.buffer.push([level, meta, ...args]) + } else { + // HACK: Check if the argument looks like a run-script banner. This can be + // replaced with proc-log.META in @npmcli/run-script + if (typeof args[0] === 'string' && args[0].startsWith('\n> ') && args[0].endsWith('\n')) { + if (this.#silent || ['exec', 'explore'].includes(this.#command)) { + // Silent mode and some specific commands always hide run script banners + break + } else if (this.#json) { + // In json mode, change output to stderr since we dont want to break json + // parsing on stdout if the user is piping to jq or something. + // XXX: in a future (breaking?) change it might make sense for run-script to + // always output these banners with proc-log.output.error if we think they + // align closer with "logging" instead of "output" + level = output.KEYS.error + } + } + this.#writeOutput(level, meta, ...args) + } + break } + }) - // HACK: if it looks like the banner and we are silent do not print it. - // There's no other way to do this right now :( - // eslint-disable-next-line max-len - if (this.#silent && args.length === 1 && args[0].startsWith('\n> ') && args[0].endsWith('\n')) { - return + #inputHandler = withMeta((level, meta, ...args) => { + switch (level) { + case input.KEYS.start: + log.pause() + this.#outputState.buffering = true + this.#progress.off() + break + + case input.KEYS.end: + log.resume() + output.flush() + this.#progress.resume() + break + + case input.KEYS.read: { + // The convention when calling input.read is to pass in a single fn that returns + // the promise to await. resolve and reject are provided by proc-log + const [res, rej, p] = args + return input.start(() => p() + .then(res) + .catch(rej) + // Any call to procLog.input.read will render a prompt to the user, so we always + // add a single newline of output to stdout to move the cursor to the next line + .finally(() => output.standard(''))) + } } - - this.#writeOutput(level, meta, ...args) }) // OUTPUT #writeOutput (level, meta, ...args) { - if (level === output.KEYS.standard) { - this.#stdoutWrite({}, ...args) - return - } - - if (level === output.KEYS.error) { - this.#stderrWrite({}, ...args) + switch (level) { + case output.KEYS.standard: + this.#write(this.#stdout, {}, ...args) + break + + case output.KEYS.error: + this.#write(this.#stderr, {}, ...args) + break } } @@ -337,22 +372,118 @@ class Display { this.#logColors[level](level), title ? this.#logColors.title(title) : null, ] - this.#stderrWrite({ prefix }, ...args) - } else if (this.#progress) { - // TODO: make this display a single log line of filtered messages + this.#write(this.#stderr, { prefix }, ...args) } } +} + +class Progress { + // Taken from https://github.com/sindresorhus/cli-spinners + // MIT License + // Copyright (c) Sindre Sorhus (https://sindresorhus.com) + static dots = { duration: 80, frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] } + static lines = { duration: 130, frames: ['-', '\\', '|', '/'] } + + #stream + #spinner + #enabled = false + + #frameIndex = 0 + #lastUpdate = 0 + #interval + #timeout + + // We are rendering is enabled option is set and we are not waiting for the render timeout + get #rendering () { + return this.#enabled && !this.#timeout + } + + // We are spinning if enabled option is set and the render interval has been set + get #spinning () { + return this.#enabled && this.#interval + } - // PROGRESS + constructor ({ stream }) { + this.#stream = stream + } + + load ({ enabled, unicode }) { + this.#enabled = enabled + this.#spinner = unicode ? Progress.dots : Progress.lines + // Dont render the spinner for short durations + this.#render(200) + } - #startProgress ({ progress, unicode }) { - if (!progress || this.#silent) { + off () { + if (!this.#enabled) { return } - this.#progress = proggy.createClient({ normalize: true }) - // TODO: implement proggy trackers in arborist/doctor - // TODO: listen to progress events here and build progress UI - // TODO: see deprecated gauge package for what unicode chars were used + clearTimeout(this.#timeout) + this.#timeout = null + clearInterval(this.#interval) + this.#interval = null + this.#frameIndex = 0 + this.#lastUpdate = 0 + this.#clearSpinner() + } + + resume () { + this.#render() + } + + // If we are currenting rendering the spinner we clear it + // before writing our line and then re-render the spinner after. + // If not then all we need to do is write the line + write (write) { + if (this.#spinning) { + this.#clearSpinner() + } + write() + if (this.#spinning) { + this.#render() + } + } + + #render (ms) { + if (ms) { + this.#timeout = setTimeout(() => { + this.#timeout = null + this.#renderSpinner() + }, ms) + // Make sure this timeout does not keep the process open + this.#timeout.unref() + } else { + this.#renderSpinner() + } + } + + #renderSpinner () { + if (!this.#rendering) { + return + } + // We always attempt to render immediately but we only request to move to the next + // frame if it has been longer than our spinner frame duration since our last update + this.#renderFrame(Date.now() - this.#lastUpdate >= this.#spinner.duration) + clearInterval(this.#interval) + this.#interval = setInterval(() => this.#renderFrame(true), this.#spinner.duration) + } + + #renderFrame (next) { + if (next) { + this.#lastUpdate = Date.now() + this.#frameIndex++ + if (this.#frameIndex >= this.#spinner.frames.length) { + this.#frameIndex = 0 + } + } + this.#clearSpinner() + this.#stream.write(this.#spinner.frames[this.#frameIndex]) + } + + #clearSpinner () { + // Move to the start of the line and clear the rest of the line + this.#stream.cursorTo(0) + this.#stream.clearLine(1) } } diff --git a/lib/utils/explain-dep.js b/lib/utils/explain-dep.js index efe0ceece0882..4e9e93454e8a2 100644 --- a/lib/utils/explain-dep.js +++ b/lib/utils/explain-dep.js @@ -44,7 +44,7 @@ const explainLinksIn = ({ linksIn }, depth, chalk) => { return str.split('\n').join('\n ') } -const explainDependents = ({ name, dependents }, depth, chalk) => { +const explainDependents = ({ dependents }, depth, chalk) => { if (!dependents || !dependents.length || depth <= 0) { return '' } diff --git a/lib/utils/format-search-stream.js b/lib/utils/format-search-stream.js index 434d21f448acd..b70bd915123da 100644 --- a/lib/utils/format-search-stream.js +++ b/lib/utils/format-search-stream.js @@ -95,7 +95,7 @@ class TextOutputStream extends Minipass { // Normalize const pkg = { authors: data.maintainers.map((m) => `${strip(m.username)}`).join(' '), - publisher: strip(data.publisher.username), + publisher: strip(data.publisher?.username || ''), date: data.date ? data.date.toISOString().slice(0, 10) : 'prehistoric', description: strip(data.description ?? ''), keywords: [], @@ -159,7 +159,11 @@ class TextOutputStream extends Minipass { } else { output = `${name}\n` } - output += `Version ${this.#chalk.blue(pkg.version)} published ${this.#chalk.blue(pkg.date)} by ${this.#chalk.blue(pkg.publisher)}\n` + if (pkg.publisher) { + output += `Version ${this.#chalk.blue(pkg.version)} published ${this.#chalk.blue(pkg.date)} by ${this.#chalk.blue(pkg.publisher)}\n` + } else { + output += `Version ${this.#chalk.blue(pkg.version)} published ${this.#chalk.blue(pkg.date)} by ${this.#chalk.yellow('???')}\n` + } output += `Maintainers: ${pkg.authors}\n` if (keywords) { output += `Keywords: ${keywords}\n` diff --git a/lib/utils/open-url-prompt.js b/lib/utils/open-url-prompt.js index 261cf370da6bd..6f4d453a959d5 100644 --- a/lib/utils/open-url-prompt.js +++ b/lib/utils/open-url-prompt.js @@ -1,5 +1,5 @@ const readline = require('readline') -const { output } = require('proc-log') +const { input, output } = require('proc-log') const open = require('./open-url.js') function print (npm, title, url) { @@ -34,7 +34,7 @@ const promptOpen = async (npm, url, title, prompt, emitter) => { output: process.stdout, }) - const tryOpen = await new Promise(resolve => { + const tryOpen = await input.read(() => new Promise(resolve => { rl.on('SIGINT', () => { rl.close() resolve('SIGINT') @@ -47,14 +47,10 @@ const promptOpen = async (npm, url, title, prompt, emitter) => { if (emitter && emitter.addListener) { emitter.addListener('abort', () => { rl.close() - - // clear the prompt line - output.standard('') - resolve(false) }) } - }) + })) if (tryOpen === 'SIGINT') { throw new Error('canceled') diff --git a/lib/utils/read-user-info.js b/lib/utils/read-user-info.js index b2cd7374c17c3..4e8def4bdf1de 100644 --- a/lib/utils/read-user-info.js +++ b/lib/utils/read-user-info.js @@ -1,6 +1,6 @@ -const { read } = require('read') +const { read: _read } = require('read') const userValidate = require('npm-user-validate') -const { log } = require('proc-log') +const { log, input } = require('proc-log') exports.otp = readOTP exports.password = readPassword @@ -16,6 +16,8 @@ const passwordPrompt = 'npm password: ' const usernamePrompt = 'npm username: ' const emailPrompt = 'email (this IS public): ' +const read = (...args) => input.read(() => _read(...args)) + function readOTP (msg = otpPrompt, otp, isRetry) { if (isRetry && otp && /^[\d ]+$|^[A-Fa-f0-9]{64,64}$/.test(otp)) { return otp.replace(/\s+/g, '') diff --git a/mock-globals/package.json b/mock-globals/package.json index dfa33c0638018..778d324fd3d32 100644 --- a/mock-globals/package.json +++ b/mock-globals/package.json @@ -15,7 +15,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "mock-globals" }, "keywords": [], diff --git a/mock-registry/lib/index.js b/mock-registry/lib/index.js index d98cb055a1713..558cb25e2674e 100644 --- a/mock-registry/lib/index.js +++ b/mock-registry/lib/index.js @@ -225,7 +225,7 @@ class MockRegistry { }) } - webadduser ({ username, password, token = 'npm_default-test-token' }) { + webadduser ({ token = 'npm_default-test-token' }) { const doneUrl = new URL('/npm-cli-test/done', this.origin).href const loginUrl = new URL('/npm-cli-test/login', this.origin).href this.nock = this.nock diff --git a/mock-registry/package.json b/mock-registry/package.json index eaa6b63e77ad8..3e6979dc3f42c 100644 --- a/mock-registry/package.json +++ b/mock-registry/package.json @@ -15,7 +15,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "mock-registry" }, "keywords": [], diff --git a/node_modules/.gitignore b/node_modules/.gitignore index ce124e0438201..2075e41dc40b5 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -100,9 +100,6 @@ !/ini !/init-package-json !/ip-address -!/ip-address/node_modules/ -/ip-address/node_modules/* -!/ip-address/node_modules/sprintf-js !/ip-regex !/is-cidr !/is-core-module @@ -199,6 +196,7 @@ !/spdx-exceptions !/spdx-expression-parse !/spdx-license-ids +!/sprintf-js !/ssri !/string-width-cjs !/string-width diff --git a/node_modules/@npmcli/redact/lib/deep-map.js b/node_modules/@npmcli/redact/lib/deep-map.js new file mode 100644 index 0000000000000..ad042dbdfc534 --- /dev/null +++ b/node_modules/@npmcli/redact/lib/deep-map.js @@ -0,0 +1,59 @@ +const deepMap = (input, handler = v => v, path = ['$'], seen = new Set([input])) => { + if (Array.isArray(input)) { + const result = [] + for (let i = 0; i < input.length; i++) { + const element = input[i] + const elementPath = [...path, i] + if (element instanceof Object) { + if (!seen.has(element)) { // avoid getting stuck in circular reference + seen.add(element) + result.push(deepMap(handler(element, elementPath), handler, elementPath, seen)) + } + } else { + result.push(handler(element, elementPath)) + } + } + return result + } + + if (input === null) { + return null + } else if (typeof input === 'object' || typeof input === 'function') { + const result = {} + + if (input instanceof Error) { + // `name` property is not included in `Object.getOwnPropertyNames(error)` + result.errorType = input.name + } + + for (const propertyName of Object.getOwnPropertyNames(input)) { + // skip logging internal properties + if (propertyName.startsWith('_')) { + continue + } + + try { + const property = input[propertyName] + const propertyPath = [...path, propertyName] + if (property instanceof Object) { + if (!seen.has(property)) { // avoid getting stuck in circular reference + seen.add(property) + result[propertyName] = deepMap( + handler(property, propertyPath), handler, propertyPath, seen + ) + } + } else { + result[propertyName] = handler(property, propertyPath) + } + } catch (err) { + // a getter may throw an error + result[propertyName] = `[error getting value: ${err.message}]` + } + } + return result + } + + return handler(input, path) +} + +module.exports = { deepMap } diff --git a/node_modules/@npmcli/redact/lib/index.js b/node_modules/@npmcli/redact/lib/index.js index e5b5e74157c2a..9b10c7f6a0081 100644 --- a/node_modules/@npmcli/redact/lib/index.js +++ b/node_modules/@npmcli/redact/lib/index.js @@ -1,29 +1,15 @@ -const { URL } = require('url') +const matchers = require('./matchers') +const { redactUrlPassword } = require('./utils') const REPLACE = '***' -const TOKEN_REGEX = /\bnpm_[a-zA-Z0-9]{36}\b/g -const GUID_REGEX = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g const redact = (value) => { if (typeof value !== 'string' || !value) { return value } - - let urlValue - try { - urlValue = new URL(value) - } catch { - // If it's not a URL then we can ignore all errors - } - - if (urlValue?.password) { - urlValue.password = REPLACE - value = urlValue.toString() - } - - return value - .replace(TOKEN_REGEX, `npm_${REPLACE}`) - .replace(GUID_REGEX, REPLACE) + return redactUrlPassword(value, REPLACE) + .replace(matchers.NPM_SECRET.pattern, `npm_${REPLACE}`) + .replace(matchers.UUID.pattern, REPLACE) } // split on \s|= similar to how nopt parses options @@ -49,7 +35,6 @@ const redactLog = (arg) => { } else if (Array.isArray(arg)) { return arg.map((a) => typeof a === 'string' ? splitAndRedact(a) : a) } - return arg } diff --git a/node_modules/@npmcli/redact/lib/matchers.js b/node_modules/@npmcli/redact/lib/matchers.js new file mode 100644 index 0000000000000..fe9b9071de8a1 --- /dev/null +++ b/node_modules/@npmcli/redact/lib/matchers.js @@ -0,0 +1,81 @@ +const TYPE_REGEX = 'regex' +const TYPE_URL = 'url' +const TYPE_PATH = 'path' + +const NPM_SECRET = { + type: TYPE_REGEX, + pattern: /\b(npms?_)[a-zA-Z0-9]{36,48}\b/gi, + replacement: `[REDACTED_NPM_SECRET]`, +} + +const AUTH_HEADER = { + type: TYPE_REGEX, + pattern: /\b(Basic\s+|Bearer\s+)[\w+=\-.]+\b/gi, + replacement: `[REDACTED_AUTH_HEADER]`, +} + +const JSON_WEB_TOKEN = { + type: TYPE_REGEX, + pattern: /\b[A-Za-z0-9-_]{10,}(?!\.\d+\.)\.[A-Za-z0-9-_]{3,}\.[A-Za-z0-9-_]{20,}\b/gi, + replacement: `[REDACTED_JSON_WEB_TOKEN]`, +} + +const UUID = { + type: TYPE_REGEX, + pattern: /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi, + replacement: `[REDACTED_UUID]`, +} + +const URL_MATCHER = { + type: TYPE_REGEX, + pattern: /(?:https?|ftp):\/\/[^\s/"$.?#].[^\s"]*/gi, + replacement: '[REDACTED_URL]', +} + +const DEEP_HEADER_AUTHORIZATION = { + type: TYPE_PATH, + predicate: ({ path }) => path.endsWith('.headers.authorization'), + replacement: '[REDACTED_HEADER_AUTHORIZATION]', +} + +const DEEP_HEADER_SET_COOKIE = { + type: TYPE_PATH, + predicate: ({ path }) => path.endsWith('.headers.set-cookie'), + replacement: '[REDACTED_HEADER_SET_COOKIE]', +} + +const REWRITE_REQUEST = { + type: TYPE_PATH, + predicate: ({ path }) => path.endsWith('.request'), + replacement: (input) => ({ + method: input?.method, + path: input?.path, + headers: input?.headers, + url: input?.url, + }), +} + +const REWRITE_RESPONSE = { + type: TYPE_PATH, + predicate: ({ path }) => path.endsWith('.response'), + replacement: (input) => ({ + data: input?.data, + status: input?.status, + headers: input?.headers, + }), +} + +module.exports = { + TYPE_REGEX, + TYPE_URL, + TYPE_PATH, + NPM_SECRET, + AUTH_HEADER, + JSON_WEB_TOKEN, + UUID, + URL_MATCHER, + DEEP_HEADER_AUTHORIZATION, + DEEP_HEADER_SET_COOKIE, + REWRITE_REQUEST, + REWRITE_RESPONSE, +} diff --git a/node_modules/@npmcli/redact/lib/server.js b/node_modules/@npmcli/redact/lib/server.js new file mode 100644 index 0000000000000..669e834da6131 --- /dev/null +++ b/node_modules/@npmcli/redact/lib/server.js @@ -0,0 +1,34 @@ +const { + AUTH_HEADER, + JSON_WEB_TOKEN, + NPM_SECRET, + DEEP_HEADER_AUTHORIZATION, + DEEP_HEADER_SET_COOKIE, + REWRITE_REQUEST, + REWRITE_RESPONSE, +} = require('./matchers') + +const { + redactUrlMatcher, + redactUrlPasswordMatcher, + redactMatchers, +} = require('./utils') + +const { deepMap } = require('./deep-map') + +const _redact = redactMatchers( + NPM_SECRET, + AUTH_HEADER, + JSON_WEB_TOKEN, + DEEP_HEADER_AUTHORIZATION, + DEEP_HEADER_SET_COOKIE, + REWRITE_REQUEST, + REWRITE_RESPONSE, + redactUrlMatcher( + redactUrlPasswordMatcher() + ) +) + +const redact = (input) => deepMap(input, (value, path) => _redact(value, { path })) + +module.exports = { redact } diff --git a/node_modules/@npmcli/redact/lib/utils.js b/node_modules/@npmcli/redact/lib/utils.js new file mode 100644 index 0000000000000..8395ab25fc373 --- /dev/null +++ b/node_modules/@npmcli/redact/lib/utils.js @@ -0,0 +1,202 @@ +const { + URL_MATCHER, + TYPE_URL, + TYPE_REGEX, + TYPE_PATH, +} = require('./matchers') + +/** + * creates a string of asterisks, + * this forces a minimum asterisk for security purposes + */ +const asterisk = (length = 0) => { + length = typeof length === 'string' ? length.length : length + if (length < 8) { + return '*'.repeat(8) + } + return '*'.repeat(length) +} + +/** + * escapes all special regex chars + * @see https://stackoverflow.com/a/9310752 + * @see https://github.com/tc39/proposal-regex-escaping + */ +const escapeRegExp = (text) => { + return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, `\\$&`) +} + +/** + * provieds a regex "or" of the url versions of a string + */ +const urlEncodeRegexGroup = (value) => { + const decoded = decodeURIComponent(value) + const encoded = encodeURIComponent(value) + const union = [...new Set([encoded, decoded, value])].map(escapeRegExp).join('|') + return union +} + +/** + * a tagged template literal that returns a regex ensures all variables are excaped + */ +const urlEncodeRegexTag = (strings, ...values) => { + let pattern = '' + for (let i = 0; i < values.length; i++) { + pattern += strings[i] + `(${urlEncodeRegexGroup(values[i])})` + } + pattern += strings[strings.length - 1] + return new RegExp(pattern) +} + +/** + * creates a matcher for redacting url hostname + */ +const redactUrlHostnameMatcher = ({ hostname, replacement } = {}) => ({ + type: TYPE_URL, + predicate: ({ url }) => url.hostname === hostname, + pattern: ({ url }) => { + return urlEncodeRegexTag`(^${url.protocol}//${url.username}:.+@)?${url.hostname}` + }, + replacement: `$1${replacement || asterisk()}`, +}) + +/** + * creates a matcher for redacting url search / query parameter values + */ +const redactUrlSearchParamsMatcher = ({ param, replacement } = {}) => ({ + type: TYPE_URL, + predicate: ({ url }) => url.searchParams.has(param), + pattern: ({ url }) => urlEncodeRegexTag`(${param}=)${url.searchParams.get(param)}`, + replacement: `$1${replacement || asterisk()}`, +}) + +/** creates a matcher for redacting the url password */ +const redactUrlPasswordMatcher = ({ replacement } = {}) => ({ + type: TYPE_URL, + predicate: ({ url }) => url.password, + pattern: ({ url }) => urlEncodeRegexTag`(^${url.protocol}//${url.username}:)${url.password}`, + replacement: `$1${replacement || asterisk()}`, +}) + +const redactUrlReplacement = (...matchers) => (subValue) => { + try { + const url = new URL(subValue) + return redactMatchers(...matchers)(subValue, { url }) + } catch (err) { + return subValue + } +} + +/** + * creates a matcher / submatcher for urls, this function allows you to first + * collect all urls within a larger string and then pass those urls to a + * submatcher + * + * @example + * console.log("this will first match all urls, then pass those urls to the password patcher") + * redactMatchers(redactUrlMatcher(redactUrlPasswordMatcher())) + * + * @example + * console.log( + * "this will assume you are passing in a string that is a url, and will redact the password" + * ) + * redactMatchers(redactUrlPasswordMatcher()) + * + */ +const redactUrlMatcher = (...matchers) => { + return { + ...URL_MATCHER, + replacement: redactUrlReplacement(...matchers), + } +} + +const matcherFunctions = { + [TYPE_REGEX]: (matcher) => (value) => { + if (typeof value === 'string') { + value = value.replace(matcher.pattern, matcher.replacement) + } + return value + }, + [TYPE_URL]: (matcher) => (value, ctx) => { + if (typeof value === 'string') { + try { + const url = ctx?.url || new URL(value) + const { predicate, pattern } = matcher + const predicateValue = predicate({ url }) + if (predicateValue) { + value = value.replace(pattern({ url }), matcher.replacement) + } + } catch (_e) { + return value + } + } + return value + }, + [TYPE_PATH]: (matcher) => (value, ctx) => { + const rawPath = ctx?.path + const path = rawPath.join('.').toLowerCase() + const { predicate, replacement } = matcher + const replace = typeof replacement === 'function' ? replacement : () => replacement + const shouldRun = predicate({ rawPath, path }) + if (shouldRun) { + value = replace(value, { rawPath, path }) + } + return value + }, +} + +/** converts a matcher to a function */ +const redactMatcher = (matcher) => { + return matcherFunctions[matcher.type](matcher) +} + +/** converts a series of matchers to a function */ +const redactMatchers = (...matchers) => (value, ctx) => { + const flatMatchers = matchers.flat() + return flatMatchers.reduce((result, matcher) => { + const fn = (typeof matcher === 'function') ? matcher : redactMatcher(matcher) + return fn(result, ctx) + }, value) +} + +/** + * replacement handler, keeping $1 (if it exists) and replacing the + * rest of the string with asterisks, maintaining string length + */ +const redactDynamicReplacement = () => (value, start) => { + if (typeof start === 'number') { + return asterisk(value) + } + return start + asterisk(value.substring(start.length).length) +} + +/** + * replacement handler, keeping $1 (if it exists) and replacing the + * rest of the string with a fixed number of asterisks + */ +const redactFixedReplacement = (length) => (_value, start) => { + if (typeof start === 'number') { + return asterisk(length) + } + return start + asterisk(length) +} + +const redactUrlPassword = (value, replacement) => { + return redactMatchers(redactUrlPasswordMatcher({ replacement }))(value) +} + +module.exports = { + asterisk, + escapeRegExp, + urlEncodeRegexGroup, + urlEncodeRegexTag, + redactUrlHostnameMatcher, + redactUrlSearchParamsMatcher, + redactUrlPasswordMatcher, + redactUrlMatcher, + redactUrlReplacement, + redactDynamicReplacement, + redactFixedReplacement, + redactMatchers, + redactUrlPassword, +} diff --git a/node_modules/@npmcli/redact/package.json b/node_modules/@npmcli/redact/package.json index 1fc64a4c02f28..2bcee9ea0884b 100644 --- a/node_modules/@npmcli/redact/package.json +++ b/node_modules/@npmcli/redact/package.json @@ -1,8 +1,13 @@ { "name": "@npmcli/redact", - "version": "1.1.0", + "version": "2.0.0", "description": "Redact sensitive npm information from output", "main": "lib/index.js", + "exports": { + ".": "./lib/index.js", + "./server": "./lib/server.js", + "./package.json": "./package.json" + }, "scripts": { "test": "tap", "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", @@ -32,7 +37,8 @@ "nyc-arg": [ "--exclude", "tap-snapshots/**" - ] + ], + "timeout": 120 }, "devDependencies": { "@npmcli/eslint-config": "^4.0.2", diff --git a/node_modules/@npmcli/run-script/lib/run-script-pkg.js b/node_modules/@npmcli/run-script/lib/run-script-pkg.js index a4f27b500718c..9900c96315f85 100644 --- a/node_modules/@npmcli/run-script/lib/run-script-pkg.js +++ b/node_modules/@npmcli/run-script/lib/run-script-pkg.js @@ -44,6 +44,7 @@ const runScriptPkg = async options => { return { code: 0, signal: null } } + let inputEnd = () => {} if (stdio === 'inherit') { let banner if (pkg._id) { @@ -56,8 +57,9 @@ const runScriptPkg = async options => { banner += ` ${args.join(' ')}` } banner += '\n' - const { output } = require('proc-log') + const { output, input } = require('proc-log') output.standard(banner) + inputEnd = input.start() } const [spawnShell, spawnArgs, spawnOpts] = makeSpawnArgs({ @@ -104,7 +106,7 @@ const runScriptPkg = async options => { } else { throw er } - }) + }).finally(inputEnd) } module.exports = runScriptPkg diff --git a/node_modules/@npmcli/run-script/package.json b/node_modules/@npmcli/run-script/package.json index dc780ad3ecbec..8a83e726fbeb2 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": "8.0.0", + "version": "8.1.0", "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)", "author": "GitHub Inc.", "license": "ISC", @@ -16,7 +16,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.21.3", + "@npmcli/template-oss": "4.21.4", "spawk": "^1.8.1", "tap": "^16.0.1" }, @@ -42,7 +42,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.21.3", + "version": "4.21.4", "publish": "true" }, "tap": { diff --git a/node_modules/lru-cache/dist/commonjs/index.min.js b/node_modules/lru-cache/dist/commonjs/index.min.js new file mode 100644 index 0000000000000..b7149f5415a45 --- /dev/null +++ b/node_modules/lru-cache/dist/commonjs/index.min.js @@ -0,0 +1,2 @@ +"use strict";var G=(o,t,e)=>{if(!t.has(o))throw TypeError("Cannot "+e)};var j=(o,t,e)=>(G(o,t,"read from private field"),e?e.call(o):t.get(o)),I=(o,t,e)=>{if(t.has(o))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(o):t.set(o,e)},D=(o,t,e,i)=>(G(o,t,"write to private field"),i?i.call(o,e):t.set(o,e),e);Object.defineProperty(exports,"__esModule",{value:!0});exports.LRUCache=void 0;var T=typeof performance=="object"&&performance&&typeof performance.now=="function"?performance:Date,N=new Set,L=typeof process=="object"&&process?process:{},P=(o,t,e,i)=>{typeof L.emitWarning=="function"?L.emitWarning(o,t,e,i):console.error(`[${e}] ${t}: ${o}`)},W=globalThis.AbortController,M=globalThis.AbortSignal;if(typeof W>"u"){M=class{onabort;_onabort=[];reason;aborted=!1;addEventListener(i,s){this._onabort.push(s)}},W=class{constructor(){t()}signal=new M;abort(i){if(!this.signal.aborted){this.signal.reason=i,this.signal.aborted=!0;for(let s of this.signal._onabort)s(i);this.signal.onabort?.(i)}}};let o=L.env?.LRU_CACHE_IGNORE_AC_WARNING!=="1",t=()=>{o&&(o=!1,P("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.","NO_ABORT_CONTROLLER","ENOTSUP",t))}}var V=o=>!N.has(o),Y=Symbol("type"),A=o=>o&&o===Math.floor(o)&&o>0&&isFinite(o),H=o=>A(o)?o<=Math.pow(2,8)?Uint8Array:o<=Math.pow(2,16)?Uint16Array:o<=Math.pow(2,32)?Uint32Array:o<=Number.MAX_SAFE_INTEGER?E:null:null,E=class extends Array{constructor(t){super(t),this.fill(0)}},v,z=class{heap;length;static create(t){let e=H(t);if(!e)return[];D(z,v,!0);let i=new z(t,e);return D(z,v,!1),i}constructor(t,e){if(!j(z,v))throw new TypeError("instantiate Stack using Stack.create(n)");this.heap=new e(t),this.length=0}push(t){this.heap[this.length++]=t}pop(){return this.heap[--this.length]}},R=z;v=new WeakMap,I(R,v,!1);var C=class{#g;#f;#p;#w;#C;ttl;ttlResolution;ttlAutopurge;updateAgeOnGet;updateAgeOnHas;allowStale;noDisposeOnSet;noUpdateTTL;maxEntrySize;sizeCalculation;noDeleteOnFetchRejection;noDeleteOnStaleGet;allowStaleOnFetchAbort;allowStaleOnFetchRejection;ignoreFetchAbort;#n;#S;#s;#i;#t;#l;#c;#o;#h;#_;#r;#b;#y;#u;#m;#T;#a;static unsafeExposeInternals(t){return{starts:t.#y,ttls:t.#u,sizes:t.#b,keyMap:t.#s,keyList:t.#i,valList:t.#t,next:t.#l,prev:t.#c,get head(){return t.#o},get tail(){return t.#h},free:t.#_,isBackgroundFetch:e=>t.#e(e),backgroundFetch:(e,i,s,n)=>t.#D(e,i,s,n),moveToTail:e=>t.#v(e),indexes:e=>t.#A(e),rindexes:e=>t.#F(e),isStale:e=>t.#d(e)}}get max(){return this.#g}get maxSize(){return this.#f}get calculatedSize(){return this.#S}get size(){return this.#n}get fetchMethod(){return this.#C}get dispose(){return this.#p}get disposeAfter(){return this.#w}constructor(t){let{max:e=0,ttl:i,ttlResolution:s=1,ttlAutopurge:n,updateAgeOnGet:h,updateAgeOnHas:l,allowStale:r,dispose:g,disposeAfter:b,noDisposeOnSet:f,noUpdateTTL:u,maxSize:c=0,maxEntrySize:F=0,sizeCalculation:d,fetchMethod:S,noDeleteOnFetchRejection:a,noDeleteOnStaleGet:w,allowStaleOnFetchRejection:y,allowStaleOnFetchAbort:p,ignoreFetchAbort:_}=t;if(e!==0&&!A(e))throw new TypeError("max option must be a nonnegative integer");let O=e?H(e):Array;if(!O)throw new Error("invalid max value: "+e);if(this.#g=e,this.#f=c,this.maxEntrySize=F||this.#f,this.sizeCalculation=d,this.sizeCalculation){if(!this.#f&&!this.maxEntrySize)throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");if(typeof this.sizeCalculation!="function")throw new TypeError("sizeCalculation set to non-function")}if(S!==void 0&&typeof S!="function")throw new TypeError("fetchMethod must be a function if specified");if(this.#C=S,this.#T=!!S,this.#s=new Map,this.#i=new Array(e).fill(void 0),this.#t=new Array(e).fill(void 0),this.#l=new O(e),this.#c=new O(e),this.#o=0,this.#h=0,this.#_=R.create(e),this.#n=0,this.#S=0,typeof g=="function"&&(this.#p=g),typeof b=="function"?(this.#w=b,this.#r=[]):(this.#w=void 0,this.#r=void 0),this.#m=!!this.#p,this.#a=!!this.#w,this.noDisposeOnSet=!!f,this.noUpdateTTL=!!u,this.noDeleteOnFetchRejection=!!a,this.allowStaleOnFetchRejection=!!y,this.allowStaleOnFetchAbort=!!p,this.ignoreFetchAbort=!!_,this.maxEntrySize!==0){if(this.#f!==0&&!A(this.#f))throw new TypeError("maxSize must be a positive integer if specified");if(!A(this.maxEntrySize))throw new TypeError("maxEntrySize must be a positive integer if specified");this.#I()}if(this.allowStale=!!r,this.noDeleteOnStaleGet=!!w,this.updateAgeOnGet=!!h,this.updateAgeOnHas=!!l,this.ttlResolution=A(s)||s===0?s:1,this.ttlAutopurge=!!n,this.ttl=i||0,this.ttl){if(!A(this.ttl))throw new TypeError("ttl must be a positive integer if specified");this.#L()}if(this.#g===0&&this.ttl===0&&this.#f===0)throw new TypeError("At least one of max, maxSize, or ttl is required");if(!this.ttlAutopurge&&!this.#g&&!this.#f){let m="LRU_CACHE_UNBOUNDED";V(m)&&(N.add(m),P("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.","UnboundedCacheWarning",m,C))}}getRemainingTTL(t){return this.#s.has(t)?1/0:0}#L(){let t=new E(this.#g),e=new E(this.#g);this.#u=t,this.#y=e,this.#U=(n,h,l=T.now())=>{if(e[n]=h!==0?l:0,t[n]=h,h!==0&&this.ttlAutopurge){let r=setTimeout(()=>{this.#d(n)&&this.delete(this.#i[n])},h+1);r.unref&&r.unref()}},this.#z=n=>{e[n]=t[n]!==0?T.now():0},this.#O=(n,h)=>{if(t[h]){let l=t[h],r=e[h];if(!l||!r)return;n.ttl=l,n.start=r,n.now=i||s();let g=n.now-r;n.remainingTTL=l-g}};let i=0,s=()=>{let n=T.now();if(this.ttlResolution>0){i=n;let h=setTimeout(()=>i=0,this.ttlResolution);h.unref&&h.unref()}return n};this.getRemainingTTL=n=>{let h=this.#s.get(n);if(h===void 0)return 0;let l=t[h],r=e[h];if(!l||!r)return 1/0;let g=(i||s())-r;return l-g},this.#d=n=>{let h=e[n],l=t[n];return!!l&&!!h&&(i||s())-h>l}}#z=()=>{};#O=()=>{};#U=()=>{};#d=()=>!1;#I(){let t=new E(this.#g);this.#S=0,this.#b=t,this.#E=e=>{this.#S-=t[e],t[e]=0},this.#x=(e,i,s,n)=>{if(this.#e(i))return 0;if(!A(s))if(n){if(typeof n!="function")throw new TypeError("sizeCalculation must be a function");if(s=n(i,e),!A(s))throw new TypeError("sizeCalculation return invalid (expect positive integer)")}else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");return s},this.#R=(e,i,s)=>{if(t[e]=i,this.#f){let n=this.#f-t[e];for(;this.#S>n;)this.#W(!0)}this.#S+=t[e],s&&(s.entrySize=i,s.totalCalculatedSize=this.#S)}}#E=t=>{};#R=(t,e,i)=>{};#x=(t,e,i,s)=>{if(i||s)throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");return 0};*#A({allowStale:t=this.allowStale}={}){if(this.#n)for(let e=this.#h;!(!this.#G(e)||((t||!this.#d(e))&&(yield e),e===this.#o));)e=this.#c[e]}*#F({allowStale:t=this.allowStale}={}){if(this.#n)for(let e=this.#o;!(!this.#G(e)||((t||!this.#d(e))&&(yield e),e===this.#h));)e=this.#l[e]}#G(t){return t!==void 0&&this.#s.get(this.#i[t])===t}*entries(){for(let t of this.#A())this.#t[t]!==void 0&&this.#i[t]!==void 0&&!this.#e(this.#t[t])&&(yield[this.#i[t],this.#t[t]])}*rentries(){for(let t of this.#F())this.#t[t]!==void 0&&this.#i[t]!==void 0&&!this.#e(this.#t[t])&&(yield[this.#i[t],this.#t[t]])}*keys(){for(let t of this.#A()){let e=this.#i[t];e!==void 0&&!this.#e(this.#t[t])&&(yield e)}}*rkeys(){for(let t of this.#F()){let e=this.#i[t];e!==void 0&&!this.#e(this.#t[t])&&(yield e)}}*values(){for(let t of this.#A())this.#t[t]!==void 0&&!this.#e(this.#t[t])&&(yield this.#t[t])}*rvalues(){for(let t of this.#F())this.#t[t]!==void 0&&!this.#e(this.#t[t])&&(yield this.#t[t])}[Symbol.iterator](){return this.entries()}[Symbol.toStringTag]="LRUCache";find(t,e={}){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;if(n!==void 0&&t(n,this.#i[i],this))return this.get(this.#i[i],e)}}forEach(t,e=this){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&t.call(e,n,this.#i[i],this)}}rforEach(t,e=this){for(let i of this.#F()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&t.call(e,n,this.#i[i],this)}}purgeStale(){let t=!1;for(let e of this.#F({allowStale:!0}))this.#d(e)&&(this.delete(this.#i[e]),t=!0);return t}info(t){let e=this.#s.get(t);if(e===void 0)return;let i=this.#t[e],s=this.#e(i)?i.__staleWhileFetching:i;if(s===void 0)return;let n={value:s};if(this.#u&&this.#y){let h=this.#u[e],l=this.#y[e];if(h&&l){let r=h-(T.now()-l);n.ttl=r,n.start=Date.now()}}return this.#b&&(n.size=this.#b[e]),n}dump(){let t=[];for(let e of this.#A({allowStale:!0})){let i=this.#i[e],s=this.#t[e],n=this.#e(s)?s.__staleWhileFetching:s;if(n===void 0||i===void 0)continue;let h={value:n};if(this.#u&&this.#y){h.ttl=this.#u[e];let l=T.now()-this.#y[e];h.start=Math.floor(Date.now()-l)}this.#b&&(h.size=this.#b[e]),t.unshift([i,h])}return t}load(t){this.clear();for(let[e,i]of t){if(i.start){let s=Date.now()-i.start;i.start=T.now()-s}this.set(e,i.value,i)}}set(t,e,i={}){if(e===void 0)return this.delete(t),this;let{ttl:s=this.ttl,start:n,noDisposeOnSet:h=this.noDisposeOnSet,sizeCalculation:l=this.sizeCalculation,status:r}=i,{noUpdateTTL:g=this.noUpdateTTL}=i,b=this.#x(t,e,i.size||0,l);if(this.maxEntrySize&&b>this.maxEntrySize)return r&&(r.set="miss",r.maxEntrySizeExceeded=!0),this.delete(t),this;let f=this.#n===0?void 0:this.#s.get(t);if(f===void 0)f=this.#n===0?this.#h:this.#_.length!==0?this.#_.pop():this.#n===this.#g?this.#W(!1):this.#n,this.#i[f]=t,this.#t[f]=e,this.#s.set(t,f),this.#l[this.#h]=f,this.#c[f]=this.#h,this.#h=f,this.#n++,this.#R(f,b,r),r&&(r.set="add"),g=!1;else{this.#v(f);let u=this.#t[f];if(e!==u){if(this.#T&&this.#e(u)){u.__abortController.abort(new Error("replaced"));let{__staleWhileFetching:c}=u;c!==void 0&&!h&&(this.#m&&this.#p?.(c,t,"set"),this.#a&&this.#r?.push([c,t,"set"]))}else h||(this.#m&&this.#p?.(u,t,"set"),this.#a&&this.#r?.push([u,t,"set"]));if(this.#E(f),this.#R(f,b,r),this.#t[f]=e,r){r.set="replace";let c=u&&this.#e(u)?u.__staleWhileFetching:u;c!==void 0&&(r.oldValue=c)}}else r&&(r.set="update")}if(s!==0&&!this.#u&&this.#L(),this.#u&&(g||this.#U(f,s,n),r&&this.#O(r,f)),!h&&this.#a&&this.#r){let u=this.#r,c;for(;c=u?.shift();)this.#w?.(...c)}return this}pop(){try{for(;this.#n;){let t=this.#t[this.#o];if(this.#W(!0),this.#e(t)){if(t.__staleWhileFetching)return t.__staleWhileFetching}else if(t!==void 0)return t}}finally{if(this.#a&&this.#r){let t=this.#r,e;for(;e=t?.shift();)this.#w?.(...e)}}}#W(t){let e=this.#o,i=this.#i[e],s=this.#t[e];return this.#T&&this.#e(s)?s.__abortController.abort(new Error("evicted")):(this.#m||this.#a)&&(this.#m&&this.#p?.(s,i,"evict"),this.#a&&this.#r?.push([s,i,"evict"])),this.#E(e),t&&(this.#i[e]=void 0,this.#t[e]=void 0,this.#_.push(e)),this.#n===1?(this.#o=this.#h=0,this.#_.length=0):this.#o=this.#l[e],this.#s.delete(i),this.#n--,e}has(t,e={}){let{updateAgeOnHas:i=this.updateAgeOnHas,status:s}=e,n=this.#s.get(t);if(n!==void 0){let h=this.#t[n];if(this.#e(h)&&h.__staleWhileFetching===void 0)return!1;if(this.#d(n))s&&(s.has="stale",this.#O(s,n));else return i&&this.#z(n),s&&(s.has="hit",this.#O(s,n)),!0}else s&&(s.has="miss");return!1}peek(t,e={}){let{allowStale:i=this.allowStale}=e,s=this.#s.get(t);if(s===void 0||!i&&this.#d(s))return;let n=this.#t[s];return this.#e(n)?n.__staleWhileFetching:n}#D(t,e,i,s){let n=e===void 0?void 0:this.#t[e];if(this.#e(n))return n;let h=new W,{signal:l}=i;l?.addEventListener("abort",()=>h.abort(l.reason),{signal:h.signal});let r={signal:h.signal,options:i,context:s},g=(d,S=!1)=>{let{aborted:a}=h.signal,w=i.ignoreFetchAbort&&d!==void 0;if(i.status&&(a&&!S?(i.status.fetchAborted=!0,i.status.fetchError=h.signal.reason,w&&(i.status.fetchAbortIgnored=!0)):i.status.fetchResolved=!0),a&&!w&&!S)return f(h.signal.reason);let y=c;return this.#t[e]===c&&(d===void 0?y.__staleWhileFetching?this.#t[e]=y.__staleWhileFetching:this.delete(t):(i.status&&(i.status.fetchUpdated=!0),this.set(t,d,r.options))),d},b=d=>(i.status&&(i.status.fetchRejected=!0,i.status.fetchError=d),f(d)),f=d=>{let{aborted:S}=h.signal,a=S&&i.allowStaleOnFetchAbort,w=a||i.allowStaleOnFetchRejection,y=w||i.noDeleteOnFetchRejection,p=c;if(this.#t[e]===c&&(!y||p.__staleWhileFetching===void 0?this.delete(t):a||(this.#t[e]=p.__staleWhileFetching)),w)return i.status&&p.__staleWhileFetching!==void 0&&(i.status.returnedStale=!0),p.__staleWhileFetching;if(p.__returned===p)throw d},u=(d,S)=>{let a=this.#C?.(t,n,r);a&&a instanceof Promise&&a.then(w=>d(w===void 0?void 0:w),S),h.signal.addEventListener("abort",()=>{(!i.ignoreFetchAbort||i.allowStaleOnFetchAbort)&&(d(void 0),i.allowStaleOnFetchAbort&&(d=w=>g(w,!0)))})};i.status&&(i.status.fetchDispatched=!0);let c=new Promise(u).then(g,b),F=Object.assign(c,{__abortController:h,__staleWhileFetching:n,__returned:void 0});return e===void 0?(this.set(t,F,{...r.options,status:void 0}),e=this.#s.get(t)):this.#t[e]=F,F}#e(t){if(!this.#T)return!1;let e=t;return!!e&&e instanceof Promise&&e.hasOwnProperty("__staleWhileFetching")&&e.__abortController instanceof W}async fetch(t,e={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,ttl:h=this.ttl,noDisposeOnSet:l=this.noDisposeOnSet,size:r=0,sizeCalculation:g=this.sizeCalculation,noUpdateTTL:b=this.noUpdateTTL,noDeleteOnFetchRejection:f=this.noDeleteOnFetchRejection,allowStaleOnFetchRejection:u=this.allowStaleOnFetchRejection,ignoreFetchAbort:c=this.ignoreFetchAbort,allowStaleOnFetchAbort:F=this.allowStaleOnFetchAbort,context:d,forceRefresh:S=!1,status:a,signal:w}=e;if(!this.#T)return a&&(a.fetch="get"),this.get(t,{allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,status:a});let y={allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,ttl:h,noDisposeOnSet:l,size:r,sizeCalculation:g,noUpdateTTL:b,noDeleteOnFetchRejection:f,allowStaleOnFetchRejection:u,allowStaleOnFetchAbort:F,ignoreFetchAbort:c,status:a,signal:w},p=this.#s.get(t);if(p===void 0){a&&(a.fetch="miss");let _=this.#D(t,p,y,d);return _.__returned=_}else{let _=this.#t[p];if(this.#e(_)){let x=i&&_.__staleWhileFetching!==void 0;return a&&(a.fetch="inflight",x&&(a.returnedStale=!0)),x?_.__staleWhileFetching:_.__returned=_}let O=this.#d(p);if(!S&&!O)return a&&(a.fetch="hit"),this.#v(p),s&&this.#z(p),a&&this.#O(a,p),_;let m=this.#D(t,p,y,d),U=m.__staleWhileFetching!==void 0&&i;return a&&(a.fetch=O?"stale":"refresh",U&&O&&(a.returnedStale=!0)),U?m.__staleWhileFetching:m.__returned=m}}get(t,e={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,status:h}=e,l=this.#s.get(t);if(l!==void 0){let r=this.#t[l],g=this.#e(r);return h&&this.#O(h,l),this.#d(l)?(h&&(h.get="stale"),g?(h&&i&&r.__staleWhileFetching!==void 0&&(h.returnedStale=!0),i?r.__staleWhileFetching:void 0):(n||this.delete(t),h&&i&&(h.returnedStale=!0),i?r:void 0)):(h&&(h.get="hit"),g?r.__staleWhileFetching:(this.#v(l),s&&this.#z(l),r))}else h&&(h.get="miss")}#j(t,e){this.#c[e]=t,this.#l[t]=e}#v(t){t!==this.#h&&(t===this.#o?this.#o=this.#l[t]:this.#j(this.#c[t],this.#l[t]),this.#j(this.#h,t),this.#h=t)}delete(t){let e=!1;if(this.#n!==0){let i=this.#s.get(t);if(i!==void 0)if(e=!0,this.#n===1)this.clear();else{this.#E(i);let s=this.#t[i];if(this.#e(s)?s.__abortController.abort(new Error("deleted")):(this.#m||this.#a)&&(this.#m&&this.#p?.(s,t,"delete"),this.#a&&this.#r?.push([s,t,"delete"])),this.#s.delete(t),this.#i[i]=void 0,this.#t[i]=void 0,i===this.#h)this.#h=this.#c[i];else if(i===this.#o)this.#o=this.#l[i];else{let n=this.#c[i];this.#l[n]=this.#l[i];let h=this.#l[i];this.#c[h]=this.#c[i]}this.#n--,this.#_.push(i)}}if(this.#a&&this.#r?.length){let i=this.#r,s;for(;s=i?.shift();)this.#w?.(...s)}return e}clear(){for(let t of this.#F({allowStale:!0})){let e=this.#t[t];if(this.#e(e))e.__abortController.abort(new Error("deleted"));else{let i=this.#i[t];this.#m&&this.#p?.(e,i,"delete"),this.#a&&this.#r?.push([e,i,"delete"])}}if(this.#s.clear(),this.#t.fill(void 0),this.#i.fill(void 0),this.#u&&this.#y&&(this.#u.fill(0),this.#y.fill(0)),this.#b&&this.#b.fill(0),this.#o=0,this.#h=0,this.#_.length=0,this.#S=0,this.#n=0,this.#a&&this.#r){let t=this.#r,e;for(;e=t?.shift();)this.#w?.(...e)}}};exports.LRUCache=C; +//# sourceMappingURL=index.min.js.map diff --git a/node_modules/lru-cache/dist/esm/index.min.js b/node_modules/lru-cache/dist/esm/index.min.js new file mode 100644 index 0000000000000..4285815f9abb1 --- /dev/null +++ b/node_modules/lru-cache/dist/esm/index.min.js @@ -0,0 +1,2 @@ +var G=(o,t,e)=>{if(!t.has(o))throw TypeError("Cannot "+e)};var I=(o,t,e)=>(G(o,t,"read from private field"),e?e.call(o):t.get(o)),j=(o,t,e)=>{if(t.has(o))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(o):t.set(o,e)},D=(o,t,e,i)=>(G(o,t,"write to private field"),i?i.call(o,e):t.set(o,e),e);var O=typeof performance=="object"&&performance&&typeof performance.now=="function"?performance:Date,M=new Set,L=typeof process=="object"&&process?process:{},P=(o,t,e,i)=>{typeof L.emitWarning=="function"?L.emitWarning(o,t,e,i):console.error(`[${e}] ${t}: ${o}`)},W=globalThis.AbortController,N=globalThis.AbortSignal;if(typeof W>"u"){N=class{onabort;_onabort=[];reason;aborted=!1;addEventListener(i,s){this._onabort.push(s)}},W=class{constructor(){t()}signal=new N;abort(i){if(!this.signal.aborted){this.signal.reason=i,this.signal.aborted=!0;for(let s of this.signal._onabort)s(i);this.signal.onabort?.(i)}}};let o=L.env?.LRU_CACHE_IGNORE_AC_WARNING!=="1",t=()=>{o&&(o=!1,P("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.","NO_ABORT_CONTROLLER","ENOTSUP",t))}}var V=o=>!M.has(o),Y=Symbol("type"),A=o=>o&&o===Math.floor(o)&&o>0&&isFinite(o),H=o=>A(o)?o<=Math.pow(2,8)?Uint8Array:o<=Math.pow(2,16)?Uint16Array:o<=Math.pow(2,32)?Uint32Array:o<=Number.MAX_SAFE_INTEGER?E:null:null,E=class extends Array{constructor(t){super(t),this.fill(0)}},v,z=class{heap;length;static create(t){let e=H(t);if(!e)return[];D(z,v,!0);let i=new z(t,e);return D(z,v,!1),i}constructor(t,e){if(!I(z,v))throw new TypeError("instantiate Stack using Stack.create(n)");this.heap=new e(t),this.length=0}push(t){this.heap[this.length++]=t}pop(){return this.heap[--this.length]}},C=z;v=new WeakMap,j(C,v,!1);var R=class{#g;#f;#p;#w;#C;ttl;ttlResolution;ttlAutopurge;updateAgeOnGet;updateAgeOnHas;allowStale;noDisposeOnSet;noUpdateTTL;maxEntrySize;sizeCalculation;noDeleteOnFetchRejection;noDeleteOnStaleGet;allowStaleOnFetchAbort;allowStaleOnFetchRejection;ignoreFetchAbort;#n;#S;#s;#i;#t;#l;#c;#o;#h;#_;#r;#b;#y;#u;#m;#O;#a;static unsafeExposeInternals(t){return{starts:t.#y,ttls:t.#u,sizes:t.#b,keyMap:t.#s,keyList:t.#i,valList:t.#t,next:t.#l,prev:t.#c,get head(){return t.#o},get tail(){return t.#h},free:t.#_,isBackgroundFetch:e=>t.#e(e),backgroundFetch:(e,i,s,n)=>t.#D(e,i,s,n),moveToTail:e=>t.#v(e),indexes:e=>t.#A(e),rindexes:e=>t.#F(e),isStale:e=>t.#d(e)}}get max(){return this.#g}get maxSize(){return this.#f}get calculatedSize(){return this.#S}get size(){return this.#n}get fetchMethod(){return this.#C}get dispose(){return this.#p}get disposeAfter(){return this.#w}constructor(t){let{max:e=0,ttl:i,ttlResolution:s=1,ttlAutopurge:n,updateAgeOnGet:h,updateAgeOnHas:l,allowStale:r,dispose:g,disposeAfter:b,noDisposeOnSet:f,noUpdateTTL:u,maxSize:c=0,maxEntrySize:F=0,sizeCalculation:d,fetchMethod:S,noDeleteOnFetchRejection:a,noDeleteOnStaleGet:w,allowStaleOnFetchRejection:y,allowStaleOnFetchAbort:p,ignoreFetchAbort:_}=t;if(e!==0&&!A(e))throw new TypeError("max option must be a nonnegative integer");let T=e?H(e):Array;if(!T)throw new Error("invalid max value: "+e);if(this.#g=e,this.#f=c,this.maxEntrySize=F||this.#f,this.sizeCalculation=d,this.sizeCalculation){if(!this.#f&&!this.maxEntrySize)throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");if(typeof this.sizeCalculation!="function")throw new TypeError("sizeCalculation set to non-function")}if(S!==void 0&&typeof S!="function")throw new TypeError("fetchMethod must be a function if specified");if(this.#C=S,this.#O=!!S,this.#s=new Map,this.#i=new Array(e).fill(void 0),this.#t=new Array(e).fill(void 0),this.#l=new T(e),this.#c=new T(e),this.#o=0,this.#h=0,this.#_=C.create(e),this.#n=0,this.#S=0,typeof g=="function"&&(this.#p=g),typeof b=="function"?(this.#w=b,this.#r=[]):(this.#w=void 0,this.#r=void 0),this.#m=!!this.#p,this.#a=!!this.#w,this.noDisposeOnSet=!!f,this.noUpdateTTL=!!u,this.noDeleteOnFetchRejection=!!a,this.allowStaleOnFetchRejection=!!y,this.allowStaleOnFetchAbort=!!p,this.ignoreFetchAbort=!!_,this.maxEntrySize!==0){if(this.#f!==0&&!A(this.#f))throw new TypeError("maxSize must be a positive integer if specified");if(!A(this.maxEntrySize))throw new TypeError("maxEntrySize must be a positive integer if specified");this.#j()}if(this.allowStale=!!r,this.noDeleteOnStaleGet=!!w,this.updateAgeOnGet=!!h,this.updateAgeOnHas=!!l,this.ttlResolution=A(s)||s===0?s:1,this.ttlAutopurge=!!n,this.ttl=i||0,this.ttl){if(!A(this.ttl))throw new TypeError("ttl must be a positive integer if specified");this.#L()}if(this.#g===0&&this.ttl===0&&this.#f===0)throw new TypeError("At least one of max, maxSize, or ttl is required");if(!this.ttlAutopurge&&!this.#g&&!this.#f){let m="LRU_CACHE_UNBOUNDED";V(m)&&(M.add(m),P("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.","UnboundedCacheWarning",m,R))}}getRemainingTTL(t){return this.#s.has(t)?1/0:0}#L(){let t=new E(this.#g),e=new E(this.#g);this.#u=t,this.#y=e,this.#x=(n,h,l=O.now())=>{if(e[n]=h!==0?l:0,t[n]=h,h!==0&&this.ttlAutopurge){let r=setTimeout(()=>{this.#d(n)&&this.delete(this.#i[n])},h+1);r.unref&&r.unref()}},this.#z=n=>{e[n]=t[n]!==0?O.now():0},this.#T=(n,h)=>{if(t[h]){let l=t[h],r=e[h];if(!l||!r)return;n.ttl=l,n.start=r,n.now=i||s();let g=n.now-r;n.remainingTTL=l-g}};let i=0,s=()=>{let n=O.now();if(this.ttlResolution>0){i=n;let h=setTimeout(()=>i=0,this.ttlResolution);h.unref&&h.unref()}return n};this.getRemainingTTL=n=>{let h=this.#s.get(n);if(h===void 0)return 0;let l=t[h],r=e[h];if(!l||!r)return 1/0;let g=(i||s())-r;return l-g},this.#d=n=>{let h=e[n],l=t[n];return!!l&&!!h&&(i||s())-h>l}}#z=()=>{};#T=()=>{};#x=()=>{};#d=()=>!1;#j(){let t=new E(this.#g);this.#S=0,this.#b=t,this.#E=e=>{this.#S-=t[e],t[e]=0},this.#U=(e,i,s,n)=>{if(this.#e(i))return 0;if(!A(s))if(n){if(typeof n!="function")throw new TypeError("sizeCalculation must be a function");if(s=n(i,e),!A(s))throw new TypeError("sizeCalculation return invalid (expect positive integer)")}else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");return s},this.#W=(e,i,s)=>{if(t[e]=i,this.#f){let n=this.#f-t[e];for(;this.#S>n;)this.#R(!0)}this.#S+=t[e],s&&(s.entrySize=i,s.totalCalculatedSize=this.#S)}}#E=t=>{};#W=(t,e,i)=>{};#U=(t,e,i,s)=>{if(i||s)throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");return 0};*#A({allowStale:t=this.allowStale}={}){if(this.#n)for(let e=this.#h;!(!this.#G(e)||((t||!this.#d(e))&&(yield e),e===this.#o));)e=this.#c[e]}*#F({allowStale:t=this.allowStale}={}){if(this.#n)for(let e=this.#o;!(!this.#G(e)||((t||!this.#d(e))&&(yield e),e===this.#h));)e=this.#l[e]}#G(t){return t!==void 0&&this.#s.get(this.#i[t])===t}*entries(){for(let t of this.#A())this.#t[t]!==void 0&&this.#i[t]!==void 0&&!this.#e(this.#t[t])&&(yield[this.#i[t],this.#t[t]])}*rentries(){for(let t of this.#F())this.#t[t]!==void 0&&this.#i[t]!==void 0&&!this.#e(this.#t[t])&&(yield[this.#i[t],this.#t[t]])}*keys(){for(let t of this.#A()){let e=this.#i[t];e!==void 0&&!this.#e(this.#t[t])&&(yield e)}}*rkeys(){for(let t of this.#F()){let e=this.#i[t];e!==void 0&&!this.#e(this.#t[t])&&(yield e)}}*values(){for(let t of this.#A())this.#t[t]!==void 0&&!this.#e(this.#t[t])&&(yield this.#t[t])}*rvalues(){for(let t of this.#F())this.#t[t]!==void 0&&!this.#e(this.#t[t])&&(yield this.#t[t])}[Symbol.iterator](){return this.entries()}[Symbol.toStringTag]="LRUCache";find(t,e={}){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;if(n!==void 0&&t(n,this.#i[i],this))return this.get(this.#i[i],e)}}forEach(t,e=this){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&t.call(e,n,this.#i[i],this)}}rforEach(t,e=this){for(let i of this.#F()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&t.call(e,n,this.#i[i],this)}}purgeStale(){let t=!1;for(let e of this.#F({allowStale:!0}))this.#d(e)&&(this.delete(this.#i[e]),t=!0);return t}info(t){let e=this.#s.get(t);if(e===void 0)return;let i=this.#t[e],s=this.#e(i)?i.__staleWhileFetching:i;if(s===void 0)return;let n={value:s};if(this.#u&&this.#y){let h=this.#u[e],l=this.#y[e];if(h&&l){let r=h-(O.now()-l);n.ttl=r,n.start=Date.now()}}return this.#b&&(n.size=this.#b[e]),n}dump(){let t=[];for(let e of this.#A({allowStale:!0})){let i=this.#i[e],s=this.#t[e],n=this.#e(s)?s.__staleWhileFetching:s;if(n===void 0||i===void 0)continue;let h={value:n};if(this.#u&&this.#y){h.ttl=this.#u[e];let l=O.now()-this.#y[e];h.start=Math.floor(Date.now()-l)}this.#b&&(h.size=this.#b[e]),t.unshift([i,h])}return t}load(t){this.clear();for(let[e,i]of t){if(i.start){let s=Date.now()-i.start;i.start=O.now()-s}this.set(e,i.value,i)}}set(t,e,i={}){if(e===void 0)return this.delete(t),this;let{ttl:s=this.ttl,start:n,noDisposeOnSet:h=this.noDisposeOnSet,sizeCalculation:l=this.sizeCalculation,status:r}=i,{noUpdateTTL:g=this.noUpdateTTL}=i,b=this.#U(t,e,i.size||0,l);if(this.maxEntrySize&&b>this.maxEntrySize)return r&&(r.set="miss",r.maxEntrySizeExceeded=!0),this.delete(t),this;let f=this.#n===0?void 0:this.#s.get(t);if(f===void 0)f=this.#n===0?this.#h:this.#_.length!==0?this.#_.pop():this.#n===this.#g?this.#R(!1):this.#n,this.#i[f]=t,this.#t[f]=e,this.#s.set(t,f),this.#l[this.#h]=f,this.#c[f]=this.#h,this.#h=f,this.#n++,this.#W(f,b,r),r&&(r.set="add"),g=!1;else{this.#v(f);let u=this.#t[f];if(e!==u){if(this.#O&&this.#e(u)){u.__abortController.abort(new Error("replaced"));let{__staleWhileFetching:c}=u;c!==void 0&&!h&&(this.#m&&this.#p?.(c,t,"set"),this.#a&&this.#r?.push([c,t,"set"]))}else h||(this.#m&&this.#p?.(u,t,"set"),this.#a&&this.#r?.push([u,t,"set"]));if(this.#E(f),this.#W(f,b,r),this.#t[f]=e,r){r.set="replace";let c=u&&this.#e(u)?u.__staleWhileFetching:u;c!==void 0&&(r.oldValue=c)}}else r&&(r.set="update")}if(s!==0&&!this.#u&&this.#L(),this.#u&&(g||this.#x(f,s,n),r&&this.#T(r,f)),!h&&this.#a&&this.#r){let u=this.#r,c;for(;c=u?.shift();)this.#w?.(...c)}return this}pop(){try{for(;this.#n;){let t=this.#t[this.#o];if(this.#R(!0),this.#e(t)){if(t.__staleWhileFetching)return t.__staleWhileFetching}else if(t!==void 0)return t}}finally{if(this.#a&&this.#r){let t=this.#r,e;for(;e=t?.shift();)this.#w?.(...e)}}}#R(t){let e=this.#o,i=this.#i[e],s=this.#t[e];return this.#O&&this.#e(s)?s.__abortController.abort(new Error("evicted")):(this.#m||this.#a)&&(this.#m&&this.#p?.(s,i,"evict"),this.#a&&this.#r?.push([s,i,"evict"])),this.#E(e),t&&(this.#i[e]=void 0,this.#t[e]=void 0,this.#_.push(e)),this.#n===1?(this.#o=this.#h=0,this.#_.length=0):this.#o=this.#l[e],this.#s.delete(i),this.#n--,e}has(t,e={}){let{updateAgeOnHas:i=this.updateAgeOnHas,status:s}=e,n=this.#s.get(t);if(n!==void 0){let h=this.#t[n];if(this.#e(h)&&h.__staleWhileFetching===void 0)return!1;if(this.#d(n))s&&(s.has="stale",this.#T(s,n));else return i&&this.#z(n),s&&(s.has="hit",this.#T(s,n)),!0}else s&&(s.has="miss");return!1}peek(t,e={}){let{allowStale:i=this.allowStale}=e,s=this.#s.get(t);if(s===void 0||!i&&this.#d(s))return;let n=this.#t[s];return this.#e(n)?n.__staleWhileFetching:n}#D(t,e,i,s){let n=e===void 0?void 0:this.#t[e];if(this.#e(n))return n;let h=new W,{signal:l}=i;l?.addEventListener("abort",()=>h.abort(l.reason),{signal:h.signal});let r={signal:h.signal,options:i,context:s},g=(d,S=!1)=>{let{aborted:a}=h.signal,w=i.ignoreFetchAbort&&d!==void 0;if(i.status&&(a&&!S?(i.status.fetchAborted=!0,i.status.fetchError=h.signal.reason,w&&(i.status.fetchAbortIgnored=!0)):i.status.fetchResolved=!0),a&&!w&&!S)return f(h.signal.reason);let y=c;return this.#t[e]===c&&(d===void 0?y.__staleWhileFetching?this.#t[e]=y.__staleWhileFetching:this.delete(t):(i.status&&(i.status.fetchUpdated=!0),this.set(t,d,r.options))),d},b=d=>(i.status&&(i.status.fetchRejected=!0,i.status.fetchError=d),f(d)),f=d=>{let{aborted:S}=h.signal,a=S&&i.allowStaleOnFetchAbort,w=a||i.allowStaleOnFetchRejection,y=w||i.noDeleteOnFetchRejection,p=c;if(this.#t[e]===c&&(!y||p.__staleWhileFetching===void 0?this.delete(t):a||(this.#t[e]=p.__staleWhileFetching)),w)return i.status&&p.__staleWhileFetching!==void 0&&(i.status.returnedStale=!0),p.__staleWhileFetching;if(p.__returned===p)throw d},u=(d,S)=>{let a=this.#C?.(t,n,r);a&&a instanceof Promise&&a.then(w=>d(w===void 0?void 0:w),S),h.signal.addEventListener("abort",()=>{(!i.ignoreFetchAbort||i.allowStaleOnFetchAbort)&&(d(void 0),i.allowStaleOnFetchAbort&&(d=w=>g(w,!0)))})};i.status&&(i.status.fetchDispatched=!0);let c=new Promise(u).then(g,b),F=Object.assign(c,{__abortController:h,__staleWhileFetching:n,__returned:void 0});return e===void 0?(this.set(t,F,{...r.options,status:void 0}),e=this.#s.get(t)):this.#t[e]=F,F}#e(t){if(!this.#O)return!1;let e=t;return!!e&&e instanceof Promise&&e.hasOwnProperty("__staleWhileFetching")&&e.__abortController instanceof W}async fetch(t,e={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,ttl:h=this.ttl,noDisposeOnSet:l=this.noDisposeOnSet,size:r=0,sizeCalculation:g=this.sizeCalculation,noUpdateTTL:b=this.noUpdateTTL,noDeleteOnFetchRejection:f=this.noDeleteOnFetchRejection,allowStaleOnFetchRejection:u=this.allowStaleOnFetchRejection,ignoreFetchAbort:c=this.ignoreFetchAbort,allowStaleOnFetchAbort:F=this.allowStaleOnFetchAbort,context:d,forceRefresh:S=!1,status:a,signal:w}=e;if(!this.#O)return a&&(a.fetch="get"),this.get(t,{allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,status:a});let y={allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,ttl:h,noDisposeOnSet:l,size:r,sizeCalculation:g,noUpdateTTL:b,noDeleteOnFetchRejection:f,allowStaleOnFetchRejection:u,allowStaleOnFetchAbort:F,ignoreFetchAbort:c,status:a,signal:w},p=this.#s.get(t);if(p===void 0){a&&(a.fetch="miss");let _=this.#D(t,p,y,d);return _.__returned=_}else{let _=this.#t[p];if(this.#e(_)){let U=i&&_.__staleWhileFetching!==void 0;return a&&(a.fetch="inflight",U&&(a.returnedStale=!0)),U?_.__staleWhileFetching:_.__returned=_}let T=this.#d(p);if(!S&&!T)return a&&(a.fetch="hit"),this.#v(p),s&&this.#z(p),a&&this.#T(a,p),_;let m=this.#D(t,p,y,d),x=m.__staleWhileFetching!==void 0&&i;return a&&(a.fetch=T?"stale":"refresh",x&&T&&(a.returnedStale=!0)),x?m.__staleWhileFetching:m.__returned=m}}get(t,e={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,status:h}=e,l=this.#s.get(t);if(l!==void 0){let r=this.#t[l],g=this.#e(r);return h&&this.#T(h,l),this.#d(l)?(h&&(h.get="stale"),g?(h&&i&&r.__staleWhileFetching!==void 0&&(h.returnedStale=!0),i?r.__staleWhileFetching:void 0):(n||this.delete(t),h&&i&&(h.returnedStale=!0),i?r:void 0)):(h&&(h.get="hit"),g?r.__staleWhileFetching:(this.#v(l),s&&this.#z(l),r))}else h&&(h.get="miss")}#I(t,e){this.#c[e]=t,this.#l[t]=e}#v(t){t!==this.#h&&(t===this.#o?this.#o=this.#l[t]:this.#I(this.#c[t],this.#l[t]),this.#I(this.#h,t),this.#h=t)}delete(t){let e=!1;if(this.#n!==0){let i=this.#s.get(t);if(i!==void 0)if(e=!0,this.#n===1)this.clear();else{this.#E(i);let s=this.#t[i];if(this.#e(s)?s.__abortController.abort(new Error("deleted")):(this.#m||this.#a)&&(this.#m&&this.#p?.(s,t,"delete"),this.#a&&this.#r?.push([s,t,"delete"])),this.#s.delete(t),this.#i[i]=void 0,this.#t[i]=void 0,i===this.#h)this.#h=this.#c[i];else if(i===this.#o)this.#o=this.#l[i];else{let n=this.#c[i];this.#l[n]=this.#l[i];let h=this.#l[i];this.#c[h]=this.#c[i]}this.#n--,this.#_.push(i)}}if(this.#a&&this.#r?.length){let i=this.#r,s;for(;s=i?.shift();)this.#w?.(...s)}return e}clear(){for(let t of this.#F({allowStale:!0})){let e=this.#t[t];if(this.#e(e))e.__abortController.abort(new Error("deleted"));else{let i=this.#i[t];this.#m&&this.#p?.(e,i,"delete"),this.#a&&this.#r?.push([e,i,"delete"])}}if(this.#s.clear(),this.#t.fill(void 0),this.#i.fill(void 0),this.#u&&this.#y&&(this.#u.fill(0),this.#y.fill(0)),this.#b&&this.#b.fill(0),this.#o=0,this.#h=0,this.#_.length=0,this.#S=0,this.#n=0,this.#a&&this.#r){let t=this.#r,e;for(;e=t?.shift();)this.#w?.(...e)}}};export{R as LRUCache}; +//# sourceMappingURL=index.min.js.map diff --git a/node_modules/lru-cache/package.json b/node_modules/lru-cache/package.json index 348e2118a7c25..ef11862319611 100644 --- a/node_modules/lru-cache/package.json +++ b/node_modules/lru-cache/package.json @@ -1,7 +1,7 @@ { "name": "lru-cache", "description": "A cache object that deletes the least-recently-used items.", - "version": "10.2.0", + "version": "10.2.2", "author": "Isaac Z. Schlueter ", "keywords": [ "mru", @@ -11,8 +11,7 @@ "sideEffects": false, "scripts": { "build": "npm run prepare", - "prepare": "tshy", - "postprepare": "bash fixup.sh", + "prepare": "tshy && bash fixup.sh", "pretest": "npm run prepare", "presnap": "npm run prepare", "test": "tap", @@ -35,8 +34,8 @@ ".": "./src/index.ts", "./min": { "import": { - "types": "./dist/mjs/index.d.ts", - "default": "./dist/mjs/index.min.js" + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.min.js" }, "require": { "types": "./dist/commonjs/index.d.ts", @@ -105,8 +104,8 @@ }, "./min": { "import": { - "types": "./dist/mjs/index.d.ts", - "default": "./dist/mjs/index.min.js" + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.min.js" }, "require": { "types": "./dist/commonjs/index.d.ts", diff --git a/node_modules/make-fetch-happen/lib/cache/entry.js b/node_modules/make-fetch-happen/lib/cache/entry.js index 45141095074ec..bfcfacbcc95e1 100644 --- a/node_modules/make-fetch-happen/lib/cache/entry.js +++ b/node_modules/make-fetch-happen/lib/cache/entry.js @@ -274,6 +274,8 @@ class CacheEntry { const cacheWritePromise = new Promise((resolve, reject) => { cacheWriteResolve = resolve cacheWriteReject = reject + }).catch((err) => { + body.emit('error', err) }) body = new CachingMinipassPipeline({ events: ['integrity', 'size'] }, new MinipassFlush({ diff --git a/node_modules/make-fetch-happen/lib/remote.js b/node_modules/make-fetch-happen/lib/remote.js index 2aef9f8f969b0..8554564074de6 100644 --- a/node_modules/make-fetch-happen/lib/remote.js +++ b/node_modules/make-fetch-happen/lib/remote.js @@ -2,6 +2,7 @@ const { Minipass } = require('minipass') const fetch = require('minipass-fetch') const promiseRetry = require('promise-retry') const ssri = require('ssri') +const { log } = require('proc-log') const CachingMinipassPipeline = require('./pipeline.js') const { getAgent } = require('@npmcli/agent') @@ -89,6 +90,8 @@ const remoteFetch = (request, options) => { options.onRetry(res) } + /* eslint-disable-next-line max-len */ + log.http('fetch', `${req.method} ${req.url} attempt ${attemptNum} failed with ${res.status}`) return retryHandler(res) } @@ -112,6 +115,7 @@ const remoteFetch = (request, options) => { options.onRetry(err) } + log.http('fetch', `${req.method} ${req.url} attempt ${attemptNum} failed with ${err.code}`) return retryHandler(err) } }, options.retry).catch((err) => { diff --git a/node_modules/make-fetch-happen/package.json b/node_modules/make-fetch-happen/package.json index a874ace6d1d47..7adb4d1e7f971 100644 --- a/node_modules/make-fetch-happen/package.json +++ b/node_modules/make-fetch-happen/package.json @@ -1,6 +1,6 @@ { "name": "make-fetch-happen", - "version": "13.0.0", + "version": "13.0.1", "description": "Opinionated, caching, retrying fetch client", "main": "lib/index.js", "files": [ @@ -11,7 +11,7 @@ "test": "tap", "posttest": "npm run lint", "eslint": "eslint", - "lint": "eslint \"**/*.js\"", + "lint": "eslint \"**/*.{js,cjs,ts,mjs,jsx,tsx}\"", "lintfix": "npm run lint -- --fix", "postlint": "template-oss-check", "snap": "tap", @@ -42,12 +42,13 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", + "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.18.0", + "@npmcli/template-oss": "4.21.4", "nock": "^13.2.4", "safe-buffer": "^5.2.1", "standard-version": "^9.3.2", @@ -68,13 +69,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "ciVersions": [ - "16.14.0", - "16.x", - "18.0.0", - "18.x" - ], - "version": "4.18.0", + "version": "4.21.4", "publish": "true" } } diff --git a/node_modules/npm-profile/lib/index.js b/node_modules/npm-profile/lib/index.js index a56a3794ba891..e5b5dd046baf2 100644 --- a/node_modules/npm-profile/lib/index.js +++ b/node_modules/npm-profile/lib/index.js @@ -276,8 +276,7 @@ class WebLoginNotSupported extends HttpErrorBase { } } -const sleep = (ms) => - new Promise((resolve, reject) => setTimeout(resolve, ms)) +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) module.exports = { adduserCouch, diff --git a/node_modules/npm-profile/package.json b/node_modules/npm-profile/package.json index 3b4b582f8c15f..acdf4d6baf2ee 100644 --- a/node_modules/npm-profile/package.json +++ b/node_modules/npm-profile/package.json @@ -1,12 +1,12 @@ { "name": "npm-profile", - "version": "9.0.1", + "version": "9.0.2", "description": "Library for updating an npmjs.com profile", "keywords": [], "author": "GitHub Inc.", "license": "ISC", "dependencies": { - "npm-registry-fetch": "^16.0.0", + "npm-registry-fetch": "^17.0.0", "proc-log": "^4.0.0" }, "main": "./lib/index.js", @@ -20,7 +20,7 @@ ], "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.21.3", + "@npmcli/template-oss": "4.21.4", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -45,7 +45,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.21.3", + "version": "4.21.4", "publish": true } } diff --git a/node_modules/npm-registry-fetch/lib/index.js b/node_modules/npm-registry-fetch/lib/index.js index 1d77a77024bf5..bce6e6b1aae0a 100644 --- a/node_modules/npm-registry-fetch/lib/index.js +++ b/node_modules/npm-registry-fetch/lib/index.js @@ -10,7 +10,6 @@ const qs = require('querystring') const url = require('url') const zlib = require('minizlib') const { Minipass } = require('minipass') -const { redact: cleanUrl } = require('@npmcli/redact') const defaultOpts = require('./default-opts.js') @@ -246,7 +245,3 @@ function getHeaders (uri, auth, opts) { return headers } - -// export cleanUrl to avoid a breaking change -// TODO: next semver major remove this. Consumers should use @npmcli/redact instead -module.exports.cleanUrl = cleanUrl diff --git a/node_modules/npm-registry-fetch/package.json b/node_modules/npm-registry-fetch/package.json index 4e450868a77f7..52820a6a206ec 100644 --- a/node_modules/npm-registry-fetch/package.json +++ b/node_modules/npm-registry-fetch/package.json @@ -1,6 +1,6 @@ { "name": "npm-registry-fetch", - "version": "16.2.1", + "version": "17.0.0", "description": "Fetch-based http client for use with npm registry APIs", "main": "lib", "files": [ @@ -31,7 +31,7 @@ "author": "GitHub Inc.", "license": "ISC", "dependencies": { - "@npmcli/redact": "^1.1.0", + "@npmcli/redact": "^2.0.0", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", @@ -42,7 +42,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", - "@npmcli/template-oss": "4.21.3", + "@npmcli/template-oss": "4.21.4", "cacache": "^18.0.0", "nock": "^13.2.4", "require-inject": "^1.4.4", @@ -62,7 +62,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.21.3", + "version": "4.21.4", "publish": "true" } } diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index a4048eee28510..4c1751644cd57 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "18.0.2", + "version": "18.0.3", "description": "JavaScript package downloader", "author": "GitHub Inc.", "bin": { @@ -55,7 +55,7 @@ "npm-package-arg": "^11.0.0", "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", + "npm-registry-fetch": "^17.0.0", "proc-log": "^4.0.0", "promise-retry": "^2.0.1", "sigstore": "^2.2.0", diff --git a/node_modules/ip-address/node_modules/sprintf-js/CONTRIBUTORS.md b/node_modules/sprintf-js/CONTRIBUTORS.md similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/CONTRIBUTORS.md rename to node_modules/sprintf-js/CONTRIBUTORS.md diff --git a/node_modules/ip-address/node_modules/sprintf-js/LICENSE b/node_modules/sprintf-js/LICENSE similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/LICENSE rename to node_modules/sprintf-js/LICENSE diff --git a/node_modules/sprintf-js/bower.json b/node_modules/sprintf-js/bower.json new file mode 100644 index 0000000000000..d90a75989f7b0 --- /dev/null +++ b/node_modules/sprintf-js/bower.json @@ -0,0 +1,14 @@ +{ + "name": "sprintf", + "description": "JavaScript sprintf implementation", + "version": "1.0.3", + "main": "src/sprintf.js", + "license": "BSD-3-Clause-Clear", + "keywords": ["sprintf", "string", "formatting"], + "authors": ["Alexandru Marasteanu (http://alexei.ro/)"], + "homepage": "https://github.com/alexei/sprintf.js", + "repository": { + "type": "git", + "url": "git://github.com/alexei/sprintf.js.git" + } +} diff --git a/node_modules/sprintf-js/demo/angular.html b/node_modules/sprintf-js/demo/angular.html new file mode 100644 index 0000000000000..3559efd763563 --- /dev/null +++ b/node_modules/sprintf-js/demo/angular.html @@ -0,0 +1,20 @@ + + + + + + + + +
{{ "%+010d"|sprintf:-123 }}
+
{{ "%+010d"|vsprintf:[-123] }}
+
{{ "%+010d"|fmt:-123 }}
+
{{ "%+010d"|vfmt:[-123] }}
+
{{ "I've got %2$d apples and %1$d oranges."|fmt:4:2 }}
+
{{ "I've got %(apples)d apples and %(oranges)d oranges."|fmt:{apples: 2, oranges: 4} }}
+ + + + diff --git a/node_modules/ip-address/node_modules/sprintf-js/dist/.gitattributes b/node_modules/sprintf-js/dist/.gitattributes similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/dist/.gitattributes rename to node_modules/sprintf-js/dist/.gitattributes diff --git a/node_modules/ip-address/node_modules/sprintf-js/dist/angular-sprintf.min.js b/node_modules/sprintf-js/dist/angular-sprintf.min.js similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/dist/angular-sprintf.min.js rename to node_modules/sprintf-js/dist/angular-sprintf.min.js diff --git a/node_modules/ip-address/node_modules/sprintf-js/dist/sprintf.min.js b/node_modules/sprintf-js/dist/sprintf.min.js similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/dist/sprintf.min.js rename to node_modules/sprintf-js/dist/sprintf.min.js diff --git a/node_modules/sprintf-js/gruntfile.js b/node_modules/sprintf-js/gruntfile.js new file mode 100644 index 0000000000000..246e1c3b9801f --- /dev/null +++ b/node_modules/sprintf-js/gruntfile.js @@ -0,0 +1,36 @@ +module.exports = function(grunt) { + grunt.initConfig({ + pkg: grunt.file.readJSON("package.json"), + + uglify: { + options: { + banner: "/*! <%= pkg.name %> | <%= pkg.author %> | <%= pkg.license %> */\n", + sourceMap: true + }, + build: { + files: [ + { + src: "src/sprintf.js", + dest: "dist/sprintf.min.js" + }, + { + src: "src/angular-sprintf.js", + dest: "dist/angular-sprintf.min.js" + } + ] + } + }, + + watch: { + js: { + files: "src/*.js", + tasks: ["uglify"] + } + } + }) + + grunt.loadNpmTasks("grunt-contrib-uglify") + grunt.loadNpmTasks("grunt-contrib-watch") + + grunt.registerTask("default", ["uglify", "watch"]) +} diff --git a/node_modules/ip-address/node_modules/sprintf-js/package.json b/node_modules/sprintf-js/package.json similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/package.json rename to node_modules/sprintf-js/package.json diff --git a/node_modules/ip-address/node_modules/sprintf-js/src/angular-sprintf.js b/node_modules/sprintf-js/src/angular-sprintf.js similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/src/angular-sprintf.js rename to node_modules/sprintf-js/src/angular-sprintf.js diff --git a/node_modules/ip-address/node_modules/sprintf-js/src/sprintf.js b/node_modules/sprintf-js/src/sprintf.js similarity index 100% rename from node_modules/ip-address/node_modules/sprintf-js/src/sprintf.js rename to node_modules/sprintf-js/src/sprintf.js diff --git a/node_modules/sprintf-js/test/test.js b/node_modules/sprintf-js/test/test.js new file mode 100644 index 0000000000000..6f57b2538c852 --- /dev/null +++ b/node_modules/sprintf-js/test/test.js @@ -0,0 +1,82 @@ +var assert = require("assert"), + sprintfjs = require("../src/sprintf.js"), + sprintf = sprintfjs.sprintf, + vsprintf = sprintfjs.vsprintf + +describe("sprintfjs", function() { + var pi = 3.141592653589793 + + it("should return formated strings for simple placeholders", function() { + assert.equal("%", sprintf("%%")) + assert.equal("10", sprintf("%b", 2)) + assert.equal("A", sprintf("%c", 65)) + assert.equal("2", sprintf("%d", 2)) + assert.equal("2", sprintf("%i", 2)) + assert.equal("2", sprintf("%d", "2")) + assert.equal("2", sprintf("%i", "2")) + assert.equal('{"foo":"bar"}', sprintf("%j", {foo: "bar"})) + assert.equal('["foo","bar"]', sprintf("%j", ["foo", "bar"])) + assert.equal("2e+0", sprintf("%e", 2)) + assert.equal("2", sprintf("%u", 2)) + assert.equal("4294967294", sprintf("%u", -2)) + assert.equal("2.2", sprintf("%f", 2.2)) + assert.equal("3.141592653589793", sprintf("%g", pi)) + assert.equal("10", sprintf("%o", 8)) + assert.equal("%s", sprintf("%s", "%s")) + assert.equal("ff", sprintf("%x", 255)) + assert.equal("FF", sprintf("%X", 255)) + assert.equal("Polly wants a cracker", sprintf("%2$s %3$s a %1$s", "cracker", "Polly", "wants")) + assert.equal("Hello world!", sprintf("Hello %(who)s!", {"who": "world"})) + }) + + it("should return formated strings for complex placeholders", function() { + // sign + assert.equal("2", sprintf("%d", 2)) + assert.equal("-2", sprintf("%d", -2)) + assert.equal("+2", sprintf("%+d", 2)) + assert.equal("-2", sprintf("%+d", -2)) + assert.equal("2", sprintf("%i", 2)) + assert.equal("-2", sprintf("%i", -2)) + assert.equal("+2", sprintf("%+i", 2)) + assert.equal("-2", sprintf("%+i", -2)) + assert.equal("2.2", sprintf("%f", 2.2)) + assert.equal("-2.2", sprintf("%f", -2.2)) + assert.equal("+2.2", sprintf("%+f", 2.2)) + assert.equal("-2.2", sprintf("%+f", -2.2)) + assert.equal("-2.3", sprintf("%+.1f", -2.34)) + assert.equal("-0.0", sprintf("%+.1f", -0.01)) + assert.equal("3.14159", sprintf("%.6g", pi)) + assert.equal("3.14", sprintf("%.3g", pi)) + assert.equal("3", sprintf("%.1g", pi)) + assert.equal("-000000123", sprintf("%+010d", -123)) + assert.equal("______-123", sprintf("%+'_10d", -123)) + assert.equal("-234.34 123.2", sprintf("%f %f", -234.34, 123.2)) + + // padding + assert.equal("-0002", sprintf("%05d", -2)) + assert.equal("-0002", sprintf("%05i", -2)) + assert.equal(" <", sprintf("%5s", "<")) + assert.equal("0000<", sprintf("%05s", "<")) + assert.equal("____<", sprintf("%'_5s", "<")) + assert.equal("> ", sprintf("%-5s", ">")) + assert.equal(">0000", sprintf("%0-5s", ">")) + assert.equal(">____", sprintf("%'_-5s", ">")) + assert.equal("xxxxxx", sprintf("%5s", "xxxxxx")) + assert.equal("1234", sprintf("%02u", 1234)) + assert.equal(" -10.235", sprintf("%8.3f", -10.23456)) + assert.equal("-12.34 xxx", sprintf("%f %s", -12.34, "xxx")) + assert.equal('{\n "foo": "bar"\n}', sprintf("%2j", {foo: "bar"})) + assert.equal('[\n "foo",\n "bar"\n]', sprintf("%2j", ["foo", "bar"])) + + // precision + assert.equal("2.3", sprintf("%.1f", 2.345)) + assert.equal("xxxxx", sprintf("%5.5s", "xxxxxx")) + assert.equal(" x", sprintf("%5.1s", "xxxxxx")) + + }) + + it("should return formated strings for callbacks", function() { + assert.equal("foobar", sprintf("%s", function() { return "foobar" })) + assert.equal(Date.now(), sprintf("%s", Date.now)) // should pass... + }) +}) diff --git a/package-lock.json b/package-lock.json index 4838840d521da..e0ee31a1f1356 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "10.6.0", + "version": "10.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "npm", - "version": "10.6.0", + "version": "10.7.0", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -63,7 +63,6 @@ "pacote", "parse-conflict-json", "proc-log", - "proggy", "qrcode-terminal", "read", "semver", @@ -94,8 +93,8 @@ "@npmcli/map-workspaces": "^3.0.6", "@npmcli/package-json": "^5.1.0", "@npmcli/promise-spawn": "^7.0.1", - "@npmcli/redact": "^1.1.0", - "@npmcli/run-script": "^8.0.0", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", "@sigstore/tuf": "^2.3.2", "abbrev": "^2.0.0", "archy": "~1.0.0", @@ -114,16 +113,16 @@ "json-parse-even-better-errors": "^3.0.1", "libnpmaccess": "^8.0.1", "libnpmdiff": "^6.0.3", - "libnpmexec": "^7.0.4", + "libnpmexec": "^8.0.0", "libnpmfund": "^5.0.1", "libnpmhook": "^10.0.0", "libnpmorg": "^6.0.1", - "libnpmpack": "^6.0.3", + "libnpmpack": "^7.0.0", "libnpmpublish": "^9.0.2", "libnpmsearch": "^7.0.0", "libnpmteam": "^6.0.0", - "libnpmversion": "^5.0.1", - "make-fetch-happen": "^13.0.0", + "libnpmversion": "^6.0.0", + "make-fetch-happen": "^13.0.1", "minimatch": "^9.0.4", "minipass": "^7.0.4", "minipass-pipeline": "^1.2.4", @@ -135,14 +134,13 @@ "npm-install-checks": "^6.3.0", "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", - "npm-profile": "^9.0.1", - "npm-registry-fetch": "^16.2.1", + "npm-profile": "^9.0.2", + "npm-registry-fetch": "^17.0.0", "npm-user-validate": "^2.0.0", "p-map": "^4.0.0", - "pacote": "^18.0.2", + "pacote": "^18.0.3", "parse-conflict-json": "^3.0.1", "proc-log": "^4.2.0", - "proggy": "^2.0.0", "qrcode-terminal": "^0.12.0", "read": "^3.0.1", "semver": "^7.6.0", @@ -243,16 +241,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@actions/core": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz", @@ -309,21 +297,21 @@ } }, "node_modules/@babel/core": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", - "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.4", + "@babel/generator": "^7.24.5", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.4", - "@babel/parser": "^7.24.4", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -354,12 +342,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", - "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.24.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -455,16 +443,16 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -474,24 +462,24 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -507,9 +495,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -525,26 +513,26 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", - "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", "dev": true, "dependencies": { "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -616,9 +604,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", - "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -642,19 +630,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -672,13 +660,13 @@ } }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1489,6 +1477,12 @@ "node": ">=8" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -1613,9 +1607,9 @@ "link": true }, "node_modules/@npmcli/eslint-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/eslint-config/-/eslint-config-4.0.2.tgz", - "integrity": "sha512-tXfO5G788/ygRYabfwHQUQrgIMEv2WDAYwEwdZfC6IoANwGUSRAzBd361ZQbhVIZ0gH2rvzkILc80EtC2nOmRw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/eslint-config/-/eslint-config-4.0.3.tgz", + "integrity": "sha512-f/r4NlJjDUQjKSiVBRAlVb9g+i8UkQQKGQpI8zfJfeRDT6J/BmYXVVhBMFQKgD1UclJzDx+cjKppHbScDp1LNg==", "dev": true, "dependencies": { "which": "^3.0.0" @@ -1793,18 +1787,18 @@ } }, "node_modules/@npmcli/redact": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-1.1.0.tgz", - "integrity": "sha512-PfnWuOkQgu7gCbnSsAisaX7hKOdZ4wSAhAzH3/ph5dSGau52kCRrMMGbiSQLwyTZpgldkZ49b0brkOr1AzGBHQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-2.0.0.tgz", + "integrity": "sha512-SEjCPAVHWYUIQR+Yn03kJmrJjZDtJLYpj300m3HV9OTRZNpC5YpbMsM3eTkECyT4aWj8lDr9WeY6TWefpubtYQ==", "inBundle": true, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@npmcli/run-script": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.0.0.tgz", - "integrity": "sha512-5noc+eCQmX1W9nlFUe65n5MIteikd3vOA2sEPdXtlUv68KWyHNFZnT/LDRXu/E4nZ5yxjciP30pADr/GQ97W1w==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-8.1.0.tgz", + "integrity": "sha512-y7efHHwghQfk28G2z3tlZ67pLG0XdfYbcVG26r7YIXALRsrVQcTq4/tdenSmdOrEsNahIYA/eh8aEVROWGFUDg==", "inBundle": true, "dependencies": { "@npmcli/node-gyp": "^3.0.0", @@ -1828,6 +1822,9 @@ "integrity": "sha512-ORqiG/HP69bhEzkP6Iq5rCm1gwIADMCJr6IlGTNvRher1aYV0y7SyrJu50jkaxEpIUuVJQV+cN2kIvhp/0y1+w==", "dev": true, "hasInstallScript": true, + "workspaces": [ + "workspace/test-workspace" + ], "dependencies": { "@actions/core": "^1.9.1", "@commitlint/cli": "^18.2.0", @@ -2211,9 +2208,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.12.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.6.tgz", - "integrity": "sha512-3KurE8taB8GCvZBPngVbp0lk5CKi8M9f9k1rsADh0Evdz5SzJ+Q+Hx9uHoFGsLnLnd1xmkDQr2hVhlA0Mn0lKQ==", + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dev": true, "peer": true, "dependencies": { @@ -2333,15 +2330,15 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -2999,9 +2996,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001607", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001607.tgz", - "integrity": "sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==", + "version": "1.0.30001614", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001614.tgz", + "integrity": "sha512-jmZQ1VpmlRwHgdP1/uiKzgiAuGOfLEJsYFP4+GBou/QQ4U6IOJCB4NP1c+1p9RGLpwObcT94jA5/uO+F1vBbog==", "dev": true, "funding": [ { @@ -3934,9 +3931,9 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -4138,9 +4135,9 @@ "inBundle": true }, "node_modules/electron-to-chromium": { - "version": "1.4.730", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.730.tgz", - "integrity": "sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==", + "version": "1.4.751", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.751.tgz", + "integrity": "sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==", "dev": true }, "node_modules/emoji-regex": { @@ -5343,6 +5340,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/front-matter/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/fs-exists-cached": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", @@ -5691,13 +5694,14 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "peer": true, "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -6280,12 +6284,6 @@ "node": ">= 12" } }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "inBundle": true - }, "node_modules/ip-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-5.0.0.tgz", @@ -7452,9 +7450,9 @@ } }, "node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "inBundle": true, "engines": { "node": "14 || >=16.14" @@ -7485,9 +7483,9 @@ } }, "node_modules/make-fetch-happen": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", - "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "inBundle": true, "dependencies": { "@npmcli/agent": "^2.0.0", @@ -7499,6 +7497,7 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", + "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" }, @@ -9013,12 +9012,12 @@ } }, "node_modules/npm-profile": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-9.0.1.tgz", - "integrity": "sha512-9o6dw5eu3tiqX1XFOXjznO73Jzin48Oyo9qAhfaEHXzeZHXpdzgDmzWruWk7uJsu5GMIsigx5hva5rB5NhfSWw==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-9.0.2.tgz", + "integrity": "sha512-4S/fd/PNyGgjaGolsdUJFsnfEb+AxJzrrZC3I9qbTYZJ3PJy8T46tIWXA4pBoaeiGh2M2GRvK1K/xMQe1Xgbvw==", "inBundle": true, "dependencies": { - "npm-registry-fetch": "^16.0.0", + "npm-registry-fetch": "^17.0.0", "proc-log": "^4.0.0" }, "engines": { @@ -9026,12 +9025,12 @@ } }, "node_modules/npm-registry-fetch": { - "version": "16.2.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.2.1.tgz", - "integrity": "sha512-8l+7jxhim55S85fjiDGJ1rZXBWGtRLi1OSb4Z3BPLObPuIaeKRlPRiYMSHU4/81ck3t71Z+UwDDl47gcpmfQQA==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-17.0.0.tgz", + "integrity": "sha512-JoOpdYqru846tJX96Jn2jyYVpc1TD1o6Oox80rjVIDAZqIsS2n+nNx+/Qd02LlQm/itGhsBgzP1VUKACLQHD+Q==", "inBundle": true, "dependencies": { - "@npmcli/redact": "^1.1.0", + "@npmcli/redact": "^2.0.0", "make-fetch-happen": "^13.0.0", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", @@ -9078,9 +9077,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", + "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==", "dev": true }, "node_modules/nyc": { @@ -9470,18 +9469,18 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "peer": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -9572,9 +9571,9 @@ } }, "node_modules/pacote": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.2.tgz", - "integrity": "sha512-oMxnZQCOZqFZyEh5oJtpMepoub4hoI6EfMUCdbwkBqkFuJ1Dwfz5IMQD344dKbwPPBNZWKwGL/kNvmDubZyvug==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-18.0.3.tgz", + "integrity": "sha512-GFCGn27RSf2xa5DHShI7DzI8dCf5F0+9N+fbSpItZvi9ykSouPRXMKzfl2jF35Zoi9QysNF/aqeqQyU2tOJBbA==", "inBundle": true, "dependencies": { "@npmcli/git": "^5.0.0", @@ -9588,7 +9587,7 @@ "npm-package-arg": "^11.0.0", "npm-packlist": "^8.0.0", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", + "npm-registry-fetch": "^17.0.0", "proc-log": "^4.0.0", "promise-retry": "^2.0.1", "sigstore": "^2.2.0", @@ -9879,7 +9878,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/proggy/-/proggy-2.0.0.tgz", "integrity": "sha512-69agxLtnI8xBs9gUGqEnK26UfiexpHy+KUpBQWabiytQjnn5wFY8rklAi7GRfABIuPNnQ/ik48+LGLkYYJcy4A==", - "inBundle": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -11265,10 +11263,10 @@ } }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "inBundle": true }, "node_modules/ssri": { "version": "10.0.5", @@ -13926,9 +13924,9 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "dev": true, "dependencies": { "psl": "^1.1.33", @@ -14165,9 +14163,9 @@ } }, "node_modules/typescript": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.4.tgz", - "integrity": "sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "peer": true, "bin": { @@ -14820,9 +14818,9 @@ } }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", "dev": true, "engines": { "node": ">=10.0.0" @@ -14880,9 +14878,9 @@ "inBundle": true }, "node_modules/yaml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", - "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", "dev": true, "bin": { "yaml": "bin.mjs" @@ -14960,7 +14958,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "7.5.0", + "version": "7.5.1", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -14972,8 +14970,8 @@ "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.1.0", "@npmcli/query": "^3.1.0", - "@npmcli/redact": "^1.1.0", - "@npmcli/run-script": "^8.0.0", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", "bin-links": "^4.0.1", "cacache": "^18.0.0", "common-ancestor-path": "^1.0.1", @@ -14985,7 +14983,7 @@ "npm-install-checks": "^6.2.0", "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.2.1", + "npm-registry-fetch": "^17.0.0", "pacote": "^18.0.1", "parse-conflict-json": "^3.0.0", "proc-log": "^4.2.0", @@ -15017,7 +15015,7 @@ }, "workspaces/config": { "name": "@npmcli/config", - "version": "8.3.0", + "version": "8.3.1", "license": "ISC", "dependencies": { "@npmcli/map-workspaces": "^3.0.2", @@ -15040,11 +15038,11 @@ } }, "workspaces/libnpmaccess": { - "version": "8.0.4", + "version": "8.0.5", "license": "ISC", "dependencies": { "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15058,7 +15056,7 @@ } }, "workspaces/libnpmdiff": { - "version": "6.1.0", + "version": "6.1.1", "license": "ISC", "dependencies": { "@npmcli/arborist": "^7.2.1", @@ -15080,11 +15078,11 @@ } }, "workspaces/libnpmexec": { - "version": "8.0.0", + "version": "8.1.0", "license": "ISC", "dependencies": { "@npmcli/arborist": "^7.2.1", - "@npmcli/run-script": "^8.0.0", + "@npmcli/run-script": "^8.1.0", "ci-info": "^4.0.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.1", @@ -15109,7 +15107,7 @@ } }, "workspaces/libnpmfund": { - "version": "5.0.8", + "version": "5.0.9", "license": "ISC", "dependencies": { "@npmcli/arborist": "^7.2.1" @@ -15124,11 +15122,11 @@ } }, "workspaces/libnpmhook": { - "version": "10.0.3", + "version": "10.0.4", "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15141,11 +15139,11 @@ } }, "workspaces/libnpmorg": { - "version": "6.0.4", + "version": "6.0.5", "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15159,11 +15157,11 @@ } }, "workspaces/libnpmpack": { - "version": "7.0.0", + "version": "7.0.1", "license": "ISC", "dependencies": { "@npmcli/arborist": "^7.2.1", - "@npmcli/run-script": "^8.0.0", + "@npmcli/run-script": "^8.1.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.1" }, @@ -15179,13 +15177,13 @@ } }, "workspaces/libnpmpublish": { - "version": "9.0.6", + "version": "9.0.7", "license": "ISC", "dependencies": { "ci-info": "^4.0.0", "normalize-package-data": "^6.0.0", "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^16.2.1", + "npm-registry-fetch": "^17.0.0", "proc-log": "^4.2.0", "semver": "^7.3.7", "sigstore": "^2.2.0", @@ -15204,10 +15202,10 @@ } }, "workspaces/libnpmsearch": { - "version": "7.0.3", + "version": "7.0.4", "license": "ISC", "dependencies": { - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15220,11 +15218,11 @@ } }, "workspaces/libnpmteam": { - "version": "6.0.3", + "version": "6.0.4", "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15237,11 +15235,11 @@ } }, "workspaces/libnpmversion": { - "version": "6.0.0", + "version": "6.0.1", "license": "ISC", "dependencies": { "@npmcli/git": "^5.0.6", - "@npmcli/run-script": "^8.0.0", + "@npmcli/run-script": "^8.1.0", "json-parse-even-better-errors": "^3.0.0", "proc-log": "^4.2.0", "semver": "^7.3.7" diff --git a/package.json b/package.json index 29ac300c41250..1aae41fbe7576 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "10.6.0", + "version": "10.7.0", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -27,7 +27,7 @@ "author": "GitHub Inc.", "repository": { "type": "git", - "url": "https://github.com/npm/cli.git" + "url": "git+https://github.com/npm/cli.git" }, "bugs": { "url": "https://github.com/npm/cli/issues" @@ -58,8 +58,8 @@ "@npmcli/map-workspaces": "^3.0.6", "@npmcli/package-json": "^5.1.0", "@npmcli/promise-spawn": "^7.0.1", - "@npmcli/redact": "^1.1.0", - "@npmcli/run-script": "^8.0.0", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", "@sigstore/tuf": "^2.3.2", "abbrev": "^2.0.0", "archy": "~1.0.0", @@ -78,16 +78,16 @@ "json-parse-even-better-errors": "^3.0.1", "libnpmaccess": "^8.0.1", "libnpmdiff": "^6.0.3", - "libnpmexec": "^7.0.4", + "libnpmexec": "^8.0.0", "libnpmfund": "^5.0.1", "libnpmhook": "^10.0.0", "libnpmorg": "^6.0.1", - "libnpmpack": "^6.0.3", + "libnpmpack": "^7.0.0", "libnpmpublish": "^9.0.2", "libnpmsearch": "^7.0.0", "libnpmteam": "^6.0.0", - "libnpmversion": "^5.0.1", - "make-fetch-happen": "^13.0.0", + "libnpmversion": "^6.0.0", + "make-fetch-happen": "^13.0.1", "minimatch": "^9.0.4", "minipass": "^7.0.4", "minipass-pipeline": "^1.2.4", @@ -99,14 +99,13 @@ "npm-install-checks": "^6.3.0", "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", - "npm-profile": "^9.0.1", - "npm-registry-fetch": "^16.2.1", + "npm-profile": "^9.0.2", + "npm-registry-fetch": "^17.0.0", "npm-user-validate": "^2.0.0", "p-map": "^4.0.0", - "pacote": "^18.0.2", + "pacote": "^18.0.3", "parse-conflict-json": "^3.0.1", "proc-log": "^4.2.0", - "proggy": "^2.0.0", "qrcode-terminal": "^0.12.0", "read": "^3.0.1", "semver": "^7.6.0", @@ -177,7 +176,6 @@ "pacote", "parse-conflict-json", "proc-log", - "proggy", "qrcode-terminal", "read", "semver", diff --git a/smoke-tests/package.json b/smoke-tests/package.json index 85b33edeb8b94..1fe8f63819d36 100644 --- a/smoke-tests/package.json +++ b/smoke-tests/package.json @@ -14,7 +14,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "smoke-tests" }, "devDependencies": { diff --git a/smoke-tests/test/pack-json-output.js b/smoke-tests/test/pack-json-output.js new file mode 100644 index 0000000000000..59a8e2cded66f --- /dev/null +++ b/smoke-tests/test/pack-json-output.js @@ -0,0 +1,12 @@ + +const t = require('tap') +const setup = require('./fixtures/setup.js') + +t.test('pack --json returns only json on stdout', async t => { + const { npmLocal } = await setup(t) + + const { stderr, stdout } = await npmLocal('pack', '--json', { force: true }) + + t.match(stderr, /> npm@.* prepack\n/, 'stderr has banner') + t.ok(JSON.parse(stdout), 'stdout can be parsed as json') +}) diff --git a/tap-snapshots/test/lib/commands/doctor.js.test.cjs b/tap-snapshots/test/lib/commands/doctor.js.test.cjs index 5c5b122477d81..0481c6d86823e 100644 --- a/tap-snapshots/test/lib/commands/doctor.js.test.cjs +++ b/tap-snapshots/test/lib/commands/doctor.js.test.cjs @@ -731,11 +731,11 @@ Object { "warn": Array [ String( doctor getGitPath Error: test error - doctor at which {STACK} - doctor at Doctor.getGitPath {STACK} - doctor at Doctor.exec {STACK} - doctor at processTicksAndRejections {STACK} - doctor at MockNpm.exec {STACK} + doctor at {STACK} + doctor at {STACK} + doctor at {STACK} + doctor at {STACK} + doctor at {STACK} ), ], } diff --git a/tap-snapshots/test/lib/commands/init.js.test.cjs b/tap-snapshots/test/lib/commands/init.js.test.cjs index 821193a55e1a9..eae04d77d2e82 100644 --- a/tap-snapshots/test/lib/commands/init.js.test.cjs +++ b/tap-snapshots/test/lib/commands/init.js.test.cjs @@ -20,5 +20,6 @@ Press ^C at any time to quit. exports[`test/lib/commands/init.js TAP workspaces no args -- yes > should print helper info 1`] = ` + added 1 package in {TIME} ` diff --git a/tap-snapshots/test/lib/commands/pack.js.test.cjs b/tap-snapshots/test/lib/commands/pack.js.test.cjs index e251e63d4c279..9ec24b3816261 100644 --- a/tap-snapshots/test/lib/commands/pack.js.test.cjs +++ b/tap-snapshots/test/lib/commands/pack.js.test.cjs @@ -109,13 +109,24 @@ Array [ "name": "@myscope/test-package", "shasum": "{sha}", "size": "{size}", - "unpackedSize": 50, + "unpackedSize": 88, "version": "1.0.0", }, ], ] ` +exports[`test/lib/commands/pack.js TAP should log scoped package output as valid json > stderr has banners 1`] = ` +Array [ + String( + + > @myscope/test-package@1.0.0 prepack + > echo prepack! + + ), +] +` + exports[`test/lib/commands/pack.js TAP should pack current directory with no arguments > logs pack contents 1`] = ` Array [ "package: test-package@1.0.0", diff --git a/tap-snapshots/test/lib/commands/search.js.test.cjs b/tap-snapshots/test/lib/commands/search.js.test.cjs index 3135964f202f5..7645e60abb88b 100644 --- a/tap-snapshots/test/lib/commands/search.js.test.cjs +++ b/tap-snapshots/test/lib/commands/search.js.test.cjs @@ -5,10 +5,6 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' -exports[`test/lib/commands/search.js TAP empty search results > should have expected search results 1`] = ` -No matches found for "foo" -` - exports[`test/lib/commands/search.js TAP search //--color > should have expected search results with color 1`] = ` libnpm Collection of programmatic APIs for the npm CLI @@ -189,6 +185,10 @@ foo Version 1.0.0 published prehistoric by foo Maintainers: foo https://npm.im/foo +custom-registry +Version 1.0.0 published prehistoric by ??? +Maintainers: foo +https://npm.im/custom-registry libnpmversion Version 1.0.0 published prehistoric by foo Maintainers: foo @@ -274,6 +274,10 @@ Maintainers: lukekarrys https://npm.im/pkg-no-desc ` +exports[`test/lib/commands/search.js TAP search empty search results > should have expected search results 1`] = ` +No matches found for "foo" +` + exports[`test/lib/commands/search.js TAP search exclude forward slash > results should not have libnpmversion 1`] = ` libnpm Collection of programmatic APIs for the npm CLI @@ -1009,3 +1013,14 @@ Version 1.0.0 published 2019-09-26 by lukekarrys Maintainers: lukekarrys https://npm.im/pkg-no-desc ` + +exports[`test/lib/commands/search.js TAP search no publisher > should have filtered expected search results 1`] = ` +custom-registry +Version 1.0.0 published prehistoric by ??? +Maintainers: foo +https://npm.im/custom-registry +libnpmversion +Version 1.0.0 published prehistoric by foo +Maintainers: foo +https://npm.im/libnpmversion +` diff --git a/tap-snapshots/test/lib/docs.js.test.cjs b/tap-snapshots/test/lib/docs.js.test.cjs index 671e614851074..85657b9e75dc4 100644 --- a/tap-snapshots/test/lib/docs.js.test.cjs +++ b/tap-snapshots/test/lib/docs.js.test.cjs @@ -4065,11 +4065,11 @@ exports[`test/lib/docs.js TAP usage search > must match snapshot 1`] = ` Search for packages Usage: -npm search [search terms ...] +npm search [ ...] Options: -[-l|--long] [--json] [--color|--no-color|--color always] [-p|--parseable] -[--no-description] [--searchlimit ] [--searchopts ] +[--json] [--color|--no-color|--color always] [-p|--parseable] [--no-description] +[--searchlimit ] [--searchopts ] [--searchexclude ] [--registry ] [--prefer-online] [--prefer-offline] [--offline] @@ -4078,14 +4078,13 @@ aliases: find, s, se Run "npm help search" for more info \`\`\`bash -npm search [search terms ...] +npm search [ ...] aliases: find, s, se \`\`\` Note: This command is unaware of workspaces. -#### \`long\` #### \`json\` #### \`color\` #### \`parseable\` diff --git a/tap-snapshots/test/lib/utils/error-message.js.test.cjs b/tap-snapshots/test/lib/utils/error-message.js.test.cjs index c6c694e2250b0..ab0f5501deb62 100644 --- a/tap-snapshots/test/lib/utils/error-message.js.test.cjs +++ b/tap-snapshots/test/lib/utils/error-message.js.test.cjs @@ -190,7 +190,7 @@ Object { "r", "g", "s", - "https://evil:***@npmjs.org/", + "https://evil:***@npmjs.org", ], Array [ "", diff --git a/test/fixtures/mock-logs.js b/test/fixtures/mock-logs.js index 346944d7405b0..ce4c189219467 100644 --- a/test/fixtures/mock-logs.js +++ b/test/fixtures/mock-logs.js @@ -41,6 +41,8 @@ module.exports = () => { const streams = { stderr: { + cursorTo: () => {}, + clearLine: () => {}, write: (str) => { str = trimTrailingNewline(str) diff --git a/test/lib/cli/entry.js b/test/lib/cli/entry.js index bca3315a5d76e..60a38b70abf89 100644 --- a/test/lib/cli/entry.js +++ b/test/lib/cli/entry.js @@ -96,7 +96,7 @@ t.test('logged argv is sanitized with equals', async t => { }) await cli(process) - t.match(logs.verbose.byTitle('argv'), ['argv "version" "--registry" "https://u:***@npmjs.org/"']) + t.match(logs.verbose.byTitle('argv'), ['argv "version" "--registry" "https://u:***@npmjs.org"']) }) t.test('print usage if no params provided', async t => { diff --git a/test/lib/cli/exit-handler.js b/test/lib/cli/exit-handler.js index fd6754b30096e..7b465643504c7 100644 --- a/test/lib/cli/exit-handler.js +++ b/test/lib/cli/exit-handler.js @@ -388,7 +388,7 @@ t.test('log files fail to write', async (t) => { '{LIB}/utils/log-file.js': tmock(t, '{LIB}/utils/log-file.js', { 'fs-minipass': { ...fsMiniPass, - WriteStreamSync: (file, ...rest) => { + WriteStreamSync: (file) => { if (file.includes('LOGS_DIR')) { throw new Error('err') } diff --git a/test/lib/commands/ci.js b/test/lib/commands/ci.js index 6ab9662fc8be5..c4b855932a9ed 100644 --- a/test/lib/commands/ci.js +++ b/test/lib/commands/ci.js @@ -142,7 +142,7 @@ t.test('--no-audit and --ignore-scripts', async t => { 'package-lock.json': JSON.stringify(packageLock), }, }) - require('nock').emitter.on('no match', req => { + require('nock').emitter.on('no match', () => { t.fail('Should not audit') }) const manifest = registry.manifest({ name: 'abbrev' }) diff --git a/test/lib/commands/doctor.js b/test/lib/commands/doctor.js index cbe74aba53ff7..bf4ea46a918a1 100644 --- a/test/lib/commands/doctor.js +++ b/test/lib/commands/doctor.js @@ -11,7 +11,7 @@ const cleanCacheSha = (str) => str.replace(/content-v2\/sha512\/[^"]+/g, 'content-v2/sha512/{sha}') t.cleanSnapshot = p => cleanCacheSha(cleanDate(cleanCwd(p))) - .replace(/\s\((\{CWD\}|node:).*\d+:\d+\)$/gm, ' {STACK}') + .replace(/(doctor\s+at\s).*$/gm, '$1{STACK}') const npmManifest = (version) => { return { diff --git a/test/lib/commands/pack.js b/test/lib/commands/pack.js index 067e84a0980e0..3ea67c78d996a 100644 --- a/test/lib/commands/pack.js +++ b/test/lib/commands/pack.js @@ -72,11 +72,14 @@ t.test('should log output as valid json', async t => { }) t.test('should log scoped package output as valid json', async t => { - const { npm, outputs, logs } = await loadMockNpm(t, { + const { npm, outputs, outputErrors, logs } = await loadMockNpm(t, { prefixDir: { 'package.json': JSON.stringify({ name: '@myscope/test-package', version: '1.0.0', + scripts: { + prepack: 'echo prepack!', + }, }), }, config: { json: true }, @@ -84,6 +87,7 @@ t.test('should log scoped package output as valid json', async t => { await npm.exec('pack', []) const filename = 'myscope-test-package-1.0.0.tgz' t.matchSnapshot(outputs.map(JSON.parse), 'outputs as json') + t.matchSnapshot(outputErrors, 'stderr has banners') t.matchSnapshot(logs.notice, 'logs pack contents') t.ok(fs.statSync(path.resolve(npm.prefix, filename))) }) diff --git a/test/lib/commands/profile.js b/test/lib/commands/profile.js index 4cf0908aae816..8bbffd1675d07 100644 --- a/test/lib/commands/profile.js +++ b/test/lib/commands/profile.js @@ -540,7 +540,7 @@ t.test('enable-2fa', async t => { t.test('from basic username/password auth', async t => { const npmProfile = { - async createToken (pass) { + async createToken () { return {} }, } @@ -587,7 +587,7 @@ t.test('enable-2fa', async t => { async get () { return userProfile }, - async set (newProfile, conf) { + async set (newProfile) { t.match( newProfile, { @@ -659,7 +659,7 @@ t.test('enable-2fa', async t => { }, } }, - async set (newProfile, conf) { + async set (newProfile) { setCount++ // when profile response shows that 2fa is pending the @@ -747,7 +747,7 @@ t.test('enable-2fa', async t => { }, } }, - async set (newProfile, conf) { + async set () { return { ...userProfile, tfa: 'http://foo?secret=1234', @@ -759,7 +759,7 @@ t.test('enable-2fa', async t => { async password () { return 'password1234' }, - async otp (label) { + async otp () { return '123456' }, } @@ -786,7 +786,7 @@ t.test('enable-2fa', async t => { async get () { return userProfile }, - async set (newProfile, conf) { + async set () { return { ...userProfile, tfa: null, @@ -809,7 +809,7 @@ t.test('enable-2fa', async t => { config: { otp: '123456' }, }) - npm.config.getCredentialsByURI = reg => { + npm.config.getCredentialsByURI = () => { return { token: 'token' } } @@ -830,7 +830,7 @@ t.test('enable-2fa', async t => { tfa: undefined, } }, - async set (newProfile, conf) { + async set () { return { ...userProfile, tfa: null, @@ -852,7 +852,7 @@ t.test('enable-2fa', async t => { readUserInfo, }) - npm.config.getCredentialsByURI = reg => { + npm.config.getCredentialsByURI = () => { return { token: 'token' } } @@ -873,7 +873,7 @@ t.test('enable-2fa', async t => { tfa: undefined, } }, - async set (newProfile, conf) { + async set () { return { ...userProfile, tfa: null, @@ -895,7 +895,7 @@ t.test('enable-2fa', async t => { readUserInfo, }) - npm.config.getCredentialsByURI = reg => { + npm.config.getCredentialsByURI = () => { return { token: 'token' } } @@ -933,7 +933,7 @@ t.test('disable-2fa', async t => { async get () { return userProfile }, - async set (newProfile, conf) { + async set (newProfile) { t.same( newProfile, { @@ -1014,7 +1014,7 @@ t.test('disable-2fa', async t => { async get () { return userProfile }, - async set (newProfile, conf) { + async set (newProfile) { t.same( newProfile, { @@ -1032,7 +1032,7 @@ t.test('disable-2fa', async t => { async password () { return 'password1234' }, - async otp (label) { + async otp () { throw new Error('should not ask for otp') }, } diff --git a/test/lib/commands/search.js b/test/lib/commands/search.js index fb0db8b21c5de..de4a58ca78a8f 100644 --- a/test/lib/commands/search.js +++ b/test/lib/commands/search.js @@ -4,222 +4,277 @@ const MockRegistry = require('@npmcli/mock-registry') const libnpmsearchResultFixture = require('../../fixtures/libnpmsearch-stream-result.js') -t.test('no args', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('search', []), - /search must be called with arguments/, - 'should throw usage instructions' - ) -}) - -t.test('search text', async t => { - const { npm, joinedOutput } = await loadMockNpm(t) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), +t.test('search', t => { + t.test('no args', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects( + npm.exec('search', []), + /search must be called with arguments/, + 'should throw usage instructions' + ) }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(joinedOutput(), 'should have expected search results') -}) + t.test(' text', async t => { + const { npm, joinedOutput } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search --json', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(joinedOutput(), 'should have expected search results') }) - registry.search({ results: libnpmsearchResultFixture }) + t.test(' --json', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) - await npm.exec('search', ['libnpm']) + registry.search({ results: libnpmsearchResultFixture }) - t.same( - JSON.parse(joinedOutput()), - libnpmsearchResultFixture, - 'should have expected search results as json' - ) -}) + await npm.exec('search', ['libnpm']) -t.test('search --parseable', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { parseable: true } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + t.same( + JSON.parse(joinedOutput()), + libnpmsearchResultFixture, + 'should have expected search results as json' + ) }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(joinedOutput(), 'should have expected search results as parseable') -}) + t.test(' --parseable', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { parseable: true } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search --color', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { color: 'always' } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(joinedOutput(), 'should have expected search results as parseable') }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(joinedOutput(), 'should have expected search results with color') -}) + t.test(' --color', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { color: 'always' } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search //--color', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { color: 'always' } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(joinedOutput(), 'should have expected search results with color') }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['/libnpm/']) - t.matchSnapshot(joinedOutput(), 'should have expected search results with color') -}) + t.test('//--color', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { color: 'always' } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search ', async t => { - const { npm, joinedOutput } = await loadMockNpm(t) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) - - registry.search({ results: [{ - name: 'foo', - scope: 'unscoped', - version: '1.0.0', - description: '', - keywords: [], - date: null, - author: { name: 'Foo', email: 'foo@npmjs.com' }, - publisher: { username: 'foo', email: 'foo@npmjs.com' }, - maintainers: [ - { username: 'foo', email: 'foo@npmjs.com' }, - ], - }, { - name: 'libnpmversion', - scope: 'unscoped', - version: '1.0.0', - description: '', - keywords: [], - date: null, - author: { name: 'Foo', email: 'foo@npmjs.com' }, - publisher: { username: 'foo', email: 'foo@npmjs.com' }, - maintainers: [ - { username: 'foo', email: 'foo@npmjs.com' }, - ], - }] }) - - await npm.exec('search', ['foo']) - - t.matchSnapshot(joinedOutput(), 'should have filtered expected search results') -}) + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['/libnpm/']) + t.matchSnapshot(joinedOutput(), 'should have expected search results with color') + }) -t.test('empty search results', async t => { - const { npm, joinedOutput } = await loadMockNpm(t) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + t.test('', async t => { + const { npm, joinedOutput } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + + registry.search({ results: [{ + name: 'foo', + scope: 'unscoped', + version: '1.0.0', + description: '', + keywords: [], + date: null, + author: { name: 'Foo', email: 'foo@npmjs.com' }, + publisher: { username: 'foo', email: 'foo@npmjs.com' }, + maintainers: [ + { username: 'foo', email: 'foo@npmjs.com' }, + ], + }, { + name: 'custom-registry', + scope: 'unscoped', + version: '1.0.0', + description: '', + keywords: [], + date: null, + author: { name: 'Foo', email: 'foo@npmjs.com' }, + maintainers: [ + { username: 'foo', email: 'foo@npmjs.com' }, + ], + }, { + name: 'libnpmversion', + scope: 'unscoped', + version: '1.0.0', + description: '', + keywords: [], + date: null, + author: { name: 'Foo', email: 'foo@npmjs.com' }, + publisher: { username: 'foo', email: 'foo@npmjs.com' }, + maintainers: [ + { username: 'foo', email: 'foo@npmjs.com' }, + ], + }] }) + + await npm.exec('search', ['foo']) + + t.matchSnapshot(joinedOutput(), 'should have filtered expected search results') }) - registry.search({ results: [] }) - await npm.exec('search', ['foo']) + t.test('no publisher', async t => { + const { npm, joinedOutput } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + + registry.search({ results: [{ + name: 'custom-registry', + scope: 'unscoped', + version: '1.0.0', + description: '', + keywords: [], + date: null, + author: { name: 'Foo', email: 'foo@npmjs.com' }, + maintainers: [ + { username: 'foo', email: 'foo@npmjs.com' }, + ], + }, { + name: 'libnpmversion', + scope: 'unscoped', + version: '1.0.0', + description: '', + keywords: [], + date: null, + author: { name: 'Foo', email: 'foo@npmjs.com' }, + publisher: { username: 'foo', email: 'foo@npmjs.com' }, + maintainers: [ + { username: 'foo', email: 'foo@npmjs.com' }, + ], + }] }) + + await npm.exec('search', ['custom']) + + t.matchSnapshot(joinedOutput(), 'should have filtered expected search results') + }) - t.matchSnapshot(joinedOutput(), 'should have expected search results') -}) + t.test('empty search results', async t => { + const { npm, joinedOutput } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('empty search results --json', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) + registry.search({ results: [] }) + await npm.exec('search', ['foo']) - registry.search({ results: [] }) + t.matchSnapshot(joinedOutput(), 'should have expected search results') + }) - await npm.exec('search', ['foo']) - t.equal(joinedOutput(), '\n[]', 'should have expected empty square brackets') -}) + t.test('empty search results --json', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search api response error', async t => { - const { npm } = await loadMockNpm(t) + registry.search({ results: [] }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + await npm.exec('search', ['foo']) + t.equal(joinedOutput(), '\n[]', 'should have expected empty square brackets') }) - registry.search({ error: 'ERR' }) + t.test('api response error', async t => { + const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('search', ['foo']), - /ERR/, - 'should throw response error' - ) -}) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + + registry.search({ error: 'ERR' }) -t.test('search exclude string', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: 'libnpmversion' } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + await t.rejects( + npm.exec('search', ['foo']), + /ERR/, + 'should throw response error' + ) }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion') -}) -t.test('search exclude string json', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { - config: { - json: true, - searchexclude: 'libnpmversion', - }, + t.test('exclude string', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + config: { + searchexclude: 'libnpmversion', + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion') }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + t.test('exclude string json', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + config: { + json: true, + searchexclude: 'libnpmversion', + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(JSON.parse(joinedOutput()), 'results should not have libnpmversion') }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(JSON.parse(joinedOutput()), 'results should not have libnpmversion') -}) + t.test('exclude username with upper case letters', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: 'NLF' } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search exclude username with upper case letters', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: 'NLF' } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(joinedOutput(), 'results should not have nlf') }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(joinedOutput(), 'results should not have nlf') -}) + t.test('exclude regex', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: '/version/' } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search exclude regex', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: '/version/' } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion') }) - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion') -}) + t.test('exclude forward slash', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: '/version' } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) -t.test('search exclude forward slash', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { config: { searchexclude: '/version' } }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + registry.search({ results: libnpmsearchResultFixture }) + await npm.exec('search', ['libnpm']) + t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion') }) - - registry.search({ results: libnpmsearchResultFixture }) - await npm.exec('search', ['libnpm']) - t.matchSnapshot(joinedOutput(), 'results should not have libnpmversion') + t.end() }) diff --git a/test/lib/commands/token.js b/test/lib/commands/token.js index 1290a5ee9cb17..f60a938b5b34b 100644 --- a/test/lib/commands/token.js +++ b/test/lib/commands/token.js @@ -265,6 +265,7 @@ t.test('token create', async t => { registry.createToken({ password, cidr }) await npm.exec('token', ['create']) t.strictSame(outputs, [ + '', 'Created publish token n3wt0k3n', 'with IP whitelist: 10.0.0.0/8,192.168.1.0/24', ]) @@ -291,6 +292,7 @@ t.test('token create read only', async t => { registry.createToken({ readonly: true, password }) await npm.exec('token', ['create']) t.strictSame(outputs, [ + '', 'Created read only token n3wt0k3n', ]) }) @@ -347,10 +349,10 @@ t.test('token create parseable output', async t => { }, { replace: true }) registry.createToken({ password, cidr }) await npm.exec('token', ['create']) - t.equal(outputs[0], 'token\tn3wt0k3n') - t.ok(outputs[1].startsWith('created\t')) - t.equal(outputs[2], 'readonly\tfalse') - t.equal(outputs[3], 'cidr_whitelist\t10.0.0.0/8,192.168.1.0/24') + t.equal(outputs[1], 'token\tn3wt0k3n') + t.ok(outputs[2].startsWith('created\t')) + t.equal(outputs[3], 'readonly\tfalse') + t.equal(outputs[4], 'cidr_whitelist\t10.0.0.0/8,192.168.1.0/24') }) t.test('token create ipv6 cidr', async t => { diff --git a/test/lib/commands/version.js b/test/lib/commands/version.js index 755caae444310..1f02f368f67bc 100644 --- a/test/lib/commands/version.js +++ b/test/lib/commands/version.js @@ -339,7 +339,7 @@ t.test('empty versions', async t => { }, }, mocks: { - libnpmversion: (arg, opts) => { + libnpmversion: () => { return '2.0.0' }, }, diff --git a/test/lib/docs.js b/test/lib/docs.js index 7ace9b9995701..67afd1b54d91e 100644 --- a/test/lib/docs.js +++ b/test/lib/docs.js @@ -22,7 +22,7 @@ t.test('shorthands', async t => { t.test('config', async t => { const keys = Object.keys(definitions) - const flat = Object.entries(definitions).filter(([_, d]) => d.flatten).map(([k]) => k) + const flat = Object.entries(definitions).filter(([, d]) => d.flatten).map(([k]) => k) const notFlat = keys.filter(k => !flat.includes(k)) t.matchSnapshot(keys, 'all keys') t.matchSnapshot(flat, 'keys that are flattened') @@ -74,7 +74,7 @@ t.test('basic usage', async t => { // are generated in the following test const { npm } = await loadMockNpm(t, { mocks: { - '{LIB}/utils/cmd-list.js': { commands: [] }, + '{LIB}/utils/cmd-list.js': { ...cmdList, commands: [] }, }, config: { userconfig: '/some/config/file/.npmrc' }, globals: { process: { platform: 'posix' } }, diff --git a/test/lib/utils/display.js b/test/lib/utils/display.js index b05690ebd8179..33f9360e5728c 100644 --- a/test/lib/utils/display.js +++ b/test/lib/utils/display.js @@ -1,11 +1,12 @@ const t = require('tap') +const timers = require('node:timers/promises') const tmock = require('../../fixtures/tmock') const mockLogs = require('../../fixtures/mock-logs') const mockGlobals = require('@npmcli/mock-globals') const { inspect } = require('util') const mockDisplay = async (t, { mocks, load } = {}) => { - const { log, output } = require('proc-log') + const procLog = require('proc-log') const logs = mockLogs() @@ -25,9 +26,8 @@ const mockDisplay = async (t, { mocks, load } = {}) => { t.teardown(() => display.off()) return { + ...procLog, display, - output, - log, displayLoad, ...logs.logs, } @@ -72,16 +72,31 @@ t.test('can buffer output when paused', async t => { }) t.test('can do progress', async (t) => { - const { log, logs } = await mockDisplay(t, { + const { log, logs, outputs, outputErrors, output, input } = await mockDisplay(t, { load: { progress: true, - loglevel: 'error', }, }) - log.silly('', 'this would go to progress') + // wait for initial timer interval to load + await timers.setTimeout(200) + + log.error('', 'before input') + output.standard('before input') + + const end = input.start() + log.error('', 'during input') + output.standard('during input') + end() + + // wait long enough for all spinner frames to render + await timers.setTimeout(800) + log.error('', 'after input') + output.standard('after input') - t.strictSame(logs, [], 'no logs were shown normally') + t.strictSame([...new Set(outputErrors)].sort(), ['-', '/', '\\', '|']) + t.strictSame(logs, ['error before input', 'error during input', 'error after input']) + t.strictSame(outputs, ['before input', 'during input', 'after input']) }) t.test('handles log throwing', async (t) => { diff --git a/test/lib/utils/log-file.js b/test/lib/utils/log-file.js index a4cf8a256a634..8e07da8671b6a 100644 --- a/test/lib/utils/log-file.js +++ b/test/lib/utils/log-file.js @@ -167,7 +167,7 @@ t.test('initial stream error', async t => { mocks: { 'fs-minipass': { WriteStreamSync: class { - constructor (...args) { + constructor () { throw new Error('no stream') } }, diff --git a/test/lib/utils/otplease.js b/test/lib/utils/otplease.js index d788c39da842c..6dc3ee0f0b069 100644 --- a/test/lib/utils/otplease.js +++ b/test/lib/utils/otplease.js @@ -119,7 +119,7 @@ t.test('prompts for otp for 401', async (t) => { }) t.test('does not prompt for non-otp errors', async (t) => { - const fn = async (opts) => { + const fn = async () => { throw new Error('nope') } @@ -132,7 +132,7 @@ t.test('does not prompt for non-otp errors', async (t) => { }) t.test('does not prompt if stdin or stdout is not a tty', async (t) => { - const fn = async (opts) => { + const fn = async () => { throw Object.assign(new Error('nope'), { code: 'EOTP' }) } diff --git a/test/lib/utils/read-user-info.js b/test/lib/utils/read-user-info.js index 854277783bb6b..35628f7f2faac 100644 --- a/test/lib/utils/read-user-info.js +++ b/test/lib/utils/read-user-info.js @@ -1,39 +1,45 @@ const t = require('tap') +const procLog = require('proc-log') const tmock = require('../../fixtures/tmock') let readOpts = null let readResult = null -const read = { read: async (opts) => { - readOpts = opts - return readResult -} } - -const npmUserValidate = { - username: (username) => { - if (username === 'invalid') { - return new Error('invalid username') - } - - return null - }, - email: (email) => { - if (email.startsWith('invalid')) { - return new Error('invalid email') - } - - return null - }, -} - let logMsg = null + const readUserInfo = tmock(t, '{LIB}/utils/read-user-info.js', { - read, + read: { + read: async (opts) => { + readOpts = opts + return readResult + }, + }, 'proc-log': { + ...procLog, log: { + ...procLog.log, warn: (msg) => logMsg = msg, }, + input: { + ...procLog.input, + read: (fn) => fn(), + }, + }, + 'npm-user-validate': { + username: (username) => { + if (username === 'invalid') { + return new Error('invalid username') + } + + return null + }, + email: (email) => { + if (email.startsWith('invalid')) { + return new Error('invalid email') + } + + return null + }, }, - 'npm-user-validate': npmUserValidate, }) t.beforeEach(() => { diff --git a/test/lib/utils/web-auth.js b/test/lib/utils/web-auth.js index a4e8f4bbc755d..ec8c1d17e9fa1 100644 --- a/test/lib/utils/web-auth.js +++ b/test/lib/utils/web-auth.js @@ -21,8 +21,8 @@ t.test('returns token on success', async (t) => { t.test('closes opener when auth check finishes', async (t) => { const opener = (_url, emitter) => { - return new Promise((resolve, reject) => { - // the only way to finish this promise is to emit aboter on the emitter + return new Promise((resolve) => { + // the only way to finish this promise is to emit abort on the emitter emitter.addListener('abort', () => { resolve() }) diff --git a/workspaces/arborist/CHANGELOG.md b/workspaces/arborist/CHANGELOG.md index f2a087b3e47af..2945e22df6958 100644 --- a/workspaces/arborist/CHANGELOG.md +++ b/workspaces/arborist/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [7.5.1](https://github.com/npm/cli/compare/arborist-v7.5.0...arborist-v7.5.1) (2024-04-30) + +### Bug Fixes + +* [`a1b95eb`](https://github.com/npm/cli/commit/a1b95ebeaf7bf32cf0c16605ad836e74370e2e24) [#7453](https://github.com/npm/cli/pull/7453) linting: no-unused-vars (@wraithgar) +* [`abcbc54`](https://github.com/npm/cli/commit/abcbc545ca226dfc39821200f2a0c9e122b400dd) [#7430](https://github.com/npm/cli/pull/7430) reify: cleanup of Symbols (#7430) (@wraithgar) +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`80eec03`](https://github.com/npm/cli/commit/80eec03462e5747cb4434d43aff25939826b7850) [#7453](https://github.com/npm/cli/pull/7453) `@npmcli/redact@2.0.0` +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` +* [`9da5738`](https://github.com/npm/cli/commit/9da57388ebd5c643c2a95bbf63abc745cad45ccc) [#7437](https://github.com/npm/cli/pull/7437) `@npmcli/run-script@8.1.0` (#7437) + ## [7.5.0](https://github.com/npm/cli/compare/arborist-v7.4.2...arborist-v7.5.0) (2024-04-25) ### Features diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index ac3062928ebd8..920403d231d6d 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -463,7 +463,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { } const dir = resolve(nm, name) const st = await lstat(dir) - .catch(/* istanbul ignore next */ er => null) + .catch(/* istanbul ignore next */ () => null) if (st && st.isSymbolicLink()) { const target = await readlink(dir) const real = resolve(dirname(dir), target).replace(/#/g, '%23') @@ -1024,7 +1024,7 @@ This is a one-time fix-up, please be patient... for (const e of this.#problemEdges(placed)) { promises.push(() => this.#fetchManifest(npa.resolve(e.name, e.spec, fromPath(placed, e))) - .catch(er => null) + .catch(() => null) ) } }, @@ -1273,7 +1273,7 @@ This is a one-time fix-up, please be patient... }) } - #linkFromSpec (name, spec, parent, edge) { + #linkFromSpec (name, spec, parent) { const realpath = spec.fetchSpec const { installLinks, legacyPeerDeps } = this return rpj(realpath + '/package.json').catch(() => ({})).then(pkg => { diff --git a/workspaces/arborist/lib/arborist/index.js b/workspaces/arborist/lib/arborist/index.js index 3726b1ecaf633..ba180f354708a 100644 --- a/workspaces/arborist/lib/arborist/index.js +++ b/workspaces/arborist/lib/arborist/index.js @@ -74,20 +74,26 @@ class Arborist extends Base { Arborist: this.constructor, binLinks: 'binLinks' in options ? !!options.binLinks : true, cache: options.cache || `${homedir()}/.npm/_cacache`, + dryRun: !!options.dryRun, + formatPackageLock: 'formatPackageLock' in options ? !!options.formatPackageLock : true, force: !!options.force, global: !!options.global, ignoreScripts: !!options.ignoreScripts, installStrategy: options.global ? 'shallow' : (options.installStrategy ? options.installStrategy : 'hoisted'), lockfileVersion: lockfileVersion(options.lockfileVersion), + packageLockOnly: !!options.packageLockOnly, packumentCache: options.packumentCache || new Map(), path: options.path || '.', rebuildBundle: 'rebuildBundle' in options ? !!options.rebuildBundle : true, replaceRegistryHost: options.replaceRegistryHost, + savePrefix: 'savePrefix' in options ? options.savePrefix : '^', scriptShell: options.scriptShell, workspaces: options.workspaces || [], workspacesEnabled: options.workspacesEnabled !== false, } - // TODO is this even used? If not is that a bug? + // TODO we only ever look at this.options.replaceRegistryHost, not + // this.replaceRegistryHost. Defaulting needs to be written back to + // this.options to work properly this.replaceRegistryHost = this.options.replaceRegistryHost = (!this.options.replaceRegistryHost || this.options.replaceRegistryHost === 'npmjs') ? 'registry.npmjs.org' : this.options.replaceRegistryHost @@ -96,6 +102,7 @@ class Arborist extends Base { throw new Error(`Invalid saveType ${options.saveType}`) } this.cache = resolve(this.options.cache) + this.diff = null this.path = resolve(this.options.path) timeEnd() } @@ -250,6 +257,24 @@ class Arborist extends Base { this.finishTracker('audit') return ret } + + async dedupe (options = {}) { + // allow the user to set options on the ctor as well. + // XXX: deprecate separate method options objects. + options = { ...this.options, ...options } + const tree = await this.loadVirtual().catch(() => this.loadActual()) + const names = [] + for (const name of tree.inventory.query('name')) { + if (tree.inventory.query('name', name).size > 1) { + names.push(name) + } + } + return this.reify({ + ...options, + preferDedupe: true, + update: { names }, + }) + } } module.exports = Arborist diff --git a/workspaces/arborist/lib/arborist/isolated-reifier.js b/workspaces/arborist/lib/arborist/isolated-reifier.js index 19e4e4a20d83a..1e60d0f696b26 100644 --- a/workspaces/arborist/lib/arborist/isolated-reifier.js +++ b/workspaces/arborist/lib/arborist/isolated-reifier.js @@ -212,7 +212,7 @@ module.exports = cls => class IsolatedReifier extends cls { return { edges, nodes } } - async [_createIsolatedTree] (idealTree) { + async [_createIsolatedTree] () { await this[_makeIdealGraph](this.options) const proxiedIdealTree = this.idealGraph diff --git a/workspaces/arborist/lib/arborist/load-actual.js b/workspaces/arborist/lib/arborist/load-actual.js index 3ab5f5983768d..81c1bd1132775 100644 --- a/workspaces/arborist/lib/arborist/load-actual.js +++ b/workspaces/arborist/lib/arborist/load-actual.js @@ -336,8 +336,8 @@ module.exports = cls => class ActualLoader extends cls { await this.#loadFSChildren(node.target) return Promise.all( [...node.target.children.entries()] - .filter(([name, kid]) => !did.has(kid.realpath)) - .map(([name, kid]) => this.#loadFSTree(kid)) + .filter(([, kid]) => !did.has(kid.realpath)) + .map(([, kid]) => this.#loadFSTree(kid)) ) } } diff --git a/workspaces/arborist/lib/arborist/load-virtual.js b/workspaces/arborist/lib/arborist/load-virtual.js index 9b681a47a8358..d96d4adc88a70 100644 --- a/workspaces/arborist/lib/arborist/load-virtual.js +++ b/workspaces/arborist/lib/arborist/load-virtual.js @@ -283,7 +283,7 @@ module.exports = cls => class VirtualLoader extends cls { return node } - #loadLink (location, targetLoc, target, meta) { + #loadLink (location, targetLoc, target) { const path = resolve(this.path, location) const link = new Link({ installLinks: this.installLinks, diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 42bbdfef8eb42..96704f6556e0d 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -38,119 +38,96 @@ const { saveTypeMap, hasSubKey } = require('../add-rm-pkg-deps.js') const Shrinkwrap = require('../shrinkwrap.js') const { defaultLockfileVersion } = Shrinkwrap -const _retiredPaths = Symbol('retiredPaths') -const _retiredUnchanged = Symbol('retiredUnchanged') -const _sparseTreeDirs = Symbol('sparseTreeDirs') -const _sparseTreeRoots = Symbol('sparseTreeRoots') -const _savePrefix = Symbol('savePrefix') +// Part of steps (steps need refactoring before we can do anything about these) const _retireShallowNodes = Symbol.for('retireShallowNodes') -const _getBundlesByDepth = Symbol('getBundlesByDepth') -const _registryResolved = Symbol('registryResolved') -const _addNodeToTrashList = Symbol.for('addNodeToTrashList') +const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees') +const _submitQuickAudit = Symbol('submitQuickAudit') +const _addOmitsToTrashList = Symbol('addOmitsToTrashList') +const _unpackNewModules = Symbol.for('unpackNewModules') +const _build = Symbol.for('build') // shared by rebuild mixin const _trashList = Symbol.for('trashList') const _handleOptionalFailure = Symbol.for('handleOptionalFailure') const _loadTrees = Symbol.for('loadTrees') +// defined by rebuild mixin +const _checkBins = Symbol.for('checkBins') // shared symbols for swapping out when testing +// TODO tests should not be this deep into internals const _diffTrees = Symbol.for('diffTrees') const _createSparseTree = Symbol.for('createSparseTree') const _loadShrinkwrapsAndUpdateTrees = Symbol.for('loadShrinkwrapsAndUpdateTrees') -const _shrinkwrapInflated = Symbol('shrinkwrapInflated') -const _bundleUnpacked = Symbol('bundleUnpacked') -const _bundleMissing = Symbol('bundleMissing') const _reifyNode = Symbol.for('reifyNode') -const _extractOrLink = Symbol('extractOrLink') const _updateAll = Symbol.for('updateAll') const _updateNames = Symbol.for('updateNames') -// defined by rebuild mixin -const _checkBins = Symbol.for('checkBins') -const _symlink = Symbol('symlink') -const _warnDeprecated = Symbol('warnDeprecated') -const _loadBundlesAndUpdateTrees = Symbol.for('loadBundlesAndUpdateTrees') -const _submitQuickAudit = Symbol('submitQuickAudit') -const _unpackNewModules = Symbol.for('unpackNewModules') const _moveContents = Symbol.for('moveContents') const _moveBackRetiredUnchanged = Symbol.for('moveBackRetiredUnchanged') -const _build = Symbol.for('build') const _removeTrash = Symbol.for('removeTrash') const _renamePath = Symbol.for('renamePath') const _rollbackRetireShallowNodes = Symbol.for('rollbackRetireShallowNodes') const _rollbackCreateSparseTree = Symbol.for('rollbackCreateSparseTree') const _rollbackMoveBackRetiredUnchanged = Symbol.for('rollbackMoveBackRetiredUnchanged') const _saveIdealTree = Symbol.for('saveIdealTree') -const _copyIdealToActual = Symbol('copyIdealToActual') -const _addOmitsToTrashList = Symbol('addOmitsToTrashList') -const _packageLockOnly = Symbol('packageLockOnly') -const _dryRun = Symbol('dryRun') -const _validateNodeModules = Symbol('validateNodeModules') -const _nmValidated = Symbol('nmValidated') -const _validatePath = Symbol('validatePath') const _reifyPackages = Symbol.for('reifyPackages') -const _omitDev = Symbol('omitDev') -const _omitOptional = Symbol('omitOptional') -const _omitPeer = Symbol('omitPeer') - -const _pruneBundledMetadeps = Symbol('pruneBundledMetadeps') - -// defined by Ideal mixin +// defined by build-ideal-tree mixin const _resolvedAdd = Symbol.for('resolvedAdd') const _usePackageLock = Symbol.for('usePackageLock') -const _formatPackageLock = Symbol.for('formatPackageLock') +// used by build-ideal-tree mixin +const _addNodeToTrashList = Symbol.for('addNodeToTrashList') const _createIsolatedTree = Symbol.for('createIsolatedTree') module.exports = cls => class Reifier extends cls { + #bundleMissing = new Set() // child nodes we'd EXPECT to be included in a bundle, but aren't + #bundleUnpacked = new Set() // the nodes we unpack to read their bundles + #dryRun + #nmValidated = new Set() + #omitDev + #omitPeer + #omitOptional + #retiredPaths = {} + #retiredUnchanged = {} + #savePrefix + #shrinkwrapInflated = new Set() + #sparseTreeDirs = new Set() + #sparseTreeRoots = new Set() + constructor (options) { super(options) - const { - savePrefix = '^', - packageLockOnly = false, - dryRun = false, - formatPackageLock = true, - } = options - - this[_dryRun] = !!dryRun - this[_packageLockOnly] = !!packageLockOnly - this[_savePrefix] = savePrefix - this[_formatPackageLock] = !!formatPackageLock - - this.diff = null - this[_retiredPaths] = {} - this[_shrinkwrapInflated] = new Set() - this[_retiredUnchanged] = {} - this[_sparseTreeDirs] = new Set() - this[_sparseTreeRoots] = new Set() this[_trashList] = new Set() - // the nodes we unpack to read their bundles - this[_bundleUnpacked] = new Set() - // child nodes we'd EXPECT to be included in a bundle, but aren't - this[_bundleMissing] = new Set() - this[_nmValidated] = new Set() } // public method async reify (options = {}) { const linked = (options.installStrategy || this.options.installStrategy) === 'linked' - if (this[_packageLockOnly] && this.options.global) { + if (this.options.packageLockOnly && this.options.global) { const er = new Error('cannot generate lockfile for global packages') er.code = 'ESHRINKWRAPGLOBAL' throw er } const omit = new Set(options.omit || []) - this[_omitDev] = omit.has('dev') - this[_omitOptional] = omit.has('optional') - this[_omitPeer] = omit.has('peer') + this.#omitDev = omit.has('dev') + this.#omitOptional = omit.has('optional') + this.#omitPeer = omit.has('peer') // start tracker block this.addTracker('reify') const timeEnd = time.start('reify') - await this[_validatePath]() + // don't create missing dirs on dry runs + if (!this.options.packageLockOnly && !this.options.dryRun) { + // we do NOT want to set ownership on this folder, especially + // recursively, because it can have other side effects to do that + // in a project directory. We just want to make it if it's missing. + await mkdir(resolve(this.path), { recursive: true }) + + // do not allow the top-level node_modules to be a symlink + await this.#validateNodeModules(resolve(this.path, 'node_modules')) + } await this[_loadTrees](options) const oldTree = this.idealTree @@ -159,7 +136,7 @@ module.exports = cls => class Reifier extends cls { // this is currently technical debt which will be resolved in a refactor // of Node/Link trees log.warn('reify', 'The "linked" install strategy is EXPERIMENTAL and may contain bugs.') - this.idealTree = await this[_createIsolatedTree](this.idealTree) + this.idealTree = await this[_createIsolatedTree]() } await this[_diffTrees]() await this[_reifyPackages]() @@ -169,7 +146,124 @@ module.exports = cls => class Reifier extends cls { this.idealTree = oldTree } await this[_saveIdealTree](options) - await this[_copyIdealToActual]() + // clean up any trash that is still in the tree + for (const path of this[_trashList]) { + const loc = relpath(this.idealTree.realpath, path) + const node = this.idealTree.inventory.get(loc) + if (node && node.root === this.idealTree) { + node.parent = null + } + } + + // if we filtered to only certain nodes, then anything ELSE needs + // to be untouched in the resulting actual tree, even if it differs + // in the idealTree. Copy over anything that was in the actual and + // was not changed, delete anything in the ideal and not actual. + // Then we move the entire idealTree over to this.actualTree, and + // save the hidden lockfile. + if (this.diff && this.diff.filterSet.size) { + const reroot = new Set() + + const { filterSet } = this.diff + const seen = new Set() + for (const [loc, ideal] of this.idealTree.inventory.entries()) { + seen.add(loc) + + // if it's an ideal node from the filter set, then skip it + // because we already made whatever changes were necessary + if (filterSet.has(ideal)) { + continue + } + + // otherwise, if it's not in the actualTree, then it's not a thing + // that we actually added. And if it IS in the actualTree, then + // it's something that we left untouched, so we need to record + // that. + const actual = this.actualTree.inventory.get(loc) + if (!actual) { + ideal.root = null + } else { + if ([...actual.linksIn].some(link => filterSet.has(link))) { + seen.add(actual.location) + continue + } + const { realpath, isLink } = actual + if (isLink && ideal.isLink && ideal.realpath === realpath) { + continue + } else { + reroot.add(actual) + } + } + } + + // now find any actual nodes that may not be present in the ideal + // tree, but were left behind by virtue of not being in the filter + for (const [loc, actual] of this.actualTree.inventory.entries()) { + if (seen.has(loc)) { + continue + } + seen.add(loc) + + // we know that this is something that ISN'T in the idealTree, + // or else we will have addressed it in the previous loop. + // If it's in the filterSet, that means we intentionally removed + // it, so nothing to do here. + if (filterSet.has(actual)) { + continue + } + + reroot.add(actual) + } + + // go through the rerooted actual nodes, and move them over. + for (const actual of reroot) { + actual.root = this.idealTree + } + + // prune out any tops that lack a linkIn, they are no longer relevant. + for (const top of this.idealTree.tops) { + if (top.linksIn.size === 0) { + top.root = null + } + } + + // need to calculate dep flags, since nodes may have been marked + // as extraneous or otherwise incorrect during transit. + calcDepFlags(this.idealTree) + } + + // save the ideal's meta as a hidden lockfile after we actualize it + this.idealTree.meta.filename = + this.idealTree.realpath + '/node_modules/.package-lock.json' + this.idealTree.meta.hiddenLockfile = true + this.idealTree.meta.lockfileVersion = defaultLockfileVersion + + this.actualTree = this.idealTree + this.idealTree = null + + if (!this.options.global) { + await this.actualTree.meta.save() + const ignoreScripts = !!this.options.ignoreScripts + // if we aren't doing a dry run or ignoring scripts and we actually made changes to the dep + // tree, then run the dependencies scripts + if (!this.options.dryRun && !ignoreScripts && this.diff && this.diff.children.length) { + const { path, package: pkg } = this.actualTree.target + const stdio = this.options.foregroundScripts ? 'inherit' : 'pipe' + const { scripts = {} } = pkg + for (const event of ['predependencies', 'dependencies', 'postdependencies']) { + if (Object.prototype.hasOwnProperty.call(scripts, event)) { + log.info('run', pkg._id, event, scripts[event]) + await time.start(`reify:run:${event}`, () => runScript({ + event, + path, + pkg, + stdio, + scriptShell: this.options.scriptShell, + })) + } + } + } + } // This is a very bad pattern and I can't wait to stop doing it this.auditReport = await this.auditReport @@ -178,28 +272,13 @@ module.exports = cls => class Reifier extends cls { return treeCheck(this.actualTree) } - async [_validatePath] () { - // don't create missing dirs on dry runs - if (this[_packageLockOnly] || this[_dryRun]) { - return - } - - // we do NOT want to set ownership on this folder, especially - // recursively, because it can have other side effects to do that - // in a project directory. We just want to make it if it's missing. - await mkdir(resolve(this.path), { recursive: true }) - - // do not allow the top-level node_modules to be a symlink - await this[_validateNodeModules](resolve(this.path, 'node_modules')) - } - async [_reifyPackages] () { // we don't submit the audit report or write to disk on dry runs - if (this[_dryRun]) { + if (this.options.dryRun) { return } - if (this[_packageLockOnly]) { + if (this.options.packageLockOnly) { // we already have the complete tree, so just audit it now, // and that's all we have to do here. return this[_submitQuickAudit]() @@ -248,6 +327,7 @@ module.exports = cls => class Reifier extends cls { throw reifyTerminated } } catch (er) { + // TODO rollbacks shouldn't be relied on to throw err await this[rollback](er) /* istanbul ignore next - rollback throws, should never hit this */ throw er @@ -272,11 +352,11 @@ module.exports = cls => class Reifier extends cls { const timeEnd = time.start('reify:loadTrees') const bitOpt = { ...options, - complete: this[_packageLockOnly] || this[_dryRun], + complete: this.options.packageLockOnly || this.options.dryRun, } // if we're only writing a package lock, then it doesn't matter what's here - if (this[_packageLockOnly]) { + if (this.options.packageLockOnly) { return this.buildIdealTree(bitOpt).then(timeEnd) } @@ -325,7 +405,7 @@ module.exports = cls => class Reifier extends cls { } [_diffTrees] () { - if (this[_packageLockOnly]) { + if (this.options.packageLockOnly) { return } @@ -383,7 +463,7 @@ module.exports = cls => class Reifier extends cls { // find all the nodes that need to change between the actual // and ideal trees. this.diff = Diff.calculate({ - shrinkwrapInflated: this[_shrinkwrapInflated], + shrinkwrapInflated: this.#shrinkwrapInflated, filterNodes, actual: this.actualTree, ideal: this.idealTree, @@ -405,7 +485,7 @@ module.exports = cls => class Reifier extends cls { // replace them when rolling back on failure. [_addNodeToTrashList] (node, retire = false) { const paths = [node.path, ...node.binPaths] - const moves = this[_retiredPaths] + const moves = this.#retiredPaths log.silly('reify', 'mark', retire ? 'retired' : 'deleted', paths) for (const path of paths) { if (retire) { @@ -422,7 +502,7 @@ module.exports = cls => class Reifier extends cls { // changed or removed, so that we can rollback if necessary. [_retireShallowNodes] () { const timeEnd = time.start('reify:retireShallow') - const moves = this[_retiredPaths] = {} + const moves = this.#retiredPaths = {} for (const diff of this.diff.children) { if (diff.action === 'CHANGE' || diff.action === 'REMOVE') { // we'll have to clean these up at the end, so add them to the list @@ -455,12 +535,12 @@ module.exports = cls => class Reifier extends cls { [_rollbackRetireShallowNodes] (er) { const timeEnd = time.start('reify:rollback:retireShallow') - const moves = this[_retiredPaths] + const moves = this.#retiredPaths const movePromises = Object.entries(moves) .map(([from, to]) => this[_renamePath](to, from)) return promiseAllRejectLate(movePromises) // ignore subsequent rollback errors - .catch(er => {}) + .catch(() => {}) .then(timeEnd) .then(() => { throw er @@ -470,7 +550,7 @@ module.exports = cls => class Reifier extends cls { // adding to the trash list will skip reifying, and delete them // if they are currently in the tree and otherwise untouched. [_addOmitsToTrashList] () { - if (!this[_omitDev] && !this[_omitOptional] && !this[_omitPeer]) { + if (!this.#omitDev && !this.#omitOptional && !this.#omitPeer) { return } @@ -492,10 +572,10 @@ module.exports = cls => class Reifier extends cls { // omit node if the dep type matches any omit flags that were set if ( - node.peer && this[_omitPeer] || - node.dev && this[_omitDev] || - node.optional && this[_omitOptional] || - node.devOptional && this[_omitOptional] && this[_omitDev] + node.peer && this.#omitPeer || + node.dev && this.#omitDev || + node.optional && this.#omitOptional || + node.devOptional && this.#omitOptional && this.#omitDev ) { this[_addNodeToTrashList](node) } @@ -511,7 +591,7 @@ module.exports = cls => class Reifier extends cls { const leaves = this.diff.leaves .filter(diff => { return (diff.action === 'ADD' || diff.action === 'CHANGE') && - !this[_sparseTreeDirs].has(diff.ideal.path) && + !this.#sparseTreeDirs.has(diff.ideal.path) && !diff.ideal.isLink }) .map(diff => diff.ideal) @@ -528,25 +608,25 @@ module.exports = cls => class Reifier extends cls { continue } dirsChecked.add(d) - const st = await lstat(d).catch(er => null) + const st = await lstat(d).catch(() => null) // this can happen if we have a link to a package with a name // that the filesystem treats as if it is the same thing. // would be nice to have conditional istanbul ignores here... /* istanbul ignore next - defense in depth */ if (st && !st.isDirectory()) { const retired = retirePath(d) - this[_retiredPaths][d] = retired + this.#retiredPaths[d] = retired this[_trashList].add(retired) await this[_renamePath](d, retired) } } - this[_sparseTreeDirs].add(node.path) + this.#sparseTreeDirs.add(node.path) const made = await mkdir(node.path, { recursive: true }) // if the directory already exists, made will be undefined. if that's the case // we don't want to remove it because we aren't the ones who created it so we - // omit it from the _sparseTreeRoots + // omit it from the #sparseTreeRoots if (made) { - this[_sparseTreeRoots].add(made) + this.#sparseTreeRoots.add(made) } })).then(timeEnd) } @@ -554,10 +634,10 @@ module.exports = cls => class Reifier extends cls { [_rollbackCreateSparseTree] (er) { const timeEnd = time.start('reify:rollback:createSparse') // cut the roots of the sparse tree that were created, not the leaves - const roots = this[_sparseTreeRoots] + const roots = this.#sparseTreeRoots // also delete the moves that we retired, so that we can move them back const failures = [] - const targets = [...roots, ...Object.keys(this[_retiredPaths])] + const targets = [...roots, ...Object.keys(this.#retiredPaths)] const unlinks = targets .map(path => rm(path, { recursive: true, force: true }).catch(er => failures.push([path, er]))) return promiseAllRejectLate(unlinks).then(() => { @@ -574,7 +654,7 @@ module.exports = cls => class Reifier extends cls { // we need to unpack them, read that shrinkwrap file, and then update // the tree by calling loadVirtual with the node as the root. [_loadShrinkwrapsAndUpdateTrees] () { - const seen = this[_shrinkwrapInflated] + const seen = this.#shrinkwrapInflated const shrinkwraps = this.diff.leaves .filter(d => (d.action === 'CHANGE' || d.action === 'ADD' || !d.action) && d.ideal.hasShrinkwrap && !seen.has(d.ideal) && @@ -632,8 +712,13 @@ module.exports = cls => class Reifier extends cls { checkPlatform(node.package, false, { cpu, os, libc }) } await this[_checkBins](node) - await this[_extractOrLink](node) - await this[_warnDeprecated](node) + await this.#extractOrLink(node) + const { _id, deprecated } = node.package + // The .catch is in _handleOptionalFailure. Not ideal, this should be cleaned up. + // eslint-disable-next-line promise/always-return + if (deprecated) { + log.warn('deprecated', `${_id}: ${deprecated}`) + } }) return this[_handleOptionalFailure](node, p) @@ -645,22 +730,22 @@ module.exports = cls => class Reifier extends cls { } // do not allow node_modules to be a symlink - async [_validateNodeModules] (nm) { - if (this.options.force || this[_nmValidated].has(nm)) { + async #validateNodeModules (nm) { + if (this.options.force || this.#nmValidated.has(nm)) { return } const st = await lstat(nm).catch(() => null) if (!st || st.isDirectory()) { - this[_nmValidated].add(nm) + this.#nmValidated.add(nm) return } log.warn('reify', 'Removing non-directory', nm) await rm(nm, { recursive: true, force: true }) } - async [_extractOrLink] (node) { + async #extractOrLink (node) { const nm = resolve(node.parent.path, 'node_modules') - await this[_validateNodeModules](nm) + await this.#validateNodeModules(nm) if (!node.isLink) { // in normal cases, node.resolved should *always* be set by now. @@ -672,7 +757,7 @@ module.exports = cls => class Reifier extends cls { // entirely, since we can't possibly reify it. let res = null if (node.resolved) { - const registryResolved = this[_registryResolved](node.resolved) + const registryResolved = this.#registryResolved(node.resolved) if (registryResolved) { res = `${node.name}@${registryResolved}` } @@ -694,7 +779,7 @@ module.exports = cls => class Reifier extends cls { return } await debug(async () => { - const st = await lstat(node.path).catch(e => null) + const st = await lstat(node.path).catch(() => null) if (st && !st.isDirectory()) { debug.log('unpacking into a non-directory', node) throw Object.assign(new Error('ENOTDIR: not a directory'), { @@ -718,10 +803,8 @@ module.exports = cls => class Reifier extends cls { // node.isLink await rm(node.path, { recursive: true, force: true }) - await this[_symlink](node) - } - async [_symlink] (node) { + // symlink const dir = dirname(node.path) const target = node.realpath const rel = relative(dir, target) @@ -729,17 +812,10 @@ module.exports = cls => class Reifier extends cls { return symlink(rel, node.path, 'junction') } - [_warnDeprecated] (node) { - const { _id, deprecated } = node.package - if (deprecated) { - log.warn('deprecated', `${_id}: ${deprecated}`) - } - } - // if the node is optional, then the failure of the promise is nonfatal // just add it and its optional set to the trash list. [_handleOptionalFailure] (node, p) { - return (node.optional ? p.catch(er => { + return (node.optional ? p.catch(() => { const set = optionalSet(node) for (node of set) { log.verbose('reify', 'failed optional dependency', node.path) @@ -748,7 +824,7 @@ module.exports = cls => class Reifier extends cls { }) : p).then(() => node) } - [_registryResolved] (resolved) { + #registryResolved (resolved) { // the default registry url is a magic value meaning "the currently // configured registry". // `resolved` must never be falsey. @@ -778,18 +854,48 @@ module.exports = cls => class Reifier extends cls { // by the contents of the package. however, in their case, rather than // shipping a virtual tree that must be reified, they ship an entire // reified actual tree that must be unpacked and not modified. - [_loadBundlesAndUpdateTrees] ( - depth = 0, bundlesByDepth = this[_getBundlesByDepth]() - ) { + [_loadBundlesAndUpdateTrees] (depth = 0, bundlesByDepth) { + let maxBundleDepth + if (!bundlesByDepth) { + bundlesByDepth = new Map() + maxBundleDepth = -1 + dfwalk({ + tree: this.diff, + visit: diff => { + const node = diff.ideal + if (!node) { + return + } + if (node.isProjectRoot) { + return + } + + const { bundleDependencies } = node.package + if (bundleDependencies && bundleDependencies.length) { + maxBundleDepth = Math.max(maxBundleDepth, node.depth) + if (!bundlesByDepth.has(node.depth)) { + bundlesByDepth.set(node.depth, [node]) + } else { + bundlesByDepth.get(node.depth).push(node) + } + } + }, + getChildren: diff => diff.children, + }) + + bundlesByDepth.set('maxBundleDepth', maxBundleDepth) + } else { + maxBundleDepth = bundlesByDepth.get('maxBundleDepth') + } + if (depth === 0) { time.start('reify:loadBundles') } - const maxBundleDepth = bundlesByDepth.get('maxBundleDepth') if (depth > maxBundleDepth) { // if we did something, then prune the tree and update the diffs if (maxBundleDepth !== -1) { - this[_pruneBundledMetadeps](bundlesByDepth) + this.#pruneBundledMetadeps(bundlesByDepth) this[_diffTrees]() } time.end('reify:loadBundles') @@ -810,7 +916,7 @@ module.exports = cls => class Reifier extends cls { // extract all the nodes with bundles return promiseCallLimit(set.map(node => { return () => { - this[_bundleUnpacked].add(node) + this.#bundleUnpacked.add(node) return this[_reifyNode](node) } }), { rejectLate: true }) @@ -839,46 +945,15 @@ module.exports = cls => class Reifier extends cls { }, }) for (const name of notTransplanted) { - this[_bundleMissing].add(node.children.get(name)) + this.#bundleMissing.add(node.children.get(name)) } }))) // move onto the next level of bundled items .then(() => this[_loadBundlesAndUpdateTrees](depth + 1, bundlesByDepth)) } - [_getBundlesByDepth] () { - const bundlesByDepth = new Map() - let maxBundleDepth = -1 - dfwalk({ - tree: this.diff, - visit: diff => { - const node = diff.ideal - if (!node) { - return - } - if (node.isProjectRoot) { - return - } - - const { bundleDependencies } = node.package - if (bundleDependencies && bundleDependencies.length) { - maxBundleDepth = Math.max(maxBundleDepth, node.depth) - if (!bundlesByDepth.has(node.depth)) { - bundlesByDepth.set(node.depth, [node]) - } else { - bundlesByDepth.get(node.depth).push(node) - } - } - }, - getChildren: diff => diff.children, - }) - - bundlesByDepth.set('maxBundleDepth', maxBundleDepth) - return bundlesByDepth - } - // https://github.com/npm/cli/issues/1597#issuecomment-667639545 - [_pruneBundledMetadeps] (bundlesByDepth) { + #pruneBundledMetadeps (bundlesByDepth) { const bundleShadowed = new Set() // Example dep graph: @@ -1012,9 +1087,9 @@ module.exports = cls => class Reifier extends cls { } const node = diff.ideal - const bd = this[_bundleUnpacked].has(node) - const sw = this[_shrinkwrapInflated].has(node) - const bundleMissing = this[_bundleMissing].has(node) + const bd = this.#bundleUnpacked.has(node) + const sw = this.#shrinkwrapInflated.has(node) + const bundleMissing = this.#bundleMissing.has(node) // check whether we still need to unpack this one. // test the inDepBundle last, since that's potentially a tree walk. @@ -1050,8 +1125,8 @@ module.exports = cls => class Reifier extends cls { // the actualTree and idealTree _don't_ differ, starting from the // shallowest nodes that we moved aside in the first place. const timeEnd = time.start('reify:unretire') - const moves = this[_retiredPaths] - this[_retiredUnchanged] = {} + const moves = this.#retiredPaths + this.#retiredUnchanged = {} return promiseAllRejectLate(this.diff.children.map(diff => { // skip if nothing was retired if (diff.action !== 'CHANGE' && diff.action !== 'REMOVE') { @@ -1074,7 +1149,7 @@ module.exports = cls => class Reifier extends cls { } }) - this[_retiredUnchanged][retireFolder] = [] + this.#retiredUnchanged[retireFolder] = [] return promiseAllRejectLate(diff.unchanged.map(node => { // no need to roll back links, since we'll just delete them anyway if (node.isLink) { @@ -1083,11 +1158,11 @@ module.exports = cls => class Reifier extends cls { } // will have been moved/unpacked along with bundler - if (node.inDepBundle && !this[_bundleMissing].has(node)) { + if (node.inDepBundle && !this.#bundleMissing.has(node)) { return } - this[_retiredUnchanged][retireFolder].push(node) + this.#retiredUnchanged[retireFolder].push(node) const rel = relative(realFolder, node.path) const fromPath = resolve(retireFolder, rel) @@ -1114,10 +1189,10 @@ module.exports = cls => class Reifier extends cls { } [_rollbackMoveBackRetiredUnchanged] (er) { - const moves = this[_retiredPaths] + const moves = this.#retiredPaths // flip the mapping around to go back const realFolders = new Map(Object.entries(moves).map(([k, v]) => [v, k])) - const promises = Object.entries(this[_retiredUnchanged]) + const promises = Object.entries(this.#retiredUnchanged) .map(([retireFolder, nodes]) => promiseAllRejectLate(nodes.map(node => { const realFolder = realFolders.get(retireFolder) const rel = relative(realFolder, node.path) @@ -1209,7 +1284,7 @@ module.exports = cls => class Reifier extends cls { const saveIdealTree = !( (!save && !hasUpdates) || this.options.global - || this[_dryRun] + || this.options.dryRun ) if (!saveIdealTree) { @@ -1245,7 +1320,7 @@ module.exports = cls => class Reifier extends cls { const isLocalDep = req.type === 'directory' || req.type === 'file' if (req.registry) { const version = child.version - const prefixRange = version ? this[_savePrefix] + version : '*' + const prefixRange = version ? this.options.savePrefix + version : '*' // if we installed a range, then we save the range specified // if it is not a subset of the ^x.y.z. eg, installing a range // of `1.x <1.2.3` will not be saved as `^1.2.0`, because that @@ -1280,7 +1355,7 @@ module.exports = cls => class Reifier extends cls { // using their relative path if (edge.type === 'workspace') { const { version } = edge.to.target - const prefixRange = version ? this[_savePrefix] + version : '*' + const prefixRange = version ? this.options.savePrefix + version : '*' newSpec = prefixRange } else { // save the relative path in package.json @@ -1449,151 +1524,12 @@ module.exports = cls => class Reifier extends cls { // TODO this ignores options.save await this.idealTree.meta.save({ - format: (this[_formatPackageLock] && format) ? format - : this[_formatPackageLock], + format: (this.options.formatPackageLock && format) ? format + : this.options.formatPackageLock, }) } timeEnd() return true } - - async [_copyIdealToActual] () { - // clean up any trash that is still in the tree - for (const path of this[_trashList]) { - const loc = relpath(this.idealTree.realpath, path) - const node = this.idealTree.inventory.get(loc) - if (node && node.root === this.idealTree) { - node.parent = null - } - } - - // if we filtered to only certain nodes, then anything ELSE needs - // to be untouched in the resulting actual tree, even if it differs - // in the idealTree. Copy over anything that was in the actual and - // was not changed, delete anything in the ideal and not actual. - // Then we move the entire idealTree over to this.actualTree, and - // save the hidden lockfile. - if (this.diff && this.diff.filterSet.size) { - const reroot = new Set() - - const { filterSet } = this.diff - const seen = new Set() - for (const [loc, ideal] of this.idealTree.inventory.entries()) { - seen.add(loc) - - // if it's an ideal node from the filter set, then skip it - // because we already made whatever changes were necessary - if (filterSet.has(ideal)) { - continue - } - - // otherwise, if it's not in the actualTree, then it's not a thing - // that we actually added. And if it IS in the actualTree, then - // it's something that we left untouched, so we need to record - // that. - const actual = this.actualTree.inventory.get(loc) - if (!actual) { - ideal.root = null - } else { - if ([...actual.linksIn].some(link => filterSet.has(link))) { - seen.add(actual.location) - continue - } - const { realpath, isLink } = actual - if (isLink && ideal.isLink && ideal.realpath === realpath) { - continue - } else { - reroot.add(actual) - } - } - } - - // now find any actual nodes that may not be present in the ideal - // tree, but were left behind by virtue of not being in the filter - for (const [loc, actual] of this.actualTree.inventory.entries()) { - if (seen.has(loc)) { - continue - } - seen.add(loc) - - // we know that this is something that ISN'T in the idealTree, - // or else we will have addressed it in the previous loop. - // If it's in the filterSet, that means we intentionally removed - // it, so nothing to do here. - if (filterSet.has(actual)) { - continue - } - - reroot.add(actual) - } - - // go through the rerooted actual nodes, and move them over. - for (const actual of reroot) { - actual.root = this.idealTree - } - - // prune out any tops that lack a linkIn, they are no longer relevant. - for (const top of this.idealTree.tops) { - if (top.linksIn.size === 0) { - top.root = null - } - } - - // need to calculate dep flags, since nodes may have been marked - // as extraneous or otherwise incorrect during transit. - calcDepFlags(this.idealTree) - } - - // save the ideal's meta as a hidden lockfile after we actualize it - this.idealTree.meta.filename = - this.idealTree.realpath + '/node_modules/.package-lock.json' - this.idealTree.meta.hiddenLockfile = true - this.idealTree.meta.lockfileVersion = defaultLockfileVersion - - this.actualTree = this.idealTree - this.idealTree = null - - if (!this.options.global) { - await this.actualTree.meta.save() - const ignoreScripts = !!this.options.ignoreScripts - // if we aren't doing a dry run or ignoring scripts and we actually made changes to the dep - // tree, then run the dependencies scripts - if (!this[_dryRun] && !ignoreScripts && this.diff && this.diff.children.length) { - const { path, package: pkg } = this.actualTree.target - const stdio = this.options.foregroundScripts ? 'inherit' : 'pipe' - const { scripts = {} } = pkg - for (const event of ['predependencies', 'dependencies', 'postdependencies']) { - if (Object.prototype.hasOwnProperty.call(scripts, event)) { - log.info('run', pkg._id, event, scripts[event]) - await time.start(`reify:run:${event}`, () => runScript({ - event, - path, - pkg, - stdio, - scriptShell: this.options.scriptShell, - })) - } - } - } - } - } - - async dedupe (options = {}) { - // allow the user to set options on the ctor as well. - // XXX: deprecate separate method options objects. - options = { ...this.options, ...options } - const tree = await this.loadVirtual().catch(() => this.loadActual()) - const names = [] - for (const name of tree.inventory.query('name')) { - if (tree.inventory.query('name', name).size > 1) { - names.push(name) - } - } - return this.reify({ - ...options, - preferDedupe: true, - update: { names }, - }) - } } diff --git a/workspaces/arborist/lib/dep-valid.js b/workspaces/arborist/lib/dep-valid.js index 4afb5e47cf111..58656e8dbbad2 100644 --- a/workspaces/arborist/lib/dep-valid.js +++ b/workspaces/arborist/lib/dep-valid.js @@ -124,7 +124,7 @@ const linkValid = (child, requested, requestor) => { return isLink && relative(child.realpath, requested.fetchSpec) === '' } -const tarballValid = (child, requested, requestor) => { +const tarballValid = (child, requested) => { if (child.isLink) { return false } diff --git a/workspaces/arborist/lib/inventory.js b/workspaces/arborist/lib/inventory.js index 0885034666b50..7b3f294fdab2c 100644 --- a/workspaces/arborist/lib/inventory.js +++ b/workspaces/arborist/lib/inventory.js @@ -130,7 +130,7 @@ class Inventory extends Map { return super.get(node.location) === node } - set (k, v) { + set () { throw new Error('direct set() not supported, use inventory.add(node)') } } diff --git a/workspaces/arborist/lib/query-selector-all.js b/workspaces/arborist/lib/query-selector-all.js index d001a5cced83d..77640a3803d13 100644 --- a/workspaces/arborist/lib/query-selector-all.js +++ b/workspaces/arborist/lib/query-selector-all.js @@ -650,27 +650,27 @@ class Results { // operators for attribute selectors const attributeOperators = { // attribute value is equivalent - '=' ({ attr, value, insensitive }) { + '=' ({ attr, value }) { return attr === value }, // attribute value contains word - '~=' ({ attr, value, insensitive }) { + '~=' ({ attr, value }) { return (attr.match(/\w+/g) || []).includes(value) }, // attribute value contains string - '*=' ({ attr, value, insensitive }) { + '*=' ({ attr, value }) { return attr.includes(value) }, // attribute value is equal or starts with - '|=' ({ attr, value, insensitive }) { + '|=' ({ attr, value }) { return attr.startsWith(`${value}-`) }, // attribute value starts with - '^=' ({ attr, value, insensitive }) { + '^=' ({ attr, value }) { return attr.startsWith(value) }, // attribute value ends with - '$=' ({ attr, value, insensitive }) { + '$=' ({ attr, value }) { return attr.endsWith(value) }, } diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index a8eec08783ddf..11c0ab4df3b52 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "7.5.0", + "version": "7.5.1", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -12,8 +12,8 @@ "@npmcli/node-gyp": "^3.0.0", "@npmcli/package-json": "^5.1.0", "@npmcli/query": "^3.1.0", - "@npmcli/redact": "^1.1.0", - "@npmcli/run-script": "^8.0.0", + "@npmcli/redact": "^2.0.0", + "@npmcli/run-script": "^8.1.0", "bin-links": "^4.0.1", "cacache": "^18.0.0", "common-ancestor-path": "^1.0.1", @@ -25,7 +25,7 @@ "npm-install-checks": "^6.2.0", "npm-package-arg": "^11.0.2", "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.2.1", + "npm-registry-fetch": "^17.0.0", "pacote": "^18.0.1", "parse-conflict-json": "^3.0.0", "proc-log": "^4.2.0", @@ -62,7 +62,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/arborist" }, "author": "GitHub Inc.", diff --git a/workspaces/arborist/test/arborist/build-ideal-tree.js b/workspaces/arborist/test/arborist/build-ideal-tree.js index 0e9264b849879..1b9940c5ae05a 100644 --- a/workspaces/arborist/test/arborist/build-ideal-tree.js +++ b/workspaces/arborist/test/arborist/build-ideal-tree.js @@ -136,7 +136,7 @@ t.test('fail on malformed package.json', t => { ) }) -t.test('ignore mismatched engine for optional dependencies', async t => { +t.test('ignore mismatched engine for optional dependencies', async () => { const path = resolve(fixtures, 'optional-engine-specification') await buildIdeal(path, { ...OPT, diff --git a/workspaces/arborist/test/arborist/load-actual-ctor-throw.js b/workspaces/arborist/test/arborist/load-actual-ctor-throw.js index 812b1667fa753..63d859b76e0ea 100644 --- a/workspaces/arborist/test/arborist/load-actual-ctor-throw.js +++ b/workspaces/arborist/test/arborist/load-actual-ctor-throw.js @@ -2,7 +2,7 @@ const rpj = require('read-package-json-fast') const t = require('tap') const rpjMock = Object.assign((...args) => rpj(...args), { ...rpj, - normalize: (...args) => { + normalize: () => { throw new Error('boom') }, }) diff --git a/workspaces/arborist/test/arborist/rebuild.js b/workspaces/arborist/test/arborist/rebuild.js index df383c6ce772c..2843155f2809e 100644 --- a/workspaces/arborist/test/arborist/rebuild.js +++ b/workspaces/arborist/test/arborist/rebuild.js @@ -438,7 +438,7 @@ t.test('rebuild node-gyp dependencies lacking both preinstall and install script t.test('do not rebuild node-gyp dependencies with gypfile:false', async t => { // use require-inject so we don't need an actual massive binary dep fixture const Arborist = t.mock('../../lib/arborist/index.js', { - '@npmcli/run-script': async opts => { + '@npmcli/run-script': async () => { throw new Error('should not run any scripts') }, }) diff --git a/workspaces/arborist/test/arborist/reify.js b/workspaces/arborist/test/arborist/reify.js index d0615add3540a..7600f2dabad8d 100644 --- a/workspaces/arborist/test/arborist/reify.js +++ b/workspaces/arborist/test/arborist/reify.js @@ -791,7 +791,7 @@ t.test('rollbacks', { buffered: false }, t => { const check = warningTracker() return t.rejects(a.reify({ update: ['@isaacs/testing-bundledeps-parent'], - }).then(tree => 'it worked'), new Error('poop')) + }).then(() => 'it worked'), new Error('poop')) // eslint-disable-next-line promise/always-return .then(() => { const warnings = check() @@ -843,7 +843,7 @@ t.test('rollbacks', { buffered: false }, t => { a[kLoadBundles] = (depth, bundlesByDepth) => { const kRN = Symbol.for('reifyNode') const reifyNode = a[kRN] - a[kRN] = node => { + a[kRN] = () => { a[kRN] = reifyNode return Promise.reject(new Error('poop')) } @@ -861,7 +861,7 @@ t.test('rollbacks', { buffered: false }, t => { a[kUnpack] = () => { const kReify = Symbol.for('reifyNode') const reifyNode = a[kReify] - a[kReify] = node => { + a[kReify] = () => { a[kReify] = reifyNode return Promise.reject(new Error('poop')) } diff --git a/workspaces/config/CHANGELOG.md b/workspaces/config/CHANGELOG.md index 935738761d07f..2de83bd254c30 100644 --- a/workspaces/config/CHANGELOG.md +++ b/workspaces/config/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [8.3.1](https://github.com/npm/cli/compare/config-v8.3.0...config-v8.3.1) (2024-04-30) + +### Bug Fixes + +* [`3ec86a0`](https://github.com/npm/cli/commit/3ec86a0e258b1d5f5182f0093adf43c54e82578e) [#7456](https://github.com/npm/cli/pull/7456) linting: no-unused-vars (#7456) (@wraithgar) +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + ## [8.3.0](https://github.com/npm/cli/compare/config-v8.2.2...config-v8.3.0) (2024-04-25) ### Features diff --git a/workspaces/config/lib/index.js b/workspaces/config/lib/index.js index 49c4f0a18115c..c99292db9afb4 100644 --- a/workspaces/config/lib/index.js +++ b/workspaces/config/lib/index.js @@ -557,7 +557,7 @@ class Config { const k = envReplace(key, this.env) const v = this.parseField(value, k) if (where !== 'default') { - this.#checkDeprecated(k, where, obj, [key, value]) + this.#checkDeprecated(k) if (this.definitions[key]?.exclusive) { for (const exclusive of this.definitions[key].exclusive) { if (!this.isDefault(exclusive)) { @@ -571,7 +571,7 @@ class Config { } } - #checkDeprecated (key, where, obj, kv) { + #checkDeprecated (key) { // XXX(npm9+) make this throw an error if (this.deprecated[key]) { log.warn('config', key, this.deprecated[key]) @@ -739,7 +739,7 @@ class Config { const iniData = ini.stringify(conf.raw).trim() + '\n' if (!iniData.trim()) { // ignore the unlink error (eg, if file doesn't exist) - await unlink(conf.source).catch(er => {}) + await unlink(conf.source).catch(() => {}) return } const dir = dirname(conf.source) @@ -774,12 +774,9 @@ class Config { this.delete(`${nerfed}:keyfile`, level) } - setCredentialsByURI (uri, { token, username, password, email, certfile, keyfile }) { + setCredentialsByURI (uri, { token, username, password, certfile, keyfile }) { const nerfed = nerfDart(uri) - // email is either provided, a top level key, or nothing - email = email || this.get('email', 'user') - // field that hasn't been used as documented for a LONG time, // and as of npm 7.10.0, isn't used at all. We just always // send auth if we have it, only to the URIs under the nerf dart. diff --git a/workspaces/config/package.json b/workspaces/config/package.json index 140640587339d..8c59bc3ae3dff 100644 --- a/workspaces/config/package.json +++ b/workspaces/config/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/config", - "version": "8.3.0", + "version": "8.3.1", "files": [ "bin/", "lib/" @@ -9,7 +9,7 @@ "description": "Configuration management for the npm cli", "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/config" }, "author": "GitHub Inc.", diff --git a/workspaces/libnpmaccess/CHANGELOG.md b/workspaces/libnpmaccess/CHANGELOG.md index d426edcb44e3f..03df1c25e4b75 100644 --- a/workspaces/libnpmaccess/CHANGELOG.md +++ b/workspaces/libnpmaccess/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [8.0.5](https://github.com/npm/cli/compare/libnpmaccess-v8.0.4...libnpmaccess-v8.0.5) (2024-04-30) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` + ## [8.0.4](https://github.com/npm/cli/compare/libnpmaccess-v8.0.3...libnpmaccess-v8.0.4) (2024-04-25) ### Dependencies diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index 75f164048c412..59b5afa7c7b5f 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -1,6 +1,6 @@ { "name": "libnpmaccess", - "version": "8.0.4", + "version": "8.0.5", "description": "programmatic library for `npm access` commands", "author": "GitHub Inc.", "license": "ISC", @@ -23,14 +23,14 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmaccess" }, "bugs": "https://github.com/npm/libnpmaccess/issues", "homepage": "https://npmjs.com/package/libnpmaccess", "dependencies": { "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" diff --git a/workspaces/libnpmdiff/CHANGELOG.md b/workspaces/libnpmdiff/CHANGELOG.md index e8207b62c38a6..c95a3c980196a 100644 --- a/workspaces/libnpmdiff/CHANGELOG.md +++ b/workspaces/libnpmdiff/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [6.1.1](https://github.com/npm/cli/compare/libnpmdiff-v6.1.0...libnpmdiff-v6.1.1) (2024-04-30) + +### Bug Fixes + +* [`3ec86a0`](https://github.com/npm/cli/commit/3ec86a0e258b1d5f5182f0093adf43c54e82578e) [#7456](https://github.com/npm/cli/pull/7456) linting: no-unused-vars (#7456) (@wraithgar) +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [workspace](https://github.com/npm/cli/releases/tag/arborist-v7.5.1): `@npmcli/arborist@7.5.1` + ## [6.1.0](https://github.com/npm/cli/compare/libnpmdiff-v6.0.9...libnpmdiff-v6.1.0) (2024-04-25) ### Features diff --git a/workspaces/libnpmdiff/lib/tarball.js b/workspaces/libnpmdiff/lib/tarball.js index 930d624f2d5b6..41ea84a6885a5 100644 --- a/workspaces/libnpmdiff/lib/tarball.js +++ b/workspaces/libnpmdiff/lib/tarball.js @@ -9,7 +9,7 @@ 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) => +const nodeModulesTarball = (manifest) => pkgContents({ path: manifest._resolved, depth: 1 }) .then(files => files.map(file => relative(manifest._resolved, file)) diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index 5ae0e86e7aba0..d601ff61ca021 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -1,10 +1,10 @@ { "name": "libnpmdiff", - "version": "6.1.0", + "version": "6.1.1", "description": "The registry diff", "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmdiff" }, "main": "lib/index.js", diff --git a/workspaces/libnpmexec/CHANGELOG.md b/workspaces/libnpmexec/CHANGELOG.md index 80ccbc544eba0..13d11b1c8ebe8 100644 --- a/workspaces/libnpmexec/CHANGELOG.md +++ b/workspaces/libnpmexec/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [8.1.0](https://github.com/npm/cli/compare/libnpmexec-v8.0.0...libnpmexec-v8.1.0) (2024-04-30) + +### Features + +* [`7e349f4`](https://github.com/npm/cli/commit/7e349f45363bb8dbe1cc803f8b48befc01aae7fd) [#7432](https://github.com/npm/cli/pull/7432) add spinner (#7432) (@lukekarrys) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`9da5738`](https://github.com/npm/cli/commit/9da57388ebd5c643c2a95bbf63abc745cad45ccc) [#7437](https://github.com/npm/cli/pull/7437) `@npmcli/run-script@8.1.0` (#7437) +* [workspace](https://github.com/npm/cli/releases/tag/arborist-v7.5.1): `@npmcli/arborist@7.5.1` + ## [8.0.0](https://github.com/npm/cli/compare/libnpmexec-v7.0.10...libnpmexec-v8.0.0) (2024-04-25) ### ⚠️ BREAKING CHANGES diff --git a/workspaces/libnpmexec/lib/index.js b/workspaces/libnpmexec/lib/index.js index 944f34b01c237..28cba79a7f227 100644 --- a/workspaces/libnpmexec/lib/index.js +++ b/workspaces/libnpmexec/lib/index.js @@ -4,18 +4,16 @@ const { mkdir } = require('fs/promises') const Arborist = require('@npmcli/arborist') const ciInfo = require('ci-info') const crypto = require('crypto') -const { log } = require('proc-log') +const { log, input } = require('proc-log') const npa = require('npm-package-arg') const pacote = require('pacote') const { read } = require('read') const semver = require('semver') - const { fileExists, localFileExists } = require('./file-exists.js') const getBinFromManifest = require('./get-bin-from-manifest.js') const noTTY = require('./no-tty.js') const runScript = require('./run-script.js') const isWindows = require('./is-windows.js') - const { dirname, resolve } = require('path') const binPaths = [] @@ -242,26 +240,24 @@ const exec = async (opts) => { if (add.length) { if (!yes) { - const missingPackages = add.map(a => `${a.replace(/@$/, '')}`) + const addList = add.map(a => `${a.replace(/@$/, '')}`) + // set -n to always say no if (yes === false) { // Error message lists missing package(s) when process is canceled /* eslint-disable-next-line max-len */ - throw new Error(`npx canceled due to missing packages and no YES option: ${JSON.stringify(missingPackages)}`) + throw new Error(`npx canceled due to missing packages and no YES option: ${JSON.stringify(addList)}`) } if (noTTY() || ciInfo.isCI) { - log.warn('exec', `The following package${ - add.length === 1 ? ' was' : 's were' - } not found and will be installed: ${ - add.map((pkg) => pkg.replace(/@$/, '')).join(', ') - }`) + /* eslint-disable-next-line max-len */ + log.warn('exec', `The following package${add.length === 1 ? ' was' : 's were'} not found and will be installed: ${addList.join(', ')}`) } else { - const addList = missingPackages.join('\n') + '\n' - const prompt = `Need to install the following packages:\n${ - addList - }Ok to proceed? ` - const confirm = await read({ prompt, default: 'y' }) + const confirm = await input.read(() => read({ + /* eslint-disable-next-line max-len */ + prompt: `Need to install the following packages:\n${addList.join('\n')}\nOk to proceed? `, + default: 'y', + })) if (confirm.trim().toLowerCase().charAt(0) !== 'y') { throw new Error('canceled') } diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index ec90878667520..fcb30087cb5d2 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -1,6 +1,6 @@ { "name": "libnpmexec", - "version": "8.0.0", + "version": "8.1.0", "files": [ "bin/", "lib/" @@ -12,7 +12,7 @@ "description": "npm exec (npx) programmatic API", "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmexec" }, "keywords": [ @@ -60,7 +60,7 @@ }, "dependencies": { "@npmcli/arborist": "^7.2.1", - "@npmcli/run-script": "^8.0.0", + "@npmcli/run-script": "^8.1.0", "ci-info": "^4.0.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.1", diff --git a/workspaces/libnpmexec/test/prompt.js b/workspaces/libnpmexec/test/prompt.js index 5edcff9a3d9cb..8c8c520d497b6 100644 --- a/workspaces/libnpmexec/test/prompt.js +++ b/workspaces/libnpmexec/test/prompt.js @@ -1,4 +1,4 @@ -const { log } = require('proc-log') +const procLog = require('proc-log') const { resolve } = require('path') const t = require('tap') const fs = require('fs/promises') @@ -15,6 +15,13 @@ t.test('prompt, accepts', async t => { 'ci-info': { isCI: false }, '../../lib/no-tty.js': () => false, read: { read: async () => 'y' }, + 'proc-log': { + ...procLog, + input: { + ...procLog.input, + read: (fn) => fn(), + }, + }, }, }) @@ -39,6 +46,13 @@ t.test('prompt, refuses', async t => { mocks: { 'ci-info': { isCI: false }, read: { read: async () => 'n' }, + 'proc-log': { + ...procLog, + input: { + ...procLog.input, + read: (fn) => fn(), + }, + }, '../../lib/no-tty.js': () => false, }, }) @@ -146,8 +160,9 @@ t.test('no prompt if CI, multiple packages', async t => { mocks: { 'ci-info': { isCI: true }, 'proc-log': { + ...procLog, log: { - ...log, + ...procLog.log, warn (title, msg) { t.equal(title, 'exec', 'should warn exec title') // this message is nondeterministic as it queries manifests so we just diff --git a/workspaces/libnpmfund/CHANGELOG.md b/workspaces/libnpmfund/CHANGELOG.md index f316593d4ffcc..3f4dbb8958ead 100644 --- a/workspaces/libnpmfund/CHANGELOG.md +++ b/workspaces/libnpmfund/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [5.0.9](https://github.com/npm/cli/compare/libnpmfund-v5.0.8...libnpmfund-v5.0.9) (2024-04-30) + +### Bug Fixes + +* [`3ec86a0`](https://github.com/npm/cli/commit/3ec86a0e258b1d5f5182f0093adf43c54e82578e) [#7456](https://github.com/npm/cli/pull/7456) linting: no-unused-vars (#7456) (@wraithgar) +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [workspace](https://github.com/npm/cli/releases/tag/arborist-v7.5.1): `@npmcli/arborist@7.5.1` + ## [5.0.8](https://github.com/npm/cli/compare/libnpmfund-v5.0.7...libnpmfund-v5.0.8) (2024-04-25) ### Dependencies diff --git a/workspaces/libnpmfund/lib/index.js b/workspaces/libnpmfund/lib/index.js index a53893dc1cf87..39b69afc0abcc 100644 --- a/workspaces/libnpmfund/lib/index.js +++ b/workspaces/libnpmfund/lib/index.js @@ -133,7 +133,7 @@ function readTree (tree, opts) { }) return directDepsWithFunding.reduce( - (res, { node, fundingItem }, i) => { + (res, { node, fundingItem }) => { if (!fundingItem || fundingItem.length === 0 || !node) { diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index 84363d55efdb5..70a53646910a5 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "5.0.8", + "version": "5.0.9", "main": "lib/index.js", "files": [ "bin/", @@ -9,7 +9,7 @@ "description": "Programmatic API for npm fund", "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmfund" }, "keywords": [ diff --git a/workspaces/libnpmhook/CHANGELOG.md b/workspaces/libnpmhook/CHANGELOG.md index f0ca57a117ed4..a654576e800e3 100644 --- a/workspaces/libnpmhook/CHANGELOG.md +++ b/workspaces/libnpmhook/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [10.0.4](https://github.com/npm/cli/compare/libnpmhook-v10.0.3...libnpmhook-v10.0.4) (2024-04-30) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` + ## [10.0.3](https://github.com/npm/cli/compare/libnpmhook-v10.0.2...libnpmhook-v10.0.3) (2024-04-25) ### Dependencies diff --git a/workspaces/libnpmhook/package.json b/workspaces/libnpmhook/package.json index dde9aed6eb7f1..2cfa16df091be 100644 --- a/workspaces/libnpmhook/package.json +++ b/workspaces/libnpmhook/package.json @@ -1,6 +1,6 @@ { "name": "libnpmhook", - "version": "10.0.3", + "version": "10.0.4", "description": "programmatic API for managing npm registry hooks", "main": "lib/index.js", "files": [ @@ -18,7 +18,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmhook" }, "keywords": [ @@ -31,7 +31,7 @@ "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", diff --git a/workspaces/libnpmorg/CHANGELOG.md b/workspaces/libnpmorg/CHANGELOG.md index dafad98ef5671..e92160f918035 100644 --- a/workspaces/libnpmorg/CHANGELOG.md +++ b/workspaces/libnpmorg/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [6.0.5](https://github.com/npm/cli/compare/libnpmorg-v6.0.4...libnpmorg-v6.0.5) (2024-04-30) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` + ## [6.0.4](https://github.com/npm/cli/compare/libnpmorg-v6.0.3...libnpmorg-v6.0.4) (2024-04-25) ### Dependencies diff --git a/workspaces/libnpmorg/package.json b/workspaces/libnpmorg/package.json index b41689ba765fe..1a7486bfc681d 100644 --- a/workspaces/libnpmorg/package.json +++ b/workspaces/libnpmorg/package.json @@ -1,6 +1,6 @@ { "name": "libnpmorg", - "version": "6.0.4", + "version": "6.0.5", "description": "Programmatic api for `npm org` commands", "author": "GitHub Inc.", "main": "lib/index.js", @@ -35,14 +35,14 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmorg" }, "bugs": "https://github.com/npm/libnpmorg/issues", "homepage": "https://npmjs.com/package/libnpmorg", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" diff --git a/workspaces/libnpmpack/CHANGELOG.md b/workspaces/libnpmpack/CHANGELOG.md index f640cfabcb793..75e5fc0cc4022 100644 --- a/workspaces/libnpmpack/CHANGELOG.md +++ b/workspaces/libnpmpack/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [7.0.1](https://github.com/npm/cli/compare/libnpmpack-v7.0.0...libnpmpack-v7.0.1) (2024-04-30) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`9da5738`](https://github.com/npm/cli/commit/9da57388ebd5c643c2a95bbf63abc745cad45ccc) [#7437](https://github.com/npm/cli/pull/7437) `@npmcli/run-script@8.1.0` (#7437) +* [workspace](https://github.com/npm/cli/releases/tag/arborist-v7.5.1): `@npmcli/arborist@7.5.1` + ## [7.0.0](https://github.com/npm/cli/compare/libnpmpack-v6.0.9...libnpmpack-v7.0.0) (2024-04-25) ### ⚠️ BREAKING CHANGES diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 0f0e2e328d535..9e40f294cc54f 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpack", - "version": "7.0.0", + "version": "7.0.1", "description": "Programmatic API for the bits behind npm pack", "author": "GitHub Inc.", "main": "lib/index.js", @@ -30,14 +30,14 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmpack" }, "bugs": "https://github.com/npm/libnpmpack/issues", "homepage": "https://npmjs.com/package/libnpmpack", "dependencies": { "@npmcli/arborist": "^7.2.1", - "@npmcli/run-script": "^8.0.0", + "@npmcli/run-script": "^8.1.0", "npm-package-arg": "^11.0.2", "pacote": "^18.0.1" }, diff --git a/workspaces/libnpmpublish/CHANGELOG.md b/workspaces/libnpmpublish/CHANGELOG.md index 87faa4e52b9ee..b52f08d4dd32f 100644 --- a/workspaces/libnpmpublish/CHANGELOG.md +++ b/workspaces/libnpmpublish/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [9.0.7](https://github.com/npm/cli/compare/libnpmpublish-v9.0.6...libnpmpublish-v9.0.7) (2024-04-30) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` + ## [9.0.6](https://github.com/npm/cli/compare/libnpmpublish-v9.0.5...libnpmpublish-v9.0.6) (2024-04-25) ### Dependencies diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index 0376bb359c7fd..31faaa7b59f26 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpublish", - "version": "9.0.6", + "version": "9.0.7", "description": "Programmatic API for the bits behind npm publish and unpublish", "author": "GitHub Inc.", "main": "lib/index.js", @@ -32,7 +32,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmpublish" }, "bugs": "https://github.com/npm/cli/issues", @@ -41,7 +41,7 @@ "ci-info": "^4.0.0", "normalize-package-data": "^6.0.0", "npm-package-arg": "^11.0.2", - "npm-registry-fetch": "^16.2.1", + "npm-registry-fetch": "^17.0.0", "proc-log": "^4.2.0", "semver": "^7.3.7", "sigstore": "^2.2.0", diff --git a/workspaces/libnpmsearch/CHANGELOG.md b/workspaces/libnpmsearch/CHANGELOG.md index 8ec158d618283..77b408bff3f0e 100644 --- a/workspaces/libnpmsearch/CHANGELOG.md +++ b/workspaces/libnpmsearch/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [7.0.4](https://github.com/npm/cli/compare/libnpmsearch-v7.0.3...libnpmsearch-v7.0.4) (2024-04-30) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` + ## [7.0.3](https://github.com/npm/cli/compare/libnpmsearch-v7.0.2...libnpmsearch-v7.0.3) (2024-04-25) ### Dependencies diff --git a/workspaces/libnpmsearch/package.json b/workspaces/libnpmsearch/package.json index b9e29322c3301..cb21747310eae 100644 --- a/workspaces/libnpmsearch/package.json +++ b/workspaces/libnpmsearch/package.json @@ -1,6 +1,6 @@ { "name": "libnpmsearch", - "version": "7.0.3", + "version": "7.0.4", "description": "Programmatic API for searching in npm and compatible registries.", "author": "GitHub Inc.", "main": "lib/index.js", @@ -32,13 +32,13 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmsearch" }, "bugs": "https://github.com/npm/libnpmsearch/issues", "homepage": "https://npmjs.com/package/libnpmsearch", "dependencies": { - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" diff --git a/workspaces/libnpmteam/CHANGELOG.md b/workspaces/libnpmteam/CHANGELOG.md index 4d08c78d64e11..e86bc55daf81b 100644 --- a/workspaces/libnpmteam/CHANGELOG.md +++ b/workspaces/libnpmteam/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [6.0.4](https://github.com/npm/cli/compare/libnpmteam-v6.0.3...libnpmteam-v6.0.4) (2024-04-30) + +### Bug Fixes + +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`a7145d4`](https://github.com/npm/cli/commit/a7145d422485fcbcb9427efa775c15180c7ee1c2) [#7453](https://github.com/npm/cli/pull/7453) `npm-registry-fetch@17.0.0` + ## [6.0.3](https://github.com/npm/cli/compare/libnpmteam-v6.0.2...libnpmteam-v6.0.3) (2024-04-25) ### Dependencies diff --git a/workspaces/libnpmteam/package.json b/workspaces/libnpmteam/package.json index e882a86c27c6d..94f264bd93bf7 100644 --- a/workspaces/libnpmteam/package.json +++ b/workspaces/libnpmteam/package.json @@ -1,7 +1,7 @@ { "name": "libnpmteam", "description": "npm Team management APIs", - "version": "6.0.3", + "version": "6.0.4", "author": "GitHub Inc.", "license": "ISC", "main": "lib/index.js", @@ -22,7 +22,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmteam" }, "files": [ @@ -32,7 +32,7 @@ "homepage": "https://npmjs.com/package/libnpmteam", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.2.1" + "npm-registry-fetch": "^17.0.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" diff --git a/workspaces/libnpmversion/CHANGELOG.md b/workspaces/libnpmversion/CHANGELOG.md index 39ae411e3c87d..d8d9bf9b5a141 100644 --- a/workspaces/libnpmversion/CHANGELOG.md +++ b/workspaces/libnpmversion/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [6.0.1](https://github.com/npm/cli/compare/libnpmversion-v6.0.0...libnpmversion-v6.0.1) (2024-04-30) + +### Bug Fixes + +* [`3ec86a0`](https://github.com/npm/cli/commit/3ec86a0e258b1d5f5182f0093adf43c54e82578e) [#7456](https://github.com/npm/cli/pull/7456) linting: no-unused-vars (#7456) (@wraithgar) +* [`57ebebf`](https://github.com/npm/cli/commit/57ebebf03d55d4eda2b6439149a97b595a191aaf) [#7418](https://github.com/npm/cli/pull/7418) update repository.url in package.json (#7418) (@wraithgar) + +### Dependencies + +* [`9da5738`](https://github.com/npm/cli/commit/9da57388ebd5c643c2a95bbf63abc745cad45ccc) [#7437](https://github.com/npm/cli/pull/7437) `@npmcli/run-script@8.1.0` (#7437) + ## [6.0.0](https://github.com/npm/cli/compare/libnpmversion-v5.0.2...libnpmversion-v6.0.0) (2024-04-25) ### ⚠️ BREAKING CHANGES diff --git a/workspaces/libnpmversion/package.json b/workspaces/libnpmversion/package.json index 7ec3866703b98..43b0d2ff825d7 100644 --- a/workspaces/libnpmversion/package.json +++ b/workspaces/libnpmversion/package.json @@ -1,6 +1,6 @@ { "name": "libnpmversion", - "version": "6.0.0", + "version": "6.0.1", "main": "lib/index.js", "files": [ "bin/", @@ -9,7 +9,7 @@ "description": "library to do the things that 'npm version' does", "repository": { "type": "git", - "url": "https://github.com/npm/cli.git", + "url": "git+https://github.com/npm/cli.git", "directory": "workspaces/libnpmversion" }, "author": "GitHub Inc.", @@ -38,7 +38,7 @@ }, "dependencies": { "@npmcli/git": "^5.0.6", - "@npmcli/run-script": "^8.0.0", + "@npmcli/run-script": "^8.1.0", "json-parse-even-better-errors": "^3.0.0", "proc-log": "^4.2.0", "semver": "^7.3.7" diff --git a/workspaces/libnpmversion/test/retrieve-tag.js b/workspaces/libnpmversion/test/retrieve-tag.js index 29155acdf5195..78989ddd57054 100644 --- a/workspaces/libnpmversion/test/retrieve-tag.js +++ b/workspaces/libnpmversion/test/retrieve-tag.js @@ -3,7 +3,7 @@ const requireInject = require('require-inject') let tag const retrieveTag = requireInject('../lib/retrieve-tag.js', { '@npmcli/git': { - spawn: async (cmd, opts) => ({ stdout: tag + '\n' }), + spawn: async () => ({ stdout: tag + '\n' }), }, })