import { fileURLToPath, Loader } from "bun"; import { describe, expect } from "bun:test"; import fs, { readdirSync } from "node:fs"; import { join } from "path"; import { itBundled } from "./expectBundled"; describe("bundler", async () => { for (let target of ["bun", "node"] as const) { describe(`${target} loader`, async () => { itBundled("bun/loader-yaml-file", { target, files: { "/entry.ts": /* js */ ` import hello from './hello.notyaml' with {type: "yaml"}; console.write(JSON.stringify(hello)); `, "/hello.notyaml": `hello: world`, }, run: { stdout: '{"hello":"world"}' }, }); itBundled("bun/loader-text-file", { target, outfile: "", outdir: "/out", files: { "/entry.ts": /* js */ ` import hello from './hello.foo' with {type: "text"}; console.log(hello); `, "/hello.foo": "Hello, world!", }, run: { stdout: "Hello, world!" }, }); itBundled("bun/loader-json-file", { target, files: { "/entry.ts": /* js */ ` import hello from './hello.notjson' with {type: "json"}; console.write(JSON.stringify(hello)); `, "/hello.notjson": JSON.stringify({ hello: "world" }), }, run: { stdout: '{"hello":"world"}' }, }); itBundled("bun/loader-toml-file", { target, files: { "/entry.ts": /* js */ ` import hello from './hello.nottoml' with {type: "toml"}; console.write(JSON.stringify(hello)); `, "/hello.nottoml": `hello = "world"`, }, run: { stdout: '{"hello":"world"}' }, }); itBundled("bun/loader-text-file", { target, files: { "/entry.ts": /* js */ ` import hello from './hello.json' with {type: "text"}; console.write(hello); `, "/hello.json": JSON.stringify({ hello: "world" }), }, run: { stdout: '{"hello":"world"}' }, }); }); } itBundled("bun/loader-text-file", { target: "bun", outfile: "", outdir: "/out", files: { "/entry.ts": /* js */ ` import first from './1.boo' with {type: "text"}; import second from './2.boo' with {type: "text"}; console.write(first + second); `, "/1.boo": "'`Hello, \nworld!`", "/2.boo": "`${Hello}\n, world!`'", }, run: { stdout: "'`Hello, \nworld!``${Hello}\n, world!`'", }, }); itBundled("bun/wasm-is-copied-to-outdir", { target: "bun", outdir: "/out", files: { "/entry.ts": /* js */ ` import wasm from './add.wasm'; import { join } from 'path'; const { instance } = await WebAssembly.instantiate(await Bun.file(join(import.meta.dir, wasm)).arrayBuffer()); console.log(instance.exports.add(1, 2)); `, "/add.wasm": fs.readFileSync(join(import.meta.dir, "fixtures", "add.wasm")), }, run: { stdout: "3", }, }); const moon = await Bun.file( fileURLToPath(import.meta.resolve("../js/bun/util/text-loader-fixture-text-file.backslashes.txt")), ).text(); // https://github.com/oven-sh/bun/issues/3449 itBundled("bun/loader-text-file-#3449", { target: "bun", outfile: "", outdir: "/out", files: { "/entry.ts": /* js */ ` import first from './1.boo' with {type: "text"}; console.write(first); `, "/1.boo": moon, }, run: { stdout: moon, }, }); const loaders: Loader[] = ["wasm", "json", "file" /* "napi" */, "text"]; const exts = ["wasm", "json", "lmao" /* ".node" */, "txt"]; for (let i = 0; i < loaders.length; i++) { const loader = loaders[i]; const ext = exts[i]; itBundled(`bun/loader-copy-file-entry-point-with-onLoad-${loader}`, { target: "bun", outdir: "/out", files: { [`/entry.${ext}`]: /* js */ `{ "hello": "friends" }`, }, entryNaming: "[dir]/[name]-[hash].[ext]", plugins(builder) { builder.onLoad({ filter: new RegExp(`.${loader}$`) }, async ({ path }) => { const result = await Bun.file(path).text(); return { contents: result, loader }; }); }, onAfterBundle(api) { const jsFile = readdirSync(api.outdir).find(x => x.endsWith(".js"))!; const module = require(join(api.outdir, jsFile)); if (loader === "json") { expect(module.default).toStrictEqual({ hello: "friends" }); } else if (loader === "text") { expect(module.default).toStrictEqual('{ "hello": "friends" }'); } else { api.assertFileExists(join("out", module.default)); } }, }); } for (let i = 0; i < loaders.length; i++) { const loader = loaders[i]; const ext = exts[i]; itBundled(`bun/loader-copy-file-entry-point-${loader}`, { target: "bun", outfile: "", outdir: "/out", files: { [`/entry.${ext}`]: /* js */ `{ "hello": "friends" }`, }, entryNaming: "[dir]/[name]-[hash].[ext]", onAfterBundle(api) { const jsFile = readdirSync(api.outdir).find(x => x.endsWith(".js"))!; const module = require(join(api.outdir, jsFile)); if (loader === "json") { expect(module.default).toStrictEqual({ hello: "friends" }); } else if (loader === "text") { expect(module.default).toStrictEqual('{ "hello": "friends" }'); } else { api.assertFileExists(join("out", module.default)); } }, }); } describe("handles empty files", () => { for (const target of ["bun", "node", "browser"] as const) { itBundled(`${target}/loader-empty-text-file`, { target: target, files: { "/entry.ts": /* js */ ` import empty from './empty.txt' with {type: "text"}; console.write(JSON.stringify(empty)); `, "/empty.txt": "", }, run: { stdout: '""' }, }); itBundled(`${target}/loader-empty-file-loader`, { target: target, outdir: "/out", files: { "/entry.ts": /* js */ ` import empty from './empty.txt' with {type: "file"}; export default empty; `, "/empty.txt": "", }, onAfterBundle(api) { const jsFile = readdirSync(api.outdir).find(x => x.endsWith(".js"))!; const module = require(join(api.outdir, jsFile)); api.assertFileExists(join("out", module.default)); }, }); } }); });