Skip to content

Conversation

@ho991217
Copy link

@ho991217 ho991217 commented Nov 4, 2025

closes: #6920

What's the problem this PR addresses?

When using the catalog plugin with TypeScript, installations would fail even with simple version specifications. For example:

catalog:
  typescript: 5.9.2
{
  "devDependencies": {
    "typescript": "catalog:"
  }
}

This would fail with:

Error: typescript@patch:typescript@npm%3A5.9.2#... isn't supported by any available resolver

Root cause: When resolving typescript: 5.9.2 from the catalog, Yarn automatically applies compatibility patches internally, resulting in a patch: protocol range in yarn.lock. However, the catalog plugin was incorrectly stripping or mangling this protocol information during resolution, causing the resolver to fail.

This issue affects not just TypeScript, but any package that uses special protocols like patch:, portal:, or link: - whether explicitly specified in the catalog or automatically applied by Yarn.

How did you fix it?

1. Added safe protocol preservation

Introduced SAFE_PROTOCOLS_TO_ALWAYS_KEEP to explicitly preserve protocols that have special semantics:

  • patch: - for applying patches to packages (including auto-applied compat patches)
  • portal: - for local workspace references
  • link: - for symlinked packages

2. Implemented tryRoundTripRange function

This function safely normalizes ranges while preserving protocol information:

  • Only removes the npm: protocol when it's exactly the default protocol
  • Never removes safe protocols that carry semantic meaning
  • Includes idempotency checks to ensure normalization doesn't change the range's meaning
  • Falls back to the original range if any errors occur

3. Fixed hook implementations

  • beforeWorkspacePacking: Now uses convertToManifestRange to strip internal params (like __locator) before applying the round-trip normalization, ensuring clean package.json files in published packages
  • reduceDependency: Returns the full range with protocol intact, as the resolver needs complete protocol information during dependency resolution

4. Added comprehensive tests

Added test cases for all three safe protocols to ensure they are correctly preserved when resolving catalog references.

Testing

Tested with both explicit and implicit patch protocol usage:

# Explicit patch in catalog
catalog:
  typescript: "patch:typescript@npm%3A^5.9.3#optional!builtin<compat/typescript>"

# Simple version that gets auto-patched
catalog:
  typescript: 5.9.2

Both cases now work correctly, with the patch protocol being properly preserved during resolution and installation.

Checklist

  • I have set the packages that need to be released for my changes to be effective.
  • I will check that all automated PR checks pass before the PR gets reviewed.

@ho991217 ho991217 force-pushed the catalog-drop-protocol branch from e657d26 to 49c2261 Compare November 4, 2025 08:24
@ho991217 ho991217 changed the title drop protocol after normalization Preserve special protocols (patch:, portal:, link:) when resolving catalog references Nov 4, 2025
@ho991217 ho991217 marked this pull request as ready for review November 4, 2025 08:33
@ho991217 ho991217 force-pushed the catalog-drop-protocol branch from 49c2261 to 05855e5 Compare November 4, 2025 08:52
Comment on lines -89 to -90
if (protocol === workspace.project.configuration.get(`defaultProtocol`))
protocol = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand - shouldn't the protocol only be stripped if it's equal to "npm:" ?

@arcanis
Copy link
Member

arcanis commented Nov 7, 2025

I think the fix might be different and just a matter of reorganizing the catalog order in the hook list, at least for typescript. See #6969.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: new catalog feature fails with typescript@catalog

3 participants