Skip to content

Commit 2169018

Browse files
manzoorwanijkowlstronaut
authored andcommitted
fix(arborist): skip extraneous fsChildren in linked-strategy reify
(cherry picked from commit 81793ae)
1 parent 1d0395e commit 2169018

2 files changed

Lines changed: 36 additions & 1 deletion

File tree

workspaces/arborist/lib/arborist/isolated-reifier.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ module.exports = cls => class IsolatedReifier extends cls {
9797
}
9898
this.counter = 0
9999

100-
this.idealGraph.workspaces = await Promise.all(Array.from(idealTree.fsChildren.values(), w => this.#workspaceProxy(w)))
100+
// Skip extraneous fsChildren: workspaces removed from the root manifest can linger in fsChildren via the lockfile, and re-materializing them here would re-create a directory the user just deleted.
101+
const fsChildren = Array.from(idealTree.fsChildren.values()).filter(w => !w.extraneous)
102+
this.idealGraph.workspaces = await Promise.all(fsChildren.map(w => this.#workspaceProxy(w)))
101103
const processed = new Set()
102104
const queue = [idealTree, ...idealTree.fsChildren]
103105
while (queue.length !== 0) {

workspaces/arborist/test/arborist/reify.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3930,6 +3930,39 @@ t.test('install strategy linked', async (t) => {
39303930
t.ok(store.isDirectory(), 'abbrev got installed')
39313931
t.ok(abbrev.isSymbolicLink(), 'abbrev got installed')
39323932
})
3933+
3934+
t.test('does not re-create a workspace dir removed from manifest', async t => {
3935+
// Regression test for https://github.com/npm/cli/issues/9331
3936+
const path = t.testdir({
3937+
'package.json': JSON.stringify({
3938+
name: 'host',
3939+
version: '1.0.0',
3940+
workspaces: ['packages/a', 'packages/b'],
3941+
}),
3942+
packages: {
3943+
a: { 'package.json': JSON.stringify({ name: 'a', version: '1.0.0' }) },
3944+
b: { 'package.json': JSON.stringify({ name: 'b', version: '1.0.0' }) },
3945+
},
3946+
})
3947+
3948+
createRegistry(t, false)
3949+
await reify(path, { installStrategy: 'linked' })
3950+
3951+
// Drop workspace b: remove its directory and its entry from package.json.
3952+
fs.rmSync(resolve(path, 'packages/b'), { recursive: true, force: true })
3953+
fs.writeFileSync(resolve(path, 'package.json'), JSON.stringify({
3954+
name: 'host',
3955+
version: '1.0.0',
3956+
workspaces: ['packages/a'],
3957+
}))
3958+
3959+
await reify(path, { installStrategy: 'linked' })
3960+
3961+
t.notOk(
3962+
fs.existsSync(resolve(path, 'packages/b')),
3963+
'packages/b should remain absent after reinstall'
3964+
)
3965+
})
39333966
})
39343967

39353968
t.test('workspace installs retain existing versions with newer package specs', async t => {

0 commit comments

Comments
 (0)