@ttsc/unplugin 0.20.1 → 0.22.0

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.
package/README.md CHANGED
@@ -165,6 +165,8 @@ await Bun.build({
165
165
  });
166
166
  ```
167
167
 
168
+ Under `Bun.build`, the adapter yields to the next loader for declarations, `node_modules`, source that `ttsc` leaves unchanged, and entries supplied through `Bun.build({ files })`. In-memory entries remain with Bun because ttsc transforms filesystem-backed project inputs. Bun's runtime `onLoad` contract does not accept an undefined result, so `Bun.plugin()` explicitly passes excluded and unchanged filesystem files through with their original source. `Bun.build` clears the project generation through its `onStart` lifecycle on every build. The runtime API has no corresponding hook, so one setup is treated as one immutable module-loading session: restart the Bun process after changing source, tsconfig, or plugin inputs.
169
+
168
170
  ## Configuration
169
171
 
170
172
  By default, `@ttsc/unplugin` finds the nearest `tsconfig.json` from the file being transformed and uses that project's plugin settings, including directly installed plugin packages.
@@ -310,7 +312,7 @@ The transform host reports the program's reference graph (the transform envelope
310
312
 
311
313
  Transform plugins may additionally report, per file, the source files they consulted (the envelope's `dependencies` field); the adapter registers those as watch files too, union semantics. A plugin that declares such a list [complete](https://ttsc.dev/docs/development/concepts/protocol#dependency-completeness) for a file narrows the registration instead: only its own list plus the tsconfig chain, so files the transform never consulted stop invalidating it. Files a plugin declares `volatile` (output depending on non-file inputs such as environment or time) bypass the adapter's transform cache and are marked uncacheable where the bundler exposes that control.
312
314
 
313
- The transform cache itself validates against the same input set: every file under the project root plus the graph-reported inputs outside it (`node_modules` declarations, monorepo sibling sources, out-of-root `extends` ancestry). Hosts that keep one cache for the process lifetime instead of per build (Metro workers, the Turbopack loader, Bun) therefore recompile when any of those inputs changes, not only in-project ones.
315
+ The transform cache uses the same input set: every regular file reached by the non-following project walk plus graph-reported inputs outside that walk (`node_modules` declarations, monorepo sibling sources, files reached through symlinks or Windows junctions, and out-of-root `extends` ancestry). One whole-project compile already contains every module's output. Adapters with a guaranteed build boundary clear the previous generation there, then check only the supplied source on each module's first delivery in that build; a repeated delivery validates the complete snapshots. This avoids one complete project walk per module on an initial build. Bun runtime setup defines one process-scoped loading session. Long-lived hosts without either boundary (Metro workers, the Turbopack loader, and Vite's development server, whose initial `buildStart` spans later HMR edits) validate the complete project and external-input snapshots on every generation hit.
314
316
 
315
317
  ## Sponsors
316
318
 
package/lib/api.js CHANGED
@@ -6,12 +6,15 @@ var options = require('./core/options.js');
6
6
 
7
7
 
8
8
 
9
+ exports.isTransformTarget = index.isTransformTarget;
9
10
  exports.sourceFilePattern = index.sourceFilePattern;
10
11
  exports.unplugin = index.default;
12
+ exports.beginTtscTransformBuild = transform.beginTtscTransformBuild;
11
13
  exports.collectExternalInputHashes = transform.collectExternalInputHashes;
12
14
  exports.collectProjectInputHashes = transform.collectProjectInputHashes;
13
15
  exports.createTtscTransformCache = transform.createTtscTransformCache;
14
16
  exports.isProjectWalkPath = transform.isProjectWalkPath;
17
+ exports.resetTtscTransformCache = transform.resetTtscTransformCache;
15
18
  exports.transformTtsc = transform.transformTtsc;
16
19
  exports.resolveOptions = options.resolveOptions;
17
20
  //# sourceMappingURL=api.js.map
package/lib/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"api.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;"}
package/lib/api.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { sourceFilePattern, default as unplugin } from './core/index.mjs';
2
- export { collectExternalInputHashes, collectProjectInputHashes, createTtscTransformCache, isProjectWalkPath, transformTtsc } from './core/transform.mjs';
1
+ export { isTransformTarget, sourceFilePattern, default as unplugin } from './core/index.mjs';
2
+ export { beginTtscTransformBuild, collectExternalInputHashes, collectProjectInputHashes, createTtscTransformCache, isProjectWalkPath, resetTtscTransformCache, transformTtsc } from './core/transform.mjs';
3
3
  export { resolveOptions } from './core/options.mjs';
4
4
  //# sourceMappingURL=api.mjs.map
package/lib/bun.d.ts CHANGED
@@ -29,18 +29,37 @@ export type TtscBunOptions = TtscUnpluginOptions | (() => TtscUnpluginOptions |
29
29
  /**
30
30
  * Minimal subset of the Bun `BuildConfig` plugin build object.
31
31
  *
32
- * Only the `onLoad` hook is used; other hooks are not needed for a
33
- * source-to-source transform.
32
+ * `onLoad` drives the source transform. Bun's bundler also exposes `onStart`,
33
+ * which is used when available to forward the shared plugin's build lifecycle
34
+ * and clear its per-build cache. The runtime plugin API omits that hook, so
35
+ * plugin setup itself starts its one process-scoped module-loading session.
34
36
  */
35
37
  export interface BunLikeBuild {
38
+ /**
39
+ * Build configuration exposed unchanged by Bun's bundler plugin builder.
40
+ *
41
+ * Runtime plugin builders do not supply `files`. Bun's bundler accepts an
42
+ * in-memory file map whose values deliberately remain `unknown` here because
43
+ * this adapter only needs to preserve ownership, not consume their contents.
44
+ */
45
+ config?: {
46
+ files?: Readonly<Record<string, unknown>>;
47
+ };
48
+ /**
49
+ * Register a callback for the start of a bundler build.
50
+ *
51
+ * Optional because `Bun.plugin()` runtime builders do not expose this hook.
52
+ */
53
+ onStart?(callback: () => void | Promise<void>): void;
36
54
  /**
37
55
  * Register a loader callback for files matching `filter`.
38
56
  *
39
- * The callback receives the absolute file path and must return the
40
- * transformed file contents plus the `loader` Bun should apply next. The
41
- * `loader` matters most for the runtime path (`Bun.plugin`), where Bun must
42
- * be told the returned contents are still TypeScript so it keeps transpiling
43
- * them before execution.
57
+ * The callback receives the file path and must return the transformed file
58
+ * contents plus the `loader` Bun should apply next. Configured in-memory
59
+ * files retain relative key spellings; ordinary disk files are normally
60
+ * absolute. The `loader` matters most for the runtime path (`Bun.plugin`),
61
+ * where Bun must be told the returned contents are still TypeScript so it
62
+ * keeps transpiling them before execution.
44
63
  */
45
64
  onLoad(options: {
46
65
  filter: RegExp;
@@ -49,21 +68,28 @@ export interface BunLikeBuild {
49
68
  }) => Promise<{
50
69
  contents: string;
51
70
  loader: BunLoader;
52
- }>): void;
71
+ } | undefined>): void;
53
72
  }
54
73
  /**
55
74
  * Create a ttsc plugin for Bun's bundler AND runtime.
56
75
  *
57
- * Bun does not implement the unplugin protocol, so this adapter instantiates
58
- * the raw unplugin transform and wires it to Bun's `onLoad` hook manually. The
59
- * adapter reads each matching file from disk and forwards the content to the
60
- * ttsc transform; if the transform returns no changes the original source is
61
- * passed through unchanged.
76
+ * Bun does not implement the unplugin protocol, so this adapter wires the
77
+ * shared ttsc transform core to Bun's `onLoad` hook directly. It reads each
78
+ * included file from disk and forwards the content to the transform. Under
79
+ * `Bun.build`, excluded files and no-op transforms return `undefined` so the
80
+ * next loader retains ownership. Entries supplied through `BuildConfig.files`
81
+ * also stay with Bun's in-memory loader: they are not filesystem project inputs
82
+ * and reading the same path from disk would either fail or silently replace the
83
+ * configured contents. The runtime `Bun.plugin()` API rejects an undefined
84
+ * `onLoad` result, so that path explicitly returns the original source and
85
+ * loader instead.
62
86
  *
63
87
  * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and
64
88
  * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see
65
89
  * `bun-register`. Every result carries an explicit `loader` so Bun keeps
66
- * transpiling the emitted TypeScript at runtime; `sourceFilePattern` only
67
- * matches TypeScript, so the loader is always `ts`/`tsx`.
90
+ * transpiling the emitted TypeScript at runtime; `bunSourceFilePattern` only
91
+ * matches TypeScript, so the loader is always `ts`/`tsx`. A runtime plugin
92
+ * instance is one immutable load session, like Bun's own module cache; restart
93
+ * the process after changing compiler inputs.
68
94
  */
69
95
  export default function bun(options?: TtscBunOptions): BunLikePlugin;
package/lib/bun.js CHANGED
@@ -4,9 +4,18 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var fs = require('node:fs/promises');
6
6
  var index = require('./core/index.js');
7
+ var transform = require('./core/transform.js');
8
+ var options = require('./core/options.js');
7
9
 
8
10
  /**
9
- * Transform context handed to the raw unplugin transform under Bun.
11
+ * Bun normally reports filesystem source paths, while plugin-created virtual
12
+ * ids may contain a NUL sentinel. A virtual id must stay with the plugin that
13
+ * created it: claiming it here and trying to read it from disk prevents that
14
+ * plugin's later loader from running.
15
+ */
16
+ const bunSourceFilePattern = /^[^\x00]*\.[cm]?tsx?$/;
17
+ /**
18
+ * Transform hooks handed to the shared transform under Bun.
10
19
  *
11
20
  * The shared transform calls `addWatchFile` once per plugin-reported dependency
12
21
  * so type-only inputs can enter a bundler's watch graph. Bun's bundler and
@@ -17,7 +26,7 @@ var index = require('./core/index.js');
17
26
  * `this.addWatchFile` `undefined`, so any plugin reporting dependencies threw
18
27
  * `TypeError: this.addWatchFile is not a function`.
19
28
  */
20
- const bunTransformContext = {
29
+ const bunTransformHooks = {
21
30
  addWatchFile() { },
22
31
  };
23
32
  /** Resolve {@link TtscBunOptions} to a plain options object (or `undefined`). */
@@ -27,59 +36,106 @@ function resolveBunOptions(options) {
27
36
  /**
28
37
  * Create a ttsc plugin for Bun's bundler AND runtime.
29
38
  *
30
- * Bun does not implement the unplugin protocol, so this adapter instantiates
31
- * the raw unplugin transform and wires it to Bun's `onLoad` hook manually. The
32
- * adapter reads each matching file from disk and forwards the content to the
33
- * ttsc transform; if the transform returns no changes the original source is
34
- * passed through unchanged.
39
+ * Bun does not implement the unplugin protocol, so this adapter wires the
40
+ * shared ttsc transform core to Bun's `onLoad` hook directly. It reads each
41
+ * included file from disk and forwards the content to the transform. Under
42
+ * `Bun.build`, excluded files and no-op transforms return `undefined` so the
43
+ * next loader retains ownership. Entries supplied through `BuildConfig.files`
44
+ * also stay with Bun's in-memory loader: they are not filesystem project inputs
45
+ * and reading the same path from disk would either fail or silently replace the
46
+ * configured contents. The runtime `Bun.plugin()` API rejects an undefined
47
+ * `onLoad` result, so that path explicitly returns the original source and
48
+ * loader instead.
35
49
  *
36
50
  * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and
37
51
  * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see
38
52
  * `bun-register`. Every result carries an explicit `loader` so Bun keeps
39
- * transpiling the emitted TypeScript at runtime; `sourceFilePattern` only
40
- * matches TypeScript, so the loader is always `ts`/`tsx`.
53
+ * transpiling the emitted TypeScript at runtime; `bunSourceFilePattern` only
54
+ * matches TypeScript, so the loader is always `ts`/`tsx`. A runtime plugin
55
+ * instance is one immutable load session, like Bun's own module cache; restart
56
+ * the process after changing compiler inputs.
41
57
  */
42
- function bun(options) {
58
+ function bun(options$1) {
43
59
  return {
44
60
  name: "ttsc-unplugin",
45
61
  setup(build) {
46
- // Build the raw transform lazily on first load rather than in `setup`.
47
- // Bun runs `setup` synchronously when the plugin is registered, so a
48
- // runtime registration (bun-register) that resolves its effective options
49
- // through a provider must defer that resolution until after any explicit
50
- // `register(options)` call in the same tick. Deferring also keeps a single
51
- // transform (and its project cache) shared across every loaded module.
52
- let raw;
53
- build.onLoad({ filter: index.sourceFilePattern }, async (args) => {
54
- raw ??= index.default.raw(resolveBunOptions(options), {});
62
+ // Resolve options lazily on first load. Runtime registration may call
63
+ // register(options) immediately after the import-time default
64
+ // registration; the provider form must observe that last synchronous
65
+ // update without installing a second shadowing loader.
66
+ let resolved;
67
+ const getOptions = () => (resolved ??= options.resolveOptions(resolveBunOptions(options$1)));
68
+ const cache = transform.createTtscTransformCache();
69
+ const runtime = build.onStart === undefined;
70
+ const ownsInMemoryFile = createBunInMemoryFileMatcher(build);
71
+ // Bun.plugin() has no onStart callback, but one setup invocation belongs
72
+ // to exactly one runtime process and module-loading session. Mark that
73
+ // session up front so first delivery of every emitted project module is
74
+ // constant-time instead of re-reading the whole project. Bun.build()
75
+ // immediately starts the same initial scope again through onStart and
76
+ // repeats it for subsequent builds.
77
+ transform.beginTtscTransformBuild(cache);
78
+ build.onStart?.(() => transform.beginTtscTransformBuild(cache));
79
+ build.onLoad({ filter: bunSourceFilePattern }, async (args) => {
80
+ if (!runtime && ownsInMemoryFile(args.path)) {
81
+ return undefined;
82
+ }
83
+ if (!index.isTransformTarget(args.path)) {
84
+ if (!runtime)
85
+ return undefined;
86
+ return {
87
+ contents: await fs.readFile(args.path, "utf8"),
88
+ loader: bunLoaderFor(args.path),
89
+ };
90
+ }
55
91
  const loader = bunLoaderFor(args.path);
56
92
  const source = await fs.readFile(args.path, "utf8");
57
- const result = typeof raw.transform === "function"
58
- ? await raw.transform.call(bunTransformContext, source, args.path)
59
- : undefined;
60
- // Unpack both shorthand string and object result shapes.
61
- if (typeof result === "string") {
62
- return { contents: result, loader };
63
- }
64
- if (typeof result === "object" &&
65
- result !== null &&
66
- "code" in result &&
67
- typeof result.code === "string") {
93
+ const result = await transform.transformTtsc(args.path, source, getOptions(), undefined, cache, bunTransformHooks);
94
+ if (result !== undefined) {
68
95
  return { contents: result.code, loader };
69
96
  }
70
- return { contents: source, loader };
97
+ return runtime ? { contents: source, loader } : undefined;
71
98
  });
72
99
  },
73
100
  };
74
101
  }
75
102
  /**
76
- * Pick the Bun loader for a matched file. `sourceFilePattern` is
103
+ * Pick the Bun loader for a matched file. `bunSourceFilePattern` is
77
104
  * `/\.[cm]?tsx?$/`, so a trailing `x` (`.tsx`/`.ctsx`/`.mtsx`) is JSX-flavored
78
105
  * TypeScript and everything else (`.ts`/`.cts`/`.mts`) is plain TypeScript.
79
106
  */
80
107
  function bunLoaderFor(filePath) {
81
108
  return /x$/i.test(filePath) ? "tsx" : "ts";
82
109
  }
110
+ /**
111
+ * Create a stable ownership matcher for Bun's `BuildConfig.files` map.
112
+ *
113
+ * Bun preserves relative `files` keys in the corresponding `onLoad` path.
114
+ * Preserve relative versus absolute spelling and dot segments exactly. Windows
115
+ * normalizes separators and drive-letter case, but not component case. No path
116
+ * is resolved against cwd, so `process.chdir()` cannot change ownership.
117
+ */
118
+ function createBunInMemoryFileMatcher(build) {
119
+ const files = build.config?.files;
120
+ if (files === undefined)
121
+ return () => false;
122
+ const identities = new Set(Object.keys(files).map(bunPathIdentityKey));
123
+ return (file) => identities.has(bunPathIdentityKey(file));
124
+ }
125
+ /**
126
+ * Normalize the path forms Bun equates for its in-memory file map.
127
+ *
128
+ * Bun normalizes Windows separators and drive-letter case, but preserves path
129
+ * component case, relative versus absolute spelling, and dot segments. A
130
+ * filesystem identity key is broader and would suppress real disk transforms.
131
+ */
132
+ function bunPathIdentityKey(file) {
133
+ if (process.platform !== "win32")
134
+ return file;
135
+ return file
136
+ .replace(/\\/g, "/")
137
+ .replace(/^([a-z]):/i, (_match, drive) => `${drive.toLowerCase()}:`);
138
+ }
83
139
 
84
140
  exports.default = bun;
85
141
  //# 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":["sourceFilePattern","unplugin"],"mappings":";;;;;;;AAuCA;;;;;;;;;;;AAWG;AACH,MAAM,mBAAmB,GAAG;AAC1B,IAAA,YAAY,KAAU,CAAC;CACxB;AAED;AACA,SAAS,iBAAiB,CACxB,OAAwB,EAAA;AAExB,IAAA,OAAO,OAAO,OAAO,KAAK,UAAU,GAAG,OAAO,EAAE,GAAG,OAAO;AAC5D;AA0BA;;;;;;;;;;;;;;AAcG;AACW,SAAU,GAAG,CAAC,OAAwB,EAAA;IAClD,OAAO;AACL,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,KAAK,CAAC,KAAK,EAAA;;;;;;;AAOT,YAAA,IAAI,GAAgD;AACpD,YAAA,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAEA,uBAAiB,EAAE,EAAE,OAAO,IAAI,KAAI;AACzD,gBAAA,GAAG,KAAKC,aAAQ,CAAC,GAAG,CAClB,iBAAiB,CAAC,OAAO,CAAC,EAC1B,EAAyB,CAC1B;gBACD,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,CACtB,mBAA4B,EAC5B,MAAM,EACN,IAAI,CAAC,IAAI;sBAEX,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;;;;"}
1
+ {"version":3,"file":"bun.js","sources":["../src/bun.ts"],"sourcesContent":[null],"names":["options","resolveOptions","createTtscTransformCache","beginTtscTransformBuild","isTransformTarget","transformTtsc"],"mappings":"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"}
package/lib/bun.mjs CHANGED
@@ -1,8 +1,17 @@
1
1
  import fs from 'node:fs/promises';
2
- import unplugin, { sourceFilePattern } from './core/index.mjs';
2
+ import { isTransformTarget } from './core/index.mjs';
3
+ import { beginTtscTransformBuild, transformTtsc, createTtscTransformCache } from './core/transform.mjs';
4
+ import { resolveOptions } from './core/options.mjs';
3
5
 
4
6
  /**
5
- * Transform context handed to the raw unplugin transform under Bun.
7
+ * Bun normally reports filesystem source paths, while plugin-created virtual
8
+ * ids may contain a NUL sentinel. A virtual id must stay with the plugin that
9
+ * created it: claiming it here and trying to read it from disk prevents that
10
+ * plugin's later loader from running.
11
+ */
12
+ const bunSourceFilePattern = /^[^\x00]*\.[cm]?tsx?$/;
13
+ /**
14
+ * Transform hooks handed to the shared transform under Bun.
6
15
  *
7
16
  * The shared transform calls `addWatchFile` once per plugin-reported dependency
8
17
  * so type-only inputs can enter a bundler's watch graph. Bun's bundler and
@@ -13,7 +22,7 @@ import unplugin, { sourceFilePattern } from './core/index.mjs';
13
22
  * `this.addWatchFile` `undefined`, so any plugin reporting dependencies threw
14
23
  * `TypeError: this.addWatchFile is not a function`.
15
24
  */
16
- const bunTransformContext = {
25
+ const bunTransformHooks = {
17
26
  addWatchFile() { },
18
27
  };
19
28
  /** Resolve {@link TtscBunOptions} to a plain options object (or `undefined`). */
@@ -23,59 +32,106 @@ function resolveBunOptions(options) {
23
32
  /**
24
33
  * Create a ttsc plugin for Bun's bundler AND runtime.
25
34
  *
26
- * Bun does not implement the unplugin protocol, so this adapter instantiates
27
- * the raw unplugin transform and wires it to Bun's `onLoad` hook manually. The
28
- * adapter reads each matching file from disk and forwards the content to the
29
- * ttsc transform; if the transform returns no changes the original source is
30
- * passed through unchanged.
35
+ * Bun does not implement the unplugin protocol, so this adapter wires the
36
+ * shared ttsc transform core to Bun's `onLoad` hook directly. It reads each
37
+ * included file from disk and forwards the content to the transform. Under
38
+ * `Bun.build`, excluded files and no-op transforms return `undefined` so the
39
+ * next loader retains ownership. Entries supplied through `BuildConfig.files`
40
+ * also stay with Bun's in-memory loader: they are not filesystem project inputs
41
+ * and reading the same path from disk would either fail or silently replace the
42
+ * configured contents. The runtime `Bun.plugin()` API rejects an undefined
43
+ * `onLoad` result, so that path explicitly returns the original source and
44
+ * loader instead.
31
45
  *
32
46
  * The same object works for `Bun.build({ plugins: [ttsc()] })` (bundler) and
33
47
  * for `Bun.plugin(ttsc())` / a `bunfig.toml` preload (runtime) — see
34
48
  * `bun-register`. Every result carries an explicit `loader` so Bun keeps
35
- * transpiling the emitted TypeScript at runtime; `sourceFilePattern` only
36
- * matches TypeScript, so the loader is always `ts`/`tsx`.
49
+ * transpiling the emitted TypeScript at runtime; `bunSourceFilePattern` only
50
+ * matches TypeScript, so the loader is always `ts`/`tsx`. A runtime plugin
51
+ * instance is one immutable load session, like Bun's own module cache; restart
52
+ * the process after changing compiler inputs.
37
53
  */
38
54
  function bun(options) {
39
55
  return {
40
56
  name: "ttsc-unplugin",
41
57
  setup(build) {
42
- // Build the raw transform lazily on first load rather than in `setup`.
43
- // Bun runs `setup` synchronously when the plugin is registered, so a
44
- // runtime registration (bun-register) that resolves its effective options
45
- // through a provider must defer that resolution until after any explicit
46
- // `register(options)` call in the same tick. Deferring also keeps a single
47
- // transform (and its project cache) shared across every loaded module.
48
- let raw;
49
- build.onLoad({ filter: sourceFilePattern }, async (args) => {
50
- raw ??= unplugin.raw(resolveBunOptions(options), {});
58
+ // Resolve options lazily on first load. Runtime registration may call
59
+ // register(options) immediately after the import-time default
60
+ // registration; the provider form must observe that last synchronous
61
+ // update without installing a second shadowing loader.
62
+ let resolved;
63
+ const getOptions = () => (resolved ??= resolveOptions(resolveBunOptions(options)));
64
+ const cache = createTtscTransformCache();
65
+ const runtime = build.onStart === undefined;
66
+ const ownsInMemoryFile = createBunInMemoryFileMatcher(build);
67
+ // Bun.plugin() has no onStart callback, but one setup invocation belongs
68
+ // to exactly one runtime process and module-loading session. Mark that
69
+ // session up front so first delivery of every emitted project module is
70
+ // constant-time instead of re-reading the whole project. Bun.build()
71
+ // immediately starts the same initial scope again through onStart and
72
+ // repeats it for subsequent builds.
73
+ beginTtscTransformBuild(cache);
74
+ build.onStart?.(() => beginTtscTransformBuild(cache));
75
+ build.onLoad({ filter: bunSourceFilePattern }, async (args) => {
76
+ if (!runtime && ownsInMemoryFile(args.path)) {
77
+ return undefined;
78
+ }
79
+ if (!isTransformTarget(args.path)) {
80
+ if (!runtime)
81
+ return undefined;
82
+ return {
83
+ contents: await fs.readFile(args.path, "utf8"),
84
+ loader: bunLoaderFor(args.path),
85
+ };
86
+ }
51
87
  const loader = bunLoaderFor(args.path);
52
88
  const source = await fs.readFile(args.path, "utf8");
53
- const result = typeof raw.transform === "function"
54
- ? await raw.transform.call(bunTransformContext, source, args.path)
55
- : undefined;
56
- // Unpack both shorthand string and object result shapes.
57
- if (typeof result === "string") {
58
- return { contents: result, loader };
59
- }
60
- if (typeof result === "object" &&
61
- result !== null &&
62
- "code" in result &&
63
- typeof result.code === "string") {
89
+ const result = await transformTtsc(args.path, source, getOptions(), undefined, cache, bunTransformHooks);
90
+ if (result !== undefined) {
64
91
  return { contents: result.code, loader };
65
92
  }
66
- return { contents: source, loader };
93
+ return runtime ? { contents: source, loader } : undefined;
67
94
  });
68
95
  },
69
96
  };
70
97
  }
71
98
  /**
72
- * Pick the Bun loader for a matched file. `sourceFilePattern` is
99
+ * Pick the Bun loader for a matched file. `bunSourceFilePattern` is
73
100
  * `/\.[cm]?tsx?$/`, so a trailing `x` (`.tsx`/`.ctsx`/`.mtsx`) is JSX-flavored
74
101
  * TypeScript and everything else (`.ts`/`.cts`/`.mts`) is plain TypeScript.
75
102
  */
76
103
  function bunLoaderFor(filePath) {
77
104
  return /x$/i.test(filePath) ? "tsx" : "ts";
78
105
  }
106
+ /**
107
+ * Create a stable ownership matcher for Bun's `BuildConfig.files` map.
108
+ *
109
+ * Bun preserves relative `files` keys in the corresponding `onLoad` path.
110
+ * Preserve relative versus absolute spelling and dot segments exactly. Windows
111
+ * normalizes separators and drive-letter case, but not component case. No path
112
+ * is resolved against cwd, so `process.chdir()` cannot change ownership.
113
+ */
114
+ function createBunInMemoryFileMatcher(build) {
115
+ const files = build.config?.files;
116
+ if (files === undefined)
117
+ return () => false;
118
+ const identities = new Set(Object.keys(files).map(bunPathIdentityKey));
119
+ return (file) => identities.has(bunPathIdentityKey(file));
120
+ }
121
+ /**
122
+ * Normalize the path forms Bun equates for its in-memory file map.
123
+ *
124
+ * Bun normalizes Windows separators and drive-letter case, but preserves path
125
+ * component case, relative versus absolute spelling, and dot segments. A
126
+ * filesystem identity key is broader and would suppress real disk transforms.
127
+ */
128
+ function bunPathIdentityKey(file) {
129
+ if (process.platform !== "win32")
130
+ return file;
131
+ return file
132
+ .replace(/\\/g, "/")
133
+ .replace(/^([a-z]):/i, (_match, drive) => `${drive.toLowerCase()}:`);
134
+ }
79
135
 
80
136
  export { bun as default };
81
137
  //# 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":";;;AAuCA;;;;;;;;;;;AAWG;AACH,MAAM,mBAAmB,GAAG;AAC1B,IAAA,YAAY,KAAU,CAAC;CACxB;AAED;AACA,SAAS,iBAAiB,CACxB,OAAwB,EAAA;AAExB,IAAA,OAAO,OAAO,OAAO,KAAK,UAAU,GAAG,OAAO,EAAE,GAAG,OAAO;AAC5D;AA0BA;;;;;;;;;;;;;;AAcG;AACW,SAAU,GAAG,CAAC,OAAwB,EAAA;IAClD,OAAO;AACL,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,KAAK,CAAC,KAAK,EAAA;;;;;;;AAOT,YAAA,IAAI,GAAgD;AACpD,YAAA,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,OAAO,IAAI,KAAI;AACzD,gBAAA,GAAG,KAAK,QAAQ,CAAC,GAAG,CAClB,iBAAiB,CAAC,OAAO,CAAC,EAC1B,EAAyB,CAC1B;gBACD,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,CACtB,mBAA4B,EAC5B,MAAM,EACN,IAAI,CAAC,IAAI;sBAEX,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;;;;"}
1
+ {"version":3,"file":"bun.mjs","sources":["../src/bun.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { UnpluginInstance } from "unplugin";
2
2
  import type { TtscUnpluginOptions } from "./options";
3
3
  import { resolveOptions } from "./options";
4
- import { collectExternalInputHashes, collectProjectInputHashes, createTtscTransformCache, isProjectWalkPath, transformTtsc } from "./transform";
4
+ import { beginTtscTransformBuild, collectExternalInputHashes, collectProjectInputHashes, createTtscTransformCache, isProjectWalkPath, resetTtscTransformCache, transformTtsc } from "./transform";
5
5
  /**
6
6
  * Matches any TypeScript or JavaScript source extension (.ts, .tsx, .mts, .cts,
7
7
  * etc.). Shared with the Bun adapter (`bun.ts`) so the filter is defined once
@@ -11,5 +11,13 @@ export declare const sourceFilePattern: RegExp;
11
11
  declare const unplugin: UnpluginInstance<TtscUnpluginOptions | undefined, false>;
12
12
  export type { TtscUnpluginCompilerOptionsJson, TtscUnpluginOptions, } from "./options";
13
13
  export type { TtscTransformHooks } from "./transform";
14
- export { collectExternalInputHashes, collectProjectInputHashes, createTtscTransformCache, isProjectWalkPath, resolveOptions, transformTtsc, unplugin, };
14
+ export { beginTtscTransformBuild, collectExternalInputHashes, collectProjectInputHashes, createTtscTransformCache, isProjectWalkPath, resetTtscTransformCache, resolveOptions, transformTtsc, unplugin, };
15
15
  export default unplugin;
16
+ /**
17
+ * Returns `true` when the module id refers to a real TypeScript/JavaScript
18
+ * source file that should be processed by the ttsc transform.
19
+ *
20
+ * Excluded ids: virtual modules (NUL prefix), `.d.ts` declaration files, and
21
+ * anything inside `node_modules`.
22
+ */
23
+ export declare function isTransformTarget(id: string): boolean;
package/lib/core/index.js CHANGED
@@ -29,9 +29,9 @@ const virtualModulePattern = /\0/;
29
29
  *
30
30
  * The factory resolves raw options once, creates a per-build transform cache,
31
31
  * and captures Vite alias configuration via the `vite.configResolved` hook so
32
- * that path aliases are forwarded to the generated tsconfig overlay. The cache
33
- * is cleared on every `buildStart` to avoid stale results across watch-mode
34
- * rebuilds.
32
+ * that path aliases are forwarded to the generated tsconfig overlay. Real build
33
+ * lifecycles use a per-build cache; Vite's development server keeps persistent
34
+ * validation because its one `buildStart` spans later HMR edits.
35
35
  */
36
36
  const unpluginFactory = (rawOptions = {}) => {
37
37
  const options$1 = options.resolveOptions(rawOptions);
@@ -67,7 +67,12 @@ const unpluginFactory = (rawOptions = {}) => {
67
67
  },
68
68
  },
69
69
  buildStart() {
70
- transformCache.clear();
70
+ if (viteCommand === "serve") {
71
+ transform.resetTtscTransformCache(transformCache);
72
+ }
73
+ else {
74
+ transform.beginTtscTransformBuild(transformCache);
75
+ }
71
76
  },
72
77
  transformInclude(id) {
73
78
  const file = transform.stripQuery(id);
@@ -128,12 +133,15 @@ function isTransformTarget(id) {
128
133
  }
129
134
 
130
135
  exports.resolveOptions = options.resolveOptions;
136
+ exports.beginTtscTransformBuild = transform.beginTtscTransformBuild;
131
137
  exports.collectExternalInputHashes = transform.collectExternalInputHashes;
132
138
  exports.collectProjectInputHashes = transform.collectProjectInputHashes;
133
139
  exports.createTtscTransformCache = transform.createTtscTransformCache;
134
140
  exports.isProjectWalkPath = transform.isProjectWalkPath;
141
+ exports.resetTtscTransformCache = transform.resetTtscTransformCache;
135
142
  exports.transformTtsc = transform.transformTtsc;
136
143
  exports.default = unplugin;
144
+ exports.isTransformTarget = isTransformTarget;
137
145
  exports.sourceFilePattern = sourceFilePattern;
138
146
  exports.unplugin = unplugin;
139
147
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/core/index.ts"],"sourcesContent":[null],"names":["options","resolveOptions","createTtscTransformCache","createViteServeMissingInputWatch","stripQuery","transformTtsc","createUnplugin","isDeclarationFile"],"mappings":";;;;;;;;;;;AAkBA,MAAM,IAAI,GAAG,eAAe;AAC5B;;;;AAIG;AACI,MAAM,iBAAiB,GAAG;AACjC;AACA,MAAM,kBAAkB,GAAG,oCAAoC;AAC/D;;;AAGG;AACH,MAAM,oBAAoB,GAAG,IAAI;AAEjC;;;;;;;;;AASG;AACH,MAAM,eAAe,GAGjB,CAAC,UAAU,GAAG,EAAE,KAAI;AACtB,IAAA,MAAMA,SAAO,GAAGC,sBAAc,CAAC,UAAU,CAAC;AAC1C,IAAA,MAAM,cAAc,GAAGC,kCAAwB,EAAE;AACjD,IAAA,MAAM,aAAa,GAAGC,0CAAgC,EAAE;AACxD,IAAA,IAAI,OAAgB;AACpB,IAAA,IAAI,WAA+B;IAEnC,OAAO;QACL,IAAI;AACJ,QAAA,OAAO,EAAE,KAAK;AAEd,QAAA,IAAI,EAAE;AACJ,YAAA,cAAc,CAAC,MAAM,EAAA;AACnB,gBAAA,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK;;;;;AAK9B,gBAAA,WAAW,GAAG,MAAM,CAAC,OAAO;YAC9B,CAAC;;;;;;;AAOD,YAAA,eAAe,CAAC,MAAM,EAAA;AACpB,gBAAA,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;YAC9B,CAAC;;;YAGD,QAAQ,GAAA;gBACN,aAAa,CAAC,OAAO,EAAE;YACzB,CAAC;AACF,SAAA;QAED,UAAU,GAAA;YACR,cAAc,CAAC,KAAK,EAAE;QACxB,CAAC;AAED,QAAA,gBAAgB,CAAC,EAAE,EAAA;AACjB,YAAA,MAAM,IAAI,GAAGC,oBAAU,CAAC,EAAE,CAAC;AAC3B,YAAA,OAAO,iBAAiB,CAAC,IAAI,CAAC;QAChC,CAAC;AAED,QAAA,MAAM,SAAS,CAAC,MAAM,EAAE,EAAE,EAAA;AACxB,YAAA,MAAM,IAAI,GAAGA,oBAAU,CAAC,EAAE,CAAC;AAC3B,YAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE;AAC5B,gBAAA,OAAO,SAAS;YAClB;YACA,OAAOC,uBAAa,CAAC,IAAI,EAAE,MAAM,EAAEL,SAAO,EAAE,OAAO,EAAE,cAAc,EAAE;;;;;;;;;;;AAWnE,gBAAA,YAAY,EAAE,CAAC,OAAO,KAAI;oBACxB,IACE,WAAW,KAAK,OAAO;wBACvB,aAAa,CAAC,OAAO,EAAE;AACvB,wBAAA,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EACvB;AACA,wBAAA,aAAa,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;wBAChD;oBACF;AACA,oBAAA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;gBAC5B,CAAC;;;;gBAID,YAAY,EAAE,MAAK;AACjB,oBAAA,MAAM,MAAM,GAAG,IAAI,CAAC,qBAAqB,IAAI;AAC7C,oBAAA,IACE,MAAM,EAAE,SAAS,KAAK,SAAS;AAC/B,wBAAA,MAAM,EAAE,SAAS,KAAK,QAAQ,EAC9B;wBACA,MAAM,CAAC,aAAa,EAAE,SAAS,GAAG,KAAK,CAAC;oBAC1C;gBACF,CAAC;AACF,aAAA,CAAC;QACJ,CAAC;KACF;AACH,CAAC;AAED,MAAM,QAAQ,GACZM,yBAAc,CAAC,eAAe;AAmBhC;;;;;;AAMG;AACH,SAAS,iBAAiB,CAAC,EAAU,EAAA;AACnC,IAAA,QACE,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1B,QAAA,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,CAACC,2BAAiB,CAAC,EAAE,CAAC;AACtB,QAAA,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AAEhC;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/core/index.ts"],"sourcesContent":[null],"names":["options","resolveOptions","createTtscTransformCache","createViteServeMissingInputWatch","resetTtscTransformCache","beginTtscTransformBuild","stripQuery","transformTtsc","createUnplugin","isDeclarationFile"],"mappings":"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"}
@@ -2,7 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { createUnplugin } from 'unplugin';
4
4
  import { resolveOptions } from './options.mjs';
5
- import { stripQuery, transformTtsc, isDeclarationFile, createTtscTransformCache } from './transform.mjs';
5
+ import { stripQuery, transformTtsc, beginTtscTransformBuild, isDeclarationFile, resetTtscTransformCache, createTtscTransformCache } from './transform.mjs';
6
6
  export { collectExternalInputHashes, collectProjectInputHashes, isProjectWalkPath } from './transform.mjs';
7
7
  import { createViteServeMissingInputWatch } from './viteServe.mjs';
8
8
 
@@ -26,9 +26,9 @@ const virtualModulePattern = /\0/;
26
26
  *
27
27
  * The factory resolves raw options once, creates a per-build transform cache,
28
28
  * and captures Vite alias configuration via the `vite.configResolved` hook so
29
- * that path aliases are forwarded to the generated tsconfig overlay. The cache
30
- * is cleared on every `buildStart` to avoid stale results across watch-mode
31
- * rebuilds.
29
+ * that path aliases are forwarded to the generated tsconfig overlay. Real build
30
+ * lifecycles use a per-build cache; Vite's development server keeps persistent
31
+ * validation because its one `buildStart` spans later HMR edits.
32
32
  */
33
33
  const unpluginFactory = (rawOptions = {}) => {
34
34
  const options = resolveOptions(rawOptions);
@@ -64,7 +64,12 @@ const unpluginFactory = (rawOptions = {}) => {
64
64
  },
65
65
  },
66
66
  buildStart() {
67
- transformCache.clear();
67
+ if (viteCommand === "serve") {
68
+ resetTtscTransformCache(transformCache);
69
+ }
70
+ else {
71
+ beginTtscTransformBuild(transformCache);
72
+ }
68
73
  },
69
74
  transformInclude(id) {
70
75
  const file = stripQuery(id);
@@ -124,5 +129,5 @@ function isTransformTarget(id) {
124
129
  !nodeModulesPattern.test(id));
125
130
  }
126
131
 
127
- export { createTtscTransformCache, unplugin as default, resolveOptions, sourceFilePattern, transformTtsc, unplugin };
132
+ export { beginTtscTransformBuild, createTtscTransformCache, unplugin as default, isTransformTarget, resetTtscTransformCache, resolveOptions, sourceFilePattern, transformTtsc, unplugin };
128
133
  //# sourceMappingURL=index.mjs.map