diff --git a/.yarn/versions/f352ecbe.yml b/.yarn/versions/f352ecbe.yml new file mode 100644 index 000000000000..0a460931acc0 --- /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" 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 1fd90e92c549..370219960cba 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( diff --git a/packages/plugin-catalog/sources/utils.ts b/packages/plugin-catalog/sources/utils.ts index 14bb04df9c61..090dcef5d1a8 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); diff --git a/packages/plugin-catalog/tests/utils.test.ts b/packages/plugin-catalog/tests/utils.test.ts index 3072b2b28979..72d234df48ca 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`],