diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e3a62ee0771b..270d524b4b205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +## v8.3.2 (2022-01-20) + +### Bug Fixes + +* [`cfd59b8c8`](https://github.com/npm/cli/commit/cfd59b8c81078f842328b13a23a234150842cd58) + [#4223](https://github.com/npm/cli/pull/4223) + fix: npm update --save + ([@ruyadorno](https://github.com/ruyadorno)) +* [`510f0ecbc`](https://github.com/npm/cli/commit/510f0ecbc9970ed8c8993107cc03cf27b7b996dc) + [#4218](https://github.com/npm/cli/pull/4218) + fix(arborist): ensure indentation is preserved + ([@ljharb](https://github.com/ljharb)) +* [`c99c2151a`](https://github.com/npm/cli/commit/c99c2151a868672c017f64ff0ecb12149a2fb095) + [#4230](https://github.com/npm/cli/pull/4230) + fix(arborist): prioritize valid workspace nodes + ([@nlf](https://github.com/nlf)) +* [`14a3d9500`](https://github.com/npm/cli/commit/14a3d95000f1cba937f3309d198a363ae65cf01f) + [#4265](https://github.com/npm/cli/pull/4265) + fix: resolve workspace paths from cwd when possible + ([@nlf](https://github.com/nlf)) + +### Dependencies + +* [`2ef9f9847`](https://github.com/npm/cli/commit/2ef9f9847c11fe8c0c0494558fe77c15ac4dbc80) + [#4254](https://github.com/npm/cli/pull/4254) + deps: `bin-links@3.0.0 write-file-atomic@4.0.0` + ## v8.3.1 (2022-01-13) ### Bug Fixes diff --git a/docs/content/commands/npm-dedupe.md b/docs/content/commands/npm-dedupe.md index 377e17d814a6f..53d2e64272a67 100644 --- a/docs/content/commands/npm-dedupe.md +++ b/docs/content/commands/npm-dedupe.md @@ -72,6 +72,12 @@ result in new modules being installed. Using `npm find-dupes` will run the command in `--dry-run` mode. +Note that by default `npm dedupe` will not update the semver values of direct +dependencies in your project `package.json`, if you want to also update +values in `package.json` you can run: `npm dedupe --save` (or add the +`save=true` option to a [configuration file](/configuring-npm/npmrc) +to make that the default behavior). + ### Configuration diff --git a/docs/content/commands/npm-update.md b/docs/content/commands/npm-update.md index ad02118e4687f..1889d60569fe5 100644 --- a/docs/content/commands/npm-update.md +++ b/docs/content/commands/npm-update.md @@ -27,6 +27,12 @@ packages. If no package name is specified, all packages in the specified location (global or local) will be updated. +Note that by default `npm update` will not update the semver values of direct +dependencies in your project `package.json`, if you want to also update +values in `package.json` you can run: `npm update --save` (or add the +`save=true` option to a [configuration file](/configuring-npm/npmrc) +to make that the default behavior). + ### Example For the examples below, assume that the current package is `app` and it depends diff --git a/docs/content/using-npm/config.md b/docs/content/using-npm/config.md index fe197e344dbc0..83a385e08344f 100644 --- a/docs/content/using-npm/config.md +++ b/docs/content/using-npm/config.md @@ -1326,13 +1326,16 @@ The base URL of the npm registry. #### `save` -* Default: true +* Default: `true` unless when using `npm update` or `npm dedupe` where it + defaults to `false` * Type: Boolean -Save installed packages to a package.json file as dependencies. +Save installed packages to a `package.json` file as dependencies. When used with the `npm rm` command, removes the dependency from -package.json. +`package.json`. + +Will also prevent writing to `package-lock.json` if set to `false`. diff --git a/lib/base-command.js b/lib/base-command.js index ad261b5148bd2..f67f99f36367c 100644 --- a/lib/base-command.js +++ b/lib/base-command.js @@ -1,4 +1,7 @@ // Base class for npm commands + +const { relative } = require('path') + const usageUtil = require('./utils/usage.js') const ConfigDefinitions = require('./utils/config/definitions.js') const getWorkspaces = require('./workspaces/get-workspaces.js') @@ -78,9 +81,14 @@ class BaseCommand { this.includeWorkspaceRoot = false } + const relativeFrom = relative(this.npm.localPrefix, process.cwd()).startsWith('..') + ? this.npm.localPrefix + : process.cwd() + const ws = await getWorkspaces(filters, { path: this.npm.localPrefix, includeWorkspaceRoot: this.includeWorkspaceRoot, + relativeFrom, }) this.workspaces = ws this.workspaceNames = [...ws.keys()] diff --git a/lib/commands/dedupe.js b/lib/commands/dedupe.js index cc4b119d09d2a..1c270249adb3f 100644 --- a/lib/commands/dedupe.js +++ b/lib/commands/dedupe.js @@ -13,6 +13,7 @@ class Dedupe extends ArboristWorkspaceCmd { 'legacy-bundling', 'strict-peer-deps', 'package-lock', + 'save', 'omit', 'ignore-scripts', 'audit', @@ -29,6 +30,12 @@ class Dedupe extends ArboristWorkspaceCmd { throw er } + // In the context of `npm dedupe` the save + // config value should default to `false` + const save = this.npm.config.isDefault('save') + ? false + : this.npm.config.get('save') + const dryRun = this.npm.config.get('dry-run') const where = this.npm.prefix const opts = { @@ -36,6 +43,7 @@ class Dedupe extends ArboristWorkspaceCmd { log, path: where, dryRun, + save, workspaces: this.workspaceNames, } const arb = new Arborist(opts) diff --git a/lib/commands/update.js b/lib/commands/update.js index a8bbc4c969251..c55d7cf575d88 100644 --- a/lib/commands/update.js +++ b/lib/commands/update.js @@ -16,6 +16,7 @@ class Update extends ArboristWorkspaceCmd { 'legacy-bundling', 'strict-peer-deps', 'package-lock', + 'save', 'omit', 'ignore-scripts', 'audit', @@ -40,19 +41,27 @@ class Update extends ArboristWorkspaceCmd { ? global : this.npm.prefix + // In the context of `npm update` the save + // config value should default to `false` + const save = this.npm.config.isDefault('save') + ? false + : this.npm.config.get('save') + if (this.npm.config.get('depth')) { log.warn('update', 'The --depth option no longer has any effect. See RFC0019.\n' + 'https://github.com/npm/rfcs/blob/latest/implemented/0019-remove-update-depth-option.md') } - const arb = new Arborist({ + const opts = { ...this.npm.flatOptions, log, path: where, + save, workspaces: this.workspaceNames, - }) + } + const arb = new Arborist(opts) - await arb.reify({ update }) + await arb.reify({ ...opts, update }) await reifyFinish(this.npm, arb) } } diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index ac8a4e2f6749d..95d79f0f05325 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -1583,14 +1583,18 @@ define('registry', { 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', type: Boolean, short: 'S', description: ` - Save installed packages to a package.json file as dependencies. + Save installed packages to a \`package.json\` file as dependencies. When used with the \`npm rm\` command, removes the dependency from - package.json. + \`package.json\`. + + Will also prevent writing to \`package-lock.json\` if set to \`false\`. `, flatten, }) diff --git a/lib/workspaces/get-workspaces.js b/lib/workspaces/get-workspaces.js index a59b5a6c54b70..0cddae2a462f1 100644 --- a/lib/workspaces/get-workspaces.js +++ b/lib/workspaces/get-workspaces.js @@ -5,7 +5,7 @@ const rpj = require('read-package-json-fast') // Returns an Map of paths to workspaces indexed by workspace name // { foo => '/path/to/foo' } -const getWorkspaces = async (filters, { path, includeWorkspaceRoot }) => { +const getWorkspaces = async (filters, { path, includeWorkspaceRoot, relativeFrom }) => { // TODO we need a better error to be bubbled up here if this rpj call fails const pkg = await rpj(resolve(path, 'package.json')) const workspaces = await mapWorkspaces({ cwd: path, pkg }) @@ -21,8 +21,8 @@ const getWorkspaces = async (filters, { path, includeWorkspaceRoot }) => { for (const filterArg of filters) { for (const [workspaceName, workspacePath] of workspaces.entries()) { if (filterArg === workspaceName - || resolve(path, filterArg) === workspacePath - || minimatch(workspacePath, `${resolve(path, filterArg)}/*`)) { + || resolve(relativeFrom || path, filterArg) === workspacePath + || minimatch(workspacePath, `${resolve(relativeFrom || path, filterArg)}/*`)) { res.set(workspaceName, workspacePath) } } diff --git a/node_modules/bin-links/lib/bin-target.js b/node_modules/bin-links/lib/bin-target.js index 7ea0c2a96ed68..0629285d5144c 100644 --- a/node_modules/bin-links/lib/bin-target.js +++ b/node_modules/bin-links/lib/bin-target.js @@ -1,9 +1,9 @@ const isWindows = require('./is-windows.js') const getPrefix = require('./get-prefix.js') const getNodeModules = require('./get-node-modules.js') -const {dirname} = require('path') +const { dirname } = require('path') -module.exports = ({top, path}) => +module.exports = ({ top, path }) => !top ? getNodeModules(path) + '/.bin' - : isWindows ? getPrefix(path) - : dirname(getPrefix(path)) + '/bin' + : isWindows ? getPrefix(path) + : dirname(getPrefix(path)) + '/bin' diff --git a/node_modules/bin-links/lib/check-bin.js b/node_modules/bin-links/lib/check-bin.js index 45eec8affc92a..8bbe45188a479 100644 --- a/node_modules/bin-links/lib/check-bin.js +++ b/node_modules/bin-links/lib/check-bin.js @@ -2,53 +2,56 @@ // either rejects or resolves to nothing. return value not relevant. const isWindows = require('./is-windows.js') const binTarget = require('./bin-target.js') -const {resolve, dirname} = require('path') +const { resolve, dirname } = require('path') const readCmdShim = require('read-cmd-shim') const fs = require('fs') -const {promisify} = require('util') +const { promisify } = require('util') const readlink = promisify(fs.readlink) -const checkBin = async ({bin, path, top, global, force}) => { +const checkBin = async ({ bin, path, top, global, force }) => { // always ok to clobber when forced // always ok to clobber local bins, or when forced - if (force || !global || !top) + if (force || !global || !top) { return + } // ok, need to make sure, then - const target = resolve(binTarget({path, top}), bin) + const target = resolve(binTarget({ path, top }), bin) path = resolve(path) - return isWindows ? checkShim({target, path}) : checkLink({target, path}) + return isWindows ? checkShim({ target, path }) : checkLink({ target, path }) } // only enoent is allowed. anything else is a problem. -const handleReadLinkError = async ({er, target}) => +const handleReadLinkError = async ({ er, target }) => er.code === 'ENOENT' ? null - : failEEXIST({target}) + : failEEXIST({ target }) -const checkLink = async ({target, path}) => { +const checkLink = async ({ target, path }) => { const current = await readlink(target) - .catch(er => handleReadLinkError({er, target})) + .catch(er => handleReadLinkError({ er, target })) - if (!current) + if (!current) { return + } const resolved = resolve(dirname(target), current) - if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) - return failEEXIST({target}) + if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) { + return failEEXIST({ target }) + } } -const handleReadCmdShimError = ({er, target}) => +const handleReadCmdShimError = ({ er, target }) => er.code === 'ENOENT' ? null - : failEEXIST({target}) + : failEEXIST({ target }) -const failEEXIST = ({target}) => +const failEEXIST = ({ target }) => Promise.reject(Object.assign(new Error('EEXIST: file already exists'), { path: target, code: 'EEXIST', })) -const checkShim = async ({target, path}) => { +const checkShim = async ({ target, path }) => { const shims = [ target, target + '.cmd', @@ -56,15 +59,17 @@ const checkShim = async ({target, path}) => { ] await Promise.all(shims.map(async target => { const current = await readCmdShim(target) - .catch(er => handleReadCmdShimError({er, target})) + .catch(er => handleReadCmdShimError({ er, target })) - if (!current) + if (!current) { return + } const resolved = resolve(dirname(target), current.replace(/\\/g, '/')) - if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) - return failEEXIST({target}) + if (resolved.toLowerCase().indexOf(path.toLowerCase()) !== 0) { + return failEEXIST({ target }) + } })) } diff --git a/node_modules/bin-links/lib/check-bins.js b/node_modules/bin-links/lib/check-bins.js index 0addbffe55abb..76a683c91d7c2 100644 --- a/node_modules/bin-links/lib/check-bins.js +++ b/node_modules/bin-links/lib/check-bins.js @@ -3,14 +3,16 @@ const normalize = require('npm-normalize-package-bin') const checkBins = async ({ pkg, path, top, global, force }) => { // always ok to clobber when forced // always ok to clobber local bins, or when forced - if (force || !global || !top) + if (force || !global || !top) { return + } pkg = normalize(pkg) - if (!pkg.bin) + if (!pkg.bin) { return + } await Promise.all(Object.keys(pkg.bin) - .map(bin => checkBin({bin, path, top, global, force}))) + .map(bin => checkBin({ bin, path, top, global, force }))) } module.exports = checkBins diff --git a/node_modules/bin-links/lib/get-node-modules.js b/node_modules/bin-links/lib/get-node-modules.js index b67c198eff348..5c16b3b8afbfb 100644 --- a/node_modules/bin-links/lib/get-node-modules.js +++ b/node_modules/bin-links/lib/get-node-modules.js @@ -2,12 +2,13 @@ // {prefix}/node_modules/{name}. Can't rely on pkg.name, because // it might be installed as an alias. -const {dirname, basename} = require('path') +const { dirname, basename } = require('path') // this gets called a lot and can't change, so memoize it const memo = new Map() module.exports = path => { - if (memo.has(path)) + if (memo.has(path)) { return memo.get(path) + } const scopeOrNm = dirname(path) const nm = basename(scopeOrNm) === 'node_modules' ? scopeOrNm diff --git a/node_modules/bin-links/lib/get-paths.js b/node_modules/bin-links/lib/get-paths.js index 614c85652a1aa..631aef9f9117f 100644 --- a/node_modules/bin-links/lib/get-paths.js +++ b/node_modules/bin-links/lib/get-paths.js @@ -3,14 +3,15 @@ // are present, then we can assume that they're associated. const binTarget = require('./bin-target.js') const manTarget = require('./man-target.js') -const {resolve, basename} = require('path') +const { resolve, basename } = require('path') const isWindows = require('./is-windows.js') -module.exports = ({path, pkg, global, top}) => { - if (top && !global) +module.exports = ({ path, pkg, global, top }) => { + if (top && !global) { return [] + } const binSet = [] - const binTarg = binTarget({path, top}) + const binTarg = binTarget({ path, top }) if (pkg.bin) { for (const bin of Object.keys(pkg.bin)) { const b = resolve(binTarg, bin) @@ -22,14 +23,15 @@ module.exports = ({path, pkg, global, top}) => { } } - const manTarg = manTarget({path, top}) + const manTarg = manTarget({ path, top }) const manSet = [] if (manTarg && pkg.man && Array.isArray(pkg.man) && pkg.man.length) { for (const man of pkg.man) { const parseMan = man.match(/(.*\.([0-9]+)(\.gz)?)$/) // invalid entries invalidate the entire man set - if (!parseMan) + if (!parseMan) { return binSet + } const stem = parseMan[1] const sxn = parseMan[2] @@ -37,8 +39,9 @@ module.exports = ({path, pkg, global, top}) => { const absFrom = resolve(path, man) /* istanbul ignore if - should be impossible */ - if (absFrom.indexOf(path) !== 0) + if (absFrom.indexOf(path) !== 0) { return binSet + } manSet.push(resolve(manTarg, 'man' + sxn, base)) } diff --git a/node_modules/bin-links/lib/get-prefix.js b/node_modules/bin-links/lib/get-prefix.js index 96112bf0a2b97..d5cf9c9d01c20 100644 --- a/node_modules/bin-links/lib/get-prefix.js +++ b/node_modules/bin-links/lib/get-prefix.js @@ -1,3 +1,3 @@ -const {dirname} = require('path') +const { dirname } = require('path') const getNodeModules = require('./get-node-modules.js') module.exports = path => dirname(getNodeModules(path)) diff --git a/node_modules/bin-links/index.js b/node_modules/bin-links/lib/index.js similarity index 70% rename from node_modules/bin-links/index.js rename to node_modules/bin-links/lib/index.js index 2e8519737220a..ab3bd13c0be6b 100644 --- a/node_modules/bin-links/index.js +++ b/node_modules/bin-links/lib/index.js @@ -1,5 +1,5 @@ -const linkBins = require('./lib/link-bins.js') -const linkMans = require('./lib/link-mans.js') +const linkBins = require('./link-bins.js') +const linkMans = require('./link-mans.js') const binLinks = opts => { const { path, pkg, force, global, top } = opts @@ -14,27 +14,28 @@ const binLinks = opts => { // non-global top pkgs don't have any bins or mans linked. From here on // out, if it's top, we know that it's global, so no need to pass that // option further down the stack. - if (top && !global) + if (top && !global) { return Promise.resolve() + } return Promise.all([ // allow clobbering within the local node_modules/.bin folder. // only global bins are protected in this way, or else it is // yet another vector for excessive dependency conflicts. - linkBins({path, pkg, top, force: force || !top}), - linkMans({path, pkg, top, force}), + linkBins({ path, pkg, top, force: force || !top }), + linkMans({ path, pkg, top, force }), ]) } -const shimBin = require('./lib/shim-bin.js') -const linkGently = require('./lib/link-gently.js') +const shimBin = require('./shim-bin.js') +const linkGently = require('./link-gently.js') const resetSeen = () => { shimBin.resetSeen() linkGently.resetSeen() } -const checkBins = require('./lib/check-bins.js') -const getPaths = require('./lib/get-paths.js') +const checkBins = require('./check-bins.js') +const getPaths = require('./get-paths.js') module.exports = Object.assign(binLinks, { checkBins, diff --git a/node_modules/bin-links/lib/link-bin.js b/node_modules/bin-links/lib/link-bin.js index 4c0bde489348a..fb579350994d0 100644 --- a/node_modules/bin-links/lib/link-bin.js +++ b/node_modules/bin-links/lib/link-bin.js @@ -2,8 +2,8 @@ const linkGently = require('./link-gently.js') const fixBin = require('./fix-bin.js') // linking bins is simple. just symlink, and if we linked it, fix the bin up -const linkBin = ({path, to, from, absFrom, force}) => - linkGently({path, to, from, absFrom, force}) +const linkBin = ({ path, to, from, absFrom, force }) => + linkGently({ path, to, from, absFrom, force }) .then(linked => linked && fixBin(absFrom)) module.exports = linkBin diff --git a/node_modules/bin-links/lib/link-bins.js b/node_modules/bin-links/lib/link-bins.js index 6a1086b92b264..9bf7d72117fbb 100644 --- a/node_modules/bin-links/lib/link-bins.js +++ b/node_modules/bin-links/lib/link-bins.js @@ -4,17 +4,18 @@ const { dirname, resolve, relative } = require('path') const linkBin = isWindows ? require('./shim-bin.js') : require('./link-bin.js') const normalize = require('npm-normalize-package-bin') -const linkBins = ({path, pkg, top, force}) => { +const linkBins = ({ path, pkg, top, force }) => { pkg = normalize(pkg) - if (!pkg.bin) + if (!pkg.bin) { return Promise.resolve([]) + } const promises = [] - const target = binTarget({path, top}) + const target = binTarget({ path, top }) for (const [key, val] of Object.entries(pkg.bin)) { const to = resolve(target, key) const absFrom = resolve(path, val) const from = relative(dirname(to), absFrom) - promises.push(linkBin({path, from, to, absFrom, force})) + promises.push(linkBin({ path, from, to, absFrom, force })) } return Promise.all(promises) } diff --git a/node_modules/bin-links/lib/link-gently.js b/node_modules/bin-links/lib/link-gently.js index 6a6e555de7cf5..671ce38a586e7 100644 --- a/node_modules/bin-links/lib/link-gently.js +++ b/node_modules/bin-links/lib/link-gently.js @@ -11,7 +11,11 @@ const fs = require('fs') const symlink = promisify(fs.symlink) const readlink = promisify(fs.readlink) const lstat = promisify(fs.lstat) -const throwNonEnoent = er => { if (er.code !== 'ENOENT') throw er } +const throwNonEnoent = er => { + if (er.code !== 'ENOENT') { + throw er + } +} // even in --force mode, we never create a link over a link we've // already created. you can have multiple packages in a tree trying @@ -24,11 +28,12 @@ const rimraf = promisify(require('rimraf')) const rm = path => rimraf(path, { glob: false }) const SKIP = Symbol('skip - missing or already installed') -const CLOBBER = Symbol('clobber - ours or in forceful mode') +const CLOBBER = Symbol('clobber - ours or in forceful mode') -const linkGently = async ({path, to, from, absFrom, force}) => { - if (seen.has(to)) +const linkGently = async ({ path, to, from, absFrom, force }) => { + if (seen.has(to)) { return true + } seen.add(to) // if the script or manpage isn't there, just ignore it. @@ -40,36 +45,42 @@ const linkGently = async ({path, to, from, absFrom, force}) => { lstat(to).catch(throwNonEnoent), ]).then(([stFrom, stTo]) => { // not present in package, skip it - if (!stFrom) + if (!stFrom) { return SKIP + } // exists! maybe clobber if we can if (stTo) { - if (!stTo.isSymbolicLink()) + if (!stTo.isSymbolicLink()) { return force && rm(to).then(() => CLOBBER) + } return readlink(to).then(target => { - if (target === from) - return SKIP // skip it, already set up like we want it. + if (target === from) { + return SKIP + } // skip it, already set up like we want it. target = resolve(dirname(to), target) - if (target.indexOf(path) === 0 || force) + if (target.indexOf(path) === 0 || force) { return rm(to).then(() => CLOBBER) + } }) } else { // doesn't exist, dir might not either return mkdirp(dirname(to)) } }) - .then(skipOrClobber => { - if (skipOrClobber === SKIP) - return false - return symlink(from, to, 'file').catch(er => { - if (skipOrClobber === CLOBBER || force) - return rm(to).then(() => symlink(from, to, 'file')) - throw er - }).then(() => true) - }) + .then(skipOrClobber => { + if (skipOrClobber === SKIP) { + return false + } + return symlink(from, to, 'file').catch(er => { + if (skipOrClobber === CLOBBER || force) { + return rm(to).then(() => symlink(from, to, 'file')) + } + throw er + }).then(() => true) + }) } const resetSeen = () => { diff --git a/node_modules/bin-links/lib/link-mans.js b/node_modules/bin-links/lib/link-mans.js index 6fb167e480a74..54b17d1fc16d4 100644 --- a/node_modules/bin-links/lib/link-mans.js +++ b/node_modules/bin-links/lib/link-mans.js @@ -2,10 +2,11 @@ const { dirname, relative, join, resolve, basename } = require('path') const linkGently = require('./link-gently.js') const manTarget = require('./man-target.js') -const linkMans = ({path, pkg, top, force}) => { - const target = manTarget({path, top}) - if (!target || !pkg.man || !Array.isArray(pkg.man) || !pkg.man.length) +const linkMans = ({ path, pkg, top, force }) => { + const target = manTarget({ path, top }) + if (!target || !pkg.man || !Array.isArray(pkg.man) || !pkg.man.length) { return Promise.resolve([]) + } // break any links to c:\\blah or /foo/blah or ../blah // and filter out duplicates @@ -44,7 +45,7 @@ const linkMans = ({path, pkg, top, force}) => { const to = resolve(target, 'man' + sxn, base) const from = relative(dirname(to), absFrom) - return linkGently({from, to, path, absFrom, force}) + return linkGently({ from, to, path, absFrom, force }) })) } diff --git a/node_modules/bin-links/lib/man-target.js b/node_modules/bin-links/lib/man-target.js index 832d2ea35e43c..efe66f38a5543 100644 --- a/node_modules/bin-links/lib/man-target.js +++ b/node_modules/bin-links/lib/man-target.js @@ -1,6 +1,6 @@ const isWindows = require('./is-windows.js') const getPrefix = require('./get-prefix.js') -const {dirname} = require('path') +const { dirname } = require('path') -module.exports = ({top, path}) => !top || isWindows ? null +module.exports = ({ top, path }) => !top || isWindows ? null : dirname(getPrefix(path)) + '/share/man' diff --git a/node_modules/bin-links/lib/shim-bin.js b/node_modules/bin-links/lib/shim-bin.js index f2dfd7a7825d1..70259a49e5b0c 100644 --- a/node_modules/bin-links/lib/shim-bin.js +++ b/node_modules/bin-links/lib/shim-bin.js @@ -2,7 +2,11 @@ const { promisify } = require('util') const { resolve, dirname } = require('path') const fs = require('fs') const lstat = promisify(fs.lstat) -const throwNonEnoent = er => { if (er.code !== 'ENOENT') throw er } +const throwNonEnoent = er => { + if (er.code !== 'ENOENT') { + throw er + } +} const cmdShim = require('cmd-shim') const readCmdShim = require('read-cmd-shim') @@ -15,20 +19,20 @@ const fixBin = require('./fix-bin.js') // nondeterminism. const seen = new Set() -const failEEXIST = ({path, to, from}) => +const failEEXIST = ({ path, to, from }) => Promise.reject(Object.assign(new Error('EEXIST: file already exists'), { path: to, dest: from, code: 'EEXIST', })) -const handleReadCmdShimError = ({er, from, to}) => +const handleReadCmdShimError = ({ er, from, to }) => er.code === 'ENOENT' ? null - : er.code === 'ENOTASHIM' ? failEEXIST({from, to}) + : er.code === 'ENOTASHIM' ? failEEXIST({ from, to }) : Promise.reject(er) const SKIP = Symbol('skip - missing or already installed') -const shimBin = ({path, to, from, absFrom, force}) => { +const shimBin = ({ path, to, from, absFrom, force }) => { const shims = [ to, to + '.cmd', @@ -36,8 +40,9 @@ const shimBin = ({path, to, from, absFrom, force}) => { ] for (const shim of shims) { - if (seen.has(shim)) + if (seen.has(shim)) { return true + } seen.add(shim) } @@ -45,30 +50,29 @@ const shimBin = ({path, to, from, absFrom, force}) => { ...shims, absFrom, ].map(f => lstat(f).catch(throwNonEnoent))).then((stats) => { - const [ - stToBase, - stToCmd, - stToPs1, - stFrom, - ] = stats - if (!stFrom) + const [, , , stFrom] = stats + if (!stFrom) { return SKIP + } - if (force) + if (force) { return + } return Promise.all(shims.map((s, i) => [s, stats[i]]).map(([s, st]) => { - if (!st) + if (!st) { return + } return readCmdShim(s) .then(target => { target = resolve(dirname(to), target) - if (target.indexOf(resolve(path)) !== 0) - return failEEXIST({from, to, path}) - }, er => handleReadCmdShimError({er, from, to})) + if (target.indexOf(resolve(path)) !== 0) { + return failEEXIST({ from, to, path }) + } + }, er => handleReadCmdShimError({ er, from, to })) })) }) - .then(skip => skip !== SKIP && doShim(absFrom, to)) + .then(skip => skip !== SKIP && doShim(absFrom, to)) } const doShim = (absFrom, to) => diff --git a/node_modules/bin-links/package.json b/node_modules/bin-links/package.json index 8293d77d1a85a..0325ab4437656 100644 --- a/node_modules/bin-links/package.json +++ b/node_modules/bin-links/package.json @@ -1,14 +1,18 @@ { "name": "bin-links", - "version": "2.3.0", + "version": "3.0.0", "description": "JavaScript package binary linker", - "main": "index.js", + "main": "./lib/index.js", "scripts": { - "preversion": "npm t", + "preversion": "npm test", "postversion": "npm publish", - "prepublishOnly": "git push --follow-tags", + "prepublishOnly": "git push origin --follow-tags", "snap": "tap", - "test": "tap" + "test": "tap", + "lint": "eslint '**/*.js'", + "postlint": "npm-template-check", + "lintfix": "npm run lint -- --fix", + "posttest": "npm run lint" }, "repository": { "type": "git", @@ -26,9 +30,10 @@ "npm-normalize-package-bin": "^1.0.0", "read-cmd-shim": "^2.0.0", "rimraf": "^3.0.0", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.0" }, "devDependencies": { + "@npmcli/template-oss": "^2.5.0", "mkdirp": "^1.0.3", "require-inject": "^1.4.4", "tap": "^15.0.10" @@ -38,10 +43,15 @@ "coverage-map": "map.js" }, "files": [ - "index.js", - "lib/*.js" + "bin", + "lib" ], "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16" + }, + "author": "GitHub Inc.", + "templateOSS": { + "windowsCI": false, + "version": "2.5.0" } } diff --git a/node_modules/typedarray-to-buffer/.airtap.yml b/node_modules/typedarray-to-buffer/.airtap.yml deleted file mode 100644 index 3417780255e8e..0000000000000 --- a/node_modules/typedarray-to-buffer/.airtap.yml +++ /dev/null @@ -1,15 +0,0 @@ -sauce_connect: true -loopback: airtap.local -browsers: - - name: chrome - version: latest - - name: firefox - version: latest - - name: safari - version: latest - - name: microsoftedge - version: latest - - name: ie - version: latest - - name: iphone - version: latest diff --git a/node_modules/typedarray-to-buffer/index.js b/node_modules/typedarray-to-buffer/index.js index 5fa394dd201d2..fd1e192b2656b 100644 --- a/node_modules/typedarray-to-buffer/index.js +++ b/node_modules/typedarray-to-buffer/index.js @@ -1,3 +1,4 @@ +/*! typedarray-to-buffer. MIT License. Feross Aboukhadijeh */ /** * Convert a typed array to a Buffer without a copy * @@ -7,19 +8,11 @@ * `npm install typedarray-to-buffer` */ -var isTypedArray = require('is-typedarray').strict - module.exports = function typedarrayToBuffer (arr) { - if (isTypedArray(arr)) { - // To avoid a copy, use the typed array's underlying ArrayBuffer to back new Buffer - var buf = Buffer.from(arr.buffer) - if (arr.byteLength !== arr.buffer.byteLength) { - // Respect the "view", i.e. byteOffset and byteLength, without doing a copy - buf = buf.slice(arr.byteOffset, arr.byteOffset + arr.byteLength) - } - return buf - } else { + return ArrayBuffer.isView(arr) + // To avoid a copy, use the typed array's underlying ArrayBuffer to back + // new Buffer, respecting the "view", i.e. byteOffset and byteLength + ? Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength) // Pass through all other types to `Buffer.from` - return Buffer.from(arr) - } + : Buffer.from(arr) } diff --git a/node_modules/typedarray-to-buffer/package.json b/node_modules/typedarray-to-buffer/package.json index 5ec5656157991..502a322c6d746 100644 --- a/node_modules/typedarray-to-buffer/package.json +++ b/node_modules/typedarray-to-buffer/package.json @@ -1,22 +1,20 @@ { "name": "typedarray-to-buffer", "description": "Convert a typed array to a Buffer without a copy", - "version": "3.1.5", + "version": "4.0.0", "author": { "name": "Feross Aboukhadijeh", "email": "feross@feross.org", - "url": "http://feross.org/" + "url": "https://feross.org" }, "bugs": { "url": "https://github.com/feross/typedarray-to-buffer/issues" }, - "dependencies": { - "is-typedarray": "^1.0.0" - }, + "dependencies": {}, "devDependencies": { - "airtap": "0.0.4", + "airtap": "^3.0.0", "standard": "*", - "tape": "^4.0.0" + "tape": "^5.0.1" }, "homepage": "http://feross.org", "keywords": [ @@ -46,5 +44,19 @@ "test-browser": "airtap -- test/*.js", "test-browser-local": "airtap --local -- test/*.js", "test-node": "tape test/*.js" - } + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] } diff --git a/node_modules/typedarray-to-buffer/test/basic.js b/node_modules/typedarray-to-buffer/test/basic.js deleted file mode 100644 index 352109682f5c1..0000000000000 --- a/node_modules/typedarray-to-buffer/test/basic.js +++ /dev/null @@ -1,50 +0,0 @@ -var test = require('tape') -var toBuffer = require('../') - -test('convert to buffer from Uint8Array', function (t) { - if (typeof Uint8Array !== 'undefined') { - var arr = new Uint8Array([1, 2, 3]) - arr = toBuffer(arr) - - t.deepEqual(arr, Buffer.from([1, 2, 3]), 'contents equal') - t.ok(Buffer.isBuffer(arr), 'is buffer') - t.equal(arr.readUInt8(0), 1) - t.equal(arr.readUInt8(1), 2) - t.equal(arr.readUInt8(2), 3) - } else { - t.pass('browser lacks Uint8Array support, skip test') - } - t.end() -}) - -test('convert to buffer from another arrayview type (Uint32Array)', function (t) { - if (typeof Uint32Array !== 'undefined' && Buffer.TYPED_ARRAY_SUPPORT !== false) { - var arr = new Uint32Array([1, 2, 3]) - arr = toBuffer(arr) - - t.deepEqual(arr, Buffer.from([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]), 'contents equal') - t.ok(Buffer.isBuffer(arr), 'is buffer') - t.equal(arr.readUInt32LE(0), 1) - t.equal(arr.readUInt32LE(4), 2) - t.equal(arr.readUInt32LE(8), 3) - t.equal(arr instanceof Uint8Array, true) - } else { - t.pass('browser lacks Uint32Array support, skip test') - } - t.end() -}) - -test('convert to buffer from ArrayBuffer', function (t) { - if (typeof Uint32Array !== 'undefined' && Buffer.TYPED_ARRAY_SUPPORT !== false) { - var arr = new Uint32Array([1, 2, 3]).subarray(1, 2) - arr = toBuffer(arr) - - t.deepEqual(arr, Buffer.from([2, 0, 0, 0]), 'contents equal') - t.ok(Buffer.isBuffer(arr), 'is buffer') - t.equal(arr.readUInt32LE(0), 2) - t.equal(arr instanceof Uint8Array, true) - } else { - t.pass('browser lacks ArrayBuffer support, skip test') - } - t.end() -}) diff --git a/node_modules/write-file-atomic/LICENSE b/node_modules/write-file-atomic/LICENSE.md similarity index 100% rename from node_modules/write-file-atomic/LICENSE rename to node_modules/write-file-atomic/LICENSE.md diff --git a/node_modules/write-file-atomic/index.js b/node_modules/write-file-atomic/lib/index.js similarity index 94% rename from node_modules/write-file-atomic/index.js rename to node_modules/write-file-atomic/lib/index.js index df5b72a14f74a..9a7d183aecb4c 100644 --- a/node_modules/write-file-atomic/index.js +++ b/node_modules/write-file-atomic/lib/index.js @@ -48,10 +48,14 @@ function cleanupOnExit (tmpfile) { function serializeActiveFile (absoluteName) { return new Promise(resolve => { // make a queue if it doesn't already exist - if (!activeFiles[absoluteName]) activeFiles[absoluteName] = [] + if (!activeFiles[absoluteName]) { + activeFiles[absoluteName] = [] + } activeFiles[absoluteName].push(resolve) // add this job to the queue - if (activeFiles[absoluteName].length === 1) resolve() // kick off the first one + if (activeFiles[absoluteName].length === 1) { + resolve() + } // kick off the first one }) } @@ -151,7 +155,9 @@ async function writeFileAsync (filename, data, options = {}) { activeFiles[absoluteName].shift() // remove the element added by serializeSameFile if (activeFiles[absoluteName].length > 0) { activeFiles[absoluteName][0]() // start next job if one is pending - } else delete activeFiles[absoluteName] + } else { + delete activeFiles[absoluteName] + } } } @@ -170,8 +176,11 @@ function writeFile (filename, data, options, callback) { } function writeFileSync (filename, data, options) { - if (typeof options === 'string') options = { encoding: options } - else if (!options) options = {} + if (typeof options === 'string') { + options = { encoding: options } + } else if (!options) { + options = {} + } try { filename = fs.realpathSync(filename) } catch (ex) { diff --git a/node_modules/write-file-atomic/package.json b/node_modules/write-file-atomic/package.json index 98a29a053453a..031eccdba8707 100644 --- a/node_modules/write-file-atomic/package.json +++ b/node_modules/write-file-atomic/package.json @@ -1,16 +1,18 @@ { "name": "write-file-atomic", - "version": "3.0.3", + "version": "4.0.0", "description": "Write files in an atomic fashion w/configurable ownership", - "main": "index.js", + "main": "./lib/index.js", "scripts": { "test": "tap", "posttest": "npm run lint", - "lint": "standard", - "postlint": "rimraf chowncopy good nochmod nochown nofsync nofsyncopt noopen norename \"norename nounlink\" nowrite", + "lint": "eslint '**/*.js'", + "postlint": "npm-template-check", "preversion": "npm test", "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags" + "prepublishOnly": "git push origin --follow-tags", + "lintfix": "npm run lint -- --fix", + "snap": "tap" }, "repository": { "type": "git", @@ -20,7 +22,7 @@ "writeFile", "atomic" ], - "author": "Rebecca Turner (http://re-becca.org)", + "author": "GitHub Inc.", "license": "ISC", "bugs": { "url": "https://github.com/npm/write-file-atomic/issues" @@ -30,19 +32,23 @@ "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "typedarray-to-buffer": "^4.0.0" }, "devDependencies": { - "mkdirp": "^0.5.1", - "require-inject": "^1.4.4", - "rimraf": "^2.6.3", - "standard": "^14.3.1", - "tap": "^14.10.6" + "@npmcli/template-oss": "^2.5.1", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2", + "tap": "^15.1.6" }, "files": [ - "index.js" + "bin", + "lib" ], - "tap": { - "100": true + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" + }, + "templateOSS": { + "windowsCI": false, + "version": "2.5.1" } } diff --git a/package-lock.json b/package-lock.json index 5498b54d795d3..f38e1e4f75c63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "8.3.1", + "version": "8.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "npm", - "version": "8.3.1", + "version": "8.3.2", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -87,7 +87,7 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^4.2.0", + "@npmcli/arborist": "^4.2.1", "@npmcli/ci-detect": "^1.4.0", "@npmcli/config": "^2.4.0", "@npmcli/map-workspaces": "^2.0.0", @@ -156,7 +156,7 @@ "treeverse": "^1.0.4", "validate-npm-package-name": "~3.0.0", "which": "^2.0.2", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.0" }, "bin": { "npm": "bin/npm-cli.js", @@ -1435,19 +1435,19 @@ } }, "node_modules/bin-links": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-2.3.0.tgz", - "integrity": "sha512-JzrOLHLwX2zMqKdyYZjkDgQGT+kHDkIhv2/IK2lJ00qLxV4TmFoHi8drDBb6H5Zrz1YfgHkai4e2MGPqnoUhqA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.0.tgz", + "integrity": "sha512-fC7kPWcEkAWBgCKxmAMqZldlIeHsXwQy9JXzrppAVQiukGiDKxmYesJcBKWu6UMwx/5GOfo10wtK/4zy+Xt/mg==", "dependencies": { "cmd-shim": "^4.0.1", "mkdirp-infer-owner": "^2.0.0", "npm-normalize-package-bin": "^1.0.0", "read-cmd-shim": "^2.0.0", "rimraf": "^3.0.0", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || >=16" } }, "node_modules/binary-extensions": { @@ -1595,6 +1595,27 @@ "node": ">=8" } }, + "node_modules/caching-transform/node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/caching-transform/node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -9597,13 +9618,24 @@ } }, "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "inBundle": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true }, "node_modules/typescript": { "version": "3.9.10", @@ -10145,15 +10177,18 @@ "inBundle": true }, "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.0.tgz", + "integrity": "sha512-JhcWoKffJNF7ivO9yflBhc7tn3wKnokMUfWpBriM9yCXj4ePQnRPcWglBkkg1AHC8nsW/EfxwwhqsLtOy59djA==", "inBundle": true, "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "typedarray-to-buffer": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" } }, "node_modules/ws": { @@ -10447,7 +10482,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "4.2.0", + "version": "4.2.1", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -10459,7 +10494,7 @@ "@npmcli/node-gyp": "^1.0.3", "@npmcli/package-json": "^1.0.1", "@npmcli/run-script": "^2.0.0", - "bin-links": "^2.3.0", + "bin-links": "^3.0.0", "cacache": "^15.0.3", "common-ancestor-path": "^1.0.1", "json-parse-even-better-errors": "^2.3.1", @@ -10572,7 +10607,7 @@ }, "devDependencies": { "@npmcli/template-oss": "^2.4.2", - "bin-links": "^2.2.1", + "bin-links": "^3.0.0", "tap": "^15.0.6" }, "engines": { @@ -11372,7 +11407,7 @@ "@npmcli/run-script": "^2.0.0", "@npmcli/template-oss": "^2.4.2", "benchmark": "^2.1.4", - "bin-links": "^2.3.0", + "bin-links": "^3.0.0", "cacache": "^15.0.3", "chalk": "^4.1.0", "common-ancestor-path": "^1.0.1", @@ -11890,16 +11925,16 @@ } }, "bin-links": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-2.3.0.tgz", - "integrity": "sha512-JzrOLHLwX2zMqKdyYZjkDgQGT+kHDkIhv2/IK2lJ00qLxV4TmFoHi8drDBb6H5Zrz1YfgHkai4e2MGPqnoUhqA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.0.tgz", + "integrity": "sha512-fC7kPWcEkAWBgCKxmAMqZldlIeHsXwQy9JXzrppAVQiukGiDKxmYesJcBKWu6UMwx/5GOfo10wtK/4zy+Xt/mg==", "requires": { "cmd-shim": "^4.0.1", "mkdirp-infer-owner": "^2.0.0", "npm-normalize-package-bin": "^1.0.0", "read-cmd-shim": "^2.0.0", "rimraf": "^3.0.0", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.0" } }, "binary-extensions": { @@ -12013,6 +12048,29 @@ "make-dir": "^3.0.0", "package-hash": "^4.0.0", "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + } } }, "call-bind": { @@ -14384,7 +14442,7 @@ "@npmcli/ci-detect": "^1.3.0", "@npmcli/run-script": "^2.0.0", "@npmcli/template-oss": "^2.4.2", - "bin-links": "^2.2.1", + "bin-links": "^3.0.0", "chalk": "^4.1.0", "mkdirp-infer-owner": "^2.0.0", "npm-package-arg": "^8.1.2", @@ -18000,12 +18058,9 @@ "dev": true }, "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==" }, "typescript": { "version": "3.9.10", @@ -18414,14 +18469,14 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.0.tgz", + "integrity": "sha512-JhcWoKffJNF7ivO9yflBhc7tn3wKnokMUfWpBriM9yCXj4ePQnRPcWglBkkg1AHC8nsW/EfxwwhqsLtOy59djA==", "requires": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "typedarray-to-buffer": "^4.0.0" } }, "ws": { diff --git a/package.json b/package.json index a4a5fcc6e8d4d..508f615847123 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "8.3.1", + "version": "8.3.2", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -55,7 +55,7 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^4.2.0", + "@npmcli/arborist": "^4.2.1", "@npmcli/ci-detect": "^1.4.0", "@npmcli/config": "^2.4.0", "@npmcli/map-workspaces": "^2.0.0", @@ -124,7 +124,7 @@ "treeverse": "^1.0.4", "validate-npm-package-name": "~3.0.0", "which": "^2.0.2", - "write-file-atomic": "^3.0.3" + "write-file-atomic": "^4.0.0" }, "bundleDependencies": [ "@isaacs/string-locale-compare", diff --git a/smoke-tests/index.js b/smoke-tests/index.js index 06ca3dee6422e..83e54ae9fc9dc 100644 --- a/smoke-tests/index.js +++ b/smoke-tests/index.js @@ -267,3 +267,56 @@ t.test('npm pkg', async t => { 'should have expected npm pkg delete modified package.json result' ) }) + +t.test('npm update --no-save --no-package-lock', async t => { + // setup, manually reset dep value + await exec(`${npmBin} pkg set "dependencies.abbrev==1.0.4"`) + await exec(`${npmBin} install`) + await exec(`${npmBin} pkg set "dependencies.abbrev=^1.0.4"`) + + const cmd = `${npmBin} update --no-save --no-package-lock` + await exec(cmd) + + t.equal( + JSON.parse(readFile('package.json')).dependencies.abbrev, + '^1.0.4', + 'should have expected update --no-save --no-package-lock package.json result' + ) + t.equal( + JSON.parse(readFile('package-lock.json')).packages['node_modules/abbrev'].version, + '1.0.4', + 'should have expected update --no-save --no-package-lock lockfile result' + ) +}) + +t.test('npm update --no-save', async t => { + const cmd = `${npmBin} update --no-save` + await exec(cmd) + + t.equal( + JSON.parse(readFile('package.json')).dependencies.abbrev, + '^1.0.4', + 'should have expected update --no-save package.json result' + ) + t.equal( + JSON.parse(readFile('package-lock.json')).packages['node_modules/abbrev'].version, + '1.1.1', + 'should have expected update --no-save lockfile result' + ) +}) + +t.test('npm update --save', async t => { + const cmd = `${npmBin} update --save` + await exec(cmd) + + t.equal( + JSON.parse(readFile('package.json')).dependencies.abbrev, + '^1.1.1', + 'should have expected update --save package.json result' + ) + t.equal( + JSON.parse(readFile('package-lock.json')).packages['node_modules/abbrev'].version, + '1.1.1', + 'should have expected update --save lockfile result' + ) +}) 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 6efecf2089e83..e7142c2492322 100644 --- a/tap-snapshots/test/lib/load-all-commands.js.test.cjs +++ b/tap-snapshots/test/lib/load-all-commands.js.test.cjs @@ -170,6 +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] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] @@ -1061,8 +1062,10 @@ npm update [...] Options: [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] -[--no-package-lock] [--omit [--omit ...]] -[--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] +[--no-package-lock] +[-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] +[--omit [--omit ...]] [--ignore-scripts] +[--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] 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 84bb22ff0ef59..459c5de8dc284 100644 --- a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -1406,13 +1406,16 @@ The base URL of the npm registry. exports[`test/lib/utils/config/definitions.js TAP > config description for save 1`] = ` #### \`save\` -* Default: true +* Default: \`true\` unless when using \`npm update\` or \`npm dedupe\` where it + defaults to \`false\` * Type: Boolean -Save installed packages to a package.json file as dependencies. +Save installed packages to a \`package.json\` file as dependencies. When used with the \`npm rm\` command, removes the dependency from -package.json. +\`package.json\`. + +Will also prevent writing to \`package-lock.json\` if set to \`false\`. ` exports[`test/lib/utils/config/definitions.js TAP > config description for save-bundle 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 3db90f7679d4e..ffa6617328bc6 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 @@ -1200,13 +1200,16 @@ The base URL of the npm registry. #### \`save\` -* Default: true +* Default: \`true\` unless when using \`npm update\` or \`npm dedupe\` where it + defaults to \`false\` * Type: Boolean -Save installed packages to a package.json file as dependencies. +Save installed packages to a \`package.json\` file as dependencies. When used with the \`npm rm\` command, removes the dependency from -package.json. +\`package.json\`. + +Will also prevent writing to \`package-lock.json\` if set to \`false\`. 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 0e48cfa613149..ab8f1cf3b4e87 100644 --- a/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs +++ b/tap-snapshots/test/lib/utils/npm-usage.js.test.cjs @@ -311,6 +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] [--omit [--omit ...]] [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] @@ -1096,8 +1097,10 @@ All commands: Options: [-g|--global] [--global-style] [--legacy-bundling] [--strict-peer-deps] - [--no-package-lock] [--omit [--omit ...]] - [--ignore-scripts] [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] + [--no-package-lock] + [-S|--save|--no-save|--save-prod|--save-dev|--save-optional|--save-peer] + [--omit [--omit ...]] [--ignore-scripts] + [--no-audit] [--no-bin-links] [--no-fund] [--dry-run] [-w|--workspace [-w|--workspace ...]] [-ws|--workspaces] [--include-workspace-root] diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js index 7518855319b4a..c3dc47f5dde4f 100644 --- a/test/fixtures/mock-npm.js +++ b/test/fixtures/mock-npm.js @@ -147,6 +147,8 @@ class MockNpm { // for now just set `find` to what config.find should return // this works cause `find` is not an existing config entry find: (k) => ({ ...realConfig.defaults, ...config })[k], + // for now isDefault is going to just return false if a value was defined + isDefault: (k) => !Object.prototype.hasOwnProperty.call(config, k), get: (k) => ({ ...realConfig.defaults, ...config })[k], set: (k, v) => config[k] = v, list: [{ ...realConfig.defaults, ...config }], diff --git a/test/lib/arborist-cmd.js b/test/lib/arborist-cmd.js index 3db862d233dc7..91d8a7b333bf9 100644 --- a/test/lib/arborist-cmd.js +++ b/test/lib/arborist-cmd.js @@ -98,7 +98,7 @@ t.test('handle getWorkspaces raising an error', async t => { }) class TestCmd extends ArboristCmd {} const cmd = new TestCmd() - cmd.npm = {} + cmd.npm = { localPrefix: t.testdir() } await t.rejects( cmd.execWorkspaces(['foo'], ['a']), diff --git a/test/lib/commands/dedupe.js b/test/lib/commands/dedupe.js index 2e2fae238103f..bf6964081ca79 100644 --- a/test/lib/commands/dedupe.js +++ b/test/lib/commands/dedupe.js @@ -38,11 +38,12 @@ t.test('should remove dupes using Arborist', async (t) => { }) t.test('should remove dupes using Arborist - no arguments', async (t) => { - t.plan(1) + t.plan(2) const { npm } = await loadMockNpm(t, { mocks: { '@npmcli/arborist': function (args) { t.ok(args.dryRun, 'gets dryRun from config') + t.ok(args.save, 'gets user-set save value from config') this.dedupe = () => {} }, '../../lib/utils/reify-output.js': () => {}, @@ -50,6 +51,7 @@ t.test('should remove dupes using Arborist - no arguments', async (t) => { }, config: { 'dry-run': true, + save: true, }, }) await npm.exec('dedupe', []) diff --git a/test/lib/commands/update.js b/test/lib/commands/update.js index aecb2c32b5e3f..2b464bfabbfcd 100644 --- a/test/lib/commands/update.js +++ b/test/lib/commands/update.js @@ -27,7 +27,7 @@ t.afterEach(() => { }) t.test('no args', async t => { - t.plan(4) + t.plan(5) npm.prefix = '/project/a' @@ -39,6 +39,7 @@ t.test('no args', async t => { { ...npm.flatOptions, path: npm.prefix, + save: false, workspaces: null, }, 'should call arborist contructor with expected args' @@ -46,7 +47,8 @@ t.test('no args', async t => { t.match(log, {}, 'log is passed in') } - reify ({ update }) { + reify ({ save, update }) { + t.equal(save, false, 'should default to save=false') t.equal(update, true, 'should update all deps') } } @@ -64,9 +66,10 @@ t.test('no args', async t => { }) t.test('with args', async t => { - t.plan(4) + t.plan(5) npm.prefix = '/project/a' + config.save = true class Arborist { constructor (args) { @@ -76,6 +79,7 @@ t.test('with args', async t => { { ...npm.flatOptions, path: npm.prefix, + save: true, workspaces: null, }, 'should call arborist contructor with expected args' @@ -83,7 +87,8 @@ t.test('with args', async t => { t.match(log, {}, 'log is passed in') } - reify ({ update }) { + reify ({ save, update }) { + t.equal(save, true, 'should pass save if manually set') t.same(update, ['ipt'], 'should update listed deps') } } @@ -140,7 +145,7 @@ t.test('update --global', async t => { const { path, log, ...rest } = args t.same( rest, - { ...npm.flatOptions, workspaces: undefined }, + { ...npm.flatOptions, save: true, workspaces: undefined }, 'should call arborist contructor with expected options' ) diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index 899d92ca937cc..f20a554bd5ee8 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -41,7 +41,7 @@ const _complete = Symbol('complete') const _depsSeen = Symbol('depsSeen') const _depsQueue = Symbol('depsQueue') const _currentDep = Symbol('currentDep') -const _updateAll = Symbol('updateAll') +const _updateAll = Symbol.for('updateAll') const _mutateTree = Symbol('mutateTree') const _flagsSuspect = Symbol.for('flagsSuspect') const _workspaces = Symbol.for('workspaces') @@ -176,7 +176,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { // public method async buildIdealTree (options = {}) { if (this.idealTree) { - return Promise.resolve(this.idealTree) + return this.idealTree } // allow the user to set reify options on the ctor as well. @@ -194,8 +194,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { process.emit('time', 'idealTree') if (!options.add && !options.rm && !options.update && this[_global]) { - const er = new Error('global requires add, rm, or update option') - return Promise.reject(er) + throw new Error('global requires add, rm, or update option') } // first get the virtual tree, if possible. If there's a lockfile, then @@ -334,6 +333,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { root.meta.lockfileVersion = defaultLockfileVersion } } + root.meta.inferFormattingOptions(root.package) return root }) @@ -1180,6 +1180,11 @@ This is a one-time fix-up, please be patient... return true } + // If the edge is a workspace, and it's valid, leave it alone + if (edge.to.isWorkspace) { + return false + } + // user explicitly asked to update this package by name, problem if (this[_updateNames].includes(edge.name)) { return true diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 547e54ac37670..d5e70323830b6 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -58,6 +58,8 @@ const _bundleUnpacked = Symbol('bundleUnpacked') const _bundleMissing = Symbol('bundleMissing') const _reifyNode = Symbol.for('reifyNode') const _extractOrLink = Symbol('extractOrLink') +const _updateAll = Symbol.for('updateAll') +const _updateNames = Symbol.for('updateNames') // defined by rebuild mixin const _checkBins = Symbol.for('checkBins') const _symlink = Symbol('symlink') @@ -1140,21 +1142,33 @@ module.exports = cls => class Reifier extends cls { // for install failures. Those still end up in the shrinkwrap, so we // save it first, then prune out the optional trash, and then return it. - // support save=false option - if (options.save === false || this[_global] || this[_dryRun]) { + const save = !(options.save === false) + + // we check for updates in order to make sure we run save ideal tree + // even though save=false since we want `npm update` to be able to + // write to package-lock files by default + const hasUpdates = this[_updateAll] || this[_updateNames].length + + // we're going to completely skip save ideal tree in case of a global or + // dry-run install and also if the save option is set to false, EXCEPT for + // update since the expected behavior for npm7+ is for update to + // NOT save to package.json, we make that exception since we still want + // saveIdealTree to be able to write the lockfile by default. + const saveIdealTree = !( + (!save && !hasUpdates) + || this[_global] + || this[_dryRun] + ) + + if (!saveIdealTree) { return false } process.emit('time', 'reify:save') const updatedTrees = new Set() - - // resolvedAdd is the list of user add requests, but with names added - // to things like git repos and tarball file/urls. However, if the - // user requested 'foo@', and we have a foo@file:../foo, then we should - // end up saving the spec we actually used, not whatever they gave us. - if (this[_resolvedAdd].length) { - for (const { name, tree: addTree } of this[_resolvedAdd]) { + const updateNodes = nodes => { + for (const { name, tree: addTree } of nodes) { // addTree either the root, or a workspace const edge = addTree.edgesOut.get(name) const pkg = addTree.package @@ -1168,7 +1182,7 @@ module.exports = cls => class Reifier extends cls { // that we couldn't resolve, this MAY be missing. if we haven't // blown up by now, it's because it was not a problem, though, so // just move on. - if (!child) { + if (!child || !addTree.isTop) { continue } @@ -1259,6 +1273,63 @@ module.exports = cls => class Reifier extends cls { } } + // helper that retrieves an array of nodes that were + // potentially updated during the reify process, in order + // to limit the number of nodes to check and update, only + // select nodes from the inventory that are direct deps + // of a given package.json (project root or a workspace) + // and in ase of using a list of `names`, restrict nodes + // to only names that are found in this list + const retrieveUpdatedNodes = names => { + const filterDirectDependencies = node => + !node.isRoot && node.resolveParent.isRoot + && (!names || names.includes(node.name)) + const directDeps = this.idealTree.inventory + .filter(filterDirectDependencies) + + // traverses the list of direct dependencies and collect all nodes + // to be updated, since any of them might have changed during reify + const nodes = [] + for (const node of directDeps) { + for (const edgeIn of node.edgesIn) { + nodes.push({ + name: node.name, + tree: edgeIn.from.target, + }) + } + } + return nodes + } + + if (save) { + // when using update all alongside with save, we'll make + // sure to refresh every dependency of the root idealTree + if (this[_updateAll]) { + const nodes = retrieveUpdatedNodes() + updateNodes(nodes) + } else { + // resolvedAdd is the list of user add requests, but with names added + // to things like git repos and tarball file/urls. However, if the + // user requested 'foo@', and we have a foo@file:../foo, then we should + // end up saving the spec we actually used, not whatever they gave us. + if (this[_resolvedAdd].length) { + updateNodes(this[_resolvedAdd]) + } + + // if updating given dependencies by name, restrict the list of + // nodes to check to only those currently in _updateNames + if (this[_updateNames].length) { + const nodes = retrieveUpdatedNodes(this[_updateNames]) + updateNodes(nodes) + } + + // grab any from explicitRequests that had deps removed + for (const { from: tree } of this.explicitRequests) { + updatedTrees.add(tree) + } + } + } + // preserve indentation, if possible const { [Symbol.for('indent')]: indent, @@ -1291,15 +1362,12 @@ module.exports = cls => class Reifier extends cls { await pkgJson.save() } - // grab any from explicitRequests that had deps removed - for (const { from: tree } of this.explicitRequests) { - updatedTrees.add(tree) - } - - for (const tree of updatedTrees) { - // refresh the edges so they have the correct specs - tree.package = tree.package - promises.push(updatePackageJson(tree)) + if (save) { + for (const tree of updatedTrees) { + // refresh the edges so they have the correct specs + tree.package = tree.package + promises.push(updatePackageJson(tree)) + } } await Promise.all(promises) diff --git a/workspaces/arborist/lib/shrinkwrap.js b/workspaces/arborist/lib/shrinkwrap.js index a7a68c98c6d6d..b45fea0ac6111 100644 --- a/workspaces/arborist/lib/shrinkwrap.js +++ b/workspaces/arborist/lib/shrinkwrap.js @@ -424,6 +424,18 @@ class Shrinkwrap { .map(fn => fn && maybeStatFile(fn))) } + inferFormattingOptions (packageJSONData) { + // don't use detect-indent, just pick the first line. + // if the file starts with {" then we have an indent of '', ie, none + // which will default to 2 at save time. + const { + [Symbol.for('indent')]: indent, + [Symbol.for('newline')]: newline, + } = packageJSONData + this.indent = indent !== undefined ? indent : this.indent + this.newline = newline !== undefined ? newline : this.newline + } + load () { // we don't need to load package-lock.json except for top of tree nodes, // only npm-shrinkwrap.json. @@ -451,15 +463,7 @@ class Shrinkwrap { return data ? parseJSON(data) : {} }).then(async data => { - // don't use detect-indent, just pick the first line. - // if the file starts with {" then we have an indent of '', ie, none - // which will default to 2 at save time. - const { - [Symbol.for('indent')]: indent, - [Symbol.for('newline')]: newline, - } = data - this.indent = indent !== undefined ? indent : this.indent - this.newline = newline !== undefined ? newline : this.newline + this.inferFormattingOptions(data) if (!this.hiddenLockfile || !data.packages) { return data diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index ac2922bc9655d..493a0a78c5c46 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "4.2.0", + "version": "4.2.1", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -12,7 +12,7 @@ "@npmcli/node-gyp": "^1.0.3", "@npmcli/package-json": "^1.0.1", "@npmcli/run-script": "^2.0.0", - "bin-links": "^2.3.0", + "bin-links": "^3.0.0", "cacache": "^15.0.3", "common-ancestor-path": "^1.0.1", "json-parse-even-better-errors": "^2.3.1", diff --git a/workspaces/arborist/tap-snapshots/test/arborist/build-ideal-tree.js.test.cjs b/workspaces/arborist/tap-snapshots/test/arborist/build-ideal-tree.js.test.cjs index ca47bbbe1b135..93ea45862e8f8 100644 --- a/workspaces/arborist/tap-snapshots/test/arborist/build-ideal-tree.js.test.cjs +++ b/workspaces/arborist/tap-snapshots/test/arborist/build-ideal-tree.js.test.cjs @@ -97673,6 +97673,37 @@ ArboristNode { } ` +exports[`test/arborist/build-ideal-tree.js TAP store files with a custom indenting > must match snapshot 1`] = ` +{ + "name": "tab-indented-package-json", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "tab-indented-package-json", + "version": "1.0.0", + "dependencies": { + "abbrev": "^1.0.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + } + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + } + } +} + +` + exports[`test/arborist/build-ideal-tree.js TAP tap vs react15 > build ideal tree with tap collision 1`] = ` ArboristNode { "children": Map { @@ -159178,6 +159209,106 @@ ArboristNode { } ` +exports[`test/arborist/build-ideal-tree.js TAP workspaces should allow adding a workspace as a dep to a workspace > must match snapshot 1`] = ` +ArboristNode { + "children": Map { + "workspace-a" => ArboristLink { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "workspace-a", + "spec": "file:{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-a", + "type": "workspace", + }, + }, + "isWorkspace": true, + "location": "node_modules/workspace-a", + "name": "workspace-a", + "path": "{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/node_modules/workspace-a", + "realpath": "{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-a", + "resolved": "file:../workspace-a", + "target": ArboristNode { + "location": "workspace-a", + }, + "version": "1.0.0", + }, + "workspace-b" => ArboristLink { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "workspace-b", + "spec": "file:{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-b", + "type": "workspace", + }, + EdgeIn { + "from": "workspace-a", + "name": "workspace-b", + "spec": "*", + "type": "prod", + }, + }, + "isWorkspace": true, + "location": "node_modules/workspace-b", + "name": "workspace-b", + "path": "{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/node_modules/workspace-b", + "realpath": "{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-b", + "resolved": "file:../workspace-b", + "target": ArboristNode { + "location": "workspace-b", + }, + "version": "1.0.0", + }, + }, + "edgesOut": Map { + "workspace-a" => EdgeOut { + "name": "workspace-a", + "spec": "file:{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-a", + "to": "node_modules/workspace-a", + "type": "workspace", + }, + "workspace-b" => EdgeOut { + "name": "workspace-b", + "spec": "file:{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-b", + "to": "node_modules/workspace-b", + "type": "workspace", + }, + }, + "fsChildren": Set { + ArboristNode { + "edgesOut": Map { + "workspace-b" => EdgeOut { + "name": "workspace-b", + "spec": "*", + "to": "node_modules/workspace-b", + "type": "prod", + }, + }, + "isWorkspace": true, + "location": "workspace-a", + "name": "workspace-a", + "path": "{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-a", + "version": "1.0.0", + }, + ArboristNode { + "isWorkspace": true, + "location": "workspace-b", + "name": "workspace-b", + "path": "{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace/workspace-b", + "version": "1.0.0", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace", + "packageName": "root", + "path": "{CWD}/test/arborist/tap-testdir-build-ideal-tree-workspaces-should-allow-adding-a-workspace-as-a-dep-to-a-workspace", + "workspaces": Map { + "workspace-a" => "workspace-a", + "workspace-b" => "workspace-b", + }, +} +` + exports[`test/arborist/build-ideal-tree.js TAP workspaces should ignore nested node_modules folders > expect resolving Promise 1`] = ` ArboristNode { "children": Map { 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 7a6a3e714ba51..6d38d724dca22 100644 --- a/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs +++ b/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs @@ -17113,7 +17113,7 @@ ArboristNode { } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-allinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-allinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-fail-allinstall" => EdgeOut { @@ -17125,14 +17125,52 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-false", "packageName": "optional-dep-allinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-install-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-allinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-fail-allinstall" => EdgeOut { + "name": "@isaacs/testing-fail-allinstall", + "spec": "^1.0.0", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-true", + "packageName": "optional-dep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-install-fail save=false > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-fail-install" => EdgeOut { + "name": "@isaacs/testing-fail-install", + "spec": "^1.0.0", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-false", + "packageName": "optional-dep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-install-fail save=true > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-fail-install" => EdgeOut { @@ -17144,14 +17182,51 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-true", "packageName": "optional-dep-install-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-postinstall-fail save=false > expect resolving Promise 1`] = ` +ArboristNode { + "children": Map { + "@isaacs/testing-fail-postinstall" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-fail-postinstall", + "spec": "^1.0.0", + "type": "optional", + }, + }, + "location": "node_modules/@isaacs/testing-fail-postinstall", + "name": "@isaacs/testing-fail-postinstall", + "optional": true, + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-false/node_modules/@isaacs/testing-fail-postinstall", + "resolved": "https://registry.npmjs.org/@isaacs/testing-fail-postinstall/-/testing-fail-postinstall-1.0.0.tgz", + "version": "1.0.0", + }, + }, + "edgesOut": Map { + "@isaacs/testing-fail-postinstall" => EdgeOut { + "name": "@isaacs/testing-fail-postinstall", + "spec": "^1.0.0", + "to": "node_modules/@isaacs/testing-fail-postinstall", + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-false", + "packageName": "optional-dep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-postinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-postinstall-fail save=true > expect resolving Promise 1`] = ` ArboristNode { "children": Map { "@isaacs/testing-fail-postinstall" => ArboristNode { @@ -17166,7 +17241,7 @@ ArboristNode { "location": "node_modules/@isaacs/testing-fail-postinstall", "name": "@isaacs/testing-fail-postinstall", "optional": true, - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail/node_modules/@isaacs/testing-fail-postinstall", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-true/node_modules/@isaacs/testing-fail-postinstall", "resolved": "https://registry.npmjs.org/@isaacs/testing-fail-postinstall/-/testing-fail-postinstall-1.0.0.tgz", "version": "1.0.0", }, @@ -17181,14 +17256,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-true", "packageName": "optional-dep-postinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-preinstall-fail save=false > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-fail-preinstall" => EdgeOut { + "name": "@isaacs/testing-fail-preinstall", + "spec": "^1.0.0", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-false", + "packageName": "optional-dep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-preinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-preinstall-fail save=true > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-fail-preinstall" => EdgeOut { @@ -17200,14 +17294,14 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-true", "packageName": "optional-dep-preinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-tgz-missing > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-tgz-missing save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-missing-tgz" => EdgeOut { @@ -17219,14 +17313,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-false", + "packageName": "@isaacs/testing-optional-dep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-tgz-missing save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-missing-tgz" => EdgeOut { + "name": "@isaacs/testing-missing-tgz", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-true", "packageName": "@isaacs/testing-optional-dep-tgz-missing", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-allinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-allinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-allinstall-fail" => EdgeOut { @@ -17238,14 +17351,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-false", + "packageName": "optional-metadep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-allinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-allinstall-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-allinstall-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-true", "packageName": "optional-metadep-allinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-install-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-install-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-install-fail" => EdgeOut { @@ -17257,14 +17389,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-false", + "packageName": "optional-metadep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-install-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-install-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-install-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-true", "packageName": "optional-metadep-install-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-postinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-postinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-postinstall-fail" => EdgeOut { @@ -17276,14 +17427,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-false", + "packageName": "optional-metadep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-postinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-postinstall-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-postinstall-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-true", "packageName": "optional-metadep-postinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-preinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-preinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-preinstall-fail" => EdgeOut { @@ -17295,14 +17465,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-false", + "packageName": "optional-metadep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-preinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-preinstall-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-preinstall-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-true", "packageName": "optional-metadep-preinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-tgz-missing > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-tgz-missing save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-tgz-missing" => EdgeOut { @@ -17314,9 +17503,28 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-false", + "packageName": "@isaacs/testing-optional-metadep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-tgz-missing save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-tgz-missing" => EdgeOut { + "name": "@isaacs/testing-prod-dep-tgz-missing", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-true", "packageName": "@isaacs/testing-optional-metadep-tgz-missing", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-true", "version": "1.0.0", } ` @@ -32468,6 +32676,422 @@ exports[`test/arborist/reify.js TAP save complete lockfile on update-all > shoul ` +exports[`test/arborist/reify.js TAP save package.json on update should not save any with save=false and package-lock=false > should update lockfile with many deps updated package.json save=false 1`] = ` +{ + "name": "workspaces-need-update", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} +` + +exports[`test/arborist/reify.js TAP save package.json on update should not save many deps in multiple package.json when using save=false > should update lockfile with many deps updated package.json save=false 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-not-save-many-deps-in-multiple-package.json-when-using-save-false", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + +exports[`test/arborist/reify.js TAP save package.json on update should save many deps in multiple package.json when using save=true > should update lockfile with many deps updated package.json save=true 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-save-many-deps-in-multiple-package.json-when-using-save-true", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.1.1", + "once": "^1.4.0" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + +exports[`test/arborist/reify.js TAP save package.json on update should update named dep across multiple package.json using save=true > should update lockfile with many deps updated package.json save=true 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-update-named-dep-across-multiple-package.json-using-save-true", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.1.1", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + +exports[`test/arborist/reify.js TAP save package.json on update should update single named dep across multiple package.json using save=true > should update lockfile with single dep updated package.json save=true 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-update-single-named-dep-across-multiple-package.json-using-save-true", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.4.0" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + exports[`test/arborist/reify.js TAP save proper lockfile with bins when upgrading lockfile complete=false > should upgrade, with bins in place 1`] = ` { "name": "tap-testdir-reify-save-proper-lockfile-with-bins-when-upgrading-lockfile-complete-false", diff --git a/workspaces/arborist/test/arborist/build-ideal-tree.js b/workspaces/arborist/test/arborist/build-ideal-tree.js index 80db25880e46c..2c058a6a3283e 100644 --- a/workspaces/arborist/test/arborist/build-ideal-tree.js +++ b/workspaces/arborist/test/arborist/build-ideal-tree.js @@ -833,6 +833,50 @@ t.test('workspaces', t => { ) }) + t.test('should allow adding a workspace as a dep to a workspace', 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'], + }), + 'workspace-a': { + 'package.json': JSON.stringify({ + name: 'workspace-a', + version: '1.0.0', + }), + }, + 'workspace-b': { + 'package.json': JSON.stringify({ + name: 'workspace-b', + version: '1.0.0', + }), + }, + }) + + const arb = new Arborist({ + ...OPT, + path, + workspaces: ['workspace-a'], + }) + + const tree = arb.buildIdealTree({ + path, + add: [ + 'workspace-b', + ], + }) + + // just assert that the buildIdealTree call resolves, if there's a + // problem here it will reject because of nock disabling requests + await t.resolves(tree) + + t.matchSnapshot(printTree(await tree)) + }) + t.end() }) @@ -3682,3 +3726,16 @@ t.test('overrides', t => { t.end() }) + +t.test('store files with a custom indenting', async t => { + const tabIndentedPackageJson = + fs.readFileSync( + resolve(__dirname, '../fixtures/tab-indented-package-json/package.json'), + 'utf8' + ).replace(/\r\n/g, '\n') + const path = t.testdir({ + 'package.json': tabIndentedPackageJson, + }) + const tree = await buildIdeal(path) + t.matchSnapshot(String(tree.meta)) +}) diff --git a/workspaces/arborist/test/arborist/deduper.js b/workspaces/arborist/test/arborist/deduper.js index 3ec37bd6250f4..511ba87bf36eb 100644 --- a/workspaces/arborist/test/arborist/deduper.js +++ b/workspaces/arborist/test/arborist/deduper.js @@ -18,7 +18,7 @@ const fixture = (t, p) => require('../fixtures/reify-cases/' + p)(t) const cache = t.testdir() const dedupeTree = (path, opt) => - new Arborist({ registry, path, cache, ...(opt || {}) }).dedupe(opt) + new Arborist({ registry, path, cache, save: false, ...(opt || {}) }).dedupe(opt) t.test('dedupes with actual tree', async t => { const path = fixture(t, 'dedupe-actual') diff --git a/workspaces/arborist/test/arborist/reify.js b/workspaces/arborist/test/arborist/reify.js index c8c4cb137d424..d5fc166a5636d 100644 --- a/workspaces/arborist/test/arborist/reify.js +++ b/workspaces/arborist/test/arborist/reify.js @@ -256,6 +256,7 @@ t.test('a workspace with a duplicated nested conflicted dep', t => t.test('testing-peer-deps nested with update', t => t.resolveMatchSnapshot(printReified(fixture(t, 'testing-peer-deps-nested'), { update: { names: ['@isaacs/testing-peer-deps'] }, + save: false, }))) t.test('update a bundling node without updating all of its deps', t => { @@ -392,7 +393,7 @@ t.test('multiple bundles at the same level', t => { t.test('update a node without updating its children', t => t.resolveMatchSnapshot(printReified(fixture(t, 'once-outdated'), - { update: { names: ['once'] } }))) + { update: { names: ['once'] }, save: false }))) t.test('do not add shrinkwrapped deps', t => t.resolveMatchSnapshot(printReified( @@ -508,6 +509,7 @@ t.test('update a node without updating a child that has bundle deps', t => { const path = fixture(t, 'testing-bundledeps-3') return t.resolveMatchSnapshot(printReified(path, { update: ['@isaacs/testing-bundledeps-parent'], + save: false, })) }) @@ -524,9 +526,16 @@ t.test('optional dependency failures', t => { 'optional-metadep-postinstall-fail', 'optional-metadep-allinstall-fail', ] - t.plan(cases.length) - cases.forEach(c => t.test(c, t => - t.resolveMatchSnapshot(printReified(fixture(t, c), { update: true })))) + t.plan(cases.length * 2) + let p = [...cases.map(c => t.test(`${c} save=false`, t => + t.resolveMatchSnapshot(printReified(fixture(t, c), + { update: true, save: false }))))] + + // npm update --save + p = [...cases.map(c => t.test(`${c} save=true`, t => + t.resolveMatchSnapshot(printReified(fixture(t, c), + { update: true, save: true }))))] + return p }) t.test('failure to fetch prod dep is failure', t => @@ -665,6 +674,7 @@ t.test('rollbacks', { buffered: false }, t => { return t.resolveMatchSnapshot(a.reify({ update: ['@isaacs/testing-bundledeps-parent'], + save: false, }).then(printTree)) }) @@ -845,6 +855,7 @@ t.test('rollbacks', { buffered: false }, t => { return t.resolveMatchSnapshot(a.reify({ update: ['@isaacs/testing-bundledeps-parent'], + save: false, }).then(tree => printTree(tree))).then(() => { const warnings = check() t.equal(warnings.length, 2) @@ -1367,7 +1378,7 @@ t.test('save complete lockfile on update-all', async t => { const lock = () => fs.readFileSync(`${path}/package-lock.json`, 'utf8') await reify(path, { add: ['abbrev@1.0.4'] }) t.matchSnapshot(lock(), 'should have abbrev 1.0.4') - await reify(path, { update: true }) + await reify(path, { update: true, save: false }) t.matchSnapshot(lock(), 'should update, but not drop root metadata') }) @@ -2432,3 +2443,134 @@ t.test('add local dep with existing dev + peer/optional', async t => { t.equal(tree.children.get('abbrev').resolved, 'file:../../dep', 'resolved') t.equal(tree.children.size, 1, 'children') }) + +t.test('save package.json on update', t => { + t.test('should save many deps in multiple package.json when using save=true', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: true, save: true }) + + t.same( + require(resolve(path, 'package.json')), + { dependencies: { abbrev: '^1.1.1' }, workspaces: ['a', 'b'] }, + 'should save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.1.1', once: '^1.4.0' } }, + 'should save workspace dep to its package.json file') + + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with many deps updated package.json save=true' + ) + }) + + t.test('should not save many deps in multiple package.json when using save=false', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: true, save: false }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.0.4' }, + workspaces: ['a', 'b'], + }, + 'should not save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.0.4', once: '^1.3.2' } }, + 'should not save workspace dep to its package.json file') + + // package-lock entries will still get updated: + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with many deps updated package.json save=false' + ) + }) + + t.test('should not save any with save=false and package-lock=false', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: true, save: false, packageLock: false }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.0.4' }, + workspaces: ['a', 'b'], + }, + 'should not save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.0.4', once: '^1.3.2' } }, + 'should not save workspace dep to its package.json file') + + // package-lock entries will still get updated: + t.matchSnapshot( + JSON.stringify(JSON.parse(fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8')), null, 2), + 'should update lockfile with many deps updated package.json save=false' + ) + }) + + t.test('should update named dep across multiple package.json using save=true', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: ['abbrev'], save: true }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.1.1' }, + workspaces: ['a', 'b'], + }, + 'should save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.1.1', once: '^1.3.2' } }, + 'should save only workspace a updated dep to its package.json file') + t.same( + require(resolve(path, 'b', 'package.json')), + { dependencies: { abbrev: '^1.1.1' } }, + 'should save only workspace b updated dep to its package.json file') + + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with many deps updated package.json save=true' + ) + }) + + t.test('should update single named dep across multiple package.json using save=true', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: ['once'], save: true }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.0.4' }, + workspaces: ['a', 'b'], + }, + 'should save no top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.0.4', once: '^1.4.0' } }, + 'should save only workspace single updated dep to its package.json file') + t.same( + require(resolve(path, 'b', 'package.json')), + { dependencies: { abbrev: '^1.0.4' } }, + 'should not change workspace b package.json file') + + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with single dep updated package.json save=true' + ) + }) + + t.end() +}) diff --git a/workspaces/arborist/test/fixtures/reify-cases/workspaces-need-update.js b/workspaces/arborist/test/fixtures/reify-cases/workspaces-need-update.js new file mode 100644 index 0000000000000..2d57f05a0504d --- /dev/null +++ b/workspaces/arborist/test/fixtures/reify-cases/workspaces-need-update.js @@ -0,0 +1,83 @@ +// generated from test/fixtures/workspaces-need-update +module.exports = t => { + const path = t.testdir({ + "a": { + "package.json": JSON.stringify({ + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }) + }, + "b": { + "package.json": JSON.stringify({ + "dependencies": { + "abbrev": "^1.0.4" + } + }) + }, + "package-lock.json": JSON.stringify({ + "name": "workspaces-need-update", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }), + "package.json": JSON.stringify({ + "dependencies": { + "abbrev": "^1.0.4" + }, + "workspaces": [ + "a", + "b" + ] + }) +}) + return path +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/a/package.json b/workspaces/arborist/test/fixtures/workspaces-need-update/a/package.json new file mode 100644 index 0000000000000..76584743763c3 --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/a/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/b/package.json b/workspaces/arborist/test/fixtures/workspaces-need-update/b/package.json new file mode 100644 index 0000000000000..8af6070f2f798 --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "abbrev": "^1.0.4" + } +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/package-lock.json b/workspaces/arborist/test/fixtures/workspaces-need-update/package-lock.json new file mode 100644 index 0000000000000..43865795a7bba --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/package-lock.json @@ -0,0 +1,53 @@ +{ + "name": "workspaces-need-update", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/package.json b/workspaces/arborist/test/fixtures/workspaces-need-update/package.json new file mode 100644 index 0000000000000..ebdce120ce0c6 --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "abbrev": "^1.0.4" + }, + "workspaces": ["a", "b"] +} diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 8c8812a651a05..ff728b5473bc9 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -46,7 +46,7 @@ }, "devDependencies": { "@npmcli/template-oss": "^2.4.2", - "bin-links": "^2.2.1", + "bin-links": "^3.0.0", "tap": "^15.0.6" }, "dependencies": {