import { expect, it, describe } from "bun:test"; describe("Bun.Transpiler", () => { const transpiler = new Bun.Transpiler({ loader: "tsx", define: { "process.env.NODE_ENV": JSON.stringify("development"), }, macro: { react: { bacon: `${import.meta.dir}/macro-check.js`, }, }, platform: "browser", }); const code = `import { useParams } from "remix"; import type { LoaderFunction, ActionFunction } from "remix"; export const loader: LoaderFunction = async ({ params }) => { console.log(params.postId); }; export const action: ActionFunction = async ({ params }) => { console.log(params.postId); }; export default function PostRoute() { const params = useParams(); console.log(params.postId); } `; describe("scanImports", () => { it("reports import paths, excluding types", () => { const imports = transpiler.scanImports(code); expect(imports.filter(({ path }) => path === "remix")).toHaveLength(1); }); }); describe("scan", () => { it("reports all export names", () => { const { imports, exports } = transpiler.scan(code); expect(exports[0]).toBe("action"); expect(exports[2]).toBe("loader"); expect(exports[1]).toBe("default"); expect(exports).toHaveLength(3); }); }); describe("transform", () => { it("supports macros", async () => { const out = await transpiler.transform(` import {keepSecondArgument} from 'macro:${ import.meta.dir }/macro-check.js'; export default keepSecondArgument("Test failed", "Test passed"); `); expect(out.includes("Test failed")).toBe(false); expect(out.includes("Test passed")).toBe(true); // ensure both the import and the macro function call are removed expect(out.includes("keepSecondArgument")).toBe(false); }); it("sync supports macros", () => { const out = transpiler.transformSync(` import {keepSecondArgument} from 'macro:${ import.meta.dir }/macro-check.js'; export default keepSecondArgument("Test failed", "Test passed"); `); expect(out.includes("Test failed")).toBe(false); expect(out.includes("Test passed")).toBe(true); expect(out.includes("keepSecondArgument")).toBe(false); }); const importLines = [ "import {createElement, bacon} from 'react';", "import {bacon, createElement} from 'react';", ]; describe("sync supports macros remap", () => { for (let importLine of importLines) { it(importLine, () => { const out = transpiler.transformSync(` ${importLine} export default bacon("Test failed", "Test passed"); export function hi() { createElement("hi"); } `); expect(out.includes("Test failed")).toBe(false); expect(out.includes("Test passed")).toBe(true); expect(out.includes("bacon")).toBe(false); expect(out.includes("createElement")).toBe(true); }); } }); it("macro remap removes import statement if its the only used one", () => { const out = transpiler.transformSync(` import {bacon} from 'react'; export default bacon("Test failed", "Test passed"); `); expect(out.includes("Test failed")).toBe(false); expect(out.includes("Test passed")).toBe(true); expect(out.includes("bacon")).toBe(false); expect(out.includes("import")).toBe(false); }); it("removes types", () => { expect(code.includes("ActionFunction")).toBe(true); expect(code.includes("LoaderFunction")).toBe(true); const out = transpiler.transformSync(code); expect(out.includes("ActionFunction")).toBe(false); expect(out.includes("LoaderFunction")).toBe(false); const { exports } = transpiler.scan(out); expect(exports[0]).toBe("action"); expect(exports[2]).toBe("loader"); expect(exports[1]).toBe("default"); expect(exports).toHaveLength(3); }); }); });