diff --git a/lib/ls.js b/lib/ls.js index 7540692911976..91e9a9dd3dba8 100644 --- a/lib/ls.js +++ b/lib/ls.js @@ -138,7 +138,7 @@ class LS extends ArboristWorkspaceCmd { !(node instanceof Arborist.Node) || (currentDepth > depthToPrint) return (shouldSkipChildren) ? [] - : [...(node.target || node).edgesOut.values()] + : [...(node.target).edgesOut.values()] .filter(filterBySelectedWorkspaces) .filter(filterByEdgesTypes({ currentDepth, diff --git a/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js b/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js index 5db11eb3832eb..fdb947dc5905c 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js +++ b/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js @@ -324,7 +324,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { .then(async root => { if (!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk) { await new this.constructor(this.options).loadActual({ root }) - const tree = root.target || root + const tree = root.target // even though we didn't load it from a package-lock.json FILE, // we still loaded it "from disk", meaning we have to reset // dep flags before assuming that any mutations were reflected. @@ -396,7 +396,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { // update.names request by queueing nodes dependent on those named. async [_applyUserRequests] (options) { process.emit('time', 'idealTree:userRequests') - const tree = this.idealTree.target || this.idealTree + const tree = this.idealTree.target if (!this[_workspaces].length) await this[_applyUserRequestsToNode](tree, options) @@ -532,7 +532,7 @@ module.exports = cls => class IdealTreeBuilder extends cls { /* istanbul ignore else - should also be covered by realpath failure */ if (filepath) { const { name } = spec - const tree = this.idealTree.target || this.idealTree + const tree = this.idealTree.target spec = npa(`file:${relpath(tree.path, filepath)}`, tree.path) spec.name = name } @@ -730,7 +730,7 @@ This is a one-time fix-up, please be patient... // or extraneous. [_buildDeps] () { process.emit('time', 'idealTree:buildDeps') - const tree = this.idealTree.target || this.idealTree + const tree = this.idealTree.target this[_depsQueue].push(tree) this.log.silly('idealTree', 'buildDeps') this.addTracker('idealTree', tree.name, '') @@ -788,7 +788,11 @@ This is a one-time fix-up, please be patient... const Arborist = this.constructor const opt = { ...this.options } await cacache.tmp.withTmp(this.cache, opt, async path => { - await pacote.extract(node.resolved, path, opt) + await pacote.extract(node.resolved, path, { + ...opt, + resolved: node.resolved, + integrity: node.integrity, + }) if (hasShrinkwrap) { await new Arborist({ ...this.options, path }) @@ -914,7 +918,7 @@ This is a one-time fix-up, please be patient... await Promise.all(promises) for (const { to } of node.edgesOut.values()) { - if (to && to.isLink) + if (to && to.isLink && to.target) this[_linkNodes].add(to) } @@ -1293,7 +1297,7 @@ This is a one-time fix-up, please be patient... // when installing globally, or just in global style, we never place // deps above the first level. - const tree = this.idealTree && this.idealTree.target || this.idealTree + const tree = this.idealTree && this.idealTree.target if (this[_globalStyle] && check.resolveParent === tree) break } @@ -1362,7 +1366,7 @@ This is a one-time fix-up, please be patient... integrity: dep.integrity, legacyPeerDeps: this.legacyPeerDeps, error: dep.errors[0], - ...(dep.target ? { target: dep.target, realpath: dep.target.path } : {}), + ...(dep.isLink ? { target: dep.target, realpath: dep.target.path } : {}), }) if (this[_loadFailures].has(dep)) this[_loadFailures].add(newDep) @@ -1421,7 +1425,7 @@ This is a one-time fix-up, please be patient... // prune anything deeper in the tree that can be replaced by this if (this.idealTree) { for (const node of this.idealTree.inventory.query('name', newDep.name)) { - if (node.isDescendantOf(target)) + if (!node.isTop && node.isDescendantOf(target)) this[_pruneDedupable](node, false) } } @@ -1819,7 +1823,7 @@ This is a one-time fix-up, please be patient... const current = target !== entryEdge.from && target.resolve(dep.name) if (current) { for (const edge of current.edgesIn.values()) { - if (edge.from.isDescendantOf(target) && edge.valid) { + if (!edge.from.isTop && edge.from.isDescendantOf(target) && edge.valid) { if (!edge.satisfiedBy(dep)) return CONFLICT } @@ -1876,7 +1880,8 @@ This is a one-time fix-up, please be patient... if (link.root !== this.idealTree) continue - const external = /^\.\.(\/|$)/.test(relpath(this.path, link.realpath)) + const tree = this.idealTree.target + const external = !link.target.isDescendantOf(tree) // outside the root, somebody else's problem, ignore it if (external && !this[_follow]) diff --git a/node_modules/@npmcli/arborist/lib/arborist/index.js b/node_modules/@npmcli/arborist/lib/arborist/index.js index 94501cae12c84..b26a26c2be2ab 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/index.js +++ b/node_modules/@npmcli/arborist/lib/arborist/index.js @@ -81,7 +81,7 @@ class Arborist extends Base { const dep = edge.to if (dep) { set.add(dep) - if (dep.target) + if (dep.isLink) set.add(dep.target) } } diff --git a/node_modules/@npmcli/arborist/lib/arborist/load-actual.js b/node_modules/@npmcli/arborist/lib/arborist/load-actual.js index 9fca7d6425da0..86856d868b426 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/load-actual.js +++ b/node_modules/@npmcli/arborist/lib/arborist/load-actual.js @@ -315,7 +315,7 @@ module.exports = cls => class ActualLoader extends cls { [_loadFSTree] (node) { const did = this[_actualTreeLoaded] - node = node.target || node + node = node.target // if a Link target has started, but not completed, then // a Promise will be in the cache to indicate this. diff --git a/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js b/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js index a98ed23b2a458..d1edcaca01d7e 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js +++ b/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js @@ -221,7 +221,7 @@ module.exports = cls => class VirtualLoader extends cls { [assignBundles] (nodes) { for (const [location, node] of nodes) { // Skip assignment of parentage for the root package - if (!location || node.target && !node.target.location) + if (!location || node.isLink && !node.target.location) continue const { name, parent, package: { inBundle }} = node diff --git a/node_modules/@npmcli/arborist/lib/arborist/rebuild.js b/node_modules/@npmcli/arborist/lib/arborist/rebuild.js index d189ad8c99e3c..8e447bb8f5ad1 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/rebuild.js +++ b/node_modules/@npmcli/arborist/lib/arborist/rebuild.js @@ -169,7 +169,7 @@ module.exports = cls => class Builder extends cls { const queue = [...set].sort(sortNodes) for (const node of queue) { - const { package: { bin, scripts = {} } } = node + const { package: { bin, scripts = {} } } = node.target const { preinstall, install, postinstall, prepare } = scripts const tests = { bin, preinstall, install, postinstall, prepare } for (const [key, has] of Object.entries(tests)) { @@ -202,7 +202,7 @@ module.exports = cls => class Builder extends cls { !(meta.originalLockfileVersion >= 2) } - const { package: pkg, hasInstallScript } = node + const { package: pkg, hasInstallScript } = node.target const { gypfile, bin, scripts = {} } = pkg const { preinstall, install, postinstall, prepare } = scripts @@ -263,7 +263,7 @@ module.exports = cls => class Builder extends cls { devOptional, package: pkg, location, - } = node.target || node + } = node.target // skip any that we know we'll be deleting if (this[_trashList].has(path)) diff --git a/node_modules/@npmcli/arborist/lib/arborist/reify.js b/node_modules/@npmcli/arborist/lib/arborist/reify.js index f259a69b548e1..18b5cd65262a6 100644 --- a/node_modules/@npmcli/arborist/lib/arborist/reify.js +++ b/node_modules/@npmcli/arborist/lib/arborist/reify.js @@ -289,8 +289,8 @@ module.exports = cls => class Reifier extends cls { const filterNodes = [] if (this[_global] && this.explicitRequests.size) { - const idealTree = this.idealTree.target || this.idealTree - const actualTree = this.actualTree.target || this.actualTree + const idealTree = this.idealTree.target + const actualTree = this.actualTree.target // we ONLY are allowed to make changes in the global top-level // children where there's an explicit request. for (const { name } of this.explicitRequests) { @@ -404,10 +404,9 @@ module.exports = cls => class Reifier extends cls { return process.emit('time', 'reify:trashOmits') - // node.parent is checked to make sure this is a node that's in the tree, and - // not the parent-less top level nodes + const filter = node => - node.isDescendantOf(this.idealTree) && + node.top.isProjectRoot && (node.peer && this[_omitPeer] || node.dev && this[_omitDev] || node.optional && this[_omitOptional] || @@ -664,7 +663,7 @@ module.exports = cls => class Reifier extends cls { const node = diff.ideal if (!node) return - if (node.isProjectRoot || (node.target && node.target.isProjectRoot)) + if (node.isProjectRoot) return const { bundleDependencies } = node.package @@ -887,6 +886,18 @@ module.exports = cls => class Reifier extends cls { filter: diff => diff.action === 'ADD' || diff.action === 'CHANGE', }) + // pick up link nodes from the unchanged list as we want to run their + // scripts in every install despite of having a diff status change + for (const node of this.diff.unchanged) { + const tree = node.root.target + + // skip links that only live within node_modules as they are most + // likely managed by packages we installed, we only want to rebuild + // unchanged links we directly manage + if (node.isLink && node.target.fsTop === tree) + nodes.push(node) + } + return this.rebuild({ nodes, handleOptionalFailure: true }) .then(() => process.emit('timeEnd', 'reify:build')) } diff --git a/node_modules/@npmcli/arborist/lib/calc-dep-flags.js b/node_modules/@npmcli/arborist/lib/calc-dep-flags.js index 21d8ddcf7b442..968fc83c5136c 100644 --- a/node_modules/@npmcli/arborist/lib/calc-dep-flags.js +++ b/node_modules/@npmcli/arborist/lib/calc-dep-flags.js @@ -29,7 +29,7 @@ const calcDepFlagsStep = (node) => { resetParents(node, 'optional') // for links, map their hierarchy appropriately - if (node.target) { + if (node.isLink) { node.target.dev = node.dev node.target.optional = node.optional node.target.devOptional = node.devOptional @@ -92,10 +92,10 @@ const unsetFlag = (node, flag) => { tree: node, visit: node => { node.extraneous = node[flag] = false - if (node.target) + if (node.isLink) node.target.extraneous = node.target[flag] = false }, - getChildren: node => [...(node.target || node).edgesOut.values()] + getChildren: node => [...node.target.edgesOut.values()] .filter(edge => edge.to && edge.to[flag] && (flag !== 'peer' && edge.type === 'peer' || edge.type === 'prod')) .map(edge => edge.to), diff --git a/node_modules/@npmcli/arborist/lib/diff.js b/node_modules/@npmcli/arborist/lib/diff.js index 1f8eff0f0c4d9..2008ef7a35bdd 100644 --- a/node_modules/@npmcli/arborist/lib/diff.js +++ b/node_modules/@npmcli/arborist/lib/diff.js @@ -45,8 +45,7 @@ class Diff { const { root } = filterNode if (root !== ideal && root !== actual) throw new Error('invalid filterNode: outside idealTree/actualTree') - const { target } = root - const rootTarget = target || root + const rootTarget = root.target const edge = [...rootTarget.edgesOut.values()].filter(e => { return e.to && (e.to === filterNode || e.to.target === filterNode) })[0] @@ -56,8 +55,7 @@ class Diff { filterSet.add(actual) if (edge && edge.to) { filterSet.add(edge.to) - if (edge.to.target) - filterSet.add(edge.to.target) + filterSet.add(edge.to.target) } filterSet.add(filterNode) @@ -65,7 +63,7 @@ class Diff { tree: filterNode, visit: node => filterSet.add(node), getChildren: node => { - node = node.target || node + node = node.target const loc = node.location const idealNode = ideal.inventory.get(loc) const ideals = !idealNode ? [] diff --git a/node_modules/@npmcli/arborist/lib/node.js b/node_modules/@npmcli/arborist/lib/node.js index c21bc46cfb539..2ef0a64f08829 100644 --- a/node_modules/@npmcli/arborist/lib/node.js +++ b/node_modules/@npmcli/arborist/lib/node.js @@ -409,7 +409,7 @@ class Node { } isDescendantOf (node) { - for (let p = this; p; p = p.parent) { + for (let p = this; p; p = p.resolveParent) { if (p === node) return true } @@ -649,7 +649,7 @@ class Node { }) if (this.isLink) { - const target = node.target || node + const target = node.target this[_target] = target this[_package] = target.package target.linksIn.add(this) @@ -1174,7 +1174,7 @@ class Node { } get target () { - return null + return this } set target (n) { @@ -1197,6 +1197,14 @@ class Node { return this.isTop ? this : this.parent.top } + get isFsTop () { + return !this.fsParent + } + + get fsTop () { + return this.isFsTop ? this : this.fsParent.fsTop + } + get resolveParent () { return this.parent || this.fsParent } diff --git a/node_modules/@npmcli/arborist/lib/shrinkwrap.js b/node_modules/@npmcli/arborist/lib/shrinkwrap.js index b251539a94c90..3b2cf0bde1036 100644 --- a/node_modules/@npmcli/arborist/lib/shrinkwrap.js +++ b/node_modules/@npmcli/arborist/lib/shrinkwrap.js @@ -802,7 +802,7 @@ class Shrinkwrap { if (this.tree) { if (this.yarnLock) this.yarnLock.fromTree(this.tree) - const root = Shrinkwrap.metaFromNode(this.tree.target || this.tree, this.path) + const root = Shrinkwrap.metaFromNode(this.tree.target, this.path) this.data.packages = {} if (Object.keys(root).length) this.data.packages[''] = root @@ -864,7 +864,7 @@ class Shrinkwrap { const spec = !edge ? rSpec : npa.resolve(node.name, edge.spec, edge.from.realpath) - if (node.target) + if (node.isLink) lock.version = `file:${relpath(this.path, node.realpath)}` else if (spec && (spec.type === 'file' || spec.type === 'remote')) lock.version = spec.saveSpec @@ -888,7 +888,7 @@ class Shrinkwrap { // when we didn't resolve to git, file, or dir, and didn't request // git, file, dir, or remote, then the resolved value is necessary. if (node.resolved && - !node.target && + !node.isLink && rSpec.type !== 'git' && rSpec.type !== 'file' && rSpec.type !== 'directory' && @@ -917,7 +917,7 @@ class Shrinkwrap { lock.optional = true } - const depender = node.target || node + const depender = node.target if (depender.edgesOut.size > 0) { if (node !== this.tree) { lock.requires = [...depender.edgesOut.entries()].reduce((set, [k, v]) => { @@ -942,7 +942,7 @@ class Shrinkwrap { } // now we walk the children, putting them in the 'dependencies' object - const {children} = node.target || node + const {children} = node.target if (!children.size) delete lock.dependencies else { diff --git a/node_modules/@npmcli/arborist/package.json b/node_modules/@npmcli/arborist/package.json index 138d6ec25b4c2..c45a61086ea5e 100644 --- a/node_modules/@npmcli/arborist/package.json +++ b/node_modules/@npmcli/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "2.6.4", + "version": "2.7.1", "description": "Manage node_modules trees", "dependencies": { "@npmcli/installed-package-contents": "^1.0.7", @@ -16,6 +16,7 @@ "common-ancestor-path": "^1.0.1", "json-parse-even-better-errors": "^2.3.1", "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", "mkdirp-infer-owner": "^2.0.0", "npm-install-checks": "^4.0.0", "npm-package-arg": "^8.1.0", @@ -28,7 +29,9 @@ "promise-call-limit": "^1.0.1", "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", "semver": "^7.3.5", + "ssri": "^8.0.1", "tar": "^6.1.0", "treeverse": "^1.0.4", "walk-up-path": "^1.0.0" diff --git a/package-lock.json b/package-lock.json index 570cded5aa58b..fa82aeddbf3c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,7 +83,7 @@ "packages/*" ], "dependencies": { - "@npmcli/arborist": "^2.6.4", + "@npmcli/arborist": "^2.7.1", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^2.2.0", "@npmcli/package-json": "^1.0.1", @@ -735,9 +735,9 @@ } }, "node_modules/@npmcli/arborist": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.6.4.tgz", - "integrity": "sha512-A/pDQ/VZpdxaqsQS5XOWrhrPuC+ER7HLq+4ZkEmnO2yo/USFCWEsiUPYKhfY+sWXK3pgKjN7B7CEFmAnSoAt3g==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.7.1.tgz", + "integrity": "sha512-EGDHJs6dna/52BrStr/6aaRcMLrYxGbSjT4V3JzvoTBY9/w5i2+1KNepmsG80CAsGADdo6nuNnFwb7sDRm8ZAw==", "inBundle": true, "dependencies": { "@npmcli/installed-package-contents": "^1.0.7", @@ -753,6 +753,7 @@ "common-ancestor-path": "^1.0.1", "json-parse-even-better-errors": "^2.3.1", "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", "mkdirp-infer-owner": "^2.0.0", "npm-install-checks": "^4.0.0", "npm-package-arg": "^8.1.0", @@ -765,7 +766,9 @@ "promise-call-limit": "^1.0.1", "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", "semver": "^7.3.5", + "ssri": "^8.0.1", "tar": "^6.1.0", "treeverse": "^1.0.4", "walk-up-path": "^1.0.0" @@ -10869,9 +10872,9 @@ "dev": true }, "@npmcli/arborist": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.6.4.tgz", - "integrity": "sha512-A/pDQ/VZpdxaqsQS5XOWrhrPuC+ER7HLq+4ZkEmnO2yo/USFCWEsiUPYKhfY+sWXK3pgKjN7B7CEFmAnSoAt3g==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-2.7.1.tgz", + "integrity": "sha512-EGDHJs6dna/52BrStr/6aaRcMLrYxGbSjT4V3JzvoTBY9/w5i2+1KNepmsG80CAsGADdo6nuNnFwb7sDRm8ZAw==", "requires": { "@npmcli/installed-package-contents": "^1.0.7", "@npmcli/map-workspaces": "^1.0.2", @@ -10886,6 +10889,7 @@ "common-ancestor-path": "^1.0.1", "json-parse-even-better-errors": "^2.3.1", "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", "mkdirp-infer-owner": "^2.0.0", "npm-install-checks": "^4.0.0", "npm-package-arg": "^8.1.0", @@ -10898,7 +10902,9 @@ "promise-call-limit": "^1.0.1", "read-package-json-fast": "^2.0.2", "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", "semver": "^7.3.5", + "ssri": "^8.0.1", "tar": "^6.1.0", "treeverse": "^1.0.4", "walk-up-path": "^1.0.0" diff --git a/package.json b/package.json index 73b03991026e1..76645816adb15 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "./package.json": "./package.json" }, "dependencies": { - "@npmcli/arborist": "^2.6.4", + "@npmcli/arborist": "^2.7.1", "@npmcli/ci-detect": "^1.2.0", "@npmcli/config": "^2.2.0", "@npmcli/package-json": "^1.0.1", diff --git a/test/lib/link.js b/test/lib/link.js index 736d18cab9906..96f689892ff83 100644 --- a/test/lib/link.js +++ b/test/lib/link.js @@ -30,7 +30,7 @@ const printLinks = async (opts) => { const linkedItems = [...tree.inventory.values()] .sort((a, b) => a.pkgid.localeCompare(b.pkgid, 'en')) for (const item of linkedItems) { - if (item.target) + if (item.isLink) res += `${item.path} -> ${item.target.path}\n` } return res