Skip to content

Commit 81793ae

Browse files
manzoorwanijkowlstronaut
authored andcommitted
fix(arborist): skip extraneous fsChildren in linked-strategy reify
1 parent 4c7f6ba commit 81793ae

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
@@ -95,7 +95,9 @@ module.exports = cls => class IsolatedReifier extends cls {
9595
}
9696
this.counter = 0
9797

98-
this.idealGraph.workspaces = await Promise.all(Array.from(idealTree.fsChildren.values(), w => this.#workspaceProxy(w)))
98+
// 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.
99+
const fsChildren = Array.from(idealTree.fsChildren.values()).filter(w => !w.extraneous)
100+
this.idealGraph.workspaces = await Promise.all(fsChildren.map(w => this.#workspaceProxy(w)))
99101
const processed = new Set()
100102
const queue = [idealTree, ...idealTree.fsChildren]
101103
while (queue.length !== 0) {

workspaces/arborist/test/arborist/reify.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3807,6 +3807,39 @@ t.test('install strategy linked', async (t) => {
38073807
t.ok(store.isDirectory(), 'abbrev got installed')
38083808
t.ok(abbrev.isSymbolicLink(), 'abbrev got installed')
38093809
})
3810+
3811+
t.test('does not re-create a workspace dir removed from manifest', async t => {
3812+
// Regression test for https://github.com/npm/cli/issues/9331
3813+
const path = t.testdir({
3814+
'package.json': JSON.stringify({
3815+
name: 'host',
3816+
version: '1.0.0',
3817+
workspaces: ['packages/a', 'packages/b'],
3818+
}),
3819+
packages: {
3820+
a: { 'package.json': JSON.stringify({ name: 'a', version: '1.0.0' }) },
3821+
b: { 'package.json': JSON.stringify({ name: 'b', version: '1.0.0' }) },
3822+
},
3823+
})
3824+
3825+
createRegistry(t, false)
3826+
await reify(path, { installStrategy: 'linked' })
3827+
3828+
// Drop workspace b: remove its directory and its entry from package.json.
3829+
fs.rmSync(resolve(path, 'packages/b'), { recursive: true, force: true })
3830+
fs.writeFileSync(resolve(path, 'package.json'), JSON.stringify({
3831+
name: 'host',
3832+
version: '1.0.0',
3833+
workspaces: ['packages/a'],
3834+
}))
3835+
3836+
await reify(path, { installStrategy: 'linked' })
3837+
3838+
t.notOk(
3839+
fs.existsSync(resolve(path, 'packages/b')),
3840+
'packages/b should remain absent after reinstall'
3841+
)
3842+
})
38103843
})
38113844

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

0 commit comments

Comments
 (0)