@ttsc/unplugin 0.16.12 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ import type { TtscUnpluginOptions } from "./core/options";
2
+ /**
3
+ * Register the ttsc transform as a Bun **runtime** plugin.
4
+ *
5
+ * The other `@ttsc/unplugin/*` adapters cover bundlers (`Bun.build`, Vite,
6
+ * Webpack, …). This entry is the runtime counterpart: loading it registers the
7
+ * same transform on Bun's module loader, so `bun run` / `bun test` apply ttsc
8
+ * plugins (e.g. typia's `typia/lib/transform`) as files are imported, with no
9
+ * bundling step. Wire it up once via a `bunfig.toml` preload entry —
10
+ * `preload = ["@ttsc/unplugin/bun-register"]` — or imperatively with
11
+ * `import "@ttsc/unplugin/bun-register"`. Options are read from the nearest
12
+ * `tsconfig.json`, identical to the bundler adapters.
13
+ *
14
+ * @throws When called explicitly off the Bun runtime (`globalThis.Bun.plugin`
15
+ * is unavailable). The auto-registration below stays silent off Bun so the
16
+ * module is harmless to import from Node (tests, tooling).
17
+ */
18
+ export declare function register(options?: TtscUnpluginOptions): void;
19
+ export default register;
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var bun = require('./bun.js');
6
+
7
+ /**
8
+ * Register the ttsc transform as a Bun **runtime** plugin.
9
+ *
10
+ * The other `@ttsc/unplugin/*` adapters cover bundlers (`Bun.build`, Vite,
11
+ * Webpack, …). This entry is the runtime counterpart: loading it registers the
12
+ * same transform on Bun's module loader, so `bun run` / `bun test` apply ttsc
13
+ * plugins (e.g. typia's `typia/lib/transform`) as files are imported, with no
14
+ * bundling step. Wire it up once via a `bunfig.toml` preload entry —
15
+ * `preload = ["@ttsc/unplugin/bun-register"]` — or imperatively with
16
+ * `import "@ttsc/unplugin/bun-register"`. Options are read from the nearest
17
+ * `tsconfig.json`, identical to the bundler adapters.
18
+ *
19
+ * @throws When called explicitly off the Bun runtime (`globalThis.Bun.plugin`
20
+ * is unavailable). The auto-registration below stays silent off Bun so the
21
+ * module is harmless to import from Node (tests, tooling).
22
+ */
23
+ function register(options) {
24
+ const runtime = bunRuntime();
25
+ if (runtime === undefined) {
26
+ throw new Error("@ttsc/unplugin/bun-register must run under the Bun runtime " +
27
+ "(globalThis.Bun.plugin is unavailable). Use a bundler adapter such as " +
28
+ "@ttsc/unplugin/vite for non-Bun toolchains.");
29
+ }
30
+ runtime.plugin(bun.default(options));
31
+ }
32
+ function bunRuntime() {
33
+ const runtime = globalThis.Bun;
34
+ return runtime !== undefined && typeof runtime.plugin === "function"
35
+ ? runtime
36
+ : undefined;
37
+ }
38
+ // Auto-register on import so a `bunfig.toml` `preload` entry — which only
39
+ // imports the module — takes effect. Guarded so importing from Node (a stray
40
+ // import, or a unit test) is a harmless no-op rather than a throw.
41
+ if (bunRuntime() !== undefined) {
42
+ register();
43
+ }
44
+
45
+ exports.default = register;
46
+ exports.register = register;
47
+ //# sourceMappingURL=bun-register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun-register.js","sources":["../src/bun-register.ts"],"sourcesContent":[null],"names":["bun"],"mappings":";;;;;;AAcA;;;;;;;;;;;;;;;AAeG;AACG,SAAU,QAAQ,CAAC,OAA6B,EAAA;AACpD,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE;AAC5B,IAAA,IAAI,OAAO,KAAK,SAAS,EAAE;QACzB,MAAM,IAAI,KAAK,CACb,6DAA6D;YAC3D,wEAAwE;AACxE,YAAA,6CAA6C,CAChD;IACH;IACA,OAAO,CAAC,MAAM,CAACA,WAAG,CAAC,OAAO,CAAC,CAAC;AAC9B;AAEA,SAAS,UAAU,GAAA;AACjB,IAAA,MAAM,OAAO,GAAI,UAAyC,CAAC,GAAG;IAC9D,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK;AACxD,UAAE;UACA,SAAS;AACf;AAEA;AACA;AACA;AACA,IAAI,UAAU,EAAE,KAAK,SAAS,EAAE;AAC9B,IAAA,QAAQ,EAAE;AACZ;;;;;"}
@@ -0,0 +1,42 @@
1
+ import bun from './bun.mjs';
2
+
3
+ /**
4
+ * Register the ttsc transform as a Bun **runtime** plugin.
5
+ *
6
+ * The other `@ttsc/unplugin/*` adapters cover bundlers (`Bun.build`, Vite,
7
+ * Webpack, …). This entry is the runtime counterpart: loading it registers the
8
+ * same transform on Bun's module loader, so `bun run` / `bun test` apply ttsc
9
+ * plugins (e.g. typia's `typia/lib/transform`) as files are imported, with no
10
+ * bundling step. Wire it up once via a `bunfig.toml` preload entry —
11
+ * `preload = ["@ttsc/unplugin/bun-register"]` — or imperatively with
12
+ * `import "@ttsc/unplugin/bun-register"`. Options are read from the nearest
13
+ * `tsconfig.json`, identical to the bundler adapters.
14
+ *
15
+ * @throws When called explicitly off the Bun runtime (`globalThis.Bun.plugin`
16
+ * is unavailable). The auto-registration below stays silent off Bun so the
17
+ * module is harmless to import from Node (tests, tooling).
18
+ */
19
+ function register(options) {
20
+ const runtime = bunRuntime();
21
+ if (runtime === undefined) {
22
+ throw new Error("@ttsc/unplugin/bun-register must run under the Bun runtime " +
23
+ "(globalThis.Bun.plugin is unavailable). Use a bundler adapter such as " +
24
+ "@ttsc/unplugin/vite for non-Bun toolchains.");
25
+ }
26
+ runtime.plugin(bun(options));
27
+ }
28
+ function bunRuntime() {
29
+ const runtime = globalThis.Bun;
30
+ return runtime !== undefined && typeof runtime.plugin === "function"
31
+ ? runtime
32
+ : undefined;
33
+ }
34
+ // Auto-register on import so a `bunfig.toml` `preload` entry — which only
35
+ // imports the module — takes effect. Guarded so importing from Node (a stray
36
+ // import, or a unit test) is a harmless no-op rather than a throw.
37
+ if (bunRuntime() !== undefined) {
38
+ register();
39
+ }
40
+
41
+ export { register as default, register };
42
+ //# sourceMappingURL=bun-register.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun-register.mjs","sources":["../src/bun-register.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAcA;;;;;;;;;;;;;;;AAeG;AACG,SAAU,QAAQ,CAAC,OAA6B,EAAA;AACpD,IAAA,MAAM,OAAO,GAAG,UAAU,EAAE;AAC5B,IAAA,IAAI,OAAO,KAAK,SAAS,EAAE;QACzB,MAAM,IAAI,KAAK,CACb,6DAA6D;YAC3D,wEAAwE;AACxE,YAAA,6CAA6C,CAChD;IACH;IACA,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC9B;AAEA,SAAS,UAAU,GAAA;AACjB,IAAA,MAAM,OAAO,GAAI,UAAyC,CAAC,GAAG;IAC9D,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK;AACxD,UAAE;UACA,SAAS;AACf;AAEA;AACA;AACA;AACA,IAAI,UAAU,EAAE,KAAK,SAAS,EAAE;AAC9B,IAAA,QAAQ,EAAE;AACZ;;;;"}
package/lib/bun.d.ts CHANGED
@@ -12,6 +12,8 @@ export interface BunLikePlugin {
12
12
  /** Called by Bun when the plugin is registered. */
13
13
  setup(build: BunLikeBuild): void | Promise<void>;
14
14
  }
15
+ /** Bun loader identifiers this adapter can emit (only TypeScript is matched). */
16
+ export type BunLoader = "ts" | "tsx";
15
17
  /**
16
18
  * Minimal subset of the Bun `BuildConfig` plugin build object.
17
19
  *
@@ -23,7 +25,10 @@ export interface BunLikeBuild {
23
25
  * Register a loader callback for files matching `filter`.
24
26
  *
25
27
  * The callback receives the absolute file path and must return the
26
- * transformed file contents.
28
+ * transformed file contents plus the `loader` Bun should apply next. The
29
+ * `loader` matters most for the runtime path (`Bun.plugin`), where Bun must
30
+ * be told the returned contents are still TypeScript so it keeps transpiling
31
+ * them before execution.
27
32
  */
28
33
  onLoad(options: {
29
34
  filter: RegExp;
@@ -31,15 +36,22 @@ export interface BunLikeBuild {
31
36
  path: string;
32
37
  }) => Promise<{
33
38
  contents: string;
39
+ loader: BunLoader;
34
40
  }>): void;
35
41
  }
36
42
  /**
37
- * Create a ttsc plugin for Bun's bundler.
43
+ * Create a ttsc plugin for Bun's bundler AND runtime.
38
44
  *
39
45
  * Bun does not implement the unplugin protocol, so this adapter instantiates
40
46
  * the raw unplugin transform and wires it to Bun's `onLoad` hook manually. The
41
47
  * adapter reads each matching file from disk and forwards the content to the
42
48
  * ttsc transform; if the transform returns no changes the original source is
43
49
  * passed through unchanged.
50
+ *
51
+ * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and
52
+ * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see
53
+ * `bun-register`. Every result carries an explicit `loader` so Bun keeps
54
+ * transpiling the emitted TypeScript at runtime; `sourceFilePattern` only
55
+ * matches TypeScript, so the loader is always `ts`/`tsx`.
44
56
  */
45
57
  export default function bun(options?: TtscUnpluginOptions): BunLikePlugin;
package/lib/bun.js CHANGED
@@ -6,13 +6,19 @@ var fs = require('node:fs/promises');
6
6
  var index = require('./core/index.js');
7
7
 
8
8
  /**
9
- * Create a ttsc plugin for Bun's bundler.
9
+ * Create a ttsc plugin for Bun's bundler AND runtime.
10
10
  *
11
11
  * Bun does not implement the unplugin protocol, so this adapter instantiates
12
12
  * the raw unplugin transform and wires it to Bun's `onLoad` hook manually. The
13
13
  * adapter reads each matching file from disk and forwards the content to the
14
14
  * ttsc transform; if the transform returns no changes the original source is
15
15
  * passed through unchanged.
16
+ *
17
+ * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and
18
+ * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see
19
+ * `bun-register`. Every result carries an explicit `loader` so Bun keeps
20
+ * transpiling the emitted TypeScript at runtime; `sourceFilePattern` only
21
+ * matches TypeScript, so the loader is always `ts`/`tsx`.
16
22
  */
17
23
  function bun(options) {
18
24
  return {
@@ -20,25 +26,34 @@ function bun(options) {
20
26
  setup(build) {
21
27
  const raw = index.default.raw(options, {});
22
28
  build.onLoad({ filter: index.sourceFilePattern }, async (args) => {
29
+ const loader = bunLoaderFor(args.path);
23
30
  const source = await fs.readFile(args.path, "utf8");
24
31
  const result = typeof raw.transform === "function"
25
32
  ? await raw.transform.call({}, source, args.path)
26
33
  : undefined;
27
34
  // Unpack both shorthand string and object result shapes.
28
35
  if (typeof result === "string") {
29
- return { contents: result };
36
+ return { contents: result, loader };
30
37
  }
31
38
  if (typeof result === "object" &&
32
39
  result !== null &&
33
40
  "code" in result &&
34
41
  typeof result.code === "string") {
35
- return { contents: result.code };
42
+ return { contents: result.code, loader };
36
43
  }
37
- return { contents: source };
44
+ return { contents: source, loader };
38
45
  });
39
46
  },
40
47
  };
41
48
  }
49
+ /**
50
+ * Pick the Bun loader for a matched file. `sourceFilePattern` is
51
+ * `/\.[cm]?tsx?$/`, so a trailing `x` (`.tsx`/`.ctsx`/`.mtsx`) is JSX-flavored
52
+ * TypeScript and everything else (`.ts`/`.cts`/`.mts`) is plain TypeScript.
53
+ */
54
+ function bunLoaderFor(filePath) {
55
+ return /x$/i.test(filePath) ? "tsx" : "ts";
56
+ }
42
57
 
43
58
  exports.default = bun;
44
59
  //# sourceMappingURL=bun.js.map
package/lib/bun.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bun.js","sources":["../src/bun.ts"],"sourcesContent":[null],"names":["unplugin","sourceFilePattern"],"mappings":";;;;;;;AAwCA;;;;;;;;AAQG;AACW,SAAU,GAAG,CAAC,OAA6B,EAAA;IACvD,OAAO;AACL,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,KAAK,CAAC,KAAK,EAAA;YACT,MAAM,GAAG,GAAGA,aAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,EAAyB,CAAC;AAC5D,YAAA,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAEC,uBAAiB,EAAE,EAAE,OAAO,IAAI,KAAI;AACzD,gBAAA,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;AACnD,gBAAA,MAAM,MAAM,GACV,OAAO,GAAG,CAAC,SAAS,KAAK;AACvB,sBAAE,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAW,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI;sBACvD,SAAS;;AAEf,gBAAA,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC9B,oBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE;gBAC7B;gBACA,IACE,OAAO,MAAM,KAAK,QAAQ;AAC1B,oBAAA,MAAM,KAAK,IAAI;AACf,oBAAA,MAAM,IAAI,MAAM;AAChB,oBAAA,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAC/B;AACA,oBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE;gBAClC;AACA,gBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE;AAC7B,YAAA,CAAC,CAAC;QACJ,CAAC;KACF;AACH;;;;"}
1
+ {"version":3,"file":"bun.js","sources":["../src/bun.ts"],"sourcesContent":[null],"names":["unplugin","sourceFilePattern"],"mappings":";;;;;;;AAgDA;;;;;;;;;;;;;;AAcG;AACW,SAAU,GAAG,CAAC,OAA6B,EAAA;IACvD,OAAO;AACL,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,KAAK,CAAC,KAAK,EAAA;YACT,MAAM,GAAG,GAAGA,aAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,EAAyB,CAAC;AAC5D,YAAA,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAEC,uBAAiB,EAAE,EAAE,OAAO,IAAI,KAAI;gBACzD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;AACtC,gBAAA,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;AACnD,gBAAA,MAAM,MAAM,GACV,OAAO,GAAG,CAAC,SAAS,KAAK;AACvB,sBAAE,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAW,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI;sBACvD,SAAS;;AAEf,gBAAA,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC9B,oBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE;gBACrC;gBACA,IACE,OAAO,MAAM,KAAK,QAAQ;AAC1B,oBAAA,MAAM,KAAK,IAAI;AACf,oBAAA,MAAM,IAAI,MAAM;AAChB,oBAAA,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAC/B;oBACA,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE;gBAC1C;AACA,gBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE;AACrC,YAAA,CAAC,CAAC;QACJ,CAAC;KACF;AACH;AAEA;;;;AAIG;AACH,SAAS,YAAY,CAAC,QAAgB,EAAA;AACpC,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,KAAK,GAAG,IAAI;AAC5C;;;;"}
package/lib/bun.mjs CHANGED
@@ -2,13 +2,19 @@ import fs from 'node:fs/promises';
2
2
  import unplugin, { sourceFilePattern } from './core/index.mjs';
3
3
 
4
4
  /**
5
- * Create a ttsc plugin for Bun's bundler.
5
+ * Create a ttsc plugin for Bun's bundler AND runtime.
6
6
  *
7
7
  * Bun does not implement the unplugin protocol, so this adapter instantiates
8
8
  * the raw unplugin transform and wires it to Bun's `onLoad` hook manually. The
9
9
  * adapter reads each matching file from disk and forwards the content to the
10
10
  * ttsc transform; if the transform returns no changes the original source is
11
11
  * passed through unchanged.
12
+ *
13
+ * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and
14
+ * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see
15
+ * `bun-register`. Every result carries an explicit `loader` so Bun keeps
16
+ * transpiling the emitted TypeScript at runtime; `sourceFilePattern` only
17
+ * matches TypeScript, so the loader is always `ts`/`tsx`.
12
18
  */
13
19
  function bun(options) {
14
20
  return {
@@ -16,25 +22,34 @@ function bun(options) {
16
22
  setup(build) {
17
23
  const raw = unplugin.raw(options, {});
18
24
  build.onLoad({ filter: sourceFilePattern }, async (args) => {
25
+ const loader = bunLoaderFor(args.path);
19
26
  const source = await fs.readFile(args.path, "utf8");
20
27
  const result = typeof raw.transform === "function"
21
28
  ? await raw.transform.call({}, source, args.path)
22
29
  : undefined;
23
30
  // Unpack both shorthand string and object result shapes.
24
31
  if (typeof result === "string") {
25
- return { contents: result };
32
+ return { contents: result, loader };
26
33
  }
27
34
  if (typeof result === "object" &&
28
35
  result !== null &&
29
36
  "code" in result &&
30
37
  typeof result.code === "string") {
31
- return { contents: result.code };
38
+ return { contents: result.code, loader };
32
39
  }
33
- return { contents: source };
40
+ return { contents: source, loader };
34
41
  });
35
42
  },
36
43
  };
37
44
  }
45
+ /**
46
+ * Pick the Bun loader for a matched file. `sourceFilePattern` is
47
+ * `/\.[cm]?tsx?$/`, so a trailing `x` (`.tsx`/`.ctsx`/`.mtsx`) is JSX-flavored
48
+ * TypeScript and everything else (`.ts`/`.cts`/`.mts`) is plain TypeScript.
49
+ */
50
+ function bunLoaderFor(filePath) {
51
+ return /x$/i.test(filePath) ? "tsx" : "ts";
52
+ }
38
53
 
39
54
  export { bun as default };
40
55
  //# sourceMappingURL=bun.mjs.map
package/lib/bun.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bun.mjs","sources":["../src/bun.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAwCA;;;;;;;;AAQG;AACW,SAAU,GAAG,CAAC,OAA6B,EAAA;IACvD,OAAO;AACL,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,KAAK,CAAC,KAAK,EAAA;YACT,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,EAAyB,CAAC;AAC5D,YAAA,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,OAAO,IAAI,KAAI;AACzD,gBAAA,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;AACnD,gBAAA,MAAM,MAAM,GACV,OAAO,GAAG,CAAC,SAAS,KAAK;AACvB,sBAAE,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAW,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI;sBACvD,SAAS;;AAEf,gBAAA,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC9B,oBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE;gBAC7B;gBACA,IACE,OAAO,MAAM,KAAK,QAAQ;AAC1B,oBAAA,MAAM,KAAK,IAAI;AACf,oBAAA,MAAM,IAAI,MAAM;AAChB,oBAAA,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAC/B;AACA,oBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE;gBAClC;AACA,gBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE;AAC7B,YAAA,CAAC,CAAC;QACJ,CAAC;KACF;AACH;;;;"}
1
+ {"version":3,"file":"bun.mjs","sources":["../src/bun.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAgDA;;;;;;;;;;;;;;AAcG;AACW,SAAU,GAAG,CAAC,OAA6B,EAAA;IACvD,OAAO;AACL,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,KAAK,CAAC,KAAK,EAAA;YACT,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,EAAyB,CAAC;AAC5D,YAAA,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,OAAO,IAAI,KAAI;gBACzD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;AACtC,gBAAA,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;AACnD,gBAAA,MAAM,MAAM,GACV,OAAO,GAAG,CAAC,SAAS,KAAK;AACvB,sBAAE,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EAAW,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI;sBACvD,SAAS;;AAEf,gBAAA,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;AAC9B,oBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE;gBACrC;gBACA,IACE,OAAO,MAAM,KAAK,QAAQ;AAC1B,oBAAA,MAAM,KAAK,IAAI;AACf,oBAAA,MAAM,IAAI,MAAM;AAChB,oBAAA,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAC/B;oBACA,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE;gBAC1C;AACA,gBAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE;AACrC,YAAA,CAAC,CAAC;QACJ,CAAC;KACF;AACH;AAEA;;;;AAIG;AACH,SAAS,YAAY,CAAC,QAAgB,EAAA;AACpC,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,KAAK,GAAG,IAAI;AAC5C;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/unplugin",
3
- "version": "0.16.12",
3
+ "version": "0.17.1",
4
4
  "description": "Bundler adapters for ttsc plugins.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.mjs",
@@ -21,6 +21,11 @@
21
21
  "import": "./lib/bun.mjs",
22
22
  "default": "./lib/bun.js"
23
23
  },
24
+ "./bun-register": {
25
+ "types": "./lib/bun-register.d.ts",
26
+ "import": "./lib/bun-register.mjs",
27
+ "default": "./lib/bun-register.js"
28
+ },
24
29
  "./esbuild": {
25
30
  "types": "./lib/esbuild.d.ts",
26
31
  "import": "./lib/esbuild.mjs",
@@ -102,7 +107,7 @@
102
107
  "tslib": "^2.8.1",
103
108
  "typescript": "7.0.1-rc",
104
109
  "vite": "^7.1.12",
105
- "ttsc": "0.16.12"
110
+ "ttsc": "0.17.1"
106
111
  },
107
112
  "repository": {
108
113
  "type": "git",
@@ -0,0 +1,57 @@
1
+ import bun, { type BunLikePlugin } from "./bun";
2
+ import type { TtscUnpluginOptions } from "./core/options";
3
+
4
+ /**
5
+ * Minimal shape of the Bun runtime global used to register a runtime plugin.
6
+ *
7
+ * Declared locally so the package needs no `bun-types` dependency; at runtime
8
+ * Bun exposes `Bun.plugin`, which accepts the same object the bundler adapter
9
+ * returns.
10
+ */
11
+ interface BunRuntimeGlobal {
12
+ plugin(plugin: BunLikePlugin): void;
13
+ }
14
+
15
+ /**
16
+ * Register the ttsc transform as a Bun **runtime** plugin.
17
+ *
18
+ * The other `@ttsc/unplugin/*` adapters cover bundlers (`Bun.build`, Vite,
19
+ * Webpack, …). This entry is the runtime counterpart: loading it registers the
20
+ * same transform on Bun's module loader, so `bun run` / `bun test` apply ttsc
21
+ * plugins (e.g. typia's `typia/lib/transform`) as files are imported, with no
22
+ * bundling step. Wire it up once via a `bunfig.toml` preload entry —
23
+ * `preload = ["@ttsc/unplugin/bun-register"]` — or imperatively with
24
+ * `import "@ttsc/unplugin/bun-register"`. Options are read from the nearest
25
+ * `tsconfig.json`, identical to the bundler adapters.
26
+ *
27
+ * @throws When called explicitly off the Bun runtime (`globalThis.Bun.plugin`
28
+ * is unavailable). The auto-registration below stays silent off Bun so the
29
+ * module is harmless to import from Node (tests, tooling).
30
+ */
31
+ export function register(options?: TtscUnpluginOptions): void {
32
+ const runtime = bunRuntime();
33
+ if (runtime === undefined) {
34
+ throw new Error(
35
+ "@ttsc/unplugin/bun-register must run under the Bun runtime " +
36
+ "(globalThis.Bun.plugin is unavailable). Use a bundler adapter such as " +
37
+ "@ttsc/unplugin/vite for non-Bun toolchains.",
38
+ );
39
+ }
40
+ runtime.plugin(bun(options));
41
+ }
42
+
43
+ function bunRuntime(): BunRuntimeGlobal | undefined {
44
+ const runtime = (globalThis as { Bun?: BunRuntimeGlobal }).Bun;
45
+ return runtime !== undefined && typeof runtime.plugin === "function"
46
+ ? runtime
47
+ : undefined;
48
+ }
49
+
50
+ // Auto-register on import so a `bunfig.toml` `preload` entry — which only
51
+ // imports the module — takes effect. Guarded so importing from Node (a stray
52
+ // import, or a unit test) is a harmless no-op rather than a throw.
53
+ if (bunRuntime() !== undefined) {
54
+ register();
55
+ }
56
+
57
+ export default register;
package/src/bun.ts CHANGED
@@ -19,6 +19,9 @@ export interface BunLikePlugin {
19
19
  setup(build: BunLikeBuild): void | Promise<void>;
20
20
  }
21
21
 
22
+ /** Bun loader identifiers this adapter can emit (only TypeScript is matched). */
23
+ export type BunLoader = "ts" | "tsx";
24
+
22
25
  /**
23
26
  * Minimal subset of the Bun `BuildConfig` plugin build object.
24
27
  *
@@ -30,22 +33,33 @@ export interface BunLikeBuild {
30
33
  * Register a loader callback for files matching `filter`.
31
34
  *
32
35
  * The callback receives the absolute file path and must return the
33
- * transformed file contents.
36
+ * transformed file contents plus the `loader` Bun should apply next. The
37
+ * `loader` matters most for the runtime path (`Bun.plugin`), where Bun must
38
+ * be told the returned contents are still TypeScript so it keeps transpiling
39
+ * them before execution.
34
40
  */
35
41
  onLoad(
36
42
  options: { filter: RegExp },
37
- loader: (args: { path: string }) => Promise<{ contents: string }>,
43
+ loader: (args: {
44
+ path: string;
45
+ }) => Promise<{ contents: string; loader: BunLoader }>,
38
46
  ): void;
39
47
  }
40
48
 
41
49
  /**
42
- * Create a ttsc plugin for Bun's bundler.
50
+ * Create a ttsc plugin for Bun's bundler AND runtime.
43
51
  *
44
52
  * Bun does not implement the unplugin protocol, so this adapter instantiates
45
53
  * the raw unplugin transform and wires it to Bun's `onLoad` hook manually. The
46
54
  * adapter reads each matching file from disk and forwards the content to the
47
55
  * ttsc transform; if the transform returns no changes the original source is
48
56
  * passed through unchanged.
57
+ *
58
+ * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and
59
+ * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see
60
+ * `bun-register`. Every result carries an explicit `loader` so Bun keeps
61
+ * transpiling the emitted TypeScript at runtime; `sourceFilePattern` only
62
+ * matches TypeScript, so the loader is always `ts`/`tsx`.
49
63
  */
50
64
  export default function bun(options?: TtscUnpluginOptions): BunLikePlugin {
51
65
  return {
@@ -53,6 +67,7 @@ export default function bun(options?: TtscUnpluginOptions): BunLikePlugin {
53
67
  setup(build) {
54
68
  const raw = unplugin.raw(options, {} as UnpluginContextMeta);
55
69
  build.onLoad({ filter: sourceFilePattern }, async (args) => {
70
+ const loader = bunLoaderFor(args.path);
56
71
  const source = await fs.readFile(args.path, "utf8");
57
72
  const result =
58
73
  typeof raw.transform === "function"
@@ -60,7 +75,7 @@ export default function bun(options?: TtscUnpluginOptions): BunLikePlugin {
60
75
  : undefined;
61
76
  // Unpack both shorthand string and object result shapes.
62
77
  if (typeof result === "string") {
63
- return { contents: result };
78
+ return { contents: result, loader };
64
79
  }
65
80
  if (
66
81
  typeof result === "object" &&
@@ -68,10 +83,19 @@ export default function bun(options?: TtscUnpluginOptions): BunLikePlugin {
68
83
  "code" in result &&
69
84
  typeof result.code === "string"
70
85
  ) {
71
- return { contents: result.code };
86
+ return { contents: result.code, loader };
72
87
  }
73
- return { contents: source };
88
+ return { contents: source, loader };
74
89
  });
75
90
  },
76
91
  };
77
92
  }
93
+
94
+ /**
95
+ * Pick the Bun loader for a matched file. `sourceFilePattern` is
96
+ * `/\.[cm]?tsx?$/`, so a trailing `x` (`.tsx`/`.ctsx`/`.mtsx`) is JSX-flavored
97
+ * TypeScript and everything else (`.ts`/`.cts`/`.mts`) is plain TypeScript.
98
+ */
99
+ function bunLoaderFor(filePath: string): BunLoader {
100
+ return /x$/i.test(filePath) ? "tsx" : "ts";
101
+ }