[Bug]: fs.readlinkSync converts relative symlinks to absolute paths
What happened?
Description
The fs.readlinkSync function in rules_js fs patches incorrectly converts relative symlinks to absolute paths. This breaks the intended relative nature of symlinks, causing issues when symlinks need to remain portable (e.g., when moving directories or using relative paths for portability).
Root Cause
In js/private/node-patches/src/fs.cts, the readlinkSync and readlink functions use path.resolve() to convert the symlink target to an absolute path:
const str = path.resolve(
path.dirname(resolved),
origReadlinkSync(...args)
)
This always returns an absolute path, even when the original symlink was created with a relative target.
Expected Behavior
Relative symlinks should remain relative when read via fs.readlinkSync(). The function should preserve the original relative path that was used when creating the symlink.
Actual Behavior
fs.readlinkSync() converts relative symlink targets to absolute paths, breaking symlink portability.
Version
Development (host) and target OS/architectures: macOS
Output of bazel --version: 8.0.0
Version of the Aspect rules, or other relevant rules from your
WORKSPACE or MODULE.bazel file: 2.5.0
Language(s) and/or frameworks involved: no
How to reproduce
### Minimal Repository
https://github.com/ashi009/rules_js-fs-patch-bug
### Steps to Reproduce
1. Clone the reproduction repository
2. Run `bazel run //:test`
3. Observe the output showing the difference between unpatched and patched behavior
Any other information?
Test Output
=== Original Node.js fs behavior ===
Unpatched readlinkSync result: ../test-symlinks/target.txt
Expected: relative path preserved
=== With rules_js fs patches ===
Patched readlinkSync result: /absolute/path/to/target.txt
=== Comparison ===
Original (correct): ../test-symlinks/target.txt
Patched (incorrect): /absolute/path/to/target.txt
Bug: CONFIRMED - relative symlink converted to absolute!
Impact
This bug affects:
- Portable symlinks that need to work when directories are moved
- Build systems that rely on relative symlinks
- Any application that expects
readlinkSync()to preserve relative paths - Cross-platform compatibility where absolute paths differ
Additional Context
- The issue is reproducible across all platforms
- Both
readlinkSyncandreadlink(async version) are affected - The bug was introduced in the fs patching system that converts paths for Bazel compatibility