fix(resolve-dependencies): dedupe deps with the same alias in direct dependencies (#6974)

close #6966
This commit is contained in:
await-ovo
2023-08-25 18:06:45 +08:00
committed by GitHub
parent 3fdaf9c60c
commit 77e24d3415
3 changed files with 78 additions and 3 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/resolve-dependencies": patch
"pnpm": patch
---
Dedupe deps with the same alias in direct dependencies [6966](https://github.com/pnpm/pnpm/issues/6966)

View File

@@ -233,3 +233,48 @@ test.skip('from a github repo that needs to be built. hoisted node linker is us
await install(manifest, await testDefaults({ frozenLockfile: true, ignoreScripts: true, nodeLinker: 'hoisted' }, { ignoreScripts: true }))
await project.hasNot('@pnpm.e2e/prepare-script-works/prepare.txt')
})
test('re-adding a git repo with a different tag', async () => {
const project = prepareEmpty()
let manifest = await addDependenciesToPackage({}, ['kevva/is-negative#1.0.0'], await testDefaults())
await project.has('is-negative')
expect(manifest.dependencies).toStrictEqual({
'is-negative': 'github:kevva/is-negative#1.0.0',
})
expect(JSON.parse(fs.readFileSync('./node_modules/is-negative/package.json', 'utf8')).version).toBe('1.0.0')
let lockfile = await project.readLockfile()
expect(lockfile.dependencies['is-negative']).toEqual({
specifier: 'github:kevva/is-negative#1.0.0',
version: 'github.com/kevva/is-negative/163360a8d3ae6bee9524541043197ff356f8ed99',
})
expect(lockfile.packages).toEqual(
{
'github.com/kevva/is-negative/163360a8d3ae6bee9524541043197ff356f8ed99': {
resolution: { tarball: 'https://codeload.github.com/kevva/is-negative/tar.gz/163360a8d3ae6bee9524541043197ff356f8ed99' },
name: 'is-negative',
version: '1.0.0',
engines: { node: '>=0.10.0' },
dev: false,
},
}
)
manifest = await addDependenciesToPackage(manifest, ['kevva/is-negative#1.0.1'], await testDefaults())
await project.has('is-negative')
expect(JSON.parse(fs.readFileSync('./node_modules/is-negative/package.json', 'utf8')).version).toBe('1.0.1')
lockfile = await project.readLockfile()
expect(lockfile.dependencies['is-negative']).toEqual({
specifier: 'github:kevva/is-negative#1.0.1',
version: 'github.com/kevva/is-negative/9a89df745b2ec20ae7445d3d9853ceaeef5b0b72',
})
expect(lockfile.packages).toEqual(
{
'github.com/kevva/is-negative/9a89df745b2ec20ae7445d3d9853ceaeef5b0b72': {
resolution: { tarball: 'https://codeload.github.com/kevva/is-negative/tar.gz/9a89df745b2ec20ae7445d3d9853ceaeef5b0b72' },
name: 'is-negative',
version: '1.0.1',
engines: { node: '>=0.10.0' },
dev: false,
},
}
)
})

View File

@@ -187,10 +187,9 @@ export async function resolveDependencyTree<T> (
}
}
for (const { id } of importers) {
const directDeps = directDepsByImporterId[id]
for (const { id, wantedDependencies } of importers) {
const directDeps = dedupeSameAliasDirectDeps(directDepsByImporterId[id], wantedDependencies)
const [linkedDependencies, directNonLinkedDeps] = partition((dep) => dep.isLinkedDependency === true, directDeps) as [LinkedDependency[], PkgAddress[]]
resolvedImporters[id] = {
directDependencies: directDeps
.map((dep) => {
@@ -269,3 +268,28 @@ function buildTree (
}
return childrenNodeIds
}
/**
* There may be cases where multiple dependencies have the same alias in the directDeps array.
* E.g., when there is "is-negative: github:kevva/is-negative#1.0.0" in the package.json dependencies,
* and then re-execute `pnpm add github:kevva/is-negative#1.0.1`.
* In order to make sure that the latest 1.0.1 version is installed, we need to remove the duplicate dependency.
* fix https://github.com/pnpm/pnpm/issues/6966
*/
function dedupeSameAliasDirectDeps (directDeps: Array<PkgAddress | LinkedDependency>, wantedDependencies: Array<WantedDependency & { isNew?: boolean }>) {
const deps = new Map()
for (const directDep of directDeps) {
const { alias, normalizedPref } = directDep
if (!deps.has(alias)) {
deps.set(alias, directDep)
} else {
const wantedDep = wantedDependencies.find(dep =>
dep.alias ? dep.alias === alias : dep.pref === normalizedPref
)
if (wantedDep?.isNew) {
deps.set(alias, directDep)
}
}
}
return Array.from(deps.values())
}