From e963d0f8ad4a0aa8cb714c4c6ded5670049fb994 Mon Sep 17 00:00:00 2001 From: parksb Date: Thu, 2 Oct 2025 23:45:45 +0900 Subject: [PATCH 1/4] Bypass binding when descriptor isn't supported by any resolver --- packages/plugin-catalog/sources/utils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/plugin-catalog/sources/utils.ts b/packages/plugin-catalog/sources/utils.ts index 14bb04df9c6..090dcef5d1a 100644 --- a/packages/plugin-catalog/sources/utils.ts +++ b/packages/plugin-catalog/sources/utils.ts @@ -53,6 +53,10 @@ export const resolveDescriptorFromCatalog = (project: Project, dependency: Descr structUtils.makeDescriptor(dependency, resolvedRange), ); + // If the descriptor isn't supported by any available resolver, return it as is + if (!resolver.supportsDescriptor(normalizedDescriptor, resolveOptions)) + return normalizedDescriptor; + // Bind the descriptor to the project's top level workspace (which should match the project root), // addressing issues with relative file paths when using `file:` protocol const boundDescriptor = resolver.bindDescriptor(normalizedDescriptor, project.topLevelWorkspace.anchoredLocator, resolveOptions); From 9beacb4e6fa6141bcd5fc6edcd93bb3363f1e0ff Mon Sep 17 00:00:00 2001 From: parksb Date: Thu, 2 Oct 2025 23:45:54 +0900 Subject: [PATCH 2/4] Write unit test --- packages/plugin-catalog/tests/utils.test.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/plugin-catalog/tests/utils.test.ts b/packages/plugin-catalog/tests/utils.test.ts index 3072b2b2897..72d234df48c 100644 --- a/packages/plugin-catalog/tests/utils.test.ts +++ b/packages/plugin-catalog/tests/utils.test.ts @@ -96,6 +96,7 @@ describe(`utils`, () => { // Create mock resolver with bindDescriptor method mockResolver = { bindDescriptor: jest.fn(descriptor => descriptor), + supportsDescriptor: jest.fn(() => true), } as any; resolveOptions = { @@ -141,6 +142,25 @@ describe(`utils`, () => { expect(structUtils.stringifyIdent(resolved)).toBe(`lodash`); }); + it(`should not resolve descriptor if it isn't supported by any resolver`, () => { + const catalog = new Map([ + [`react`, `custom:^18.0.0`], + ]); + configuration.values.set(`catalog`, catalog); + + const dependency = structUtils.makeDescriptor( + structUtils.makeIdent(null, `react`), + `catalog:`, + ); + mockResolver.supportsDescriptor.mockReturnValue(false); + + const resolved = resolveDescriptorFromCatalog(project, dependency, mockResolver, resolveOptions); + + expect(mockResolver.bindDescriptor).toHaveBeenCalledTimes(0); + expect(resolved.range).toBe(`custom:^18.0.0`); + expect(structUtils.stringifyIdent(resolved)).toBe(`react`); + }); + it(`should normalize the resolved descriptor`, () => { const catalog = new Map([ [`typescript`, `^5.0.0`], From b8ff0a6643018d72175d2114dab58680c6957c4d Mon Sep 17 00:00:00 2001 From: parksb Date: Fri, 3 Oct 2025 00:04:18 +0900 Subject: [PATCH 3/4] Check version --- .yarn/versions/f352ecbe.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .yarn/versions/f352ecbe.yml diff --git a/.yarn/versions/f352ecbe.yml b/.yarn/versions/f352ecbe.yml new file mode 100644 index 00000000000..0a460931acc --- /dev/null +++ b/.yarn/versions/f352ecbe.yml @@ -0,0 +1,24 @@ +releases: + "@yarnpkg/cli": patch + "@yarnpkg/plugin-catalog": patch + +declined: + - "@yarnpkg/plugin-compat" + - "@yarnpkg/plugin-constraints" + - "@yarnpkg/plugin-dlx" + - "@yarnpkg/plugin-essentials" + - "@yarnpkg/plugin-init" + - "@yarnpkg/plugin-interactive-tools" + - "@yarnpkg/plugin-nm" + - "@yarnpkg/plugin-npm-cli" + - "@yarnpkg/plugin-pack" + - "@yarnpkg/plugin-patch" + - "@yarnpkg/plugin-pnp" + - "@yarnpkg/plugin-pnpm" + - "@yarnpkg/plugin-stage" + - "@yarnpkg/plugin-typescript" + - "@yarnpkg/plugin-version" + - "@yarnpkg/plugin-workspace-tools" + - "@yarnpkg/builder" + - "@yarnpkg/core" + - "@yarnpkg/doctor" From b3708d03f100398296e1a4fc08aac06727826431 Mon Sep 17 00:00:00 2001 From: parksb Date: Fri, 3 Oct 2025 00:41:18 +0900 Subject: [PATCH 4/4] Write integration test --- .../sources/features/catalogs.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/features/catalogs.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/features/catalogs.test.ts index 1fd90e92c54..370219960cb 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/features/catalogs.test.ts +++ b/packages/acceptance-tests/pkg-tests-specs/sources/features/catalogs.test.ts @@ -271,6 +271,26 @@ describe(`Features`, () => { ), ); + test( + `it should throw an error when protocol in catalog isn't supported by any resolver`, + makeTemporaryEnv( + { + dependencies: { + [`no-deps`]: `catalog:`, + }, + }, + async ({path, run, source}) => { + await yarn.writeConfiguration(path, { + catalog: { + [`no-deps`]: `unknown-protocol:2.0.0`, + }, + }); + + await expect(run(`install`)).rejects.toThrow(); + }, + ), + ); + test( `it should work with file: protocol ranges in catalogs`, makeTemporaryEnv(