Files
bun.sh/test/bundler/bundler_loader.test.ts
Dylan Conway 8fad98ffdb Add Bun.YAML.parse and YAML imports (#22073)
### What does this PR do?
This PR adds builtin YAML parsing with `Bun.YAML.parse`
```js
import { YAML } from "bun";
const items = YAML.parse("- item1");
console.log(items); // [ "item1" ]
```

Also YAML imports work just like JSON and TOML imports
```js
import pkg from "./package.yaml"
console.log({ pkg }); // { pkg: { name: "pkg", version: "1.1.1" } }
```
### How did you verify your code works?
Added some tests for YAML imports and parsed values.

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-08-23 06:55:30 -07:00

222 lines
6.4 KiB
TypeScript

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));
},
});
}
});
});