Skip to content

feat: add findPackageJSON to node:module#29206

Open
SAY-5 wants to merge 4 commits intooven-sh:mainfrom
SAY-5:feat/node-module-findpackagejson
Open

feat: add findPackageJSON to node:module#29206
SAY-5 wants to merge 4 commits intooven-sh:mainfrom
SAY-5:feat/node-module-findpackagejson

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 12, 2026

`import { findPackageJSON } from 'node:module'` throws a SyntaxError because the export doesn't exist in Bun's polyfill. Node.js added this in v22.

Implements the full API: handles bare specifiers (resolves via Bun's resolver first), relative and absolute paths, and file:// URLs. Walks up the directory tree from the resolved location to find the nearest package.json.

Fixes #23898

Bun's node:module polyfill was missing findPackageJSON, causing a
SyntaxError on import. Handles bare specifiers (resolves via Bun's
resolver), relative/absolute paths, and file:// URLs. Walks up the
directory tree to find the nearest package.json.

Fixes oven-sh#23898
Copy link
Copy Markdown
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8ac46285-4565-4718-98eb-ab301fd1b3e6

📥 Commits

Reviewing files that changed from the base of the PR and between 88a32e8 and 856a908.

📒 Files selected for processing (1)
  • src/js/builtins/NodeModuleObject.ts

Walkthrough

Adds exported findPackageJSON(specifier: string | URL, base?: string | URL) to Node module builtins. Validates and normalizes inputs (including file:// → path), branches for bare vs path specifiers, resolves targets, and walks parent directories to locate and return the nearest package.json or undefined.

Changes

Cohort / File(s) Summary
Node Module Builtins
src/js/builtins/NodeModuleObject.ts
Introduced exported findPackageJSON(specifier, base?). Validates argument types; converts file:// URLs to filesystem paths; distinguishes bare package specifiers from relative/absolute ones; resolves package entry (retries packageName after packageName/package.json); computes start directory from base (file → parent dir); walks upward to find nearest package.json (handles node_modules roots and scoped @scope/pkg) or returns undefined.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding the findPackageJSON export to the node:module polyfill.
Description check ✅ Passed The PR description covers what the PR does and references the fixed issue, but lacks a 'How did you verify your code works?' section from the template.
Linked Issues check ✅ Passed The PR implementation addresses all requirements from issue #23898: exports findPackageJSON, handles bare specifiers via Bun's resolver, processes relative/absolute paths and file:// URLs, and walks up directories to locate package.json.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing findPackageJSON in NodeModuleObject.ts with no unrelated modifications detected.

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


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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/js/builtins/NodeModuleObject.ts`:
- Around line 28-33: Remove the redundant typeof checks around specifier and
base in NodeModuleObject.ts: since specifier has already been normalized to a
string (or produced from URL.href) you can drop `typeof specifier === "string"`
and just call `specifier.startsWith("file://")`; for base (which may be string
or undefined) replace `typeof base === "string" && base.startsWith("file://")`
with a null-safe check such as `base && base.startsWith("file://")` or
`base?.startsWith("file://")` and then run fileURLToPath accordingly so you
preserve behavior while eliminating unnecessary type guards on specifier and
base.
- Around line 75-80: The code incorrectly assumes `base` is a file by always
calling `path.dirname(base)` before resolving `startDir`; update the
relative-specifier branch (the block using `specifier`, `base`, `baseDir`,
`startDir`, `path.dirname`, and `path.resolve`) to first detect whether `base`
is a directory (e.g., using `fs.statSync(base).isDirectory()` in a try/catch or
`fs.existsSync` + `statSync`) and if so use `base` as `baseDir`, otherwise fall
back to `path.dirname(base)`; keep the existing `path.resolve(baseDir,
specifier)` logic and handle errors from stat checks gracefully by falling back
to `dirname`.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d3afeb87-297e-4240-944d-7d68e5814475

📥 Commits

Reviewing files that changed from the base of the PR and between b18f268 and d48f4e9.

📒 Files selected for processing (1)
  • src/js/builtins/NodeModuleObject.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/js/builtins/NodeModuleObject.ts`:
- Around line 47-68: The fallback that resolves a bare specifier using
$resolveSync and then returns the first package.json walking upward can return a
nested manifest; change findPackageJSON's fallback so after resolving the module
entry (using $resolveSync(specifier, base, ...)), walk up to find the package
root boundary (stop when parent directory is a node_modules directory or when
you reach filesystem root) and then return the package.json in that package root
directory; do not return an inner package.json encountered before reaching the
node_modules boundary (handle scoped packages by treating
"node_modules/@scope/<pkg>" as the boundary as well).
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d6c7ea8a-c750-4d3d-b6d2-bde8c808dcb1

📥 Commits

Reviewing files that changed from the base of the PR and between d48f4e9 and 1224798.

📒 Files selected for processing (1)
  • src/js/builtins/NodeModuleObject.ts

…JSON

The fallback path was returning the first package.json found walking
upward, which could be a nested manifest inside a subdirectory. For
bare specifiers Node.js returns the package root manifest, which is
the directory directly inside node_modules/ (or node_modules/@scope/pkg
for scoped packages). Now walks up until hitting the node_modules
boundary and returns that directory's package.json.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/js/builtins/NodeModuleObject.ts`:
- Around line 42-50: The code currently resolves specifier + "/package.json"
which can return nested subpath manifests for inputs like "pkg/subpath" or
"@scope/pkg/subpath"; update the isBare branch to first strip subpaths from
specifier by extracting the package-name-only (if specifier starts with "@" take
the first two path segments, otherwise take the first segment), then call
$resolveSync with that packageName + "/package.json" (still checking base
undefined as currently done) before probing fs.existsSync; use the existing
symbols isBare, base, specifier, and $resolveSync to locate and change this
logic so you always resolve the package-root manifest.
- Around line 18-25: After the URL-to-string conversion of the local variable
base in NodeModuleObject.ts, validate that base represents an absolute module
location: if base was a URL ensure its protocol is "file" (accept "file" or
"file:" before conversion), and if it's a string ensure path.isAbsolute(base) is
true; otherwise throw $ERR_INVALID_ARG_VALUE for "base". Do this before calling
$resolveSync() or path.resolve() so relative paths or non-file URLs are rejected
early; retain the existing $ERR_INVALID_ARG_TYPE check for non-string/URL inputs
and reference the same local variable name base when adding the new validation.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0241efdd-f1ef-4ec3-8ffb-f90f3a89216f

📥 Commits

Reviewing files that changed from the base of the PR and between 1224798 and 88a32e8.

📒 Files selected for processing (1)
  • src/js/builtins/NodeModuleObject.ts

Two issues from review:
- base must be a file: URL or absolute path, not a relative string
  or non-file URL. Now rejects early with ERR_INVALID_ARG_VALUE.
- Bare specifiers like 'pkg/subpath' or '@scope/pkg/sub' were
  resolving subpath manifests. Now strips to package name only
  before looking up package.json.
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.

Error when importing findPackageJSON method from node:module

1 participant