fix(npm): resolve catalog: overrides from workspaces object form#33816
Conversation
The package.json `workspaces` field can be either an array of globs or an object with `packages` and `catalog`/`catalogs` sub-fields (Bun/Yarn format). The parser only handled the array form, so `catalog:` references in overrides couldn't be resolved when the catalog was defined inside the workspaces object. Fixes the "could not be resolved (package not found in catalog)" warning reported against #33799.
|
@sigmaSd can you try this one? |
fibibot
left a comment
There was a problem hiding this comment.
LGTM. Clean, focused fix for catalog: overrides under the Bun/Yarn workspaces: { packages, catalog, catalogs } object form. Substance walks correctly and the test coverage pins the new path.
What I verified
Detection logic (libs/package_json/lib.rs:526-552): cleanly branches on workspaces value shape:
Value::Array(arr)→ legacy/npm form, treat asparse_string_array→ workspace globs only, no catalog extraction.Value::Object(mut obj)→ Bun/Yarn form, extractpackages(array of globs),catalog(string map), andcatalogs(named map of catalogs).- Anything else (
Null,String, etc.) →(None, None, None). Sane default.
Precedence (:567-580): top-level catalog/catalogs win over the workspaces-object versions via .or(ws_catalog) / .or(ws_catalogs). Matches Bun/Yarn semantics where the explicit top-level field is the override.
Test coverage:
- Unit test
test_workspaces_object_form_cataloginlib.rs:1104-1121exercises the parse and asserts bothpj.workspaces(extracted from the innerpackagesfield) andpj.catalog(extracted from the innercatalogfield) resolve correctly. - Spec test
tests/specs/npm/overrides/catalog_override_workspaces_object/does the full end-to-end:package.jsonwithworkspaces: { packages, catalog }+overrides: { ...: "catalog:" }, runs the resolved override, asserts the resolved version printed.
CI
All 6 platforms × test specs / test unit / test unit_node debug mode jobs pass (the relevant signal for a libs/package_json parsing change). 4 of 5 release-mode shards pass; release-linux-x86_64 still in flight.
One failure row on test specs (2/2) debug macos-x86_64, but the [error] line is Failed to CreateArtifact: Unable to make request: ENOTFOUND - a GitHub Actions runner DNS flake during the post-job artifact upload, not a test failure. All 1000+ test cases in that shard show ok. Treating that as infra flake; the parsing logic is platform-independent so the in-flight release-linux shards aren't going to reveal anything the debug shards didn't.
Smaller observations (non-blocking)
- The duplicated
catalogs-parsing closure (extracted once forws_catalogsand once for the top-level fallback) could be lifted into a helperfn parse_catalogs(v: Value) -> Option<IndexMap<String, IndexMap<String, String>>>. Pure code-cleanliness; doesn't change behavior. - Edge case:
workspaces: { catalog: {...} }with nopackagesis parsed without error (returningpkgs = None). Yarn would warn on this shape since workspaces without packages is meaningless, but treating it leniently is reasonable - the catalog still gets extracted, which is what the user clearly intended.
|
|
@sigmaSd that appears to be correct then; github: specifiers support is a separate problem. |
|
what about these so this time this one is expected ? though I don't see bun warn about this |
|
I checked with Claude and got this: It appears all these package managers ignore it, but only Deno warns that it's ignored. We might want to relax that in the future and not print a warning. |
…oland#33816) - Fixes `catalog:` overrides failing with "could not be resolved (package not found in catalog)" when the catalog is defined inside the `workspaces` object form (Bun/Yarn format: `"workspaces": { "packages": [...], "catalog": {...} }`) - The package.json parser now handles both the array form (`"workspaces": [...]`) and the object form, extracting `catalog`/`catalogs` from the latter - Top-level `catalog`/`catalogs` fields take precedence over those nested in the workspaces object Reported in denoland#33799 (comment)
Summary
catalog:overrides failing with "could not be resolved (package not found in catalog)" when the catalog is defined inside theworkspacesobject form (Bun/Yarn format:"workspaces": { "packages": [...], "catalog": {...} })"workspaces": [...]) and the object form, extractingcatalog/catalogsfrom the lattercatalog/catalogsfields take precedence over those nested in the workspaces objectReported in #33799 (comment)
Test plan
test_workspaces_object_form_catalog,test_workspaces_object_form_top_level_catalog_takes_precedencespecs::npm::overrides::catalog_override_workspaces_object