Fix: convert relative paths to absolute in require.resolve paths option

When using `require.resolve()` with relative paths in the `paths` option,
Bun was passing them directly to the resolver without converting them to
absolute paths. This caused a panic on Windows with the error:
"cannot resolve DirInfo for non-absolute path: libs\barcode-svg"

The fix converts relative paths to absolute paths (relative to CWD) before
passing them to `checkPackagePath`, matching Node.js behavior where the
`paths` option accepts both absolute and relative paths.

Fixes #14911

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Bot
2025-10-10 21:22:05 +00:00
parent 086eb73fe7
commit fcfc97e1c7
2 changed files with 111 additions and 1 deletions

View File

@@ -1298,7 +1298,18 @@ pub const Resolver = struct {
for (custom_paths) |custom_path| {
const custom_utf8 = custom_path.toUTF8WithoutRef(bun.default_allocator);
defer custom_utf8.deinit();
switch (r.checkPackagePath(custom_utf8.slice(), import_path, kind, global_cache)) {
// Resolve relative paths to absolute paths relative to CWD, matching Node.js behavior
const custom_dir = if (!std.fs.path.isAbsolute(custom_utf8.slice()))
ResolvePath.joinAbsString(
r.fs.top_level_dir,
&.{custom_utf8.slice()},
.auto,
)
else
custom_utf8.slice();
switch (r.checkPackagePath(custom_dir, import_path, kind, global_cache)) {
.success => |res| return .{ .success = res },
.pending => |p| return .{ .pending = p },
.failure => |p| return .{ .failure = p },

View File

@@ -0,0 +1,99 @@
// Test for https://github.com/oven-sh/bun/issues/14911
// require.resolve with relative paths in the `paths` option should not panic
import { expect, test } from "bun:test";
import { bunEnv, bunExe, tempDir } from "harness";
test("require.resolve with relative path in paths option should not panic", async () => {
using dir = tempDir("issue-14911", {
"libs/node_modules/barcode-svg/package.json": JSON.stringify({
name: "barcode-svg",
main: "index.js",
}),
"libs/node_modules/barcode-svg/index.js": "module.exports = { test: true };",
"test.js": `
try {
// When using relative paths in the 'paths' option, Node.js treats them
// as starting directories and searches for node_modules from there.
// This was causing a panic on Windows: "cannot resolve DirInfo for non-absolute path"
const resolved = require.resolve('barcode-svg', { paths: ['libs'] });
console.log('RESOLVED:', resolved);
// Verify it resolved successfully
if (!resolved.includes('barcode-svg')) {
console.log('ERROR: Did not resolve barcode-svg');
process.exit(1);
}
console.log('SUCCESS');
} catch (err) {
console.log('ERROR:', err.message);
process.exit(1);
}
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "test.js"],
cwd: String(dir),
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
// Should not panic with "cannot resolve DirInfo for non-absolute path"
expect(stderr).not.toContain("panic");
expect(stderr).not.toContain("cannot resolve DirInfo for non-absolute path");
expect(stdout).toContain("SUCCESS");
expect(exitCode).toBe(0);
});
test("require.resolve with multiple relative paths in paths option", async () => {
using dir = tempDir("issue-14911-multiple", {
"dir1/node_modules/pkg1/package.json": JSON.stringify({
name: "pkg1",
main: "index.js",
}),
"dir1/node_modules/pkg1/index.js": "module.exports = { pkg1: true };",
"dir2/node_modules/pkg2/package.json": JSON.stringify({
name: "pkg2",
main: "index.js",
}),
"dir2/node_modules/pkg2/index.js": "module.exports = { pkg2: true };",
"test.js": `
try {
// Test with multiple relative paths - they should all be converted to absolute
const resolved1 = require.resolve('pkg1', { paths: ['dir1', 'dir2'] });
console.log('RESOLVED1:', resolved1);
const resolved2 = require.resolve('pkg2', { paths: ['dir1', 'dir2'] });
console.log('RESOLVED2:', resolved2);
if (!resolved1.includes('pkg1') || !resolved2.includes('pkg2')) {
console.log('ERROR: Paths did not resolve correctly');
process.exit(1);
}
console.log('SUCCESS');
} catch (err) {
console.log('ERROR:', err.message);
process.exit(1);
}
`,
});
await using proc = Bun.spawn({
cmd: [bunExe(), "test.js"],
cwd: String(dir),
env: bunEnv,
stdout: "pipe",
stderr: "pipe",
});
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
expect(stderr).not.toContain("panic");
expect(stdout).toContain("SUCCESS");
expect(exitCode).toBe(0);
});