mirror of
https://github.com/oven-sh/bun
synced 2026-02-19 07:12:24 +00:00
fix(resolver): allow builtins to be imported via subpath imports
This commit is contained in:
@@ -1569,10 +1569,15 @@ pub const Resolver = struct {
|
||||
|
||||
// Find the parent directory with the "package.json" file
|
||||
var dir_info_package_json: ?*DirInfo = dir_info;
|
||||
while (dir_info_package_json != null and dir_info_package_json.?.package_json == null) : (dir_info_package_json = dir_info_package_json.?.getParent()) {}
|
||||
while (dir_info_package_json != null and dir_info_package_json.?.package_json == null)
|
||||
dir_info_package_json = dir_info_package_json.?.getParent();
|
||||
|
||||
// Check for subpath imports: https://nodejs.org/api/packages.html#subpath-imports
|
||||
if (dir_info_package_json != null and strings.hasPrefix(import_path, "#") and !forbid_imports and dir_info_package_json.?.package_json.?.imports != null) {
|
||||
if (dir_info_package_json != null and
|
||||
strings.hasPrefixComptime(import_path, "#") and
|
||||
!forbid_imports and
|
||||
dir_info_package_json.?.package_json.?.imports != null)
|
||||
{
|
||||
return r.loadPackageImports(import_path, dir_info_package_json.?, kind, global_cache);
|
||||
}
|
||||
|
||||
@@ -2871,7 +2876,9 @@ pub const Resolver = struct {
|
||||
|
||||
const esmodule = ESModule{
|
||||
.conditions = switch (kind) {
|
||||
ast.ImportKind.require, ast.ImportKind.require_resolve => r.opts.conditions.require,
|
||||
ast.ImportKind.require,
|
||||
ast.ImportKind.require_resolve,
|
||||
=> r.opts.conditions.require,
|
||||
else => r.opts.conditions.import,
|
||||
},
|
||||
.allocator = r.allocator,
|
||||
@@ -2881,7 +2888,15 @@ pub const Resolver = struct {
|
||||
|
||||
const esm_resolution = esmodule.resolveImports(import_path, imports_map.root);
|
||||
|
||||
if (esm_resolution.status == .PackageResolve)
|
||||
if (esm_resolution.status == .PackageResolve) {
|
||||
if (JSC.HardcodedModule.Aliases.get(esm_resolution.path, .bun)) |builtin| {
|
||||
return .{
|
||||
.success = .{
|
||||
.path_pair = .{ .primary = bun.fs.Path.init(builtin.path) },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return r.loadNodeModules(
|
||||
esm_resolution.path,
|
||||
kind,
|
||||
@@ -2889,6 +2904,7 @@ pub const Resolver = struct {
|
||||
global_cache,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
if (r.handleESMResolution(esm_resolution, package_json.source.path.name.dir, kind, package_json, "")) |result| {
|
||||
return .{ .success = result };
|
||||
|
||||
8
test/js/bun/resolve/package.json
Normal file
8
test/js/bun/resolve/package.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "hello",
|
||||
"imports": {
|
||||
"#async_hooks": "async_hooks",
|
||||
"#bun": "bun",
|
||||
"#bun_test": "bun:test"
|
||||
}
|
||||
}
|
||||
@@ -51,20 +51,20 @@ it("#imports with wildcard", async () => {
|
||||
});
|
||||
|
||||
it("import.meta.resolve", async () => {
|
||||
expect(await import.meta.resolve("./resolve-test.test.js")).toBe(import.meta.path);
|
||||
expect(await import.meta.resolve("./resolve-test.js")).toBe(import.meta.path);
|
||||
|
||||
expect(await import.meta.resolve("./resolve-test.test.js", import.meta.path)).toBe(import.meta.path);
|
||||
expect(await import.meta.resolve("./resolve-test.js", import.meta.path)).toBe(import.meta.path);
|
||||
|
||||
expect(
|
||||
// optional second param can be any path, including a dir
|
||||
await import.meta.resolve("./resolve/resolve-test.test.js", join(import.meta.path, "../")),
|
||||
await import.meta.resolve("./resolve/resolve-test.js", join(import.meta.path, "../")),
|
||||
).toBe(import.meta.path);
|
||||
|
||||
// can be a package path
|
||||
expect((await import.meta.resolve("react", import.meta.path)).length > 0).toBe(true);
|
||||
|
||||
// file extensions are optional
|
||||
expect(await import.meta.resolve("./resolve-test.test")).toBe(import.meta.path);
|
||||
expect(await import.meta.resolve("./resolve-test")).toBe(import.meta.path);
|
||||
|
||||
// works with tsconfig.json "paths"
|
||||
expect(await import.meta.resolve("foo/bar")).toBe(join(import.meta.path, "../baz.js"));
|
||||
@@ -108,12 +108,12 @@ it("import.meta.resolve", async () => {
|
||||
// the slightly lower level API, which doesn't prefill the second param
|
||||
// and expects a directory instead of a filepath
|
||||
it("Bun.resolve", async () => {
|
||||
expect(await Bun.resolve("./resolve-test.test.js", import.meta.dir)).toBe(import.meta.path);
|
||||
expect(await Bun.resolve("./resolve-test.js", import.meta.dir)).toBe(import.meta.path);
|
||||
});
|
||||
|
||||
// synchronous
|
||||
it("Bun.resolveSync", () => {
|
||||
expect(Bun.resolveSync("./resolve-test.test.js", import.meta.dir)).toBe(import.meta.path);
|
||||
expect(Bun.resolveSync("./resolve-test.js", import.meta.dir)).toBe(import.meta.path);
|
||||
});
|
||||
|
||||
it("self-referencing imports works", async () => {
|
||||
|
||||
@@ -7,18 +7,14 @@ it("spawn test file", () => {
|
||||
writePackageJSONImportsFixture();
|
||||
writePackageJSONExportsFixture();
|
||||
|
||||
copyFileSync(join(import.meta.dir, "resolve-test.js"), join(import.meta.dir, "resolve-test.test.js"));
|
||||
|
||||
const { exitCode } = Bun.spawnSync({
|
||||
cmd: [bunExe(), "test", "resolve-test.test.js"],
|
||||
cmd: [bunExe(), "test", "./resolve-test.js"],
|
||||
env: bunEnv,
|
||||
cwd: import.meta.dir,
|
||||
stdio: ['inherit', 'inherit', 'inherit'],
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
rmSync(join(import.meta.dir, "resolve-test.test.js"));
|
||||
expect(existsSync(join(import.meta.dir, "resolve-test.test.js"))).toBe(false);
|
||||
});
|
||||
|
||||
function writePackageJSONExportsFixture() {
|
||||
@@ -78,6 +74,8 @@ function writePackageJSONImportsFixture() {
|
||||
"#foo": "./foo/private-foo.js",
|
||||
|
||||
"#internal-react": "react",
|
||||
|
||||
"#to_node_module": "async_hooks",
|
||||
},
|
||||
},
|
||||
null,
|
||||
@@ -291,3 +289,18 @@ it("import long string should not segfault", async () => {
|
||||
await import.meta.require.resolve("a".repeat(10000));
|
||||
} catch {}
|
||||
});
|
||||
|
||||
it('import override to node builtin', async() => {
|
||||
// @ts-expect-error
|
||||
expect(await import("#async_hooks")).toBeDefined();
|
||||
});
|
||||
|
||||
it('import override to bun', async() => {
|
||||
// @ts-expect-error
|
||||
expect(await import("#bun")).toBeDefined();
|
||||
});
|
||||
|
||||
it.todo('import override to bun:test', async() => {
|
||||
// @ts-expect-error
|
||||
expect(await import("#bun_test")).toBeDefined();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user