diff --git a/.changeset/young-insects-grab.md b/.changeset/young-insects-grab.md new file mode 100644 index 0000000000..faa017cb42 --- /dev/null +++ b/.changeset/young-insects-grab.md @@ -0,0 +1,6 @@ +--- +"@pnpm/resolve-dependencies": patch +"pnpm": patch +--- + +Fix peer dependency resolution dead lock [#8570](https://github.com/pnpm/pnpm/issues/8570). diff --git a/pkg-manager/core/test/install/misc.ts b/pkg-manager/core/test/install/misc.ts index 62b9bc9280..a63d6c0cda 100644 --- a/pkg-manager/core/test/install/misc.ts +++ b/pkg-manager/core/test/install/misc.ts @@ -1243,3 +1243,11 @@ test('a package should be able to be a dependency of itself', async () => { expect(pkg.version).toBe('1.0.0') } }) + +// Covers https://github.com/pnpm/pnpm/issues/8570 +test('install should not hang on circular peer dependencies', async () => { + prepareEmpty() + + // cspell:disable-next-line + await addDependenciesToPackage({}, ['@medusajs/medusa-js@6.1.7'], testDefaults()) +}) diff --git a/pkg-manager/core/test/install/peerDependencies.ts b/pkg-manager/core/test/install/peerDependencies.ts index 628360b55a..b6839bff52 100644 --- a/pkg-manager/core/test/install/peerDependencies.ts +++ b/pkg-manager/core/test/install/peerDependencies.ts @@ -987,7 +987,7 @@ test('peer dependency is resolved from parent package via its alias', async () = const lockfile = readYamlFile(WANTED_LOCKFILE) expect(Object.keys(lockfile.snapshots ?? {}).sort()).toStrictEqual([ - '@pnpm.e2e/has-tango-as-peer-dep@1.0.0(@pnpm.e2e/tango-tango@1.0.0(@pnpm.e2e/tango-tango@1.0.0))', + '@pnpm.e2e/has-tango-as-peer-dep@1.0.0(@pnpm.e2e/tango-tango@1.0.0)', '@pnpm.e2e/tango-tango@1.0.0(@pnpm.e2e/tango-tango@1.0.0)', ].sort()) }) diff --git a/pkg-manager/resolve-dependencies/src/resolvePeers.ts b/pkg-manager/resolve-dependencies/src/resolvePeers.ts index 58d1117dcd..0c287fff7c 100644 --- a/pkg-manager/resolve-dependencies/src/resolvePeers.ts +++ b/pkg-manager/resolve-dependencies/src/resolvePeers.ts @@ -567,7 +567,9 @@ async function resolvePeersOfNode ( .map(async (peerNodeId) => { if (cyclicPeerNodeIds.has(peerNodeId)) { const { name, version } = (ctx.dependenciesTree.get(peerNodeId)!.resolvedPackage as T) - return `${name}@${version}` + const id = `${name}@${version}` + ctx.pathsByNodeIdPromises.get(peerNodeId)?.resolve(id as DepPath) + return id } return ctx.pathsByNodeIdPromises.get(peerNodeId)!.promise })