fix(core): prevent duplication of peerDependencyRules in the lockfile (#4576)

If a workspace has a global peerDependencyRule that is applied by more
than one package, the lockfile could contain duplicate copies
of the patched range. For example react-dom might have
`peerDependencies: 17.0.2 | 17 | 17 | 17 | 17` in the lockfile.

This causes merge conflicts as package updates seem to regularly change
the number of duplicates, causing lockfile conflicts.

The fix checks if the same widened range has already been appended,
and ignores subsequent duplicates if they exist.
This commit is contained in:
Kam Figy
2022-04-15 10:06:11 -07:00
committed by GitHub
parent b2d00316f3
commit 88289a42c9
3 changed files with 55 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/core": patch
---
peerDependencyRules will no longer cause duplicated peer dependency rules in the lockfile when used in workspaces

View File

@@ -21,10 +21,23 @@ export default function (
if (peerDependencyRules.allowedVersions[peerName] === '*') {
pkg.peerDependencies![peerName] = '*'
} else {
pkg.peerDependencies![peerName] += ` || ${peerDependencyRules.allowedVersions[peerName]}`
const allowedVersions = parseVersions(peerDependencyRules.allowedVersions[peerName])
const currentVersions = parseVersions(pkg.peerDependencies![peerName])
allowedVersions.forEach(allowedVersion => {
if (!currentVersions.includes(allowedVersion)) {
currentVersions.push(allowedVersion)
}
})
pkg.peerDependencies![peerName] = currentVersions.join(' || ')
}
}
}
return pkg
}) as ReadPackageHook
}
function parseVersions (versions: string) {
return versions.split('||').map(v => v.trim())
}

View File

@@ -40,3 +40,39 @@ test('createPeerDependencyPatcher() extends peer ranges', () => {
baz: '*',
})
})
test('createPeerDependencyPatcher() does not create duplicate extended ranges', async () => {
const patcher = createPeerDependencyPatcher({
allowedVersions: {
foo: '1',
same: '12',
multi: '16',
mix: '1 || 2 || 3',
partialmatch: '1',
nopadding: '^17.0.1||18.x',
},
})
const patchedPkg = patcher({
peerDependencies: {
foo: '0',
same: '12',
multi: '16 || 17',
mix: '1 || 4',
partialmatch: '16 || 1.2.1',
nopadding: '15.0.1||16',
},
})
// double apply the same patch to the same package
// this can occur in a monorepo when several packages
// all try to apply the same patch
const patchedAgainPkg = patcher(await patchedPkg)
expect(patchedAgainPkg['peerDependencies']).toStrictEqual({
// the patch is applied only once (not 0 || 1 || 1)
foo: '0 || 1',
same: '12',
multi: '16 || 17',
mix: '1 || 4 || 2 || 3',
partialmatch: '16 || 1.2.1 || 1',
nopadding: '15.0.1 || 16 || ^17.0.1 || 18.x',
})
})