1import path from "node:path";
2import type {
3 InputOptions,
4 OutputChunk,
5 OutputOptions,
6 RolldownOutput,
7 RolldownPluginOption,
8} from "rolldown";
9import { rolldown } from "rolldown";
10import type { RolldownPluginOptions } from "../../plugin.ts";
11import cloudflare from "../../plugin.ts";
12import { getEntryChunk } from "./output.ts";
13
14const DEFAULT_PLUGIN_OPTIONS: RolldownPluginOptions = {
15 compatibilityDate: "2025-07-01",
16};
17
18interface BuildFixtureOptions {
19 fixture: string;
20 pluginOptions?: RolldownPluginOptions;
21 plugins?: Array<RolldownPluginOption>;
22 inputOptions?: Omit<InputOptions, "input" | "plugins">;
23 generateOptions?: Omit<OutputOptions, "file" | "format" | "sourcemap">;
24}
25
26export interface BuiltFixture {
27 fixture: string;
28 output: RolldownOutput;
29 entry: OutputChunk;
30}
31
32export async function buildFixture(
33 options: BuildFixtureOptions,
34): Promise<BuiltFixture> {
35 const fixture = normalizeFixturePath(options.fixture);
36 const bundle = await rolldown({
37 input: fixture,
38 ...(options.inputOptions ?? {}),
39 plugins: [
40 ...(options.plugins ?? []),
41 cloudflare(options.pluginOptions ?? DEFAULT_PLUGIN_OPTIONS),
42 ],
43 });
44
45 try {
46 const output = await bundle.write({
47 file: defaultOutputPath(fixture),
48 format: "esm",
49 sourcemap: true,
50 ...(options.generateOptions ?? {}),
51 });
52 return {
53 fixture,
54 output,
55 entry: getEntryChunk(output),
56 };
57 } finally {
58 await bundle.close();
59 }
60}
61
62function normalizeFixturePath(fixture: string): string {
63 return path.isAbsolute(fixture)
64 ? fixture
65 : path.join("test", "fixtures", fixture);
66}
67
68function defaultOutputPath(fixture: string): string {
69 const fixtureName =
70 path.basename(path.dirname(fixture)) === "fixtures"
71 ? path.basename(fixture, path.extname(fixture))
72 : path.basename(path.dirname(fixture));
73 return path.join("out", fixtureName, "index.js");
74}