import { it, expect } from "bun:test"; import { mkdirSync, writeFileSync } from "fs"; import { join, sep } from "path"; import { bunExe, bunEnv, tempDirWithFiles, isWindows } from "harness"; import { pathToFileURL } from "bun"; it("spawn test file", () => { writePackageJSONImportsFixture(); writePackageJSONExportsFixture(); const { exitCode } = Bun.spawnSync({ cmd: [bunExe(), "test", "./resolve-test.js"], env: bunEnv, cwd: import.meta.dir, stdio: ["inherit", "inherit", "inherit"], }); expect(exitCode).toBe(0); }); function writePackageJSONExportsFixture() { try { mkdirSync(join(import.meta.dir, "./node_modules/package-json-exports/foo"), { recursive: true, }); } catch (exception) {} writeFileSync(join(import.meta.dir, "./node_modules/package-json-exports/foo/bar.js"), "export const bar = 1;"); writeFileSync( join(import.meta.dir, "./node_modules/package-json-exports/foo/references-baz.js"), "export {bar} from 'package-json-exports/baz';", ); writeFileSync( join(import.meta.dir, "./node_modules/package-json-exports/package.json"), JSON.stringify( { name: "package-json-exports", exports: { "./baz": "./foo/bar.js", "./references-baz": "./foo/references-baz.js", }, }, null, 2, ), ); } function writePackageJSONImportsFixture() { try { mkdirSync(join(import.meta.dir, "./node_modules/package-json-imports/foo"), { recursive: true, }); } catch (exception) {} writeFileSync(join(import.meta.dir, "./node_modules/package-json-imports/foo/bar.js"), "export const bar = 1;"); writeFileSync( join(import.meta.dir, "./node_modules/package-json-imports/foo/wildcard.js"), "export const wildcard = 1;", ); writeFileSync( join(import.meta.dir, "./node_modules/package-json-imports/foo/private-foo.js"), "export {bar} from 'package-json-imports/#foo';", ); writeFileSync( join(import.meta.dir, "./node_modules/package-json-imports/package.json"), JSON.stringify( { name: "package-json-imports", exports: { "./baz": "./foo/bar.js", }, imports: { "#foo/bar": "./foo/private-foo.js", "#foo/*.js": "./foo/*.js", "#foo/extensionless/*": "./foo/*.js", "#foo": "./foo/private-foo.js", "#internal-react": "react", "#to_node_module": "async_hooks", }, }, null, 2, ), ); } it("file url in import resolves", async () => { const dir = tempDirWithFiles("fileurl", { "index.js": "export const foo = 1;", }); writeFileSync(`${dir}/test.js`, `import {foo} from '${pathToFileURL(dir)}/index.js';\nconsole.log(foo);`); console.log(dir); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); try { expect(exitCode).toBe(0); } catch (e) { console.log(stdout.toString("utf8")); throw e; } expect(stdout.toString("utf8")).toBe("1\n"); }); it("invalid file url in import throws error", async () => { const dir = tempDirWithFiles("fileurl", {}); writeFileSync(`${dir}/test.js`, `import {foo} from 'file://\0invalid url';\nconsole.log(foo);`); const { exitCode, stdout, stderr } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).not.toBe(0); expect(stderr.toString("utf8")).toContain("file://\0invalid url"); }); it("file url in await import resolves", async () => { const dir = tempDirWithFiles("fileurl", { "index.js": "export const foo = 1;", }); writeFileSync(`${dir}/test.js`, `const {foo} = await import('${pathToFileURL(dir)}/index.js');\nconsole.log(foo);`); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe("1\n"); }); it("file url with special characters in await import resolves", async () => { const filename = "🅱️ndex.js"; const dir = tempDirWithFiles("file url", { [filename]: "export const foo = 1;", }); console.log(dir); writeFileSync( `${dir}/test.js`, `const {foo} = await import('${pathToFileURL(dir)}/${encodeURIComponent(filename)}');\nconsole.log(foo);`, ); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe("1\n"); }); it("file url with special characters not encoded in await import resolves", async () => { const filename = "🅱️ndex.js"; const dir = tempDirWithFiles("file url", { [filename]: "export const foo = 1;", }); writeFileSync( `${dir}/test.js`, `const {foo} = await import('${pathToFileURL(dir)}/${filename}');\nconsole.log(foo);`, ); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe("1\n"); }); it("file url with special characters in import statement resolves", async () => { const filename = "🅱️ndex.js"; const dir = tempDirWithFiles("file url", { [filename]: "export const foo = 1;", }); writeFileSync( `${dir}/test.js`, `import {foo} from '${pathToFileURL(dir)}/${encodeURIComponent(filename)}';\nconsole.log(foo);`, ); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe("1\n"); }); it("file url with special characters not encoded in import statement resolves", async () => { const filename = "🅱️ndex.js"; const dir = tempDirWithFiles("file url", { [filename]: "export const foo = 1;", }); writeFileSync(`${dir}/test.js`, `import {foo} from '${pathToFileURL(dir)}/${filename}';\nconsole.log(foo);`); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe("1\n"); }); it("file url in require resolves", async () => { const dir = tempDirWithFiles("fileurl", { "index.js": "export const foo = 1;", }); writeFileSync(`${dir}/test.js`, `const {foo} = require('${pathToFileURL(dir)}/index.js');\nconsole.log(foo);`); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe("1\n"); }); it("file url with special characters in require resolves", async () => { const filename = "🅱️ndex.js"; const dir = tempDirWithFiles("file url", { [filename]: "export const foo = 1;", }); writeFileSync( `${dir}/test.js`, `const {foo} = require('${pathToFileURL(dir)}/${encodeURIComponent(filename)}');\nconsole.log(foo);`, ); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe("1\n"); }); it("file url in require.resolve resolves", async () => { const dir = tempDirWithFiles("fileurl", { "index.js": "export const foo = 1;", }); writeFileSync(`${dir}/test.js`, `const to = require.resolve('${pathToFileURL(dir)}/index.js');\nconsole.log(to);`); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe(`${dir}${sep}index.js\n`); }); it("file url with special characters in require resolves", async () => { const filename = "🅱️ndex.js"; const dir = tempDirWithFiles("file url", { [filename]: "export const foo = 1;", }); writeFileSync( `${dir}/test.js`, `const to = require.resolve('${pathToFileURL(dir)}/${encodeURIComponent(filename)}');\nconsole.log(to);`, ); const { exitCode, stdout } = Bun.spawnSync({ cmd: [bunExe(), `${dir}/test.js`], env: bunEnv, cwd: import.meta.dir, }); expect(exitCode).toBe(0); expect(stdout.toString("utf8")).toBe(`${dir}${sep}${filename}\n`); }); it("import long string should not segfault", async () => { try { await import("a".repeat(10000)); } catch {} }); it("import long string should not segfault", async () => { try { import.meta.require("a".repeat(10000)); } catch {} }); it("import long string should not segfault", async () => { try { await import.meta.resolve!("a".repeat(10000)); } catch {} }); it("import long string should not segfault", async () => { try { 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(); }); it.if(isWindows)("directory cache key computation", () => { expect(import(`${process.cwd()}\\\\doesnotexist.ts`)).rejects.toThrow(); expect(import(`${process.cwd()}\\\\\\doesnotexist.ts`)).rejects.toThrow(); expect(import(`\\\\Test\\\\doesnotexist.ts\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\doesnotexist.ts\\\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\doesnotexist.ts\\\\\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\\\doesnotexist.ts` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\\\\\doesnotexist.ts` as any)).rejects.toThrow(); expect(import(`\\\\Test\\doesnotexist.ts` as any)).rejects.toThrow(); expect(import(`\\\\\\Test\\doesnotexist.ts` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\\\doesnotexist.ts\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\\\\\doesnotexist.ts\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\doesnotexist.ts\\` as any)).rejects.toThrow(); expect(import(`\\\\\\Test\\doesnotexist.ts\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\\\doesnotexist.ts\\\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\\\\\\\doesnotexist.ts\\\\` as any)).rejects.toThrow(); expect(import(`\\\\Test\\doesnotexist.ts\\\\` as any)).rejects.toThrow(); expect(import(`\\\\\\Test\\doesnotexist.ts\\\\` as any)).rejects.toThrow(); });