diff --git a/AUTHORS b/AUTHORS index 8b882e1bfeca3..1230739b5c723 100644 --- a/AUTHORS +++ b/AUTHORS @@ -819,3 +819,5 @@ Tierney Cyren Guillaume Grossetie linkgoron Quentin Barbe +dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> +Delapouite diff --git a/CHANGELOG.md b/CHANGELOG.md index 17ce9e0bf6ec7..bc2e2e1d0e1eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,71 @@ +## v8.5.0 (2022-02-10) + +### Features + +* [`0cc9d4c51`](https://github.com/npm/cli/commit/0cc9d4c51a337af0edd2e20c6fadb26807e5d09f) + [#4372](https://github.com/npm/cli/pull/4372) + feat(deps): `@npmcli/config@3.0.0 - introduce automatic workspace roots` + ([@nlf](https://github.com/nlf)) + +### Bug Fixes + +* [`fb6e2ddf9`](https://github.com/npm/cli/commit/fb6e2ddf942bacf5ae745d16c2d57f3836dce75a) + [#4386](https://github.com/npm/cli/pull/4386) + fix(log): pass in logger to more external modules + ([@wraithgar](https://github.com/wraithgar)) +* [`0e231d4a4`](https://github.com/npm/cli/commit/0e231d4a40526608411aca0a6e7cf27c750f2409) + [#4389](https://github.com/npm/cli/pull/4389) + fix(pack): let libnpmpack take care of file writes + ([@nlf](https://github.com/nlf)) +* [`e2f1f7b04`](https://github.com/npm/cli/commit/e2f1f7b045a3ae9840f431cb4266ba046831247b) + [#4389](https://github.com/npm/cli/pull/4389) + fix(publish): pass dryRun: true to libnpmpack so it doesnt write a tarball + ([@nlf](https://github.com/nlf)) +* [`2937b43d4`](https://github.com/npm/cli/commit/2937b43d4629225d83b6c71833df00743209f5ff) + [#4389](https://github.com/npm/cli/pull/4389) + fix(config): add pack-destination flattener + ([@nlf](https://github.com/nlf)) + +### Documentation + +* [`b836d596f`](https://github.com/npm/cli/commit/b836d596f9d98cd7849882000cad11ad2a0b9a26) + [#4384](https://github.com/npm/cli/pull/4384) + docs: add cross-references between npx and npm exec + ([@Delapouite](https://github.com/Delapouite)) +* [`f3fbeea5a`](https://github.com/npm/cli/commit/f3fbeea5a173902ca7455c6c94a9e677591b0410) + [#4388](https://github.com/npm/cli/pull/4388) + docs: add --save-bundle to --save usage output + ([@wraithgar](https://github.com/wraithgar)) + +### Dependencies + +* [`8732f393e`](https://github.com/npm/cli/commit/8732f393ee547e2eada4317613599517c1d8ec0a) + deps: `@npmcli/arborist@4.3.1` + * [`2ba09cc0d`](https://github.com/npm/cli/commit/2ba09cc0d7d56a064aa67bbb1881d381e6504888) + [#4371](https://github.com/npm/cli/pull/4371) + fix(arborist): check if a spec is a workspace before fetching a manifest, closes #3637 + ([@nlf](https://github.com/nlf)) + * [`e631faf7b`](https://github.com/npm/cli/commit/e631faf7b5f414c233d723ee11413264532b37de) + [#4387](https://github.com/npm/cli/pull/4387) + fix(arborist): save bundleDependencies to package.json when reifying + ([@wraithgar](https://github.com/wraithgar)) +* [`d3a7c15e1`](https://github.com/npm/cli/commit/d3a7c15e1e3d305a0bf781493406dfb1fdbaca35) + deps: `libnpmpack@3.1.0` + * [`4884821f6`](https://github.com/npm/cli/commit/4884821f637ca1992b494fbdbd94d000e4428a40) + [#4389](https://github.com/npm/cli/pull/4389) + feat(libnpmpack): write tarball file when dryRun === false + ([@nlf](https://github.com/nlf)) +* [`ab926995e`](https://github.com/npm/cli/commit/ab926995e43ccdd048a6e1164b436fea1940f932) + [#4393](https://github.com/npm/cli/pull/4393) + deps: `npm-registry-fetch@12.0.2` +* [`1c0d0699c`](https://github.com/npm/cli/commit/1c0d0699c13e1cb36a69f2ac4acdb78ea205aa3e) + [#4394](https://github.com/npm/cli/pull/4394) + deps: `npmlog@6.0.1` + * changed notice color from blue to cyan for improved readability +* [`3c33a5842`](https://github.com/npm/cli/commit/3c33a584213e4f2230f3b912fad2c2f5786906fb) + [#4400](https://github.com/npm/cli/pull/4400) + deps: `make-fetch-happen@10.0.2` + ## v8.4.1 (2022-02-03) ### Bug Fixes diff --git a/docs/content/commands/npm-exec.md b/docs/content/commands/npm-exec.md index db23536628e47..d154f5780b9c9 100644 --- a/docs/content/commands/npm-exec.md +++ b/docs/content/commands/npm-exec.md @@ -388,3 +388,4 @@ project. * [npm stop](/commands/npm-stop) * [npm config](/commands/npm-config) * [npm workspaces](/using-npm/workspaces) +* [npx](/commands/npx) diff --git a/docs/content/commands/npx.md b/docs/content/commands/npx.md index 625ac3d8cd602..c1aae0b9ff0f8 100644 --- a/docs/content/commands/npx.md +++ b/docs/content/commands/npx.md @@ -175,3 +175,4 @@ This resulted in some shifts in its functionality: * [npm restart](/commands/npm-restart) * [npm stop](/commands/npm-stop) * [npm config](/commands/npm-config) +* [npm exec](/commands/npm-exec) diff --git a/docs/content/using-npm/config.md b/docs/content/using-npm/config.md index 0af538fed52bc..9fbb614564df8 100644 --- a/docs/content/using-npm/config.md +++ b/docs/content/using-npm/config.md @@ -1351,7 +1351,7 @@ If a package would be saved at install time by the use of `--save`, `--save-dev`, or `--save-optional`, then also put it in the `bundleDependencies` list. -Ignore if `--save-peer` is set, since peerDependencies cannot be bundled. +Ignored if `--save-peer` is set, since peerDependencies cannot be bundled. diff --git a/lib/commands/org.js b/lib/commands/org.js index c6882a8e26313..89859200fed6b 100644 --- a/lib/commands/org.js +++ b/lib/commands/org.js @@ -2,6 +2,7 @@ const liborg = require('libnpmorg') const otplease = require('../utils/otplease.js') const Table = require('cli-table3') const BaseCommand = require('../base-command.js') +const log = require('../utils/log-shim.js') class Org extends BaseCommand { static description = 'Manage orgs' @@ -32,7 +33,10 @@ class Org extends BaseCommand { } async exec ([cmd, orgname, username, role], cb) { - return otplease(this.npm.flatOptions, opts => { + return otplease({ + ...this.npm.flatOptions, + log, + }, opts => { switch (cmd) { case 'add': case 'set': diff --git a/lib/commands/pack.js b/lib/commands/pack.js index 0719fa3b85828..74c29699a05c9 100644 --- a/lib/commands/pack.js +++ b/lib/commands/pack.js @@ -1,11 +1,8 @@ -const util = require('util') const pacote = require('pacote') const libpack = require('libnpmpack') const npa = require('npm-package-arg') -const path = require('path') const log = require('../utils/log-shim') const { getContents, logTar } = require('../utils/tar.js') -const writeFile = util.promisify(require('fs').writeFile) const BaseCommand = require('../base-command.js') class Pack extends BaseCommand { @@ -28,7 +25,6 @@ class Pack extends BaseCommand { } const unicode = this.npm.config.get('unicode') - const dryRun = this.npm.config.get('dry-run') const json = this.npm.config.get('json') // Get the manifests and filenames first so we can bail early on manifest @@ -40,24 +36,15 @@ class Pack extends BaseCommand { if (!manifest._id) { throw new Error('Invalid package, must have name and version') } - - const filename = `${manifest.name}-${manifest.version}.tgz` - .replace(/^@/, '').replace(/\//, '-') - manifests.push({ arg, filename, manifest }) + manifests.push({ arg, manifest }) } // Load tarball names up for printing afterward to isolate from the // noise generated during packing const tarballs = [] - for (const { arg, filename, manifest } of manifests) { + for (const { arg, manifest } of manifests) { const tarballData = await libpack(arg, this.npm.flatOptions) const pkgContents = await getContents(manifest, tarballData) - const tarballFilename = path.resolve(this.npm.config.get('pack-destination'), filename) - - if (!dryRun) { - await writeFile(tarballFilename, tarballData) - } - tarballs.push(pkgContents) } diff --git a/lib/commands/publish.js b/lib/commands/publish.js index 339c80daad65e..63106c520bd58 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -83,7 +83,8 @@ class Publish extends BaseCommand { }) } - const tarballData = await pack(spec, opts) + // we pass dryRun: true to libnpmpack so it doesn't write the file to disk + const tarballData = await pack(spec, { ...opts, dryRun: true }) const pkgContents = await getContents(manifest, tarballData) // The purpose of re-reading the manifest is in case it changed, diff --git a/lib/commands/unpublish.js b/lib/commands/unpublish.js index 42c9c1db963e1..d8410cc13481b 100644 --- a/lib/commands/unpublish.js +++ b/lib/commands/unpublish.js @@ -84,7 +84,7 @@ class Unpublish extends BaseCommand { ) } - const opts = this.npm.flatOptions + const opts = { ...this.npm.flatOptions, log } if (!spec || path.resolve(spec.name) === this.npm.localPrefix) { // if there's a package.json in the current folder, then // read the package name and version out of that. diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index 79222881c9734..79e686ca75134 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -1455,6 +1455,7 @@ define('pack-destination', { description: ` Directory in which \`npm pack\` will save tarballs. `, + flatten, }) define('parseable', { @@ -1587,7 +1588,7 @@ define('save', { default: true, defaultDescription: `\`true\` unless when using \`npm update\` or \`npm dedupe\` where it defaults to \`false\``, - usage: '-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer', + usage: '-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle', type: Boolean, short: 'S', description: ` @@ -1610,7 +1611,7 @@ define('save-bundle', { \`--save-dev\`, or \`--save-optional\`, then also put it in the \`bundleDependencies\` list. - Ignore if \`--save-peer\` is set, since peerDependencies cannot be bundled. + Ignored if \`--save-peer\` is set, since peerDependencies cannot be bundled. `, flatten (key, obj, flatOptions) { // XXX update arborist to just ignore it if resulting saveType is peer diff --git a/node_modules/@npmcli/config/lib/env-replace.js b/node_modules/@npmcli/config/lib/env-replace.js index 464dc550b00fb..a6e4b2968d04e 100644 --- a/node_modules/@npmcli/config/lib/env-replace.js +++ b/node_modules/@npmcli/config/lib/env-replace.js @@ -3,11 +3,12 @@ const envExpr = /(\\*)\$\{([^}]+)\}/g module.exports = (f, env) => f.replace(envExpr, (orig, esc, name) => { - const val = env[name] !== undefined ? env[name] : `\$\{${name}\}` + const val = env[name] !== undefined ? env[name] : `$\{${name}}` // consume the escape chars that are relevant. - if (esc.length % 2) + if (esc.length % 2) { return orig.substr((esc.length + 1) / 2) + } return (esc.substr(esc.length / 2)) + val }) diff --git a/node_modules/@npmcli/config/lib/index.js b/node_modules/@npmcli/config/lib/index.js index 293fad2ec56c3..dc839a5389c3a 100644 --- a/node_modules/@npmcli/config/lib/index.js +++ b/node_modules/@npmcli/config/lib/index.js @@ -3,6 +3,8 @@ const walkUp = require('walk-up-path') const ini = require('ini') const nopt = require('nopt') const mkdirp = require('mkdirp-infer-owner') +const mapWorkspaces = require('@npmcli/map-workspaces') +const rpj = require('read-package-json-fast') /* istanbul ignore next */ const myUid = process.getuid && process.getuid() @@ -91,7 +93,6 @@ class Config { execPath = process.execPath, cwd = process.cwd(), }) { - // turn the definitions into nopt's weirdo syntax this.definitions = definitions const types = {} @@ -100,8 +101,9 @@ class Config { for (const [key, def] of Object.entries(definitions)) { defaults[key] = def.default types[key] = def.type - if (def.deprecated) + if (def.deprecated) { this.deprecated[key] = def.deprecated.trim().replace(/\n +/, '\n') + } } // populated the first time we flatten the object @@ -162,41 +164,48 @@ class Config { // return the location where key is found. find (key) { - if (!this.loaded) + if (!this.loaded) { throw new Error('call config.load() before reading values') + } return this[_find](key) } + [_find] (key) { // have to look in reverse order const entries = [...this.data.entries()] for (let i = entries.length - 1; i > -1; i--) { const [where, { data }] = entries[i] - if (hasOwnProperty(data, key)) + if (hasOwnProperty(data, key)) { return where + } } return null } get (key, where) { - if (!this.loaded) + if (!this.loaded) { throw new Error('call config.load() before reading values') + } return this[_get](key, where) } + // we need to get values sometimes, so use this internal one to do so // while in the process of loading. [_get] (key, where = null) { if (where !== null && !confTypes.has(where)) { throw new Error('invalid config location param: ' + where) } - const { data, source } = this.data.get(where || 'cli') + const { data } = this.data.get(where || 'cli') return where === null || hasOwnProperty(data, key) ? data[key] : undefined } set (key, val, where = 'cli') { - if (!this.loaded) + if (!this.loaded) { throw new Error('call config.load() before setting values') - if (!confTypes.has(where)) + } + if (!confTypes.has(where)) { throw new Error('invalid config location param: ' + where) + } this[_checkDeprecated](key) const { data } = this.data.get(where) data[key] = val @@ -209,8 +218,9 @@ class Config { } get flat () { - if (this[_flatOptions]) + if (this[_flatOptions]) { return this[_flatOptions] + } // create the object for flat options passed to deps process.emit('time', 'config:load:flatten') @@ -225,16 +235,19 @@ class Config { } delete (key, where = 'cli') { - if (!this.loaded) + if (!this.loaded) { throw new Error('call config.load() before deleting values') - if (!confTypes.has(where)) + } + if (!confTypes.has(where)) { throw new Error('invalid config location param: ' + where) + } delete this.data.get(where).data[key] } async load () { - if (this.loaded) + if (this.loaded) { throw new Error('attempting to load npm config multiple times') + } process.emit('time', 'config:load') // first load the defaults, which sets the global prefix @@ -282,7 +295,9 @@ class Config { const creds = this.getCredentialsByURI(reg) // ignore this error because a failed set will strip out anything that // might be a security hazard, which was the intention. - try { this.setCredentialsByURI(reg, creds) } catch (_) {} + try { + this.setCredentialsByURI(reg, creds) + } catch (_) {} process.emit('timeEnd', 'config:load:credentials') // set proper globalPrefix now that everything is loaded @@ -319,14 +334,16 @@ class Config { } loadHome () { - if (this.env.HOME) + if (this.env.HOME) { return this.home = this.env.HOME + } this.home = homedir() } loadGlobalPrefix () { - if (this.globalPrefix) + if (this.globalPrefix) { throw new Error('cannot load default global prefix more than once') + } if (this.env.PREFIX) { this.globalPrefix = this.env.PREFIX @@ -338,17 +355,18 @@ class Config { this.globalPrefix = dirname(dirname(this.execPath)) // destdir only is respected on Unix - if (this.env.DESTDIR) + if (this.env.DESTDIR) { this.globalPrefix = join(this.env.DESTDIR, this.globalPrefix) + } } } loadEnv () { - const prefix = 'npm_config_' const conf = Object.create(null) for (const [envKey, envVal] of Object.entries(this.env)) { - if (!/^npm_config_/i.test(envKey) || envVal === '') + if (!/^npm_config_/i.test(envKey) || envVal === '') { continue + } const key = envKey.substr('npm_config_'.length) .replace(/(?!^)_/g, '-') // don't replace _ at the start of the key .toLowerCase() @@ -368,9 +386,10 @@ class Config { } get valid () { - for (const [where, {valid}] of this.data.entries()) { - if (valid === false || valid === null && !this.validate(where)) + for (const [where, { valid }] of this.data.entries()) { + if (valid === false || valid === null && !this.validate(where)) { return false + } } return true } @@ -378,11 +397,12 @@ class Config { validate (where) { if (!where) { let valid = true - for (const [where, obj] of this.data.entries()) { + for (const [where] of this.data.entries()) { // no need to validate our defaults, we know they're fine // cli was already validated when parsed the first time - if (where === 'default' || where === 'builtin' || where === 'cli') + if (where === 'default' || where === 'builtin' || where === 'cli') { continue + } const ret = this.validate(where) valid = valid && ret } @@ -424,14 +444,15 @@ class Config { this.data.get(where)[_valid] = false if (Array.isArray(type)) { - if (type.includes(typeDefs.url.type)) + if (type.includes(typeDefs.url.type)) { type = typeDefs.url.type - else { + } else { /* istanbul ignore if - no actual configs matching this, but * path types SHOULD be handled this way, like URLs, for the * same reason */ - if (type.includes(typeDefs.path.type)) + if (type.includes(typeDefs.path.type)) { type = typeDefs.path.type + } } } @@ -469,15 +490,17 @@ class Config { this.sources.set(source, where) if (er) { conf.loadError = er - if (er.code !== 'ENOENT') + if (er.code !== 'ENOENT') { this.log.verbose('config', `error loading ${where} config`, er) + } } else { conf.raw = obj for (const [key, value] of Object.entries(obj)) { const k = envReplace(key, this.env) const v = this.parseField(value, k) - if (where !== 'default') + if (where !== 'default') { this[_checkDeprecated](k, where, obj, [key, value]) + } conf.data[k] = v } } @@ -528,9 +551,9 @@ class Config { // up loading the "project" config where the "userconfig" will be, // which causes some calamaties. So, we only load project config if // it doesn't match what the userconfig will be. - if (projectFile !== this[_get]('userconfig')) + if (projectFile !== this[_get]('userconfig')) { return this[_loadFile](projectFile, 'project') - else { + } else { this.data.get('project').source = '(same as "user" config, ignored)' this.sources.set(this.data.get('project').source, 'project') } @@ -543,23 +566,65 @@ class Config { return } + const cliWorkspaces = this[_get]('workspaces', 'cli') + for (const p of walkUp(this.cwd)) { - // walk up until we have a nm dir or a pj file - const hasAny = (await Promise.all([ - stat(resolve(p, 'node_modules')) - .then(st => st.isDirectory()) - .catch(() => false), - stat(resolve(p, 'package.json')) - .then(st => st.isFile()) - .catch(() => false), - ])).some(is => is) - if (hasAny) { + const hasNodeModules = await stat(resolve(p, 'node_modules')) + .then((st) => st.isDirectory()) + .catch(() => false) + + const hasPackageJson = await stat(resolve(p, 'package.json')) + .then((st) => st.isFile()) + .catch(() => false) + + if (!this.localPrefix && (hasNodeModules || hasPackageJson)) { this.localPrefix = p - return + + // if workspaces are disabled, return now + if (cliWorkspaces === false) { + return + } + + // otherwise, continue the loop + continue + } + + if (this.localPrefix && hasPackageJson) { + // if we already set localPrefix but this dir has a package.json + // then we need to see if `p` is a workspace root by reading its package.json + // however, if reading it fails then we should just move on + const pkg = await rpj(resolve(p, 'package.json')).catch(() => false) + if (!pkg) { + continue + } + + const workspaces = await mapWorkspaces({ cwd: p, pkg }) + for (const w of workspaces.values()) { + if (w === this.localPrefix) { + // see if there's a .npmrc file in the workspace, if so log a warning + const hasNpmrc = await stat(resolve(this.localPrefix, '.npmrc')) + .then((st) => st.isFile()) + .catch(() => false) + + if (hasNpmrc) { + this.log.warn(`ignoring workspace config at ${this.localPrefix}/.npmrc`) + } + + // set the workspace in the default layer, which allows it to be overridden easily + const { data } = this.data.get('default') + data.workspace = [this.localPrefix] + this.localPrefix = p + this.log.info(`found workspace root at ${this.localPrefix}`) + // we found a root, so we return now + return + } + } } } - this.localPrefix = this.cwd + if (!this.localPrefix) { + this.localPrefix = this.cwd + } } loadUserConfig () { @@ -571,10 +636,12 @@ class Config { } async save (where) { - if (!this.loaded) + if (!this.loaded) { throw new Error('call config.load() before saving') - if (!confFileTypes.has(where)) + } + if (!confFileTypes.has(where)) { throw new Error('invalid config location param: ' + where) + } const conf = this.data.get(where) conf[_raw] = { ...conf.data } conf[_loadError] = null @@ -586,7 +653,9 @@ class Config { // we ignore this error because the failed set already removed // anything that might be a security hazard, and it won't be // saved back to the .npmrc file, so we're good. - try { this.setCredentialsByURI(reg, creds) } catch (_) {} + try { + this.setCredentialsByURI(reg, creds) + } catch (_) {} } const iniData = ini.stringify(conf.data).trim() + '\n' @@ -602,8 +671,9 @@ class Config { /* istanbul ignore if - this is best-effort and a pita to test */ if (myUid === 0) { const st = await stat(dir).catch(() => null) - if (st && (st.uid !== myUid || st.gid !== myGid)) + if (st && (st.uid !== myUid || st.gid !== myGid)) { await chown(conf.source, st.uid, st.gid).catch(() => {}) + } } const mode = where === 'user' ? 0o600 : 0o666 await chmod(conf.source, mode) @@ -651,8 +721,9 @@ class Config { email = email || this.get('email', 'user') || this.get(`${nerfed}:email`, 'user') - if (email) + if (email) { this.set('email', email, 'user') + } } // field that hasn't been used as documented for a LONG time, @@ -668,10 +739,12 @@ class Config { this.delete(`${nerfed}:_password`, 'user') this.delete(`${nerfed}:username`, 'user') } else if (username || password) { - if (!username) + if (!username) { throw new Error('must include username') - if (!password) + } + if (!password) { throw new Error('must include password') + } this.delete(`${nerfed}:_authToken`, 'user') this.set(`${nerfed}:username`, username, 'user') // note: not encrypted, no idea why we bothered to do this, but oh well @@ -689,8 +762,9 @@ class Config { const creds = {} const email = this.get(`${nerfed}:email`) || this.get('email') - if (email) + if (email) { creds.email = email + } const tokenReg = this.get(`${nerfed}:_authToken`) || this.get(`${nerfed}:_authtoken`) || @@ -725,8 +799,9 @@ class Config { // at this point, we can only use the values if the URI is the // default registry. const defaultNerf = nerfDart(this.get('registry')) - if (nerfed !== defaultNerf) + if (nerfed !== defaultNerf) { return creds + } const userDef = this.get('username') const passDef = this.get('_password') @@ -741,8 +816,9 @@ class Config { // Handle the old-style _auth= style for the default // registry, if set. const auth = this.get('_auth') - if (!auth) + if (!auth) { return creds + } const authDecode = Buffer.from(auth, 'base64').toString('utf8') const authSplit = authDecode.split(':') @@ -755,7 +831,9 @@ class Config { // set up the environment object we have with npm_config_* environs // for all configs that are different from their default values, and // set EDITOR and HOME. - setEnvs () { setEnvs(this) } + setEnvs () { + setEnvs(this) + } } const _data = Symbol('data') @@ -781,25 +859,37 @@ class ConfigData { } set source (s) { - if (this[_source]) + if (this[_source]) { throw new Error('cannot set ConfigData source more than once') + } this[_source] = s } - get source () { return this[_source] } + + get source () { + return this[_source] + } set loadError (e) { - if (this[_loadError] || this[_raw]) + if (this[_loadError] || this[_raw]) { throw new Error('cannot set ConfigData loadError after load') + } this[_loadError] = e } - get loadError () { return this[_loadError] } + + get loadError () { + return this[_loadError] + } set raw (r) { - if (this[_raw] || this[_loadError]) + if (this[_raw] || this[_loadError]) { throw new Error('cannot set ConfigData raw after load') + } this[_raw] = r } - get raw () { return this[_raw] } + + get raw () { + return this[_raw] + } } module.exports = Config diff --git a/node_modules/@npmcli/config/lib/parse-field.js b/node_modules/@npmcli/config/lib/parse-field.js index 95b8d9f272003..9428996c98a35 100644 --- a/node_modules/@npmcli/config/lib/parse-field.js +++ b/node_modules/@npmcli/config/lib/parse-field.js @@ -6,10 +6,11 @@ const { resolve } = require('path') const { parse: umaskParse } = require('./umask.js') const parseField = (f, key, opts, listElement = false) => { - if (typeof f !== 'string' && !Array.isArray(f)) + if (typeof f !== 'string' && !Array.isArray(f)) { return f + } - const { platform, types, log, home, env } = opts + const { platform, types, home, env } = opts // type can be array or a single thing. coerce to array. const typeList = new Set([].concat(types[key])) @@ -20,8 +21,9 @@ const parseField = (f, key, opts, listElement = false) => { const isNumber = typeList.has(typeDefs.Number.type) const isList = !listElement && typeList.has(Array) - if (Array.isArray(f)) + if (Array.isArray(f)) { return !isList ? f : f.map(field => parseField(field, key, opts, true)) + } // now we know it's a string f = f.trim() @@ -29,12 +31,14 @@ const parseField = (f, key, opts, listElement = false) => { // list types get put in the environment separated by double-\n // usually a single \n would suffice, but ca/cert configs can contain // line breaks and multiple entries. - if (isList) + if (isList) { return parseField(f.split('\n\n'), key, opts) + } // --foo is like --foo=true for boolean types - if (isBool && !isString && f === '') + if (isBool && !isString && f === '') { return true + } // string types can be the string 'true', 'false', etc. // otherwise, parse these values out @@ -51,10 +55,11 @@ const parseField = (f, key, opts, listElement = false) => { if (isPath) { const homePattern = platform === 'win32' ? /^~(\/|\\)/ : /^~\// - if (homePattern.test(f) && home) + if (homePattern.test(f) && home) { f = resolve(home, f.substr(2)) - else + } else { f = resolve(f) + } } if (isUmask) { @@ -66,8 +71,9 @@ const parseField = (f, key, opts, listElement = false) => { } } - if (isNumber && !isNaN(f)) + if (isNumber && !isNaN(f)) { f = +f + } return f } diff --git a/node_modules/@npmcli/config/lib/set-envs.js b/node_modules/@npmcli/config/lib/set-envs.js index 8eed0221ba80e..0f5781aaf3395 100644 --- a/node_modules/@npmcli/config/lib/set-envs.js +++ b/node_modules/@npmcli/config/lib/set-envs.js @@ -22,15 +22,17 @@ const sameConfigValue = (def, val) => : sameArrayValue(def, val) const sameArrayValue = (def, val) => { - if (def.length !== val.length) + if (def.length !== val.length) { return false + } for (let i = 0; i < def.length; i++) { /* istanbul ignore next - there are no array configs where the default * is not an empty array, so this loop is a no-op, but it's the correct * thing to do if we ever DO add a config like that. */ - if (def[i] !== val[i]) + if (def[i] !== val[i]) { return false + } } return true } @@ -38,16 +40,15 @@ const sameArrayValue = (def, val) => { const setEnv = (env, rawKey, rawVal) => { const val = envVal(rawVal) const key = envKey(rawKey, val) - if (key && val !== null) + if (key && val !== null) { env[key] = val + } } const setEnvs = (config) => { // This ensures that all npm config values that are not the defaults are // shared appropriately with child processes, without false positives. const { - globalPrefix, - platform, env, defaults, definitions, @@ -68,19 +69,22 @@ const setEnvs = (config) => { const envSet = new Set(Object.keys(envConf)) for (const key in cliConf) { const { deprecated, envExport = true } = definitions[key] || {} - if (deprecated || envExport === false) + if (deprecated || envExport === false) { continue + } if (sameConfigValue(defaults[key], cliConf[key])) { // config is the default, if the env thought different, then we // have to set it BACK to the default in the environment. - if (!sameConfigValue(envConf[key], cliConf[key])) + if (!sameConfigValue(envConf[key], cliConf[key])) { setEnv(env, key, cliConf[key]) + } } else { // config is not the default. if the env wasn't the one to set // it that way, then we have to put it in the env - if (!(envSet.has(key) && !cliSet.has(key))) + if (!(envSet.has(key) && !cliSet.has(key))) { setEnv(env, key, cliConf[key]) + } } } @@ -88,16 +92,19 @@ const setEnvs = (config) => { env.HOME = config.home env.npm_config_global_prefix = config.globalPrefix env.npm_config_local_prefix = config.localPrefix - if (cliConf.editor) + if (cliConf.editor) { env.EDITOR = cliConf.editor + } // note: this doesn't afect the *current* node process, of course, since // it's already started, but it does affect the options passed to scripts. - if (cliConf['node-options']) + if (cliConf['node-options']) { env.NODE_OPTIONS = cliConf['node-options'] + } - if (require.main && require.main.filename) + if (require.main && require.main.filename) { env.npm_execpath = require.main.filename + } env.NODE = env.npm_node_execpath = config.execPath } diff --git a/node_modules/@npmcli/config/lib/type-defs.js b/node_modules/@npmcli/config/lib/type-defs.js index 049945a3e5812..20a827c3d164e 100644 --- a/node_modules/@npmcli/config/lib/type-defs.js +++ b/node_modules/@npmcli/config/lib/type-defs.js @@ -5,15 +5,17 @@ const { Umask, validate: validateUmask } = require('./umask.js') const semver = require('semver') const validateSemver = (data, k, val) => { const valid = semver.valid(val) - if (!valid) + if (!valid) { return false + } data[k] = valid } const noptValidatePath = nopt.typeDefs.path.validate const validatePath = (data, k, val) => { - if (typeof val !== 'string') + if (typeof val !== 'string') { return false + } return noptValidatePath(data, k, val) } diff --git a/node_modules/@npmcli/config/lib/type-description.js b/node_modules/@npmcli/config/lib/type-description.js index 828a747db4aac..f5e0d164f9edc 100644 --- a/node_modules/@npmcli/config/lib/type-description.js +++ b/node_modules/@npmcli/config/lib/type-description.js @@ -2,15 +2,18 @@ // returns a string for one thing, or an array of descriptions const typeDefs = require('./type-defs.js') const typeDescription = t => { - if (!t || typeof t !== 'function' && typeof t !== 'object') + if (!t || typeof t !== 'function' && typeof t !== 'object') { return t + } - if (Array.isArray(t)) + if (Array.isArray(t)) { return t.map(t => typeDescription(t)) + } for (const { type, description } of Object.values(typeDefs)) { - if (type === t) + if (type === t) { return description || type + } } return t diff --git a/node_modules/@npmcli/config/lib/umask.js b/node_modules/@npmcli/config/lib/umask.js index b445c6fca95bf..195fad2386702 100644 --- a/node_modules/@npmcli/config/lib/umask.js +++ b/node_modules/@npmcli/config/lib/umask.js @@ -1,18 +1,21 @@ class Umask {} const parse = val => { if (typeof val === 'string') { - if (/^0o?[0-7]+$/.test(val)) + if (/^0o?[0-7]+$/.test(val)) { return parseInt(val.replace(/^0o?/, ''), 8) - else if (/^[1-9][0-9]*$/.test(val)) + } else if (/^[1-9][0-9]*$/.test(val)) { return parseInt(val, 10) - else + } else { throw new Error(`invalid umask value: ${val}`) + } } - if (typeof val !== 'number') + if (typeof val !== 'number') { throw new Error(`invalid umask value: ${val}`) + } val = Math.floor(val) - if (val < 0 || val > 511) + if (val < 0 || val > 511) { throw new Error(`invalid umask value: ${val}`) + } return val } diff --git a/node_modules/@npmcli/config/package.json b/node_modules/@npmcli/config/package.json index 83d8a349d224d..b0722db413e5b 100644 --- a/node_modules/@npmcli/config/package.json +++ b/node_modules/@npmcli/config/package.json @@ -1,7 +1,8 @@ { "name": "@npmcli/config", - "version": "2.4.0", + "version": "3.0.0", "files": [ + "bin", "lib" ], "main": "lib/index.js", @@ -10,30 +11,41 @@ "type": "git", "url": "git+https://github.com/npm/config" }, - "author": "Isaac Z. Schlueter (https://izs.me)", + "author": "GitHub Inc.", "license": "ISC", "scripts": { "test": "tap", "snap": "tap", "preversion": "npm test", "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags" + "prepublishOnly": "git push origin --follow-tags", + "lint": "eslint '**/*.js'", + "postlint": "npm-template-check", + "lintfix": "npm run lint -- --fix", + "posttest": "npm run lint", + "template-copy": "npm-template-copy --force" }, "tap": { "check-coverage": true, "coverage-map": "map.js" }, "devDependencies": { + "@npmcli/template-oss": "^2.5.1", "tap": "^15.0.4" }, "dependencies": { + "@npmcli/map-workspaces": "^2.0.0", "ini": "^2.0.0", "mkdirp-infer-owner": "^2.0.0", "nopt": "^5.0.0", + "read-package-json-fast": "^2.0.3", "semver": "^7.3.4", "walk-up-path": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16" + }, + "templateOSS": { + "version": "2.6.0" } } diff --git a/node_modules/are-we-there-yet/package.json b/node_modules/are-we-there-yet/package.json index 5714e09c3b371..67c01e9cbc8e4 100644 --- a/node_modules/are-we-there-yet/package.json +++ b/node_modules/are-we-there-yet/package.json @@ -1,6 +1,6 @@ { "name": "are-we-there-yet", - "version": "2.0.0", + "version": "3.0.0", "description": "Keep track of the overall completion of many disparate processes", "main": "lib/index.js", "scripts": { @@ -13,7 +13,9 @@ "preversion": "npm test", "postversion": "npm publish", "prepublishOnly": "git push origin --follow-tags", - "snap": "tap" + "snap": "tap", + "postlint": "npm-template-check", + "template-copy": "npm-template-copy --force" }, "repository": { "type": "git", @@ -26,9 +28,9 @@ }, "homepage": "https://github.com/npm/are-we-there-yet", "devDependencies": { - "@npmcli/eslint-config": "^1.0.0", - "@npmcli/template-oss": "^1.0.2", - "eslint": "^7.32.0", + "@npmcli/eslint-config": "^2.0.0", + "@npmcli/template-oss": "^2.7.1", + "eslint": "^8.8.0", "eslint-plugin-node": "^11.1.0", "tap": "^15.0.9" }, @@ -41,7 +43,7 @@ "lib" ], "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16" }, "tap": { "branches": 68, @@ -49,5 +51,7 @@ "functions": 86, "lines": 92 }, - "templateVersion": "1.0.2" + "templateOSS": { + "version": "2.7.1" + } } diff --git a/node_modules/make-fetch-happen/lib/agent.js b/node_modules/make-fetch-happen/lib/agent.js index 095c35c5a2523..b87427755efed 100644 --- a/node_modules/make-fetch-happen/lib/agent.js +++ b/node_modules/make-fetch-happen/lib/agent.js @@ -89,7 +89,7 @@ function checkNoProxy (uri, opts) { const host = new url.URL(uri).hostname.split('.').reverse() let noproxy = (opts.noProxy || getProcessEnv('no_proxy')) if (typeof noproxy === 'string') { - noproxy = noproxy.split(/\s*,\s*/g) + noproxy = noproxy.split(',').map(n => n.trim()) } return noproxy && noproxy.some(no => { diff --git a/node_modules/make-fetch-happen/node_modules/lru-cache/LICENSE b/node_modules/make-fetch-happen/node_modules/lru-cache/LICENSE new file mode 100644 index 0000000000000..9b58a3e03d1df --- /dev/null +++ b/node_modules/make-fetch-happen/node_modules/lru-cache/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) 2010-2022 Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/make-fetch-happen/node_modules/lru-cache/index.js b/node_modules/make-fetch-happen/node_modules/lru-cache/index.js new file mode 100644 index 0000000000000..ede2f30cc4b23 --- /dev/null +++ b/node_modules/make-fetch-happen/node_modules/lru-cache/index.js @@ -0,0 +1,581 @@ +const perf = typeof performance === 'object' && performance && + typeof performance.now === 'function' ? performance : Date + +const warned = new Set() +const deprecatedOption = (opt, msg) => { + const code = `LRU_CACHE_OPTION_${opt}` + if (shouldWarn(code)) { + warn(code, `The ${opt} option is deprecated. ${msg}`, LRUCache) + } +} +const deprecatedMethod = (method, msg) => { + const code = `LRU_CACHE_METHOD_${method}` + if (shouldWarn(code)) { + const { prototype } = LRUCache + const { get } = Object.getOwnPropertyDescriptor(prototype, method) + warn(code, `The ${method} method is deprecated. ${msg}`, get) + } +} +const deprecatedProperty = (field, msg) => { + const code = `LRU_CACHE_PROPERTY_${field}` + if (shouldWarn(code)) { + const { prototype } = LRUCache + const { get } = Object.getOwnPropertyDescriptor(prototype, field) + warn(code, `The ${field} property is deprecated. ${msg}`, get) + } +} +const shouldWarn = (code) => !(process.noDeprecation || warned.has(code)) +const warn = (code, msg, fn) => { + warned.add(code) + process.emitWarning(msg, 'DeprecationWarning', code, fn) +} + +const isPosInt = n => n && n === Math.floor(n) && n > 0 && isFinite(n) + +/* istanbul ignore next - This is a little bit ridiculous, tbh. + * The maximum array length is 2^32-1 or thereabouts on most JS impls. + * And well before that point, you're caching the entire world, I mean, + * that's ~32GB of just integers for the next/prev links, plus whatever + * else to hold that many keys and values. Just filling the memory with + * zeroes at init time is brutal when you get that big. + * But why not be complete? + * Maybe in the future, these limits will have expanded. */ +const getUintArray = max => !isPosInt(max) ? null +: max <= Math.pow(2, 8) ? Uint8Array +: max <= Math.pow(2, 16) ? Uint16Array +: max <= Math.pow(2, 32) ? Uint32Array +: max <= Number.MAX_SAFE_INTEGER ? ZeroArray +: null + +class ZeroArray extends Array { + constructor (size) { + super(size) + this.fill(0) + } +} + +class Stack { + constructor (max) { + const UintArray = getUintArray(max) + this.heap = new UintArray(max) + this.length = 0 + } + push (n) { + this.heap[this.length++] = n + } + pop () { + return this.heap[--this.length] + } +} + +class LRUCache { + constructor (options = {}) { + const { + max, + ttl, + ttlResolution = 1, + ttlAutopurge, + updateAgeOnGet, + allowStale, + dispose, + disposeAfter, + noDisposeOnSet, + maxSize, + sizeCalculation, + } = options + + // deprecated options, don't trigger a warning for getting them if + // the thing being passed in is another LRUCache we're copying. + const { + length, + maxAge, + stale, + } = options instanceof LRUCache ? {} : options + + if (!isPosInt(max)) { + throw new TypeError('max option must be an integer') + } + + const UintArray = getUintArray(max) + if (!UintArray) { + throw new Error('invalid max value: ' + max) + } + + this.max = max + this.maxSize = maxSize || 0 + this.sizeCalculation = sizeCalculation || length + if (this.sizeCalculation) { + if (!this.maxSize) { + throw new TypeError('cannot set sizeCalculation without setting maxSize') + } + if (typeof this.sizeCalculation !== 'function') { + throw new TypeError('sizeCalculating set to non-function') + } + } + this.keyMap = new Map() + this.keyList = new Array(max).fill(null) + this.valList = new Array(max).fill(null) + this.next = new UintArray(max) + this.prev = new UintArray(max) + this.head = 0 + this.tail = 0 + this.free = new Stack(max) + this.initialFill = 1 + this.size = 0 + + if (typeof dispose === 'function') { + this.dispose = dispose + } + if (typeof disposeAfter === 'function') { + this.disposeAfter = disposeAfter + this.disposed = [] + } else { + this.disposeAfter = null + this.disposed = null + } + this.noDisposeOnSet = !!noDisposeOnSet + + if (this.maxSize) { + if (!isPosInt(this.maxSize)) { + throw new TypeError('maxSize must be a positive integer if specified') + } + this.initializeSizeTracking() + } + + this.allowStale = !!allowStale || !!stale + this.updateAgeOnGet = !!updateAgeOnGet + this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 + ? ttlResolution : 1 + this.ttlAutopurge = !!ttlAutopurge + this.ttl = ttl || maxAge || 0 + if (this.ttl) { + if (!isPosInt(this.ttl)) { + throw new TypeError('ttl must be a positive integer if specified') + } + this.initializeTTLTracking() + } + + if (stale) { + deprecatedOption('stale', 'please use options.allowStale instead') + } + if (maxAge) { + deprecatedOption('maxAge', 'please use options.ttl instead') + } + if (length) { + deprecatedOption('length', 'please use options.sizeCalculation instead') + } + } + + initializeTTLTracking () { + this.ttls = new ZeroArray(this.max) + this.starts = new ZeroArray(this.max) + this.setItemTTL = (index, ttl) => { + this.starts[index] = ttl !== 0 ? perf.now() : 0 + this.ttls[index] = ttl + if (ttl !== 0 && this.ttlAutopurge) { + const t = setTimeout(() => { + if (this.isStale(index)) { + this.delete(this.keyList[index]) + } + }, ttl + 1) + /* istanbul ignore else - unref() not supported on all platforms */ + if (t.unref) { + t.unref() + } + } + } + this.updateItemAge = (index) => { + this.starts[index] = this.ttls[index] !== 0 ? perf.now() : 0 + } + // debounce calls to perf.now() to 1s so we're not hitting + // that costly call repeatedly. + let cachedNow = 0 + const getNow = () => { + const n = perf.now() + if (this.ttlResolution > 0) { + cachedNow = n + const t = setTimeout(() => cachedNow = 0, this.ttlResolution) + /* istanbul ignore else - not available on all platforms */ + if (t.unref) { + t.unref() + } + } + return n + } + this.isStale = (index) => { + return this.ttls[index] !== 0 && this.starts[index] !== 0 && + ((cachedNow || getNow()) - this.starts[index] > this.ttls[index]) + } + } + updateItemAge (index) {} + setItemTTL (index, ttl) {} + isStale (index) { return false } + + initializeSizeTracking () { + this.calculatedSize = 0 + this.sizes = new ZeroArray(this.max) + this.removeItemSize = index => this.calculatedSize -= this.sizes[index] + this.addItemSize = (index, v, k, size, sizeCalculation) => { + const s = size || (sizeCalculation ? sizeCalculation(v, k) : 0) + this.sizes[index] = isPosInt(s) ? s : 0 + const maxSize = this.maxSize - this.sizes[index] + while (this.calculatedSize > maxSize) { + this.evict() + } + this.calculatedSize += this.sizes[index] + } + this.delete = k => { + if (this.size !== 0) { + const index = this.keyMap.get(k) + if (index !== undefined) { + this.calculatedSize -= this.sizes[index] + } + } + return LRUCache.prototype.delete.call(this, k) + } + } + removeItemSize (index) {} + addItemSize (index, v, k, size, sizeCalculation) {} + + *indexes () { + if (this.size) { + for (let i = this.tail; true; i = this.prev[i]) { + if (!this.isStale(i)) { + yield i + } + if (i === this.head) { + break + } + } + } + } + *rindexes () { + if (this.size) { + for (let i = this.head; true; i = this.next[i]) { + if (!this.isStale(i)) { + yield i + } + if (i === this.tail) { + break + } + } + } + } + + *entries () { + for (const i of this.indexes()) { + yield [this.keyList[i], this.valList[i]] + } + } + + *keys () { + for (const i of this.indexes()) { + yield this.keyList[i] + } + } + + *values () { + for (const i of this.indexes()) { + yield this.valList[i] + } + } + + [Symbol.iterator] () { + return this.entries() + } + + find (fn, getOptions = {}) { + for (const i of this.indexes()) { + if (fn(this.valList[i], this.keyList[i], this)) { + return this.get(this.keyList[i], getOptions) + } + } + } + + forEach (fn, thisp = this) { + for (const i of this.indexes()) { + fn.call(thisp, this.valList[i], this.keyList[i], this) + } + } + + rforEach (fn, thisp = this) { + for (const i of this.rindexes()) { + fn.call(thisp, this.valList[i], this.keyList[i], this) + } + } + + get prune () { + deprecatedMethod('prune', 'Please use cache.purgeStale() instead.') + return this.purgeStale + } + + purgeStale () { + let deleted = false + if (this.size) { + for (let i = this.head; true; i = this.next[i]) { + const b = i === this.tail + if (this.isStale(i)) { + this.delete(this.keyList[i]) + deleted = true + } + if (b) { + break + } + } + } + return deleted + } + + dump () { + const arr = [] + for (const i of this.indexes()) { + const key = this.keyList[i] + const value = this.valList[i] + const entry = { value } + if (this.ttls) { + entry.ttl = this.ttls[i] + } + if (this.sizes) { + entry.size = this.sizes[i] + } + arr.unshift([key, entry]) + } + return arr + } + + load (arr) { + this.clear() + for (const [key, entry] of arr) { + this.set(key, entry.value, entry) + } + } + + dispose (v, k, reason) {} + + set (k, v, { + ttl = this.ttl, + noDisposeOnSet = this.noDisposeOnSet, + size = 0, + sizeCalculation = this.sizeCalculation, + } = {}) { + let index = this.size === 0 ? undefined : this.keyMap.get(k) + if (index === undefined) { + // addition + index = this.newIndex() + this.keyList[index] = k + this.valList[index] = v + this.keyMap.set(k, index) + this.next[this.tail] = index + this.prev[index] = this.tail + this.tail = index + this.size ++ + this.addItemSize(index, v, k, size, sizeCalculation) + } else { + // update + const oldVal = this.valList[index] + if (v !== oldVal) { + if (!noDisposeOnSet) { + this.dispose(oldVal, k, 'set') + if (this.disposeAfter) { + this.disposed.push([oldVal, k, 'set']) + } + } + this.removeItemSize(index) + this.valList[index] = v + this.addItemSize(index, v, k, size, sizeCalculation) + } + this.moveToTail(index) + } + if (ttl !== 0 && this.ttl === 0 && !this.ttls) { + this.initializeTTLTracking() + } + this.setItemTTL(index, ttl) + if (this.disposeAfter) { + while (this.disposed.length) { + this.disposeAfter(...this.disposed.shift()) + } + } + return this + } + + newIndex () { + if (this.size === 0) { + return this.tail + } + if (this.size === this.max) { + return this.evict() + } + if (this.free.length !== 0) { + return this.free.pop() + } + // initial fill, just keep writing down the list + return this.initialFill++ + } + + pop () { + if (this.size) { + const val = this.valList[this.head] + this.evict() + return val + } + } + + evict () { + const head = this.head + const k = this.keyList[head] + const v = this.valList[head] + this.dispose(v, k, 'evict') + if (this.disposeAfter) { + this.disposed.push([v, k, 'evict']) + } + this.removeItemSize(head) + this.head = this.next[head] + this.keyMap.delete(k) + this.size -- + return head + } + + has (k) { + return this.keyMap.has(k) && !this.isStale(this.keyMap.get(k)) + } + + // like get(), but without any LRU updating or TTL expiration + peek (k, { allowStale = this.allowStale } = {}) { + const index = this.keyMap.get(k) + if (index !== undefined && (allowStale || !this.isStale(index))) { + return this.valList[index] + } + } + + get (k, { + allowStale = this.allowStale, + updateAgeOnGet = this.updateAgeOnGet, + } = {}) { + const index = this.keyMap.get(k) + if (index !== undefined) { + if (this.isStale(index)) { + const value = allowStale ? this.valList[index] : undefined + this.delete(k) + return value + } else { + this.moveToTail(index) + if (updateAgeOnGet) { + this.updateItemAge(index) + } + return this.valList[index] + } + } + } + + connect (p, n) { + this.prev[n] = p + this.next[p] = n + } + + moveToTail (index) { + // if tail already, nothing to do + // if head, move head to next[index] + // else + // move next[prev[index]] to next[index] (head has no prev) + // move prev[next[index]] to prev[index] + // prev[index] = tail + // next[tail] = index + // tail = index + if (index !== this.tail) { + if (index === this.head) { + this.head = this.next[index] + } else { + this.connect(this.prev[index], this.next[index]) + } + this.connect(this.tail, index) + this.tail = index + } + } + + get del () { + deprecatedMethod('del', 'Please use cache.delete() instead.') + return this.delete + } + delete (k) { + let deleted = false + if (this.size !== 0) { + const index = this.keyMap.get(k) + if (index !== undefined) { + deleted = true + if (this.size === 1) { + this.clear() + } else { + this.removeItemSize(index) + this.dispose(this.valList[index], k, 'delete') + if (this.disposeAfter) { + this.disposed.push([this.valList[index], k, 'delete']) + } + this.keyMap.delete(k) + this.keyList[index] = null + this.valList[index] = null + if (index === this.tail) { + this.tail = this.prev[index] + } else if (index === this.head) { + this.head = this.next[index] + } else { + this.next[this.prev[index]] = this.next[index] + this.prev[this.next[index]] = this.prev[index] + } + this.size -- + this.free.push(index) + } + } + } + if (this.disposed) { + while (this.disposed.length) { + this.disposeAfter(...this.disposed.shift()) + } + } + return deleted + } + + clear () { + if (this.dispose !== LRUCache.prototype.dispose) { + for (const index of this.rindexes()) { + this.dispose(this.valList[index], this.keyList[index], 'delete') + } + } + if (this.disposeAfter) { + for (const index of this.rindexes()) { + this.disposed.push([this.valList[index], this.keyList[index], 'delete']) + } + } + this.keyMap.clear() + this.valList.fill(null) + this.keyList.fill(null) + if (this.ttls) { + this.ttls.fill(0) + this.starts.fill(0) + } + if (this.sizes) { + this.sizes.fill(0) + } + this.head = 0 + this.tail = 0 + this.initialFill = 1 + this.free.length = 0 + this.calculatedSize = 0 + this.size = 0 + if (this.disposed) { + while (this.disposed.length) { + this.disposeAfter(...this.disposed.shift()) + } + } + } + get reset () { + deprecatedMethod('reset', 'Please use cache.clear() instead.') + return this.clear + } + + get length () { + deprecatedProperty('length', 'Please use cache.size instead.') + return this.size + } +} + +module.exports = LRUCache diff --git a/node_modules/make-fetch-happen/node_modules/lru-cache/package.json b/node_modules/make-fetch-happen/node_modules/lru-cache/package.json new file mode 100644 index 0000000000000..66dbbd9c11503 --- /dev/null +++ b/node_modules/make-fetch-happen/node_modules/lru-cache/package.json @@ -0,0 +1,34 @@ +{ + "name": "lru-cache", + "description": "A cache object that deletes the least-recently-used items.", + "version": "7.3.1", + "author": "Isaac Z. Schlueter ", + "keywords": [ + "mru", + "lru", + "cache" + ], + "scripts": { + "test": "tap", + "snap": "tap", + "preversion": "npm test", + "postversion": "npm publish", + "prepublishOnly": "git push origin --follow-tags" + }, + "main": "index.js", + "repository": "git://github.com/isaacs/node-lru-cache.git", + "devDependencies": { + "benchmark": "^2.1.4", + "tap": "^15.1.6" + }, + "license": "ISC", + "files": [ + "index.js" + ], + "engines": { + "node": ">=12" + }, + "tap": { + "coverage-map": "map.js" + } +} diff --git a/node_modules/make-fetch-happen/package.json b/node_modules/make-fetch-happen/package.json index 7b61953e56f57..bd11b7cddbf5e 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": "10.0.0", + "version": "10.0.2", "description": "Opinionated, caching, retrying fetch client", "main": "lib/index.js", "files": [ @@ -17,7 +17,8 @@ "lint": "eslint '**/*.js'", "lintfix": "npm run lint -- --fix", "postlint": "npm-template-check", - "snap": "tap" + "snap": "tap", + "template-copy": "npm-template-copy --force" }, "repository": "https://github.com/npm/make-fetch-happen", "keywords": [ @@ -32,34 +33,33 @@ "author": "GitHub Inc.", "license": "ISC", "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", + "agentkeepalive": "^4.2.0", + "cacache": "^15.3.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", + "lru-cache": "^7.3.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", + "minipass-fetch": "^1.4.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "socks-proxy-agent": "^6.1.1", + "ssri": "^8.0.1" }, "devDependencies": { - "@npmcli/template-oss": "^2.5.1", - "eslint": "^8.7.0", + "@npmcli/template-oss": "^2.7.1", + "eslint": "^8.8.0", "mkdirp": "^1.0.4", - "nock": "^13.0.11", - "npmlog": "^6.0.0", - "require-inject": "^1.4.2", + "nock": "^13.2.4", + "npmlog": "^6.0.1", "rimraf": "^3.0.2", "safe-buffer": "^5.2.1", - "standard-version": "^9.3.0", - "tap": "^15.0.9" + "standard-version": "^9.3.2", + "tap": "^15.1.6" }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16" @@ -70,6 +70,6 @@ "check-coverage": true }, "templateOSS": { - "version": "2.5.1" + "version": "2.7.1" } } diff --git a/node_modules/npm-registry-fetch/lib/auth.js b/node_modules/npm-registry-fetch/lib/auth.js index e6b50b12eb207..17da6a17d7193 100644 --- a/node_modules/npm-registry-fetch/lib/auth.js +++ b/node_modules/npm-registry-fetch/lib/auth.js @@ -1,5 +1,6 @@ 'use strict' const npa = require('npm-package-arg') +const { URL } = require('url') // Find the longest registry key that is used for some kind of auth // in the options. diff --git a/node_modules/npm-registry-fetch/package.json b/node_modules/npm-registry-fetch/package.json index ff4482b1fdc9e..f1aab5c7bb4a8 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": "12.0.1", + "version": "12.0.2", "description": "Fetch-based http client for use with npm registry APIs", "main": "lib", "files": [ @@ -19,7 +19,8 @@ "npmclilint": "npmcli-lint", "postsnap": "npm run lintfix --", "postlint": "npm-template-check", - "snap": "tap" + "snap": "tap", + "template-copy": "npm-template-copy --force" }, "repository": "https://github.com/npm/npm-registry-fetch", "keywords": [ @@ -30,21 +31,21 @@ "author": "GitHub Inc.", "license": "ISC", "dependencies": { - "make-fetch-happen": "^10.0.0", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "make-fetch-happen": "^10.0.1", + "minipass": "^3.1.6", + "minipass-fetch": "^1.4.1", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^8.1.5" }, "devDependencies": { - "@npmcli/template-oss": "^2.5.1", - "cacache": "^15.0.0", - "nock": "^13.1.0", - "npmlog": "^4.1.2", + "@npmcli/template-oss": "^2.7.1", + "cacache": "^15.3.0", + "nock": "^13.2.4", + "npmlog": "^6.0.0", "require-inject": "^1.4.4", - "ssri": "^8.0.0", - "tap": "^15.0.4" + "ssri": "^8.0.1", + "tap": "^15.1.6" }, "tap": { "check-coverage": true, @@ -54,6 +55,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16" }, "templateOSS": { - "version": "2.5.1" + "version": "2.7.1" } } diff --git a/node_modules/npmlog/lib/log.js b/node_modules/npmlog/lib/log.js index aec98d7bdd62a..be650c6a42608 100644 --- a/node_modules/npmlog/lib/log.js +++ b/node_modules/npmlog/lib/log.js @@ -292,8 +292,9 @@ log.emitLog = function (m) { var disp = log.disp[m.level] != null ? log.disp[m.level] : m.level this.clearProgress() m.message.split(/\r?\n/).forEach(function (line) { - if (this.heading) { - this.write(this.heading, this.headingStyle) + var heading = this.heading + if (heading) { + this.write(heading, this.headingStyle) this.write(' ') } this.write(disp, log.style[m.level]) @@ -390,11 +391,11 @@ log.style = {} log.levels = {} log.disp = {} log.addLevel('silly', -Infinity, { inverse: true }, 'sill') -log.addLevel('verbose', 1000, { fg: 'blue', bg: 'black' }, 'verb') +log.addLevel('verbose', 1000, { fg: 'cyan', bg: 'black' }, 'verb') log.addLevel('info', 2000, { fg: 'green' }) log.addLevel('timing', 2500, { fg: 'green', bg: 'black' }) log.addLevel('http', 3000, { fg: 'green', bg: 'black' }) -log.addLevel('notice', 3500, { fg: 'blue', bg: 'black' }) +log.addLevel('notice', 3500, { fg: 'cyan', bg: 'black' }) log.addLevel('warn', 4000, { fg: 'black', bg: 'yellow' }, 'WARN') log.addLevel('error', 5000, { fg: 'red', bg: 'black' }, 'ERR!') log.addLevel('silent', Infinity) diff --git a/node_modules/npmlog/package.json b/node_modules/npmlog/package.json index 36abf1e44332d..cf38f7fca475c 100644 --- a/node_modules/npmlog/package.json +++ b/node_modules/npmlog/package.json @@ -2,7 +2,7 @@ "author": "GitHub Inc.", "name": "npmlog", "description": "logger for npm", - "version": "6.0.0", + "version": "6.0.1", "repository": { "type": "git", "url": "https://github.com/npm/npmlog.git" @@ -23,24 +23,27 @@ "preversion": "npm test", "postversion": "npm publish", "prepublishOnly": "git push origin --follow-tags", - "snap": "tap" + "snap": "tap", + "template-copy": "npm-template-copy --force" }, "dependencies": { - "are-we-there-yet": "^2.0.0", + "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.0", "set-blocking": "^2.0.0" }, "devDependencies": { - "@npmcli/template-oss": "^2.3.0", - "tap": "^15.0.9" + "@npmcli/template-oss": "^2.7.1", + "tap": "^15.1.6" }, "license": "ISC", - "templateVersion": "2.3.0", "engines": { "node": "^12.13.0 || ^14.15.0 || >=16" }, "tap": { "branches": 95 + }, + "templateOSS": { + "version": "2.7.1" } } diff --git a/package-lock.json b/package-lock.json index 7e5b6d7a6fad3..e1cffb032dd26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "8.4.1", + "version": "8.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "npm", - "version": "8.4.1", + "version": "8.5.0", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -87,9 +87,9 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^4.3.0", + "@npmcli/arborist": "^4.3.1", "@npmcli/ci-detect": "^1.4.0", - "@npmcli/config": "^2.4.0", + "@npmcli/config": "^3.0.0", "@npmcli/map-workspaces": "^2.0.0", "@npmcli/package-json": "^1.0.1", "@npmcli/run-script": "^2.0.0", @@ -117,12 +117,12 @@ "libnpmfund": "^2.0.2", "libnpmhook": "^7.0.1", "libnpmorg": "^3.0.1", - "libnpmpack": "^3.0.1", + "libnpmpack": "^3.1.0", "libnpmpublish": "^5.0.1", "libnpmsearch": "^4.0.1", "libnpmteam": "^3.0.1", "libnpmversion": "^2.0.2", - "make-fetch-happen": "^10.0.0", + "make-fetch-happen": "^10.0.2", "minipass": "^3.1.6", "minipass-pipeline": "^1.2.4", "mkdirp": "^1.0.4", @@ -135,9 +135,9 @@ "npm-package-arg": "^8.1.5", "npm-pick-manifest": "^6.1.1", "npm-profile": "^6.0.0", - "npm-registry-fetch": "^12.0.1", + "npm-registry-fetch": "^12.0.2", "npm-user-validate": "^1.0.1", - "npmlog": "^6.0.0", + "npmlog": "^6.0.1", "opener": "^1.5.2", "pacote": "^12.0.3", "parse-conflict-json": "^2.0.1", @@ -812,19 +812,21 @@ "inBundle": true }, "node_modules/@npmcli/config": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@npmcli/config/-/config-2.4.0.tgz", - "integrity": "sha512-fwxu/zaZnvBJohXM3igzqa3P1IVYWi5N343XcKvKkJbAx+rTqegS5tAul4NLiMPQh6WoS5a4er6oo/ieUx1f4g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/config/-/config-3.0.0.tgz", + "integrity": "sha512-2cYe2MCGintq1s6izbLYO2gAHZwNFQ92lIb5QhtpRizwHwqrV9v4+xNpvx1EBaEaqTHFR4QuozgZLA1scao/5Q==", "inBundle": true, "dependencies": { + "@npmcli/map-workspaces": "^2.0.0", "ini": "^2.0.0", "mkdirp-infer-owner": "^2.0.0", "nopt": "^5.0.0", + "read-package-json-fast": "^2.0.3", "semver": "^7.3.4", "walk-up-path": "^1.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16" } }, "node_modules/@npmcli/disparity-colors": { @@ -1239,16 +1241,16 @@ "inBundle": true }, "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", + "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", "inBundle": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16" } }, "node_modules/arg": { @@ -5018,32 +5020,41 @@ "peer": true }, "node_modules/make-fetch-happen": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.0.tgz", - "integrity": "sha512-CREcDkbKZZ64g5MN1FT+u58mDHX9FQFFtFyio5HonX44BdQdytqPZBXUz+6ibi2w/6ncji59f2phyXGSMGpgzA==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.2.tgz", + "integrity": "sha512-JSFLK53NJP22FL/eAGOyKsWbc2G3v+toPMD7Dq9PJKQCvK0i3t8hGkKxe+3YZzwYa+c0kxRHu7uxH3fvO+rsaA==", "inBundle": true, "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", + "agentkeepalive": "^4.2.0", + "cacache": "^15.3.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", + "lru-cache": "^7.3.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", + "minipass-fetch": "^1.4.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "socks-proxy-agent": "^6.1.1", + "ssri": "^8.0.1" }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16" } }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.3.1.tgz", + "integrity": "sha512-nX1x4qUrKqwbIAhv4s9et4FIUVzNOpeY07bsjGUy8gwJrXH/wScImSQqXErmo/b2jZY2r0mohbLA9zVj7u1cNw==", + "inBundle": true, + "engines": { + "node": ">=12" + } + }, "node_modules/markdown-escapes": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz", @@ -5636,17 +5647,17 @@ } }, "node_modules/npm-registry-fetch": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.1.tgz", - "integrity": "sha512-ricy4ezH3Uv0d4am6RSwHjCYTWJI74NJjurIigWMAG7Vs3PFyd0TUlkrez5L0AgaPzDLRsEzqb5cOZ/Ue01bmA==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.2.tgz", + "integrity": "sha512-Df5QT3RaJnXYuOwtXBXS9BWs+tHH2olvkCLh6jcR/b/u3DvPMlp3J0TvvYwplPKxHMOwfg287PYih9QqaVFoKA==", "inBundle": true, "dependencies": { - "make-fetch-happen": "^10.0.0", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "make-fetch-happen": "^10.0.1", + "minipass": "^3.1.6", + "minipass-fetch": "^1.4.1", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^8.1.5" }, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16" @@ -5659,12 +5670,12 @@ "inBundle": true }, "node_modules/npmlog": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz", - "integrity": "sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.1.tgz", + "integrity": "sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg==", "inBundle": true, "dependencies": { - "are-we-there-yet": "^2.0.0", + "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.0", "set-blocking": "^2.0.0" @@ -7012,9 +7023,9 @@ ] }, "node_modules/simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dev": true, "dependencies": { "decompress-response": "^4.2.0", @@ -10511,7 +10522,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "4.3.0", + "version": "4.3.1", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -10750,7 +10761,7 @@ } }, "workspaces/libnpmpack": { - "version": "3.0.1", + "version": "3.1.0", "license": "ISC", "dependencies": { "@npmcli/run-script": "^2.0.0", @@ -11486,13 +11497,15 @@ "integrity": "sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==" }, "@npmcli/config": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@npmcli/config/-/config-2.4.0.tgz", - "integrity": "sha512-fwxu/zaZnvBJohXM3igzqa3P1IVYWi5N343XcKvKkJbAx+rTqegS5tAul4NLiMPQh6WoS5a4er6oo/ieUx1f4g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/config/-/config-3.0.0.tgz", + "integrity": "sha512-2cYe2MCGintq1s6izbLYO2gAHZwNFQ92lIb5QhtpRizwHwqrV9v4+xNpvx1EBaEaqTHFR4QuozgZLA1scao/5Q==", "requires": { + "@npmcli/map-workspaces": "^2.0.0", "ini": "^2.0.0", "mkdirp-infer-owner": "^2.0.0", "nopt": "^5.0.0", + "read-package-json-fast": "^2.0.3", "semver": "^7.3.4", "walk-up-path": "^1.0.0" } @@ -11801,9 +11814,9 @@ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" }, "are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", + "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -14801,26 +14814,33 @@ "peer": true }, "make-fetch-happen": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.0.tgz", - "integrity": "sha512-CREcDkbKZZ64g5MN1FT+u58mDHX9FQFFtFyio5HonX44BdQdytqPZBXUz+6ibi2w/6ncji59f2phyXGSMGpgzA==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.0.2.tgz", + "integrity": "sha512-JSFLK53NJP22FL/eAGOyKsWbc2G3v+toPMD7Dq9PJKQCvK0i3t8hGkKxe+3YZzwYa+c0kxRHu7uxH3fvO+rsaA==", "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", + "agentkeepalive": "^4.2.0", + "cacache": "^15.3.0", "http-cache-semantics": "^4.1.0", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", + "lru-cache": "^7.3.1", + "minipass": "^3.1.6", "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", + "minipass-fetch": "^1.4.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" + "socks-proxy-agent": "^6.1.1", + "ssri": "^8.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.3.1.tgz", + "integrity": "sha512-nX1x4qUrKqwbIAhv4s9et4FIUVzNOpeY07bsjGUy8gwJrXH/wScImSQqXErmo/b2jZY2r0mohbLA9zVj7u1cNw==" + } } }, "markdown-escapes": { @@ -15257,16 +15277,16 @@ } }, "npm-registry-fetch": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.1.tgz", - "integrity": "sha512-ricy4ezH3Uv0d4am6RSwHjCYTWJI74NJjurIigWMAG7Vs3PFyd0TUlkrez5L0AgaPzDLRsEzqb5cOZ/Ue01bmA==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.2.tgz", + "integrity": "sha512-Df5QT3RaJnXYuOwtXBXS9BWs+tHH2olvkCLh6jcR/b/u3DvPMlp3J0TvvYwplPKxHMOwfg287PYih9QqaVFoKA==", "requires": { - "make-fetch-happen": "^10.0.0", - "minipass": "^3.1.3", - "minipass-fetch": "^1.3.0", + "make-fetch-happen": "^10.0.1", + "minipass": "^3.1.6", + "minipass-fetch": "^1.4.1", "minipass-json-stream": "^1.0.1", - "minizlib": "^2.0.0", - "npm-package-arg": "^8.0.0" + "minizlib": "^2.1.2", + "npm-package-arg": "^8.1.5" } }, "npm-user-validate": { @@ -15275,11 +15295,11 @@ "integrity": "sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw==" }, "npmlog": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.0.tgz", - "integrity": "sha512-03ppFRGlsyUaQFbGC2C8QWJN/C/K7PsfyD9aQdhVKAQIH4sQBc8WASqFBP7O+Ut4d2oo5LoeoboB3cGdBZSp6Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.1.tgz", + "integrity": "sha512-BTHDvY6nrRHuRfyjt1MAufLxYdVXZfd099H4+i1f0lPywNQyI4foeNXJRObB/uy+TYqUW0vAD9gbdSOXPst7Eg==", "requires": { - "are-we-there-yet": "^2.0.0", + "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", "gauge": "^4.0.0", "set-blocking": "^2.0.0" @@ -16289,9 +16309,9 @@ "dev": true }, "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dev": true, "requires": { "decompress-response": "^4.2.0", diff --git a/package.json b/package.json index 10688636e6655..ef564abd0aca0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "8.4.1", + "version": "8.5.0", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -55,9 +55,9 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^4.3.0", + "@npmcli/arborist": "^4.3.1", "@npmcli/ci-detect": "^1.4.0", - "@npmcli/config": "^2.4.0", + "@npmcli/config": "^3.0.0", "@npmcli/map-workspaces": "^2.0.0", "@npmcli/package-json": "^1.0.1", "@npmcli/run-script": "^2.0.0", @@ -85,12 +85,12 @@ "libnpmfund": "^2.0.2", "libnpmhook": "^7.0.1", "libnpmorg": "^3.0.1", - "libnpmpack": "^3.0.1", + "libnpmpack": "^3.1.0", "libnpmpublish": "^5.0.1", "libnpmsearch": "^4.0.1", "libnpmteam": "^3.0.1", "libnpmversion": "^2.0.2", - "make-fetch-happen": "^10.0.0", + "make-fetch-happen": "^10.0.2", "minipass": "^3.1.6", "minipass-pipeline": "^1.2.4", "mkdirp": "^1.0.4", @@ -103,9 +103,9 @@ "npm-package-arg": "^8.1.5", "npm-pick-manifest": "^6.1.1", "npm-profile": "^6.0.0", - "npm-registry-fetch": "^12.0.1", + "npm-registry-fetch": "^12.0.2", "npm-user-validate": "^1.0.1", - "npmlog": "^6.0.0", + "npmlog": "^6.0.1", "opener": "^1.5.2", "pacote": "^12.0.3", "parse-conflict-json": "^2.0.1", diff --git a/tap-snapshots/test/lib/load-all-commands.js.test.cjs b/tap-snapshots/test/lib/load-all-commands.js.test.cjs index e7142c2492322..c9da1e23671ea 100644 --- a/tap-snapshots/test/lib/load-all-commands.js.test.cjs +++ b/tap-snapshots/test/lib/load-all-commands.js.test.cjs @@ -170,7 +170,7 @@ npm dedupe Options: [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] -[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] +[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] @@ -447,7 +447,7 @@ npm install npm install / Options: -[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] +[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--ignore-scripts] @@ -494,7 +494,7 @@ npm install-test npm install-test / Options: -[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] +[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--ignore-scripts] @@ -517,7 +517,7 @@ npm link (in package dir) npm link [<@scope>/][@] Options: -[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] +[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--ignore-scripts] @@ -1013,7 +1013,7 @@ Usage: npm uninstall [<@scope>/]... Options: -[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] +[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] @@ -1063,7 +1063,7 @@ npm update [...] Options: [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] -[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] +[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] diff --git a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index ab706be89b835..d75d32d9b74ea 100644 --- a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -1430,7 +1430,7 @@ If a package would be saved at install time by the use of \`--save\`, \`--save-dev\`, or \`--save-optional\`, then also put it in the \`bundleDependencies\` list. -Ignore if \`--save-peer\` is set, since peerDependencies cannot be bundled. +Ignored if \`--save-peer\` is set, since peerDependencies cannot be bundled. ` exports[`test/lib/utils/config/definitions.js TAP > config description for save-dev 1`] = ` diff --git a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index 58958ebdab954..27b8278fd388e 100644 --- a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -1225,7 +1225,7 @@ If a package would be saved at install time by the use of \`--save\`, \`--save-dev\`, or \`--save-optional\`, then also put it in the \`bundleDependencies\` list. -Ignore if \`--save-peer\` is set, since peerDependencies cannot be bundled. +Ignored if \`--save-peer\` is set, since peerDependencies cannot be bundled. diff --git a/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs b/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs index ab8f1cf3b4e87..f91f2b11d3533 100644 --- a/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs +++ b/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs @@ -311,7 +311,7 @@ All commands: Options: [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] - [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] + [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] @@ -556,7 +556,7 @@ All commands: npm install / Options: - [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] + [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--ignore-scripts] @@ -599,7 +599,7 @@ All commands: npm install-test / Options: - [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] + [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--ignore-scripts] @@ -620,7 +620,7 @@ All commands: npm link [<@scope>/][@] Options: - [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] + [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-E|--save-exact] [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] [--omit [--omit ...]] [--ignore-scripts] @@ -1054,7 +1054,7 @@ All commands: npm uninstall [<@scope>/]... Options: - [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] + [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] @@ -1098,7 +1098,7 @@ All commands: Options: [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] [--no-package-lock] - [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] + [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer|--save-bundle] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] diff --git a/test/lib/commands/org.js b/test/lib/commands/org.js index 903b9de4f6084..b716adc097523 100644 --- a/test/lib/commands/org.js +++ b/test/lib/commands/org.js @@ -83,7 +83,8 @@ t.test('npm org add', async t => { await org.exec(['add', 'orgname', 'username']) - t.strictSame( + t.ok(orgSetArgs.opts.log, 'got passed a logger') + t.match( orgSetArgs, { org: 'orgname', @@ -148,7 +149,8 @@ t.test('npm org add - more users', async t => { }) await org.exec(['add', 'orgname', 'username']) - t.strictSame( + t.ok(orgSetArgs.opts.log, 'got passed a logger') + t.match( orgSetArgs, { org: 'orgname', @@ -175,7 +177,8 @@ t.test('npm org add - json output', async t => { await org.exec(['add', 'orgname', 'username']) - t.strictSame( + t.ok(orgSetArgs.opts.log, 'got passed a logger') + t.match( orgSetArgs, { org: 'orgname', @@ -209,7 +212,8 @@ t.test('npm org add - parseable output', async t => { await org.exec(['add', 'orgname', 'username']) - t.strictSame( + t.ok(orgSetArgs.opts.log, 'got passed a logger') + t.match( orgSetArgs, { org: 'orgname', @@ -239,7 +243,8 @@ t.test('npm org add - silent output', async t => { await org.exec(['add', 'orgname', 'username']) - t.strictSame( + t.ok(orgSetArgs.opts.log, 'got passed a logger') + t.match( orgSetArgs, { org: 'orgname', @@ -261,7 +266,8 @@ t.test('npm org rm', async t => { await org.exec(['rm', 'orgname', 'username']) - t.strictSame( + t.ok(orgRmArgs.opts.log, 'got passed a logger') + t.match( orgRmArgs, { org: 'orgname', @@ -270,7 +276,8 @@ t.test('npm org rm', async t => { }, 'libnpmorg.rm received the correct args' ) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -323,7 +330,8 @@ t.test('npm org rm - one user left', async t => { await org.exec(['rm', 'orgname', 'username']) - t.strictSame( + t.ok(orgRmArgs.opts.log, 'got passed a logger') + t.match( orgRmArgs, { org: 'orgname', @@ -332,7 +340,8 @@ t.test('npm org rm - one user left', async t => { }, 'libnpmorg.rm received the correct args' ) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -358,7 +367,8 @@ t.test('npm org rm - json output', async t => { await org.exec(['rm', 'orgname', 'username']) - t.strictSame( + t.ok(orgRmArgs.opts.log, 'got passed a logger') + t.match( orgRmArgs, { org: 'orgname', @@ -367,7 +377,8 @@ t.test('npm org rm - json output', async t => { }, 'libnpmorg.rm received the correct args' ) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -398,7 +409,8 @@ t.test('npm org rm - parseable output', async t => { await org.exec(['rm', 'orgname', 'username']) - t.strictSame( + t.ok(orgRmArgs.opts.log, 'got passed a logger') + t.match( orgRmArgs, { org: 'orgname', @@ -407,7 +419,8 @@ t.test('npm org rm - parseable output', async t => { }, 'libnpmorg.rm received the correct args' ) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -436,7 +449,8 @@ t.test('npm org rm - silent output', async t => { await org.exec(['rm', 'orgname', 'username']) - t.strictSame( + t.ok(orgRmArgs.opts.log, 'got passed a logger') + t.match( orgRmArgs, { org: 'orgname', @@ -445,7 +459,8 @@ t.test('npm org rm - silent output', async t => { }, 'libnpmorg.rm received the correct args' ) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -470,7 +485,8 @@ t.test('npm org ls', async t => { await org.exec(['ls', 'orgname']) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -497,7 +513,8 @@ t.test('npm org ls - user filter', async t => { await org.exec(['ls', 'orgname', 'username']) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -522,7 +539,8 @@ t.test('npm org ls - user filter, missing user', async t => { await org.exec(['ls', 'orgname', 'username']) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -560,7 +578,8 @@ t.test('npm org ls - json output', async t => { await org.exec(['ls', 'orgname']) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -587,7 +606,8 @@ t.test('npm org ls - parseable output', async t => { await org.exec(['ls', 'orgname']) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', @@ -623,7 +643,8 @@ t.test('npm org ls - silent output', async t => { await org.exec(['ls', 'orgname']) - t.strictSame( + t.ok(orgLsArgs.opts.log, 'got passed a logger') + t.match( orgLsArgs, { org: 'orgname', diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js index b1b148a7c27ec..99d55294fbacf 100644 --- a/test/lib/commands/unpublish.js +++ b/test/lib/commands/unpublish.js @@ -76,8 +76,9 @@ t.test('no args --force', async t => { const libnpmpublish = { unpublish (spec, opts) { + t.ok(opts.log, 'gets passed a logger') t.equal(spec.raw, 'pkg@1.0.0', 'should unpublish expected spec') - t.same( + t.match( opts, { publishConfig: undefined, @@ -177,12 +178,8 @@ t.test('unpublish @version', async t => { const libnpmpublish = { unpublish (spec, opts) { + t.ok(opts.log, 'gets passed a logger') t.equal(spec.raw, 'pkg@1.0.0', 'should unpublish expected parsed spec') - t.same( - opts, - {}, - 'should unpublish with expected opts' - ) }, } diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index 0375e1851495a..b7bc56f3e9797 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -1250,24 +1250,40 @@ This is a one-time fix-up, please be patient... // Don't bother to load the manifest for link deps, because the target // might be within another package that doesn't exist yet. const { legacyPeerDeps } = this - return spec.type === 'directory' - ? this[_linkFromSpec](name, spec, parent, edge) - : this[_fetchManifest](spec) - .then(pkg => new Node({ name, pkg, parent, legacyPeerDeps }), error => { - error.requiredBy = edge.from.location || '.' - - // failed to load the spec, either because of enotarget or - // fetch failure of some other sort. save it so we can verify - // later that it's optional, otherwise the error is fatal. - const n = new Node({ - name, - parent, - error, - legacyPeerDeps, - }) - this[_loadFailures].add(n) - return n + + // spec is a directory, link it + if (spec.type === 'directory') { + return this[_linkFromSpec](name, spec, parent, edge) + } + + // if the spec matches a workspace name, then see if the workspace node will + // satisfy the edge. if it does, we return the workspace node to make sure it + // takes priority. + if (this.idealTree.workspaces && this.idealTree.workspaces.has(spec.name)) { + const existingNode = this.idealTree.edgesOut.get(spec.name).to + if (existingNode && existingNode.isWorkspace && existingNode.satisfies(edge)) { + return edge.to + } + } + + // spec isn't a directory, and either isn't a workspace or the workspace we have + // doesn't satisfy the edge. try to fetch a manifest and build a node from that. + return this[_fetchManifest](spec) + .then(pkg => new Node({ name, pkg, parent, legacyPeerDeps }), error => { + error.requiredBy = edge.from.location || '.' + + // failed to load the spec, either because of enotarget or + // fetch failure of some other sort. save it so we can verify + // later that it's optional, otherwise the error is fatal. + const n = new Node({ + name, + parent, + error, + legacyPeerDeps, }) + this[_loadFailures].add(n) + return n + }) } [_linkFromSpec] (name, spec, parent, edge) { diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 45ef93985358b..91507fd791871 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -1369,6 +1369,10 @@ module.exports = cls => class Reifier extends cls { devDependencies = {}, optionalDependencies = {}, peerDependencies = {}, + // bundleDependencies is not required by PackageJson like the other fields here + // PackageJson also doesn't omit an empty array for this field so defaulting this + // to an empty array would add that field to every package.json file. + bundleDependencies, } = tree.package pkgJson.update({ @@ -1376,6 +1380,7 @@ module.exports = cls => class Reifier extends cls { devDependencies, optionalDependencies, peerDependencies, + bundleDependencies, }) await pkgJson.save() } diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 5c33f71678a70..a915c9d8b1f6f 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "4.3.0", + "version": "4.3.1", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", diff --git a/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs b/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs index 6d38d724dca22..ffd568c686103 100644 --- a/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs +++ b/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs @@ -33164,6 +33164,10 @@ exports[`test/arborist/reify.js TAP save-prod, with optional > must match snapsh {"dependencies":{"abbrev":"^1.1.1"}} ` +exports[`test/arborist/reify.js TAP saveBundle > must match snapshot 1`] = ` +{"dependencies":{"abbrev":"^1.1.1"},"bundleDependencies":["abbrev"]} +` + exports[`test/arborist/reify.js TAP saving the ideal tree save some stuff > lock after save 1`] = ` Object { "dependencies": Object { diff --git a/workspaces/arborist/test/arborist/build-ideal-tree.js b/workspaces/arborist/test/arborist/build-ideal-tree.js index 368df05bcfaf4..e718b0b58cca4 100644 --- a/workspaces/arborist/test/arborist/build-ideal-tree.js +++ b/workspaces/arborist/test/arborist/build-ideal-tree.js @@ -877,6 +877,105 @@ t.test('workspaces', t => { t.matchSnapshot(printTree(await tree)) }) + t.test('workspace nodes are used instead of fetching manifests when they are valid', async t => { + // turn off networking, this should never make a registry request + nock.disableNetConnect() + t.teardown(() => nock.enableNetConnect()) + + const path = t.testdir({ + 'package.json': JSON.stringify({ + name: 'root', + workspaces: ['workspace-a', 'workspace-b'], + }), + // the package-lock.json references version 1.0.0 of the workspace deps + // as it would if a user hand edited their workspace's package.json and + // now are attempting to reify with a stale package-lock + 'package-lock.json': JSON.stringify({ + name: 'root', + lockfileVersion: 2, + requires: true, + packages: { + '': { + name: 'root', + workspaces: ['workspace-a', 'workspace-b'], + }, + 'node_modules/workspace-a': { + resolved: 'workspace-a', + link: true, + }, + 'node_modules/workspace-b': { + resolved: 'workspace-b', + link: true, + }, + 'workspace-a': { + name: 'workspace-a', + version: '1.0.0', + dependencies: { + 'workspace-b': '1.0.0', + }, + }, + 'workspace-b': { + name: 'workspace-b', + version: '1.0.0', + }, + }, + dependencies: { + 'workspace-a': { + version: 'file:workspace-a', + requires: { + 'workspace-b': '1.0.0', + }, + }, + 'workspace-b': { + version: 'file:workspace-b', + }, + }, + }), + node_modules: { + 'workspace-a': t.fixture('symlink', '../workspace-a'), + 'workspace-b': t.fixture('symlink', '../workspace-b'), + }, + // the workspaces themselves are at 2.0.0 because they're what was edited + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '2.0.0', + dependencies: { + 'workspace-b': '2.0.0', + }, + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '2.0.0', + }), + }, + }) + + const arb = new Arborist({ + ...OPT, + path, + workspaces: ['workspace-a', 'workspace-b'], + }) + + // this will reject if we try to fetch a manifest for some reason + const tree = await arb.buildIdealTree({ + path, + }) + + const edgeA = tree.edgesOut.get('workspace-a') + t.ok(edgeA.valid, 'workspace-a should be valid') + const edgeB = tree.edgesOut.get('workspace-b') + t.ok(edgeB.valid, 'workspace-b should be valid') + const nodeA = edgeA.to.target + t.ok(nodeA.isWorkspace, 'workspace-a is definitely a workspace') + const nodeB = edgeB.to.target + t.ok(nodeB.isWorkspace, 'workspace-b is definitely a workspace') + const nodeBfromA = nodeA.edgesOut.get('workspace-b').to.target + t.equal(nodeBfromA, nodeB, 'workspace-b edgeOut from workspace-a is the workspace') + }) + t.end() }) diff --git a/workspaces/arborist/test/arborist/reify.js b/workspaces/arborist/test/arborist/reify.js index caa15f59f2476..7fb1f1f2bfdf8 100644 --- a/workspaces/arborist/test/arborist/reify.js +++ b/workspaces/arborist/test/arborist/reify.js @@ -1783,6 +1783,17 @@ t.test('save-prod, with optional', async t => { t.matchSnapshot(fs.readFileSync(path + '/package.json', 'utf8')) }) +t.test('saveBundle', async t => { + const path = t.testdir({ + 'package.json': JSON.stringify({ + dependencies: { abbrev: '*' }, + }), + }) + const arb = newArb({ path }) + await arb.reify({ add: ['abbrev'], saveType: 'prod', saveBundle: true }) + t.matchSnapshot(fs.readFileSync(path + '/package.json', 'utf8')) +}) + t.test('no saveType: dev w/ compatible peer', async t => { const path = t.testdir({ 'package.json': JSON.stringify({ diff --git a/workspaces/libnpmpack/lib/index.js b/workspaces/libnpmpack/lib/index.js index 23bb9df4b2247..a2c95cf938dcf 100644 --- a/workspaces/libnpmpack/lib/index.js +++ b/workspaces/libnpmpack/lib/index.js @@ -3,6 +3,9 @@ const pacote = require('pacote') const npa = require('npm-package-arg') const runScript = require('@npmcli/run-script') +const path = require('path') +const util = require('util') +const writeFile = util.promisify(require('fs').writeFile) module.exports = pack async function pack (spec = 'file:.', opts = {}) { @@ -33,6 +36,14 @@ async function pack (spec = 'file:.', opts = {}) { integrity: manifest._integrity, }) + // check for explicit `false` so the default behavior is to skip writing to disk + if (opts.dryRun === false) { + const filename = `${manifest.name}-${manifest.version}.tgz` + .replace(/^@/, '').replace(/\//, '-') + const destination = path.resolve(opts.packDestination, filename) + await writeFile(destination, tarball) + } + if (spec.type === 'directory') { // postpack await runScript({ diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index dad28c398585f..7317c272f7e22 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpack", - "version": "3.0.1", + "version": "3.1.0", "description": "Programmatic API for the bits behind npm pack", "author": "GitHub Inc.", "main": "lib/index.js", diff --git a/workspaces/libnpmpack/test/index.js b/workspaces/libnpmpack/test/index.js index dcc5e41f4b509..5f25f416655fd 100644 --- a/workspaces/libnpmpack/test/index.js +++ b/workspaces/libnpmpack/test/index.js @@ -1,6 +1,8 @@ 'use strict' const t = require('tap') +const fs = require('fs') +const path = require('path') const pack = require('../lib/index.js') const tnock = require('./fixtures/tnock.js') @@ -29,6 +31,43 @@ t.test('packs from local directory', async t => { }) }) +t.test('writes tarball to file when dryRun === false', async t => { + const testDir = t.testdir({ + 'package.json': JSON.stringify({ + name: 'my-cool-pkg', + version: '1.0.0', + scripts: { + prepack: 'touch prepack', + postpack: 'touch postpack', + }, + }, null, 2), + }) + + const cwd = process.cwd() + process.chdir(testDir) + + const tarball = await pack('file:.', { + dryRun: false, + packDestination: testDir, + log: { level: 'silent' }, // so the test doesn't try to log + }) + t.ok(tarball) + const expectedTarball = path.join(testDir, 'my-cool-pkg-1.0.0.tgz') + t.ok(fs.existsSync(expectedTarball), 'file was written') + t.same(fs.readFileSync(expectedTarball), tarball, 'wrote same data that was returned') + + const prepackTimestamp = (await fs.promises.stat(path.join(testDir, 'prepack'))).mtime + const tarballTimestamp = (await fs.promises.stat(expectedTarball)).mtime + const postpackTimestamp = (await fs.promises.stat(path.join(testDir, 'postpack'))).mtime + + t.ok(prepackTimestamp < tarballTimestamp, 'prepack ran before tarball was written') + t.ok(tarballTimestamp < postpackTimestamp, 'postpack ran after tarball was written') + + t.teardown(async () => { + process.chdir(cwd) + }) +}) + t.test('packs from local directory with silent loglevel', async t => { const testDir = t.testdir({ 'package.json': JSON.stringify({