import type { TtscUnpluginOptions } from "./core/options.cjs"; /** * Minimal subset of the Bun plugin API consumed by this adapter. * * Bun does not yet ship TypeScript types for its bundler plugin interface, so * we define the subset we need here. This keeps the adapter free of a Bun * runtime dependency while remaining type-safe. */ export interface BunLikePlugin { /** Plugin identifier shown in Bun bundler output. */ name: string; /** Called by Bun when the plugin is registered. */ setup(build: BunLikeBuild): void | Promise; } /** Bun loader identifiers this adapter can emit (only TypeScript is matched). */ export type BunLoader = "ts" | "tsx"; /** * Options accepted by {@link bun}, either resolved eagerly or supplied through a * provider evaluated lazily on the first `onLoad` call. * * The provider form exists for the runtime registration path (`bun-register`), * where a single Bun plugin is registered on import but its effective options * may be overridden by explicit `register(options)` calls made before the first * transformable TypeScript load. Resolving through the provider on that first * load, rather than at registration, lets the last pending call win without Bun * ever seeing a second shadowing loader. */ export type TtscBunOptions = TtscUnpluginOptions | (() => TtscUnpluginOptions | undefined); /** * Minimal subset of the Bun `BuildConfig` plugin build object. * * `onLoad` drives the source transform. Bun's bundler also exposes `onStart` * and `onEnd`, which bracket the shared plugin's build lifecycle. The runtime * plugin API omits those hooks, so plugin setup itself starts its one * process-scoped module-loading session. */ export interface BunLikeBuild { /** * Build configuration exposed unchanged by Bun's bundler plugin builder. * * Runtime plugin builders do not supply `files`. Bun's bundler accepts an * in-memory file map whose values deliberately remain `unknown` here because * this adapter only needs to preserve ownership, not consume their contents. */ config?: { files?: Readonly>; }; /** * Register a callback for the start of a bundler build. * * Optional because `Bun.plugin()` runtime builders do not expose this hook. */ onStart?(callback: () => void | Promise): void; /** Register a callback for deterministic bundler-session teardown. */ onEnd?(callback: () => void | Promise): void; /** * Register a loader callback for files matching `filter`. * * The callback receives the file path and must return the transformed file * contents plus the `loader` Bun should apply next. Configured in-memory * files retain relative key spellings; ordinary disk files are normally * absolute. The `loader` matters most for the runtime path (`Bun.plugin`), * where Bun must be told the returned contents are still TypeScript so it * keeps transpiling them before execution. */ onLoad(options: { filter: RegExp; }, loader: (args: { path: string; }) => Promise<{ contents: string; loader: BunLoader; } | undefined>): void; } /** * Create a ttsc plugin for Bun's bundler AND runtime. * * Bun does not implement the unplugin protocol, so this adapter wires the * shared ttsc transform core to Bun's `onLoad` hook directly. It reads each * included file from disk and forwards the content to the transform. Under * `Bun.build`, excluded files and no-op transforms return `undefined` so the * next loader retains ownership. Entries supplied through `BuildConfig.files` * also stay with Bun's in-memory loader: they are not filesystem project inputs * and reading the same path from disk would either fail or silently replace the * configured contents. The runtime `Bun.plugin()` API rejects an undefined * `onLoad` result, so that path explicitly returns the original source and * loader instead. * * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see * `bun-register`. Every result carries an explicit `loader` so Bun keeps * transpiling the emitted TypeScript at runtime; `bunSourceFilePattern` only * matches TypeScript, so the loader is always `ts`/`tsx`. A runtime plugin * instance is one immutable load session, like Bun's own module cache; restart * the process after changing compiler inputs. */ export default function bun(options?: TtscBunOptions): BunLikePlugin;