Skip to content

feat: sync internal with latest Node.js upstream - #49

Merged
pi0 merged 4 commits into
mainfrom
feat/upstream-sync
Jun 22, 2026
Merged

feat: sync internal with latest Node.js upstream#49
pi0 merged 4 commits into
mainfrom
feat/upstream-sync

Conversation

@pi0x

@pi0x pi0x commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

This PR carefully diffs each forked file against current Node.js main, syncs the lagging logic, fixes correctness bugs surfaced by the comparison, and adds regression tests for every changed surface.

Changes & end-user impact

Area Change Effect on end users
resolve.ts Allow #/-prefixed subpath imports (Node dropped this restriction in upstream commit e8c9c43) resolveModuleURL("#/foo.js", …) now resolves against a package's imports map instead of throwing ERR_INVALID_MODULE_SPECIFIER.
resolve.ts Fix null vs undefined return in resolvePackageTarget for conditional targets Conditional exports where a nested condition object matches nothing now correctly falls through to default (and sibling conditions) instead of wrongly throwing ERR_PACKAGE_PATH_NOT_EXPORTED. Fewer false "subpath not exported" failures.
get-format.ts Anchor the data: MIME-detection regex (/^…$/) Bogus MIME types like text/javascriptx are no longer mis-detected as JavaScript modules — correct format classification for data: URLs.
errors.ts ERR_INVALID_ARG_TYPE splice fix (was a no-op slice) Type-mismatch error messages are now correct when both a plain object type and class instances are expected (no more stray "of type object").
errors.ts Full sync to upstream class-based NodeError machinery + determineSpecificType rewrite Thrown errors match current Node wording/shape (incl. kIsNodeError, precise "Received …" details for bigint/-0/NaN/Infinity/symbol/etc.). ERR_MODULE_NOT_FOUND / ERR_UNSUPPORTED_DIR_IMPORT now set error.url for import.meta.resolve consumers.
errors.ts Typed createError so error instances carry .code/.url Internal type-safety improvement — removes the @ts-expect-error workarounds in resolve.ts. No runtime change.
errors.ts Removed ERR_NETWORK_IMPORT_DISALLOWED Dead code (deleted upstream, unused here). No user impact.
builtins.ts Verified against Node v24.x List already in sync; node:-prefix-only modules (sqlite, test, sea) remain correctly excluded so bare sqlite/test don't falsely resolve as builtins.

Most changes are behaviour-preserving syncs; the user-visible behaviour changes are the three resolver/format bug fixes in the first rows (all in the more-correct, more-permissive direction).

Intentionally left unsynced

  • legacyMainResolve/packageResolve C++-binding refactor + experimental package-map feature (the JS implementation remains correct for standard resolution; tracked by the existing header TODO).
  • Source-based module detection (detectModuleFormat) and the typeless-package.json warning — not feasible/desired without a source buffer in exsolve's architecture.

Tests

Added 44 regression tests (suite: 33 → 77 passing, 1 skipped) across test/internal-errors.test.ts, test/internal-get-format.test.ts, and test/resolve-imports-exports.test.ts (+ imports-pkg/exports-pkg fixtures). Both resolver fixes were confirmed by reverting them and observing the new tests fail. tsc, eslint, and prettier all pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved module-resolution error formatting, including more accurate argument/type descriptions and toString() output.
    • Refined ESM/CJS format detection for TypeScript extensions and data: URLs, with safer fallback rules for .js and extensionless paths.
    • Corrected package imports/exports subpath validation and conditional export fall-through behavior.
  • Tests
    • Added/extended test suites covering error behavior, format detection regressions, and package resolution edge cases.
    • Updated test fixtures to include new export bindings and imports/exports maps.

Sync the forked ESM resolver internals against current Node.js `main`,
fix correctness bugs found during the diff, and add regression tests.

- errors.ts: full sync (class-based NodeError machinery, determineSpecificType,
  splice fix, drop removed ERR_NETWORK_IMPORT_DISALLOWED), and fix createError
  return type so error instances carry .code/.url (removes @ts-expect-error)
- get-format.ts: full sync of structure + anchor the data: MIME regex
- resolve.ts: allow `#/`-prefixed subpath imports; fix conditional-exports
  null/undefined fall-through in resolvePackageTarget
- builtins.ts: verified in sync with Node v24.x (node:-only modules excluded)
- tests: add regression coverage for all changed surfaces

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@pi0x, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 22 minutes and 40 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 87b82efa-c82a-47bd-9055-6ab4fcc47349

📥 Commits

Reviewing files that changed from the base of the PR and between 3e73342 and 881cc48.

📒 Files selected for processing (1)
  • src/internal/errors.ts
📝 Walkthrough

Walkthrough

Updates error class construction from closure-based to class-based NodeError subclasses with kIsNodeError, this.url side effects on ERR_MODULE_NOT_FOUND/ERR_UNSUPPORTED_DIR_IMPORT, and a rewritten determineSpecificType. Fixes MIME regex anchoring and extname algorithm in get-format.ts. Widens resolvePackageTarget return type, fixes #/-import validation, drops stale TS suppressions, and updates Node.js version references.

Changes

Error System, Format Detection, and Resolution Logic

Layer / File(s) Summary
Error class machinery refactor and ERR_* callback signatures
src/internal/errors.ts, test/internal-errors.test.ts
makeNodeErrorWithCode is replaced with class-based NodeError subclasses keyed on placeholder count; introduces kIsNodeError, switch-based formatList, getExpectedArgumentLength, and a rewritten determineSpecificType with explicit null/undefined and number edge-case handling. ERR_MODULE_NOT_FOUND and ERR_UNSUPPORTED_DIR_IMPORT become typed function callbacks that assign this.url. Fixes a slicesplice bug in object-type list handling. Tests cover .code, instanceof, toString(), this.url side effects, and "Received" suffix formatting for all JS value categories.
get-format: MIME anchoring, extname rewrite, extensionless fallback
src/internal/get-format.ts, test/internal-get-format.test.ts
Adds divergence comments for TypeScript extensions and WASM omission. Tightens JavaScript MIME regex anchoring, introduces DOT_CODE/SLASH_CODE constants, and replaces the codePointAt-based extname with a right-to-left charCodeAt scan. Reworks .js/extensionless getFileProtocolModuleFormat so packageType === "none" explicitly returns commonjs. Tests cover data:, node:, file:, dotfile, trailing-dot, and unknown-protocol cases.
resolvePackageTarget return type, #/ import validation, and comment cleanup
src/internal/builtins.ts, src/internal/resolve.ts, test/fixture/imports-pkg/*, test/fixture/exports-pkg/*, test/resolve-imports-exports.test.ts
Updates nodeBuiltins header to v24.16.0. Widens resolvePackageTarget return type to URL | null | undefined; the array path returns lastException instead of forcing null on exhaustion; the object path returns undefined when no condition matches. Removes name.startsWith("#/") from the invalid-specifier guard. Replaces @ts-expect-error annotations with plain inline comments in finalizeResolution and moduleResolve. Adds imports-pkg and exports-pkg fixtures and tests for #/-subpath imports and conditional exports fall-through.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 Hop hop, the errors now wear proper coats,
With kIsNodeError stitched in their throats.
The MIME regex anchored, no substring slip,
And #/ paths freed from their old iron grip.
undefined returns where null once stayed —
A cleaner resolve, well-tested, well-made! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: sync internal with latest Node.js upstream' directly and accurately summarizes the main objective of the PR: synchronizing internal fork files with Node.js upstream changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/upstream-sync

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.61538% with 46 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.62%. Comparing base (3177a7e) to head (881cc48).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/internal/errors.ts 62.38% 39 Missing and 2 partials ⚠️
src/internal/get-format.ts 76.47% 4 Missing ⚠️
src/internal/resolve.ts 75.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main      #49       +/-   ##
===========================================
+ Coverage   50.66%   64.62%   +13.95%     
===========================================
  Files           6        6               
  Lines         825      896       +71     
  Branches      307      331       +24     
===========================================
+ Hits          418      579      +161     
+ Misses        306      257       -49     
+ Partials      101       60       -41     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pi0 pi0 changed the title feat: sync src/internal with latest Node.js upstream feat: sync internal with latest Node.js upstream Jun 21, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
test/internal-errors.test.ts (1)

81-87: ⚡ Quick win

Add coverage for ERR_UNSUPPORTED_DIR_IMPORT .url assignment.

This suite verifies message formatting, but not the new .url side-effect path for the 3rd constructor argument.

Suggested test addition
   it("formats ERR_UNSUPPORTED_DIR_IMPORT message", () => {
     const err = new ERR_UNSUPPORTED_DIR_IMPORT("/dir", "/base");
     expect(err.message).toBe(
       "Directory import '/dir' is not supported resolving ES modules imported from /base",
     );
   });
+
+  it("sets url when exact url is provided for ERR_UNSUPPORTED_DIR_IMPORT", () => {
+    const err = new ERR_UNSUPPORTED_DIR_IMPORT(
+      "/dir",
+      "/base",
+      "file:///dir/index.js",
+    );
+    expect(err.url).toBe("file:///dir/index.js");
+  });
🤖 Prompt for 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.

In `@test/internal-errors.test.ts` around lines 81 - 87, The current test for
ERR_UNSUPPORTED_DIR_IMPORT only verifies the message formatting but does not
test the `.url` property assignment. Add a new test case in the same suite that
instantiates ERR_UNSUPPORTED_DIR_IMPORT with a third constructor argument and
verifies that the resulting error object has the `.url` property correctly set
to that third argument value.
🤖 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 `@src/internal/errors.ts`:
- Line 247: Replace the self-comparison pattern `value !== value` with
`Number.isNaN(value)` at line 247 in the errors.ts file. The self-comparison is
flagged by Biome's noSelfCompare rule, and Number.isNaN() is the standard and
recommended approach for detecting NaN values.
- Around line 266-269: The condition checking `if (value.constructor && "name"
in value.constructor)` can throw a TypeError when value.constructor is a
primitive value like a string, because the `in` operator requires an object on
its right-hand side. Add a type guard to verify that value.constructor is
actually an object before using the `in` operator on it, for example by checking
`typeof value.constructor === "object"` in addition to the existing truthiness
check, to prevent TypeError from being thrown during error message formatting.

In `@test/internal-get-format.test.ts`:
- Around line 88-90: The test uses a Unix-style file URL (file:///tmp/.foobar)
which fails on Windows because getFormat() calls getPackageScopeConfig()
internally when extname() returns empty string for dotfiles, and fileURLToPath()
throws an error on Windows with non-Windows paths. Replace the hardcoded /tmp/
path with a platform-appropriate file URL using conditional logic based on the
platform or by using import.meta.url as a base to construct a valid file URL
that works on both Windows and Unix systems. Apply the same fix to other tests
in this file that use /tmp paths and call getPackageScopeConfig.

---

Nitpick comments:
In `@test/internal-errors.test.ts`:
- Around line 81-87: The current test for ERR_UNSUPPORTED_DIR_IMPORT only
verifies the message formatting but does not test the `.url` property
assignment. Add a new test case in the same suite that instantiates
ERR_UNSUPPORTED_DIR_IMPORT with a third constructor argument and verifies that
the resulting error object has the `.url` property correctly set to that third
argument value.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9fa983a2-b4c8-401f-b89e-1d01df67f0d4

📥 Commits

Reviewing files that changed from the base of the PR and between 3177a7e and 555b233.

📒 Files selected for processing (15)
  • src/internal/builtins.ts
  • src/internal/errors.ts
  • src/internal/get-format.ts
  • src/internal/resolve.ts
  • test/fixture/exports-pkg/default.js
  • test/fixture/exports-pkg/index.js
  • test/fixture/exports-pkg/package.json
  • test/fixture/exports-pkg/worker.js
  • test/fixture/imports-pkg/index.js
  • test/fixture/imports-pkg/internal.js
  • test/fixture/imports-pkg/package.json
  • test/fixture/imports-pkg/src/util.js
  • test/internal-errors.test.ts
  • test/internal-get-format.test.ts
  • test/resolve-imports-exports.test.ts

Comment thread src/internal/errors.ts Outdated
Comment thread src/internal/errors.ts Outdated
Comment thread test/internal-get-format.test.ts
pi0 and others added 2 commits June 22, 2026 07:43
- use Number.isNaN(value) instead of self-comparison for NaN check
- guard constructor.name access to avoid TypeError on primitive constructor
  (aligns determineSpecificType with upstream Node)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pi0
pi0 merged commit bb6318c into main Jun 22, 2026
7 checks passed
@pi0
pi0 deleted the feat/upstream-sync branch June 22, 2026 08:23
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