feat(pacquet): port excludeLinksFromLockfile#12025
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (18)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (17)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
📝 WalkthroughWalkthroughAdds an ChangesExclude Links from Lockfile
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review Summary by QodoPort excludeLinksFromLockfile setting to pacquet for stable peer-suffix hashes across machines
WalkthroughsDescription• Port pnpm's excludeLinksFromLockfile setting to pacquet for stable peer-suffix hashes • Add config flag exclude_links_from_lockfile with env-overlay and workspace YAML support • Omit bare link: direct deps from lockfile importer entries (keep workspace: links) • Remap external link targets to stable link:/ node IDs for peer resolution • Extract shared is_subdir helper and port linkPathToPeerVersion for link-path encoding Diagramflowchart LR
Config["Config: exclude_links_from_lockfile flag"]
Importer["build_importer: skip bare link: deps"]
PeerRemap["remap_link_node_id: link:node_modules/alias"]
PeerId["build_peer_id: link_path_to_peer_version"]
Snapshot["Snapshot child: use remapped link node ID"]
Config --> Importer
Config --> PeerRemap
PeerRemap --> PeerId
PeerId --> Snapshot
File Changes1. pacquet/crates/config/src/lib.rs
|
Micro-Benchmark ResultsLinux |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #12025 +/- ##
==========================================
+ Coverage 88.30% 88.39% +0.09%
==========================================
Files 228 230 +2
Lines 28961 29111 +150
==========================================
+ Hits 25573 25733 +160
+ Misses 3388 3378 -10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pacquet/crates/deps-path/src/link_path_to_peer_version.rs`:
- Around line 15-43: The code currently iterates raw bytes and uses out.push(c
as char) which corrupts non-ASCII UTF-8; change the loop to iterate Unicode
scalar values (chars) from rel_path rather than bytes: compute the index/offset
for skipping leading '.' using char iteration (or use
rel_path.trim_start_matches('.') to get the slice after leading dots), then
iterate over rel_path.chars() (or the trimmed &str) checking replacement
conditions on char values (e.g. c < '\u{20}' || c == '"' || c == '*' || c == '+'
... ) and push the char with out.push(c) while preserving the existing
last_was_plus logic and '+' insertion behavior so UTF‑8 segments are preserved
and pnpm token behavior is matched; replace references to bytes, bytes[i], and c
as char with char-based variables (use rel_path, out, last_was_plus to locate
changes).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 25bd2515-2822-4c28-9b19-4d6997ea2a73
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (18)
pacquet/crates/cmd-shim/src/bin_resolver.rspacquet/crates/config/README.mdpacquet/crates/config/src/env_overlay.rspacquet/crates/config/src/lib.rspacquet/crates/config/src/workspace_yaml.rspacquet/crates/deps-path/src/lib.rspacquet/crates/deps-path/src/link_path_to_peer_version.rspacquet/crates/fs/src/is_subdir.rspacquet/crates/fs/src/lib.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile/tests.rspacquet/crates/package-manager/src/install_package_from_registry/tests.rspacquet/crates/package-manager/src/install_with_fresh_lockfile.rspacquet/crates/resolving-deps-resolver/Cargo.tomlpacquet/crates/resolving-deps-resolver/src/resolve_importer.rspacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rspacquet/crates/resolving-deps-resolver/src/resolve_peers.rspacquet/crates/resolving-deps-resolver/src/tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
pacquet/**/*.rs
📄 CodeRabbit inference engine (pacquet/AGENTS.md)
pacquet/**/*.rs: When porting a function that firespnpm:<channel>events throughglobalLogger,logger.debug(), orstreamParser.write(), mirror the call site, payload, and ordering so the reporter parses pacquet's NDJSON the same way it parses pnpm's.
Declare a newtype wrapper for branded string types. Do not collapse the brand into a plainStringor&str.
If upstream always validates before construction, validate in pacquet's wrapper too. The wrapper must construct only viaTryFrom<String>and/orFromStr. Do not provide an infallible public constructor.
If upstream never validates, just brand for type-safety. Expose an infallibleFrom<String>(andFrom<&str>when convenient).
If upstream occasionally constructs without validation, exposefrom_str_uncheckedas an escape hatch alongside the validating constructor.
Match upstream serde behavior for branded types that cross JSON, YAML, or INI boundaries. Use#[serde(try_from = "String")]for deserialization and#[serde(into = "String")]for serialization.
Use#[derive(derive_more::From)]and#[derive(derive_more::Into)]for mechanical conversion impls. Fall back to manualimplonly when conversion needs custom logic.
String-literal unions should becomeenums, not newtype wrappers. Model closed sets of valid string values as enums.
Template literal types should be treated as branded strings with validation discipline from rules 2-5.
Choose owned vs. borrowed parameters to minimize copies. Widen to the most encompassing type (&Pathover&PathBuf,&strover&String) when it doesn't force extra copies.
PreferArc::clone(&x)/Rc::clone(&x)overx.clone()for reference-counted types, so the cost is visible at the call site.
Follow Rust API Guidelines for naming conventions.
Do not use star imports inside module bodies. Writeuse super::{Foo, bar}instead ofuse super::*;. Two forms stay allowed: external-crate preludes likeuse rayon::prelude::*;and root-of-module re-...
Files:
pacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rspacquet/crates/package-manager/src/install_package_from_registry/tests.rspacquet/crates/config/src/env_overlay.rspacquet/crates/deps-path/src/lib.rspacquet/crates/deps-path/src/link_path_to_peer_version.rspacquet/crates/fs/src/is_subdir.rspacquet/crates/config/src/workspace_yaml.rspacquet/crates/fs/src/lib.rspacquet/crates/resolving-deps-resolver/src/resolve_importer.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile/tests.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile.rspacquet/crates/resolving-deps-resolver/src/tests.rspacquet/crates/config/src/lib.rspacquet/crates/package-manager/src/install_with_fresh_lockfile.rspacquet/crates/resolving-deps-resolver/src/resolve_peers.rspacquet/crates/cmd-shim/src/bin_resolver.rs
🧠 Learnings (5)
📚 Learning: 2026-05-20T19:40:55.051Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11774
File: pacquet/crates/resolving-deps-resolver/src/resolve_peers.rs:0-0
Timestamp: 2026-05-20T19:40:55.051Z
Learning: In the pacquet Rust code, ensure the semver implementation uses the `node-semver` crate (not `nodejs-semver`). `node-semver`’s public API does not include a `satisfies_with_prerelease`-style method; prerelease-tolerant matching should be implemented inline by first calling `Range::satisfies`, and when it rejects a prerelease version, retry matching against a stripped `MAJOR.MINOR.PATCH` base of the prerelease version.
Applied to files:
pacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rspacquet/crates/package-manager/src/install_package_from_registry/tests.rspacquet/crates/config/src/env_overlay.rspacquet/crates/deps-path/src/lib.rspacquet/crates/deps-path/src/link_path_to_peer_version.rspacquet/crates/fs/src/is_subdir.rspacquet/crates/config/src/workspace_yaml.rspacquet/crates/fs/src/lib.rspacquet/crates/resolving-deps-resolver/src/resolve_importer.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile/tests.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile.rspacquet/crates/resolving-deps-resolver/src/tests.rspacquet/crates/config/src/lib.rspacquet/crates/package-manager/src/install_with_fresh_lockfile.rspacquet/crates/resolving-deps-resolver/src/resolve_peers.rspacquet/crates/cmd-shim/src/bin_resolver.rs
📚 Learning: 2026-05-22T00:08:44.646Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11837
File: pacquet/crates/resolving-npm-resolver/src/pick_package.rs:33-51
Timestamp: 2026-05-22T00:08:44.646Z
Learning: In the pnpm/pnpm repo’s pacquet Rust crates, do not flag Unicode ellipsis characters (U+2026, `…`) in Rust doc comments (`///` / `/** */`) as a lint violation. The pacquet crate’s `dylint.toml` only enables `perfectionist::derive_ordering`, and the Dylint `unicode-ellipsis` rule is not enabled for this project—so `…` in doc comments is an intentional, repo-consistent style.
Applied to files:
pacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rspacquet/crates/package-manager/src/install_package_from_registry/tests.rspacquet/crates/config/src/env_overlay.rspacquet/crates/deps-path/src/lib.rspacquet/crates/deps-path/src/link_path_to_peer_version.rspacquet/crates/fs/src/is_subdir.rspacquet/crates/config/src/workspace_yaml.rspacquet/crates/fs/src/lib.rspacquet/crates/resolving-deps-resolver/src/resolve_importer.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile/tests.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile.rspacquet/crates/resolving-deps-resolver/src/tests.rspacquet/crates/config/src/lib.rspacquet/crates/package-manager/src/install_with_fresh_lockfile.rspacquet/crates/resolving-deps-resolver/src/resolve_peers.rspacquet/crates/cmd-shim/src/bin_resolver.rs
📚 Learning: 2026-05-20T23:07:58.444Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:07:58.444Z
Learning: When reviewing code in this pacquet Rust port, follow the upstream pnpm compatibility rule: only match pnpm’s behavior exactly. Do not propose review changes that intentionally deviate from pnpm’s documented/observed behavior, even if pnpm appears buggy. If you identify a real bug in pnpm behavior, the review should prioritize fixing it upstream in pnpm first, and avoid implementing a pnpm-behavior workaround here unless the same fix has already landed upstream.
Applied to files:
pacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rspacquet/crates/package-manager/src/install_package_from_registry/tests.rspacquet/crates/config/src/env_overlay.rspacquet/crates/deps-path/src/lib.rspacquet/crates/deps-path/src/link_path_to_peer_version.rspacquet/crates/fs/src/is_subdir.rspacquet/crates/config/src/workspace_yaml.rspacquet/crates/fs/src/lib.rspacquet/crates/resolving-deps-resolver/src/resolve_importer.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile/tests.rspacquet/crates/package-manager/src/dependencies_graph_to_lockfile.rspacquet/crates/resolving-deps-resolver/src/tests.rspacquet/crates/config/src/lib.rspacquet/crates/package-manager/src/install_with_fresh_lockfile.rspacquet/crates/resolving-deps-resolver/src/resolve_peers.rspacquet/crates/cmd-shim/src/bin_resolver.rs
📚 Learning: 2026-05-24T21:10:50.292Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11915
File: pacquet/crates/resolving-deps-resolver/src/resolve_dependency_tree.rs:553-617
Timestamp: 2026-05-24T21:10:50.292Z
Learning: When implementing dependency “revisit”/optional-folding in pacquet, mirror pnpm’s `resolveDependencies.ts` behavior: on revisit, update the `optional` flag only for the directly visited package, and do not automatically change `optional` for transitive descendants. pnpm corrects stale optional flags later via `copyDependencySubGraph` (a BFS in `lockfile/pruner/src/index.ts`/`copyDependencySubGraph`). Until pacquet has an equivalent pruner/copy-subgraph step, be aware that the raw `node.optional` can flow through to the lockfile/virtual store via `dependencies_graph_to_lockfile.rs` → `create_virtual_store.rs` → `installability.rs`, so review changes that affect optional flag propagation for this mismatch.
Applied to files:
pacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rspacquet/crates/resolving-deps-resolver/src/resolve_importer.rspacquet/crates/resolving-deps-resolver/src/tests.rspacquet/crates/resolving-deps-resolver/src/resolve_peers.rs
📚 Learning: 2026-05-24T21:10:50.292Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11915
File: pacquet/crates/resolving-deps-resolver/src/resolve_dependency_tree.rs:553-617
Timestamp: 2026-05-24T21:10:50.292Z
Learning: In pacquet’s Rust resolver layer, the behavior of `ResolvedPackage.optional` “AND-folding”/revisit updates is intentionally aligned with pnpm: when a package is directly revisited, only that package’s `optional` flag is updated; transitive descendants are not re-walked/rescored in this stage. pnpm later corrects any stale optional flags downstream via its pruner/BFS logic (`copyDependencySubGraph` + `nonOptional` reachability stamping in the lockfile pruner). Since pacquet does not yet have that pruner equivalent, review should NOT flag the downstream/stale optional propagation as a bug in pacquet PRs; treat the resolver-layer optional propagation gap as expected parity until the pruning/stamping step is ported.
Applied to files:
pacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rspacquet/crates/resolving-deps-resolver/src/resolve_importer.rspacquet/crates/resolving-deps-resolver/src/tests.rspacquet/crates/resolving-deps-resolver/src/resolve_peers.rs
🔇 Additional comments (17)
pacquet/crates/config/src/lib.rs (1)
531-538: LGTM!pacquet/crates/config/src/workspace_yaml.rs (1)
135-135: LGTM!Also applies to: 411-411, 504-504
pacquet/crates/config/src/env_overlay.rs (1)
141-141: LGTM!pacquet/crates/config/README.md (1)
31-31: LGTM!pacquet/crates/package-manager/src/dependencies_graph_to_lockfile.rs (1)
103-103: LGTM!Also applies to: 128-141, 171-173
pacquet/crates/package-manager/src/dependencies_graph_to_lockfile/tests.rs (1)
1108-1204: LGTM!pacquet/crates/package-manager/src/install_package_from_registry/tests.rs (1)
49-49: LGTM!pacquet/crates/fs/src/is_subdir.rs (1)
1-45: LGTM!pacquet/crates/fs/src/lib.rs (1)
2-2: LGTM!Also applies to: 7-7
pacquet/crates/deps-path/src/lib.rs (1)
19-19: LGTM!Also applies to: 28-28
pacquet/crates/cmd-shim/src/bin_resolver.rs (1)
1-2: LGTM!pacquet/crates/resolving-deps-resolver/Cargo.toml (1)
17-18: LGTM!Also applies to: 29-29
pacquet/crates/resolving-deps-resolver/src/resolve_importer.rs (1)
95-112: LGTM!Also applies to: 156-165, 210-210, 291-291
pacquet/crates/resolving-deps-resolver/src/resolve_importer/tests.rs (1)
94-96: LGTM!pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs (1)
550-554: LGTM!Also applies to: 561-561, 590-592, 1049-1049
pacquet/crates/resolving-deps-resolver/src/resolve_peers.rs (1)
48-49: LGTM!Also applies to: 76-88, 99-135, 397-418, 694-696, 726-735, 873-905, 1155-1187, 1189-1229
pacquet/crates/resolving-deps-resolver/src/tests.rs (1)
1413-1512: LGTM!
Integrated-Benchmark Report (Linux)Scenario: Isolated linker: fresh restore, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.69087667744,
"stddev": 0.07950632332954874,
"median": 1.67448450574,
"user": 2.8220533399999996,
"system": 1.9964311,
"min": 1.61967607574,
"max": 1.88665772074,
"times": [
1.63209673574,
1.88665772074,
1.7287456287399998,
1.67983796874,
1.6439006407399999,
1.67152391574,
1.67744509574,
1.61967607574,
1.73752659974,
1.63135639274
]
},
{
"command": "pacquet@main",
"mean": 1.7526575560400002,
"stddev": 0.2369288043806878,
"median": 1.67660143874,
"user": 2.80474074,
"system": 2.0073233999999998,
"min": 1.61188601874,
"max": 2.40861024474,
"times": [
2.40861024474,
1.64437898774,
1.63234858274,
1.73575559674,
1.73458818374,
1.61188601874,
1.64562419274,
1.77317601374,
1.63262905474,
1.7075786847399999
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.4832891943,
"stddev": 0.01706743488296279,
"median": 0.4785631518000001,
"user": 0.35769539999999994,
"system": 0.7932845799999999,
"min": 0.47503948130000007,
"max": 0.5314427233000001,
"times": [
0.5314427233000001,
0.47515647930000005,
0.47542501130000003,
0.47828133130000006,
0.48142292130000003,
0.4808329633,
0.47503948130000007,
0.47745116130000004,
0.47884497230000006,
0.4789948983
]
},
{
"command": "pacquet@main",
"mean": 0.4849217586,
"stddev": 0.025212295682907115,
"median": 0.4744150838000001,
"user": 0.3504655,
"system": 0.8010804800000001,
"min": 0.46785726530000005,
"max": 0.5462511523000001,
"times": [
0.5462511523000001,
0.47491178130000006,
0.5141575403,
0.4716758643,
0.4784263503,
0.4773411993000001,
0.46785726530000005,
0.47391838630000005,
0.47175461730000007,
0.47292342930000003
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 2.0522259606800004,
"stddev": 0.019750756354975228,
"median": 2.05655644258,
"user": 4.07996662,
"system": 1.9231735,
"min": 2.0133580935800004,
"max": 2.0761420845800003,
"times": [
2.0133580935800004,
2.0576363415800003,
2.03944187958,
2.05571013558,
2.0761420845800003,
2.05740274958,
2.0696135105800004,
2.0694173465800003,
2.0279861735800004,
2.05555129158
]
},
{
"command": "pacquet@main",
"mean": 2.04943609338,
"stddev": 0.026195259855351816,
"median": 2.05869736158,
"user": 4.083802620000001,
"system": 1.9149888000000002,
"min": 2.0107088185800004,
"max": 2.08186772158,
"times": [
2.06951379858,
2.0107088185800004,
2.02164560758,
2.01836582558,
2.03173477758,
2.0588559875800003,
2.07464982958,
2.0684798315800004,
2.0585387355800004,
2.08186772158
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.2721351328800001,
"stddev": 0.01466636180914383,
"median": 1.2671180511800002,
"user": 1.70210456,
"system": 1.09306214,
"min": 1.2528635161800001,
"max": 1.29268899318,
"times": [
1.2528635161800001,
1.25802159518,
1.26594320718,
1.2847676271800001,
1.2885204731800002,
1.29268899318,
1.26307699318,
1.26829289518,
1.2598869641800001,
1.28728906418
]
},
{
"command": "pacquet@main",
"mean": 1.2754044545799998,
"stddev": 0.026411181800023508,
"median": 1.27107848668,
"user": 1.6890561600000003,
"system": 1.0917308399999999,
"min": 1.25440778618,
"max": 1.34495922018,
"times": [
1.25535277618,
1.26838107018,
1.26059047218,
1.27384199918,
1.28486926818,
1.2602744321800001,
1.27759161818,
1.27377590318,
1.25440778618,
1.34495922018
]
}
]
} |
|
| Branch | pr/12025 |
| Testbed | pacquet |
Click to view all benchmark results
| Benchmark | Latency | Benchmark Result milliseconds (ms) (Result Δ%) | Upper Boundary milliseconds (ms) (Limit %) |
|---|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 2,052.23 ms(-11.87%)Baseline: 2,328.67 ms | 2,794.40 ms (73.44%) |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 1,272.14 ms(-12.58%)Baseline: 1,455.27 ms | 1,746.33 ms (72.85%) |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot 🚷 view threshold | 1,690.88 ms(-17.86%)Baseline: 2,058.58 ms | 2,470.30 ms (68.45%) |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot 🚷 view threshold | 483.29 ms(-28.86%)Baseline: 679.34 ms | 815.21 ms (59.28%) |
a85dbbc to
494d203
Compare
|
Actionable comments posted: 0 |
Mirror pnpm's `excludeLinksFromLockfile` setting: * `pacquet-config`: add `exclude_links_from_lockfile` (default `false`) with env-overlay and `pnpm-workspace.yaml` wiring. * `pacquet-package-manager`: thread the flag through `install_with_fresh_lockfile` into the lockfile renderer. A `link:` direct dep is omitted from the importer's snapshot unless its manifest specifier starts with `workspace:`. * `pacquet-resolving-deps-resolver`: port the peer-resolution arm of the feature — `resolve_peers` now seeds `ParentRefs` for external `link:` direct deps with a node id rewritten to `link:<rel-from-lockfile_dir-to-modules_dir>/<alias>` when the link target is outside the lockfile root, mirroring upstream's `index.ts:232-244` `target` rewrite plus the `peerNodeIdToPeerId` link arm. The snapshot child edge falls back to the link node id verbatim when `pathsByNodeId` misses, matching upstream's `pathsByNodeId.get(childNodeId) ?? childNodeId` arm in `resolveChildren`. * `pacquet-deps-path`: port `linkPathToPeerVersion`. * `pacquet-fs`: extract `is_subdir` from `pacquet-cmd-shim` so the resolver and the cmd-shim share one implementation. Ports #6570, refs #12009.
494d203 to
fac8817
Compare
|
Actionable comments posted: 0 |
Summary
Port the
excludeLinksFromLockfilesetting to pacquet so its behavior matches the TypeScript pnpm CLI (which has had this setting since pnpm/pnpm#6570). Refs pnpm/pnpm#12009.When
excludeLinksFromLockfile: trueis set, pacquet now:link:direct dependencies from each importer'spnpm-lock.yamlentry (keepingworkspace:-resolved links recorded).link:<rel-from-lockfile_dir-to-modules_dir>/<alias>node id when seeding peer-resolution parents, so peer suffixes for snapshots that depend on a linked package don't carry the absolute path of the external link. The remap fires only when the link target is outside the lockfile root (per upstream'sisSubdirgate).settings:block sogetOutdatedLockfileSettingcan spot drift on the next install.Where it's hooked (mirrors pnpm)
pacquet-configaddsexclude_links_from_lockfile: bool(defaultfalse) — mirrorsconfig/reader/src/Config.ts:71and thefalsedefault.dependencies_graph_to_lockfile::build_importermirrors upstream'saddDirectDependenciesToLockfileexclude-link gate — dropslink:direct deps from the importer entry unless their manifest specifier starts withworkspace:.resolve_peers::build_importer_parentsports thetargetrewrite atindex.ts:232-244. Externallink:parents are seeded intoParentRefswith a remapped node id (link:<rel-from-lockfile_dir-to-modules_dir>/<alias>), so the peer suffix stays stable across machines.build_peer_idspecial-caseslink:node ids and emitsPeerId::Pair { name: peer_alias, version: link_path_to_peer_version(rel) }— the exact port of upstream'speerNodeIdToPeerIdlink arm.link:<rel>and isn't innode_dep_pathsuses the link node id verbatim as the snapshot child ref — mirrors upstream'spathsByNodeId.get(childNodeId) ?? (childNodeId as DepPath)inresolveChildren.New shared helpers
pacquet-deps-path::link_path_to_peer_version— faithful port of upstream'slinkPathToPeerVersion.ts. Iterates Unicode scalars (not raw bytes), so multi-byte UTF-8 path segments round-trip intact; pinned by anon_ascii_path_segments_round_triptest covering Latin-1, CJK, and a non-BMP emoji.pacquet-fs::is_subdir— promoted from a privatepacquet-cmd-shimhelper so the resolver and the cmd-shim share one implementation. Mirrors npm'sis-subdir.Test plan
cargo nextest run -p pacquet-resolving-deps-resolver— all green, including the newtests::peers::external_link_peer_remaps_to_node_modules_when_exclude_links_onend-to-end check that mirrors the upstream e2e test `path to external link is not added to the lockfile, when it resolves a peer dependency`.cargo nextest run -p pacquet-package-manager— all green, including two newdependencies_graph_to_lockfiletests ported from the upstream e2e tests for the importer-omit andworkspace:carve-out behaviors.cargo nextest run -p pacquet-deps-path -p pacquet-fs -p pacquet-cmd-shim -p pacquet-config— all green (newlink_path_to_peer_versionandis_subdirunit tests).cargo check --locked --workspace --all-targets— clean.cargo clippy --locked --workspace --all-targets -- --deny warnings— clean.cargo fmt -- --check— clean.Marked draft because
The pacquet-only port is complete and tested. Marking draft to invite review on the hook-point choice and the
ResolvePeersOptions/ResolveImporterOptionsfield additions before landing.Written by an agent (Claude Code, claude-opus-4-7).
Summary by CodeRabbit
Release Notes
exclude_links_from_lockfileconfiguration option to control lockfile behavior. When enabled, dependencies using thelink:protocol are excluded from the lockfile, whileworkspace:link dependencies are retained. Configure viapnpm-workspace.yamlor environment variable.