diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index e1cb0a7b2e..cbf3842fdf 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -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 }; diff --git a/test/js/bun/resolve/package.json b/test/js/bun/resolve/package.json new file mode 100644 index 0000000000..0a4ec0264b --- /dev/null +++ b/test/js/bun/resolve/package.json @@ -0,0 +1,8 @@ +{ + "name": "hello", + "imports": { + "#async_hooks": "async_hooks", + "#bun": "bun", + "#bun_test": "bun:test" + } +} \ No newline at end of file diff --git a/test/js/bun/resolve/resolve-test.js b/test/js/bun/resolve/resolve-test.js index 17e2b4eb45..297a7c9361 100644 --- a/test/js/bun/resolve/resolve-test.js +++ b/test/js/bun/resolve/resolve-test.js @@ -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 () => { diff --git a/test/js/bun/resolve/resolve.test.ts b/test/js/bun/resolve/resolve.test.ts index 217d3dc814..bdde0b2149 100644 --- a/test/js/bun/resolve/resolve.test.ts +++ b/test/js/bun/resolve/resolve.test.ts @@ -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(); +});