Zoltan Kochan b2a95fa1f7 feat(pacquet): port catalogs (types, protocol-parser, resolver, config) (#11787)
* feat(pacquet): port catalogs (types, protocol-parser, resolver, config)

Adds four new crates mirroring upstream's `catalogs/*` packages:

- pacquet-catalogs-types: `Catalog`/`Catalogs` map aliases plus
  `DEFAULT_CATALOG_NAME`.
- pacquet-catalogs-protocol-parser: `parse_catalog_protocol`; folds
  `catalog:` shorthand into `"default"` to match upstream.
- pacquet-catalogs-resolver: `resolve_from_catalog` with the four
  upstream `PnpmError` codes (`CATALOG_ENTRY_NOT_FOUND_FOR_SPEC`,
  `CATALOG_ENTRY_INVALID_RECURSIVE_DEFINITION`,
  `CATALOG_ENTRY_INVALID_WORKSPACE_SPEC`,
  `CATALOG_ENTRY_INVALID_SPEC`). Rust callers `match` on the result
  enum directly instead of porting the TS-ergonomic
  `matchCatalogResolveResult` visitor.
- pacquet-catalogs-config: `get_catalogs_from_workspace_manifest` plus
  the `INVALID_CATALOGS_CONFIGURATION` mutual-exclusion check.

`pacquet-workspace`'s `WorkspaceManifest` now actually deserializes
the `catalog` and `catalogs` fields (previously dropped). The
resolver is not yet wired into the install path — `deps-installer`
hasn't been ported — but the crates are ready for that next step.

Tests are 1:1 ports of the upstream Jest suites.

* fix(pacquet): satisfy rustdoc and perfectionist lints in catalogs port

- catalogs-resolver: drop the intra-doc-link form on the
  `pacquet_resolving_resolver_base::WantedDependency` reference; the
  crate isn't a dependency, so rustdoc failed to resolve it under
  `-D rustdoc::broken-intra-doc-links`.
- catalogs-resolver, catalogs-config: reorder the `CatalogResolutionError`
  / `InvalidCatalogsConfigurationError` derive lists to
  `Debug, Display, Error, Diagnostic, Clone, PartialEq, Eq` so they
  match the `prefix_then_alphabetical` rule that the CI-only
  Perfectionist dylint enforces. `just ready` doesn't surface this lint
  locally.

* feat(pacquet): resolve catalog: specifiers during install

Wires the catalogs port into the install path:

- `install.rs`: read `pnpm-workspace.yaml` after `find_workspace_dir`
  and normalize via `get_catalogs_from_workspace_manifest` into a
  `Catalogs` map. Adds `InstallError::{ReadWorkspaceManifest,
  InvalidCatalogsConfiguration}` so the upstream
  `ERR_PNPM_INVALID_CATALOGS_CONFIGURATION` propagates verbatim.
- `install_without_lockfile.rs`: threads the `Catalogs` map into
  `ResolveDependencyTreeOptions`. (Frozen-lockfile catalog handling
  needs a lockfile-snapshot pass and is a separate slice.)
- `resolve_dependency_tree`: replaces direct (importer-level)
  `catalog:` bare specifiers with the catalog's recorded version
  before the resolver chain dispatches. Catalog resolution does NOT
  run on transitive deps, matching upstream's importer-only scope.
  Misconfigured entries surface as `CatalogMisconfiguration` with
  the upstream `ERR_PNPM_CATALOG_ENTRY_*` code instead of leaking
  through to `SPEC_NOT_SUPPORTED_BY_ANY_RESOLVER`.

Tests:

- deps-resolver: two new unit tests prove direct-dep rewriting and
  the misconfiguration code path.
- cli (e2e): `install_resolves_catalog_protocol` runs the binary
  against a workspace with a `catalog:` entry and checks the
  virtual-store layout; `install_surfaces_catalog_misconfiguration`
  asserts the upstream message is surfaced when the catalog has no
  matching alias.

* style(pacquet): apply rustfmt to catalogs test after rebase

* fix(pacquet): rename single-letter closure param in catalogs e2e test

Perfectionist's `single_letter_closure_param` lint (CI-only via
Dylint) flagged `|c|` in the box-drawing-strip filter.
2026-05-21 02:06:05 +02:00
2026-04-10 18:30:33 +02:00
2026-04-10 18:30:33 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 12:41:09 +02:00
2026-04-30 23:03:46 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 16:51:13 +02:00
2026-04-30 23:19:31 +02:00
2026-05-20 16:51:13 +02:00
2026-05-20 16:51:13 +02:00
2026-04-30 23:03:46 +02:00
2026-05-20 12:41:09 +02:00
2026-05-20 16:51:13 +02:00
2026-01-16 16:31:31 +01:00
2024-03-21 01:09:22 +01:00
2022-06-01 02:48:58 +03:00

简体中文 | 日本語 | 한국어 | Italiano | Português Brasileiro

pnpm

Fast, disk space efficient package manager:

  • Fast. Up to 2x faster than the alternatives (see benchmark).
  • Efficient. Files inside node_modules are linked from a single content-addressable storage.
  • Great for monorepos.
  • Strict. A package can access only dependencies that are specified in its package.json.
  • Deterministic. Has a lockfile called pnpm-lock.yaml.
  • Works as a Node.js version manager. See pnpm runtime.
  • Works everywhere. Supports Windows, Linux, and macOS.
  • Battle-tested. Used in production by teams of all sizes since 2016.
  • See the full feature comparison with npm and Yarn.

To quote the Rush team:

Microsoft uses pnpm in Rush repos with hundreds of projects and hundreds of PRs per day, and weve found it to be very fast and reliable.

npm version OpenCollective OpenCollective X Follow Stand With Ukraine

Platinum Sponsors

Bit

Gold Sponsors

Sanity Discord Vite
SerpApi CodeRabbit Stackblitz
Workleap Nx

Silver Sponsors

Replit Cybozu devowl.io
u|screen Leniolabs_ Depot
Cerbos ⏱️ Time.now

Support this project by becoming a sponsor.

Background

pnpm uses a content-addressable filesystem to store all files from all module directories on a disk. When using npm, if you have 100 projects using lodash, you will have 100 copies of lodash on disk. With pnpm, lodash will be stored in a content-addressable storage, so:

  1. If you depend on different versions of lodash, only the files that differ are added to the store. If lodash has 100 files, and a new version has a change only in one of those files, pnpm update will only add 1 new file to the storage.
  2. All the files are saved in a single place on the disk. When packages are installed, their files are linked from that single place consuming no additional disk space. Linking is performed using either hard-links or reflinks (copy-on-write).

As a result, you save gigabytes of space on your disk and you have a lot faster installations! If you'd like more details about the unique node_modules structure that pnpm creates and why it works fine with the Node.js ecosystem, read this small article: Flat node_modules is not the only way.

💖 Like this project? Let people know with a tweet

Getting Started

Benchmark

pnpm is up to 2x faster than npm and Yarn classic. See all benchmarks here.

Benchmarks on an app with lots of dependencies:

License

MIT

Description
No description provided
Readme MIT 346 MiB
Languages
Rust 56.4%
TypeScript 43%
JavaScript 0.5%