Skip to content

fix: align package exports fallback array resolution with Node.js spec#177

Open
stormslowly wants to merge 2 commits intomainfrom
fix/align_node_export_resolve_array
Open

fix: align package exports fallback array resolution with Node.js spec#177
stormslowly wants to merge 2 commits intomainfrom
fix/align_node_export_resolve_array

Conversation

@stormslowly
Copy link
Collaborator

@stormslowly stormslowly commented Mar 18, 2026

Summary

  • Fix off-by-one bug in package_target_resolve: the condition resolved.is_err() && i == targets.len() was always false, causing InvalidPackageTarget errors to be silently dropped when all targets in a fallback array are invalid
  • Implement Debug trait for CachedPathImpl (displays its path) and derive Debug for CachedPath

Test plan

  • Added test array_fallback_all_invalid_targets_should_return_invalid_package_target to verify the fix
  • cargo test --all-features passes
  • cargo clippy --all-features passes

The condition `resolved.is_err() && i == targets.len()` was always false
(off-by-one) causing InvalidPackageTarget errors to be silently dropped
when all targets in a fallback array are invalid.

Also implement Debug for CachedPathImpl to display its path.
Copilot AI review requested due to automatic review settings March 18, 2026 06:19
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug in package resolution where InvalidPackageTarget errors were not correctly propagated when handling fallback arrays in package exports. The changes ensure that the resolver behaves as expected according to the Node.js specification, preventing silent failures. Additionally, debuggability has been improved for cached path structures, which will aid in future development and troubleshooting.

Highlights

  • Bug Fix: Resolved an off-by-one bug in package_target_resolve that caused InvalidPackageTarget errors to be silently dropped when all targets in a fallback array were invalid, aligning resolution with the Node.js spec.
  • Debuggability Improvement: Implemented the Debug trait for CachedPathImpl (displaying its path) and derived Debug for CachedPath, enhancing logging and debugging capabilities.
  • Test Coverage: Added a new test case, array_fallback_all_invalid_targets_should_return_invalid_package_target, to specifically verify the fix for invalid fallback array targets.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly fixes an off-by-one bug in package_target_resolve that caused InvalidPackageTarget errors to be silently dropped when all targets in a fallback array are invalid. The addition of Debug implementations for CachedPath and CachedPathImpl is a nice improvement for developer experience, and the new test case effectively verifies the bug fix. However, I've identified a potential issue in the new error handling logic that could swallow other important errors, which I've detailed in a comment.

Comment on lines +1966 to 1978
match resolved {
// Only track InvalidPackageTarget for re-throwing after the loop.
Err(e @ ResolveError::InvalidPackageTarget(..)) => {
last_error = Some(e);
}
Err(_) => {}
// 2. If resolved is undefined, continue the loop.
Ok(None) => {
last_error = None;
}
// 3. Return resolved.
return Ok(Some(path));
Ok(Some(path)) => return Ok(Some(path)),
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While this change correctly handles InvalidPackageTarget errors in a fallback array, the Err(_) => {} case will silently swallow any other type of ResolveError. This could hide other resolution issues. According to the Node.js spec and enhanced-resolve's behavior, only InvalidPackageTarget errors should allow the loop to continue. Other errors should be propagated immediately.

            match resolved {
              // Only track InvalidPackageTarget for re-throwing after the loop.
              Err(e @ ResolveError::InvalidPackageTarget(..)) => {
                last_error = Some(e);
              }
              // Other errors should be propagated immediately.
              Err(e) => return Err(e),
              // 2. If resolved is undefined, continue the loop.
              Ok(None) => {
                last_error = None;
              }
              // 3. Return resolved.
              Ok(Some(path)) => return Ok(Some(path)),
            }

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes exports-field fallback array resolution to correctly propagate InvalidPackageTarget when all fallback targets are invalid, aligning behavior with the Node.js resolution algorithm. Also improves debuggability of cached paths.

Changes:

  • Fix fallback-array error propagation in package_target_resolve (avoid dropping the final InvalidPackageTarget).
  • Add a regression test covering “all fallback targets invalid” behavior.
  • Implement/derive Debug for CachedPathImpl/CachedPath to print the underlying path.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/lib.rs Adjusts array-fallback logic in package_target_resolve to track and rethrow the last InvalidPackageTarget.
src/tests/exports_field.rs Adds regression test ensuring invalid fallback arrays propagate InvalidPackageTarget.
src/cache.rs Adds Debug output for cached paths (prints the path).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Err(e @ ResolveError::InvalidPackageTarget(..)) => {
last_error = Some(e);
}
Err(_) => {}
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 18, 2026

Merging this PR will not alter performance

✅ 12 untouched benchmarks


Comparing fix/align_node_export_resolve_array (a71c4ef) with main (b36ec51)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (3edc3cb) during the generation of this report, so b36ec51 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f35bd7475

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Err(e @ ResolveError::InvalidPackageTarget(..)) => {
last_error = Some(e);
}
Err(_) => {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Propagate non-InvalidPackageTarget fallback errors

This Err(_) => {} arm drops later fallback errors even though the array algorithm is only supposed to continue on InvalidPackageTarget. A config like {"./foo/": ["invalid", "./bar"]} resolving pkg/foo/x makes the second entry fail with InvalidPackageConfigDirectory in normalize_string_target, but this loop ignores that and rethrows the stale first InvalidPackageTarget from last_error. That changes the surfaced error away from the entry that actually failed and makes misconfigured fallback arrays much harder to diagnose.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants