Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions workspaces/arborist/lib/arborist/build-ideal-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,8 @@ This is a one-time fix-up, please be patient...
const crackOpen = this.#complete &&
node !== this.idealTree &&
node.resolved &&
(hasBundle || hasShrinkwrap)
(hasBundle || hasShrinkwrap) &&
!node.ideallyInert
if (crackOpen) {
const Arborist = this.constructor
const opt = { ...this.options }
Expand Down Expand Up @@ -1527,7 +1528,7 @@ This is a one-time fix-up, please be patient...

const set = optionalSet(node)
for (const node of set) {
node.parent = null
node.ideallyInert = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking about this, and maybe it's better to just call it inert instead of ideallyInert. I think putting the ideally in there is probably a bit too much clever inside baseball and it's more verbose to boot. :)

Some other name would be good, too, as long as it communicates that this is in the tree, but we don't physically install it.

}
}
}
Expand All @@ -1548,6 +1549,7 @@ This is a one-time fix-up, please be patient...
node.parent !== null
&& !node.isProjectRoot
&& !excludeNodes.has(node)
&& !node.ideallyInert
) {
this[_addNodeToTrashList](node)
}
Expand Down
6 changes: 3 additions & 3 deletions workspaces/arborist/lib/arborist/isolated-reifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ module.exports = cls => class IsolatedReifier extends cls {
}
queue.push(e.to)
})
if (!next.isProjectRoot && !next.isWorkspace) {
if (!next.isProjectRoot && !next.isWorkspace && !next.ideallyInert) {
root.external.push(await this.externalProxyMemo(next))
}
}
Expand Down Expand Up @@ -147,8 +147,8 @@ module.exports = cls => class IsolatedReifier extends cls {
const nonOptionalDeps = edges.filter(e => !e.optional).map(e => e.to.target)

result.localDependencies = await Promise.all(nonOptionalDeps.filter(n => n.isWorkspace).map(this.workspaceProxyMemo))
result.externalDependencies = await Promise.all(nonOptionalDeps.filter(n => !n.isWorkspace).map(this.externalProxyMemo))
result.externalOptionalDependencies = await Promise.all(optionalDeps.map(this.externalProxyMemo))
result.externalDependencies = await Promise.all(nonOptionalDeps.filter(n => !n.isWorkspace && !n.ideallyInert).map(this.externalProxyMemo))
result.externalOptionalDependencies = await Promise.all(optionalDeps.filter(n => !n.ideallyInert).map(this.externalProxyMemo))
result.dependencies = [
...result.externalDependencies,
...result.localDependencies,
Expand Down
1 change: 1 addition & 0 deletions workspaces/arborist/lib/arborist/load-virtual.js
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ module.exports = cls => class VirtualLoader extends cls {
integrity: sw.integrity,
resolved: consistentResolve(sw.resolved, this.path, path),
pkg: sw,
ideallyInert: sw.ideallyInert,
hasShrinkwrap: sw.hasShrinkwrap,
dev,
optional,
Expand Down
27 changes: 25 additions & 2 deletions workspaces/arborist/lib/arborist/reify.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ module.exports = cls => class Reifier extends cls {
for (const path of this[_trashList]) {
const loc = relpath(this.idealTree.realpath, path)
const node = this.idealTree.inventory.get(loc)
if (node && node.root === this.idealTree) {
if (node && node.root === this.idealTree && !node.ideallyInert) {
node.parent = null
}
}
Expand Down Expand Up @@ -237,6 +237,18 @@ module.exports = cls => class Reifier extends cls {
this.idealTree.meta.hiddenLockfile = true
this.idealTree.meta.lockfileVersion = defaultLockfileVersion

// Preserve inertness for failed stuff.
if (this.actualTree) {
for (const [loc, actual] of this.actualTree.inventory.entries()) {
if (actual.ideallyInert) {
const ideal = this.idealTree.inventory.get(loc)
if (ideal) {
ideal.ideallyInert = true
}
}
}
}

this.actualTree = this.idealTree
this.idealTree = null

Expand Down Expand Up @@ -599,6 +611,9 @@ module.exports = cls => class Reifier extends cls {
// retire the same path at the same time.
const dirsChecked = new Set()
return promiseAllRejectLate(leaves.map(async node => {
if (node.ideallyInert) {
return
}
for (const d of walkUp(node.path)) {
if (d === node.top.path) {
break
Expand Down Expand Up @@ -743,6 +758,10 @@ module.exports = cls => class Reifier extends cls {
}

async #extractOrLink (node) {
if (node.ideallyInert) {
return
}

const nm = resolve(node.parent.path, 'node_modules')
await this.#validateNodeModules(nm)

Expand Down Expand Up @@ -818,6 +837,7 @@ module.exports = cls => class Reifier extends cls {
const set = optionalSet(node)
for (node of set) {
log.verbose('reify', 'failed optional dependency', node.path)
node.ideallyInert = true
this[_addNodeToTrashList](node)
}
}) : p).then(() => node)
Expand Down Expand Up @@ -1152,6 +1172,9 @@ module.exports = cls => class Reifier extends cls {

this.#retiredUnchanged[retireFolder] = []
return promiseAllRejectLate(diff.unchanged.map(node => {
if (node.ideallyInert) {
return
}
// no need to roll back links, since we'll just delete them anyway
if (node.isLink) {
return mkdir(dirname(node.path), { recursive: true, force: true })
Expand Down Expand Up @@ -1231,7 +1254,7 @@ module.exports = cls => class Reifier extends cls {
// 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
const linkedFromRoot = node.parent === tree || node.target.fsTop === tree
const linkedFromRoot = (node.parent === tree && !node.ideallyInert) || node.target.fsTop === tree
if (node.isLink && linkedFromRoot) {
nodes.push(node)
}
Expand Down
3 changes: 3 additions & 0 deletions workspaces/arborist/lib/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class Node {
global = false,
dummy = false,
sourceReference = null,
ideallyInert = false,
} = options
// this object gives querySelectorAll somewhere to stash context about a node
// while processing a query
Expand Down Expand Up @@ -197,6 +198,8 @@ class Node {
this.extraneous = false
}

this.ideallyInert = ideallyInert

this.edgesIn = new Set()
this.edgesOut = new CaseInsensitiveMap()

Expand Down
17 changes: 16 additions & 1 deletion workspaces/arborist/lib/shrinkwrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const nodeMetaKeys = [
'inBundle',
'hasShrinkwrap',
'hasInstallScript',
'ideallyInert',
]

const metaFieldFromPkg = (pkg, key) => {
Expand All @@ -135,6 +136,10 @@ const assertNoNewer = async (path, data, lockTime, dir, seen) => {

const parent = isParent ? dir : resolve(dir, 'node_modules')
const rel = relpath(path, dir)
const inert = data.packages[rel]?.ideallyInert
if (inert) {
return
}
seen.add(rel)
let entries
if (dir === path) {
Expand Down Expand Up @@ -173,7 +178,7 @@ const assertNoNewer = async (path, data, lockTime, dir, seen) => {

// assert that all the entries in the lockfile were seen
for (const loc in data.packages) {
if (!seen.has(loc)) {
if (!seen.has(loc) && !data.packages[loc].ideallyInert) {
throw new Error(`missing from node_modules: ${loc}`)
}
}
Expand Down Expand Up @@ -783,6 +788,10 @@ class Shrinkwrap {
// ok, I did my best! good luck!
}

if (lock.ideallyInert) {
meta.ideallyInert = true
}

if (lock.bundled) {
meta.inBundle = true
}
Expand Down Expand Up @@ -953,6 +962,12 @@ class Shrinkwrap {
this.#buildLegacyLockfile(this.tree, this.data)
}

if (!this.hiddenLockfile) {
for (const node of Object.values(this.data.packages)) {
delete node.ideallyInert
}
}

// lf version 1 = dependencies only
// lf version 2 = dependencies and packages
// lf version 3 = packages only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77868,11 +77868,34 @@ ArboristNode {

exports[`test/arborist/build-ideal-tree.js TAP optional dependency failures > optional-dep-enotarget 1`] = `
ArboristNode {
"children": Map {
"tap" => ArboristNode {
"edgesIn": Set {
EdgeIn {
"error": "INVALID",
"from": "",
"name": "tap",
"spec": "9999.0000.9999",
"type": "optional",
},
},
"errors": Array [
Object {
"code": "ETARGET",
},
],
"location": "node_modules/tap",
"name": "tap",
"optional": true,
"path": "{CWD}/test/fixtures/optional-dep-enotarget/node_modules/tap",
},
},
"edgesOut": Map {
"tap" => EdgeOut {
"error": "INVALID",
"name": "tap",
"spec": "9999.0000.9999",
"to": null,
"to": "node_modules/tap",
"type": "optional",
},
},
Expand All @@ -77887,11 +77910,32 @@ ArboristNode {

exports[`test/arborist/build-ideal-tree.js TAP optional dependency failures > optional-dep-missing 1`] = `
ArboristNode {
"children": Map {
"@isaacs/this-does-not-exist-at-all" => ArboristNode {
"edgesIn": Set {
EdgeIn {
"from": "",
"name": "@isaacs/this-does-not-exist-at-all",
"spec": "*",
"type": "optional",
},
},
"errors": Array [
Object {
"code": "E404",
},
],
"location": "node_modules/@isaacs/this-does-not-exist-at-all",
"name": "@isaacs/this-does-not-exist-at-all",
"optional": true,
"path": "{CWD}/test/fixtures/optional-dep-missing/node_modules/@isaacs/this-does-not-exist-at-all",
},
},
"edgesOut": Map {
"@isaacs/this-does-not-exist-at-all" => EdgeOut {
"name": "@isaacs/this-does-not-exist-at-all",
"spec": "*",
"to": null,
"to": "node_modules/@isaacs/this-does-not-exist-at-all",
"type": "optional",
},
},
Expand All @@ -77906,11 +77950,60 @@ ArboristNode {

exports[`test/arborist/build-ideal-tree.js TAP optional dependency failures > optional-metadep-enotarget 1`] = `
ArboristNode {
"children": Map {
"@isaacs/prod-dep-enotarget" => ArboristNode {
"children": Map {
"tap" => ArboristNode {
"edgesIn": Set {
EdgeIn {
"error": "INVALID",
"from": "node_modules/@isaacs/prod-dep-enotarget",
"name": "tap",
"spec": "9999.0000.9999",
"type": "prod",
},
},
"errors": Array [
Object {
"code": "ETARGET",
},
],
"location": "node_modules/@isaacs/prod-dep-enotarget/node_modules/tap",
"name": "tap",
"optional": true,
"path": "{CWD}/test/fixtures/optional-metadep-enotarget/node_modules/@isaacs/prod-dep-enotarget/node_modules/tap",
},
},
"edgesIn": Set {
EdgeIn {
"from": "",
"name": "@isaacs/prod-dep-enotarget",
"spec": "*",
"type": "optional",
},
},
"edgesOut": Map {
"tap" => EdgeOut {
"error": "INVALID",
"name": "tap",
"spec": "9999.0000.9999",
"to": "node_modules/@isaacs/prod-dep-enotarget/node_modules/tap",
"type": "prod",
},
},
"location": "node_modules/@isaacs/prod-dep-enotarget",
"name": "@isaacs/prod-dep-enotarget",
"optional": true,
"path": "{CWD}/test/fixtures/optional-metadep-enotarget/node_modules/@isaacs/prod-dep-enotarget",
"resolved": "https://registry.npmjs.org/@isaacs/prod-dep-enotarget/-/prod-dep-enotarget-1.0.0.tgz",
"version": "1.0.0",
},
},
"edgesOut": Map {
"@isaacs/prod-dep-enotarget" => EdgeOut {
"name": "@isaacs/prod-dep-enotarget",
"spec": "*",
"to": null,
"to": "node_modules/@isaacs/prod-dep-enotarget",
"type": "optional",
},
},
Expand All @@ -77924,11 +78017,58 @@ ArboristNode {

exports[`test/arborist/build-ideal-tree.js TAP optional dependency failures > optional-metadep-missing 1`] = `
ArboristNode {
"children": Map {
"@isaacs/testing-prod-dep-metadata-missing" => ArboristNode {
"children": Map {
"@isaacs/this-does-not-exist-at-all" => ArboristNode {
"edgesIn": Set {
EdgeIn {
"from": "node_modules/@isaacs/testing-prod-dep-metadata-missing",
"name": "@isaacs/this-does-not-exist-at-all",
"spec": "*",
"type": "prod",
},
},
"errors": Array [
Object {
"code": "E404",
},
],
"location": "node_modules/@isaacs/testing-prod-dep-metadata-missing/node_modules/@isaacs/this-does-not-exist-at-all",
"name": "@isaacs/this-does-not-exist-at-all",
"optional": true,
"path": "{CWD}/test/fixtures/optional-metadep-missing/node_modules/@isaacs/testing-prod-dep-metadata-missing/node_modules/@isaacs/this-does-not-exist-at-all",
},
},
"edgesIn": Set {
EdgeIn {
"from": "",
"name": "@isaacs/testing-prod-dep-metadata-missing",
"spec": "*",
"type": "optional",
},
},
"edgesOut": Map {
"@isaacs/this-does-not-exist-at-all" => EdgeOut {
"name": "@isaacs/this-does-not-exist-at-all",
"spec": "*",
"to": "node_modules/@isaacs/testing-prod-dep-metadata-missing/node_modules/@isaacs/this-does-not-exist-at-all",
"type": "prod",
},
},
"location": "node_modules/@isaacs/testing-prod-dep-metadata-missing",
"name": "@isaacs/testing-prod-dep-metadata-missing",
"optional": true,
"path": "{CWD}/test/fixtures/optional-metadep-missing/node_modules/@isaacs/testing-prod-dep-metadata-missing",
"resolved": "https://registry.npmjs.org/@isaacs/testing-prod-dep-metadata-missing/-/testing-prod-dep-metadata-missing-1.0.0.tgz",
"version": "1.0.0",
},
},
"edgesOut": Map {
"@isaacs/testing-prod-dep-metadata-missing" => EdgeOut {
"name": "@isaacs/testing-prod-dep-metadata-missing",
"spec": "*",
"to": null,
"to": "node_modules/@isaacs/testing-prod-dep-metadata-missing",
"type": "optional",
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7784,4 +7784,4 @@ ArboristNode {
"name": "yarn-lock-mkdirp-file-dep",
"path": "yarn-lock-mkdirp-file-dep",
}
`
`
Loading
Loading