fix: make symlink_metadata VPath-aware for Yarn PnP#1183
Conversation
Merge activity
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1183 +/- ##
=======================================
Coverage 93.33% 93.33%
=======================================
Files 22 22
Lines 4184 4184
=======================================
Hits 3905 3905
Misses 279 279 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
## Summary
`FileSystemOs::metadata` already translates Yarn PnP **virtual** and **zip** paths through `VPath` before hitting the filesystem, but `symlink_metadata` did not — it `lstat`'d the raw path directly:
```rust
fn symlink_metadata(&self, path: &Path) -> io::Result<FileMetadata> {
Self::symlink_metadata(path) // no VPath translation
}
```
For a virtual/zip path that has no physical existence, that `lstat` fails, so canonicalization (`canonicalize_with_visited`) sees the error, treats the path as a non-symlink, and cannot resolve symlinks correctly under PnP.
This makes `symlink_metadata` mirror `metadata`'s `VPath` handling. Zip entries are never symlinks, so they reuse the same `file_type` lookup as `metadata`; virtual/native paths fall through to the real `lstat` on the translated physical path.
This is also a prerequisite for #1182, which routes `is_file`/`is_dir` through the cached `lstat` and so requires `symlink_metadata` to be VPath-aware.
## Verification
- `cargo test --all-features` (includes the Yarn PnP suite) — green
- `fixtures/pnp` JS resolver test — green
🤖 Generated with [Claude Code](https://claude.com/claude-code)
96c398e to
a539c40
Compare
Merging this PR will improve performance by 4.45%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | pm/pnpm-isolated |
1.1 ms | 1.1 ms | +3.48% |
| ⚡ | pm/npm-flat |
1,030.4 µs | 954.4 µs | +7.97% |
| ⚡ | pm/yarn-flat |
1,037.5 µs | 951.8 µs | +9% |
| ⚡ | pm/pnpm-hoisted |
1.1 ms | 1.1 ms | +3.17% |
| ❌ | small |
11.4 µs | 11.8 µs | -3.61% |
| ⚡ | resolver_real[multi-thread] |
407.9 µs | 382.6 µs | +6.61% |
| ⚡ | resolver_memory[multi-thread] |
409 µs | 389.4 µs | +5.04% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing fix/symlink-metadata-vpath (a539c40) with main (4654e32)2
Footnotes
-
5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
-
No successful run was found on
main(a539c40) during the generation of this report, so 4654e32 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩
## 🤖 New release * `oxc_resolver`: 11.20.0 -> 11.21.0 * `oxc_resolver_napi`: 11.20.0 -> 11.21.0 <details><summary><i><b>Changelog</b></i></summary><p> ## `oxc_resolver` <blockquote> ## [11.21.0](v11.20.0...v11.21.0) - 2026-06-03 ### <!-- 0 -->🚀 Features - *(tsconfig)* support package.json imports field in extends ([#1199](#1199)) (by @Boshen) ### <!-- 1 -->🐛 Bug Fixes - *(tsconfig)* apply each referenced project's own `allowJs` ([#1198](#1198)) (by @shulaoda) - make symlink_metadata VPath-aware for Yarn PnP ([#1183](#1183)) (by @Boshen) ### <!-- 4 -->⚡ Performance - borrow relative main field instead of allocating a "./" prefix ([#1187](#1187)) (by @Boshen) - *(cache)* move package.json path into parse instead of cloning ([#1186](#1186)) (by @Boshen) - eliminate symlink stat syscalls by reusing canonicalization ([#1184](#1184)) (by @Boshen) - reduce resolution syscalls by unifying stat and lstat ([#1182](#1182)) (by @Boshen) ### <!-- 9 -->💼 Other - add baselines for each package manager x node_modules layout ([#1176](#1176)) (by @Boshen) ### Contributors * @shulaoda * @Boshen * @renovate[bot] </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). Co-authored-by: oxc-guard[bot] <276638029+oxc-guard[bot]@users.noreply.github.com>
Summary
FileSystemOs::metadataalready translates Yarn PnP virtual and zip paths throughVPathbefore hitting the filesystem, butsymlink_metadatadid not — itlstat'd the raw path directly:For a virtual/zip path that has no physical existence, that
lstatfails, so canonicalization (canonicalize_with_visited) sees the error, treats the path as a non-symlink, and cannot resolve symlinks correctly under PnP.This makes
symlink_metadatamirrormetadata'sVPathhandling. Zip entries are never symlinks, so they reuse the samefile_typelookup asmetadata; virtual/native paths fall through to the reallstaton the translated physical path.This is also a prerequisite for #1182, which routes
is_file/is_dirthrough the cachedlstatand so requiressymlink_metadatato be VPath-aware.Verification
cargo test --all-features(includes the Yarn PnP suite) — greenfixtures/pnpJS resolver test — green🤖 Generated with Claude Code