@ttsc/unplugin 0.15.2 → 0.15.4

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,306 @@
1
+ import fs from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import path from 'node:path';
4
+
5
+ /**
6
+ * Read the effective `compilerOptions.paths` of a tsconfig, following its
7
+ * `extends` chain, and absolutize every mapping target.
8
+ *
9
+ * TypeScript merges `compilerOptions` per option key, so the effective `paths`
10
+ * is the whole object from the nearest config in the chain that declares one
11
+ * (own config first, then `extends` entries in reverse priority order).
12
+ * Relative targets are anchored at the directory of the config that declares
13
+ * them — TypeScript-Go resolves inherited relative `paths` against the
14
+ * declaring file, not the extending one.
15
+ *
16
+ * The generated transform tsconfig replaces `paths` wholesale (standard
17
+ * `extends` semantics), so the alias overlay must re-state these base mappings
18
+ * or every tsconfig-only alias silently stops resolving. Absolutizing is
19
+ * required because the generated config lives in a system temp directory and
20
+ * TypeScript-Go rejects non-relative targets (TS5090) while accepting absolute
21
+ * ones.
22
+ *
23
+ * Best-effort by design: a missing or unparsable config in the chain yields
24
+ * `{}` here and a real config error from the compiler, which owns config
25
+ * diagnostics.
26
+ */
27
+ function readEffectiveTsconfigPaths(tsconfig) {
28
+ const declared = findDeclaredPaths(path.resolve(tsconfig), new Set());
29
+ if (declared === null) {
30
+ return {};
31
+ }
32
+ const output = {};
33
+ for (const [key, targets] of Object.entries(declared.paths)) {
34
+ if (!Array.isArray(targets)) {
35
+ continue;
36
+ }
37
+ const absolute = targets
38
+ .filter((target) => typeof target === "string")
39
+ .map((target) => absolutizePathsTarget(declared.baseDir, target));
40
+ if (absolute.length !== 0) {
41
+ output[key] = absolute;
42
+ }
43
+ }
44
+ return output;
45
+ }
46
+ /**
47
+ * Anchor a single `paths` target at `baseDir` unless it is already absolute,
48
+ * normalizing to forward slashes. The `*` wildcard survives `path.resolve` as a
49
+ * literal segment, so patterns like `./src/*` stay patterns.
50
+ */
51
+ function absolutizePathsTarget(baseDir, target) {
52
+ const resolved = path.isAbsolute(target)
53
+ ? target
54
+ : path.resolve(baseDir, target);
55
+ return resolved.replace(/\\/g, "/");
56
+ }
57
+ /**
58
+ * Locate the nearest `compilerOptions.paths` declaration in the `extends` chain
59
+ * rooted at `tsconfig`. The own config wins over its bases; within an `extends`
60
+ * array, later entries win over earlier ones. `seen` breaks circular chains —
61
+ * the compiler reports the actual config error.
62
+ */
63
+ function findDeclaredPaths(tsconfig, seen) {
64
+ const canonical = resolveRealPath(tsconfig);
65
+ if (seen.has(canonical)) {
66
+ return null;
67
+ }
68
+ seen.add(canonical);
69
+ let parsed;
70
+ try {
71
+ parsed = parseJsonc(fs.readFileSync(canonical, "utf8"));
72
+ }
73
+ catch {
74
+ return null;
75
+ }
76
+ if (typeof parsed !== "object" || parsed === null) {
77
+ return null;
78
+ }
79
+ const own = parsed.compilerOptions?.paths;
80
+ if (typeof own === "object" && own !== null && !Array.isArray(own)) {
81
+ return {
82
+ baseDir: path.dirname(canonical),
83
+ paths: own,
84
+ };
85
+ }
86
+ for (const specifier of extendsSpecifiers(parsed.extends).reverse()) {
87
+ const base = resolveExtendsConfig(canonical, specifier);
88
+ if (base === null) {
89
+ continue;
90
+ }
91
+ const declared = findDeclaredPaths(base, seen);
92
+ if (declared !== null) {
93
+ return declared;
94
+ }
95
+ }
96
+ return null;
97
+ }
98
+ /** Normalize the `extends` field into a list of string specifiers. */
99
+ function extendsSpecifiers(extended) {
100
+ if (typeof extended === "string") {
101
+ return [extended];
102
+ }
103
+ if (Array.isArray(extended)) {
104
+ return extended.filter((entry) => typeof entry === "string");
105
+ }
106
+ return [];
107
+ }
108
+ /**
109
+ * Resolve an `extends` specifier to an absolute config path using TypeScript's
110
+ * rules: absolute paths and relative specifiers get `.json` /
111
+ * `tsconfig.json`-directory fallbacks; bare specifiers go through Node's module
112
+ * resolver scoped to the declaring config. Returns `null` instead of throwing —
113
+ * the compiler reports unresolvable `extends` itself.
114
+ */
115
+ function resolveExtendsConfig(tsconfig, specifier) {
116
+ if (path.isAbsolute(specifier)) {
117
+ return resolveExistingExtendsPath(specifier);
118
+ }
119
+ if (isRelativeSpecifier(specifier)) {
120
+ return resolveExistingExtendsPath(path.resolve(path.dirname(tsconfig), specifier));
121
+ }
122
+ const resolver = createRequire(tsconfig);
123
+ try {
124
+ return resolveRealPath(resolver.resolve(specifier));
125
+ }
126
+ catch {
127
+ try {
128
+ return resolveRealPath(resolver.resolve(`${specifier}.json`));
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ }
134
+ }
135
+ /**
136
+ * Try an on-disk `extends` location as-is, with `.json` appended, and as a
137
+ * directory containing `tsconfig.json`. Returns the first existing match.
138
+ */
139
+ function resolveExistingExtendsPath(location) {
140
+ for (const candidate of new Set([
141
+ location,
142
+ `${location}.json`,
143
+ path.join(location, "tsconfig.json"),
144
+ ])) {
145
+ if (fs.existsSync(candidate)) {
146
+ return resolveRealPath(candidate);
147
+ }
148
+ }
149
+ return null;
150
+ }
151
+ /**
152
+ * Return true when `specifier` is a relative path reference: `.`, `..`, or a
153
+ * string starting with `./`, `../`, `.\\`, or `..\\`.
154
+ */
155
+ function isRelativeSpecifier(specifier) {
156
+ return (specifier === "." ||
157
+ specifier === ".." ||
158
+ specifier.startsWith("./") ||
159
+ specifier.startsWith("../") ||
160
+ specifier.startsWith(".\\") ||
161
+ specifier.startsWith("..\\"));
162
+ }
163
+ /**
164
+ * Resolve symlinks on `location`, returning the original path when
165
+ * `realpathSync` fails (e.g. when the file does not exist).
166
+ */
167
+ function resolveRealPath(location) {
168
+ try {
169
+ return fs.realpathSync(location);
170
+ }
171
+ catch {
172
+ return location;
173
+ }
174
+ }
175
+ /**
176
+ * Parse a JSONC (JSON with Comments) string by stripping comments and trailing
177
+ * commas before handing off to `JSON.parse`. A leading UTF-8 BOM is dropped —
178
+ * `JSON.parse` rejects it, and this reader must not lose `paths` for a config
179
+ * the compiler accepts.
180
+ */
181
+ function parseJsonc(input) {
182
+ const text = input.charCodeAt(0) === 0xfeff ? input.slice(1) : input;
183
+ return JSON.parse(stripTrailingCommas(stripComments(text)));
184
+ }
185
+ /**
186
+ * Remove `//` line comments and `/* block comments *\/` from a JSONC string.
187
+ * Correctly handles strings that contain comment-like character sequences by
188
+ * tracking string boundaries and escape characters.
189
+ */
190
+ function stripComments(input) {
191
+ let output = "";
192
+ let inBlockComment = false;
193
+ let inLineComment = false;
194
+ let inString = false;
195
+ let quote = "";
196
+ let escape = false;
197
+ for (let i = 0; i < input.length; i += 1) {
198
+ const current = input[i];
199
+ const next = input[i + 1];
200
+ if (inBlockComment) {
201
+ if (current === "*" && next === "/") {
202
+ inBlockComment = false;
203
+ i += 1;
204
+ }
205
+ continue;
206
+ }
207
+ if (inLineComment) {
208
+ if (current === "\n") {
209
+ inLineComment = false;
210
+ output += current;
211
+ }
212
+ continue;
213
+ }
214
+ if (inString) {
215
+ output += current;
216
+ if (escape) {
217
+ escape = false;
218
+ }
219
+ else if (current === "\\") {
220
+ escape = true;
221
+ }
222
+ else if (current === quote) {
223
+ inString = false;
224
+ quote = "";
225
+ }
226
+ continue;
227
+ }
228
+ if (current === '"' || current === "'") {
229
+ inString = true;
230
+ quote = current;
231
+ output += current;
232
+ continue;
233
+ }
234
+ if (current === "/" && next === "/") {
235
+ inLineComment = true;
236
+ i += 1;
237
+ continue;
238
+ }
239
+ if (current === "/" && next === "*") {
240
+ inBlockComment = true;
241
+ i += 1;
242
+ continue;
243
+ }
244
+ output += current;
245
+ }
246
+ return output;
247
+ }
248
+ /**
249
+ * Remove trailing commas before `}` or `]` from a JSON string (after comments
250
+ * have already been stripped). Handles string boundaries and escape characters
251
+ * to avoid removing commas inside string values.
252
+ */
253
+ function stripTrailingCommas(input) {
254
+ let output = "";
255
+ let inString = false;
256
+ let quote = "";
257
+ let escape = false;
258
+ for (let i = 0; i < input.length; i += 1) {
259
+ const current = input[i];
260
+ if (inString) {
261
+ output += current;
262
+ if (escape) {
263
+ escape = false;
264
+ }
265
+ else if (current === "\\") {
266
+ escape = true;
267
+ }
268
+ else if (current === quote) {
269
+ inString = false;
270
+ quote = "";
271
+ }
272
+ continue;
273
+ }
274
+ if (current === '"' || current === "'") {
275
+ inString = true;
276
+ quote = current;
277
+ output += current;
278
+ continue;
279
+ }
280
+ if (current === ",") {
281
+ const next = nextNonWhitespace(input, i + 1);
282
+ if (next === "}" || next === "]") {
283
+ continue;
284
+ }
285
+ }
286
+ output += current;
287
+ }
288
+ return output;
289
+ }
290
+ /**
291
+ * Return the first non-whitespace character at or after position `from` in
292
+ * `input`, or `undefined` when only whitespace remains. Used by
293
+ * `stripTrailingCommas` to detect whether a comma is trailing.
294
+ */
295
+ function nextNonWhitespace(input, from) {
296
+ for (let i = from; i < input.length; i += 1) {
297
+ const current = input[i];
298
+ if (/\s/.test(current) === false) {
299
+ return current;
300
+ }
301
+ }
302
+ return undefined;
303
+ }
304
+
305
+ export { absolutizePathsTarget, readEffectiveTsconfigPaths };
306
+ //# sourceMappingURL=tsconfigPaths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsconfigPaths.mjs","sources":["../../src/core/tsconfigPaths.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { TtscUnpluginOptions } from "./core/options";
2
+ /**
3
+ * Subset of the webpack loader context Turbopack provides to loaders wired
4
+ * through `turbopack.rules`. Turbopack has no JS plugin API, but it runs
5
+ * webpack-compatible loaders: source string in, source string out, with
6
+ * `async()` for asynchronous completion and `getOptions()` for the rule's
7
+ * `options` object.
8
+ */
9
+ export interface TtscTurbopackLoaderContext {
10
+ /** Marks the loader asynchronous and returns the completion callback. */
11
+ async(): (error?: unknown, content?: string) => void;
12
+ /** Absolute path of the module being loaded. */
13
+ resourcePath: string;
14
+ /** The rule's `options` object, when one was configured. */
15
+ getOptions?(): TtscUnpluginOptions | undefined;
16
+ }
17
+ /**
18
+ * Standalone webpack-loader entrypoint for Turbopack.
19
+ *
20
+ * Turbopack cannot load unplugin-based plugins (no JS plugin API), but its
21
+ * `turbopack.rules` accept webpack loaders, and a ttsc transform is exactly
22
+ * loader-shaped: pure TypeScript source in, transformed source out. Wire it per
23
+ * extension:
24
+ *
25
+ * ```js
26
+ * // next.config.mjs
27
+ * const nextConfig = {
28
+ * turbopack: {
29
+ * rules: {
30
+ * "*.ts": { loaders: ["@ttsc/unplugin/turbopack"] },
31
+ * "*.tsx": { loaders: ["@ttsc/unplugin/turbopack"] },
32
+ * },
33
+ * },
34
+ * };
35
+ * ```
36
+ *
37
+ * Pass {@link TtscUnpluginOptions} through the rule's `options` object. The
38
+ * loader returns the source unchanged for declaration files, `node_modules`
39
+ * paths, and transforms that produce no change — mirroring the unplugin
40
+ * adapters' `transformInclude` filter, since a broad rule glob routes
41
+ * everything matching the extension through the loader.
42
+ */
43
+ export default function turbopack(this: TtscTurbopackLoaderContext, source: string): void;
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var options = require('./core/options.js');
6
+ var transform = require('./core/transform.js');
7
+
8
+ /** Matches any path segment that is a `node_modules` directory (cross-platform). */
9
+ const nodeModulesPattern = /(?:^|[/\\])node_modules(?:[/\\]|$)/;
10
+ /**
11
+ * Per-process transform cache. Turbopack runs loaders in a worker pool and
12
+ * never signals build boundaries to a loader, so the cache lives for the
13
+ * worker's lifetime; entries self-invalidate by re-hashing the project's input
14
+ * files on every request (see `transformTtsc`), which is the same freshness
15
+ * rule the bundler-plugin adapters rely on between watch rebuilds.
16
+ */
17
+ const transformCache = transform.createTtscTransformCache();
18
+ /**
19
+ * Standalone webpack-loader entrypoint for Turbopack.
20
+ *
21
+ * Turbopack cannot load unplugin-based plugins (no JS plugin API), but its
22
+ * `turbopack.rules` accept webpack loaders, and a ttsc transform is exactly
23
+ * loader-shaped: pure TypeScript source in, transformed source out. Wire it per
24
+ * extension:
25
+ *
26
+ * ```js
27
+ * // next.config.mjs
28
+ * const nextConfig = {
29
+ * turbopack: {
30
+ * rules: {
31
+ * "*.ts": { loaders: ["@ttsc/unplugin/turbopack"] },
32
+ * "*.tsx": { loaders: ["@ttsc/unplugin/turbopack"] },
33
+ * },
34
+ * },
35
+ * };
36
+ * ```
37
+ *
38
+ * Pass {@link TtscUnpluginOptions} through the rule's `options` object. The
39
+ * loader returns the source unchanged for declaration files, `node_modules`
40
+ * paths, and transforms that produce no change — mirroring the unplugin
41
+ * adapters' `transformInclude` filter, since a broad rule glob routes
42
+ * everything matching the extension through the loader.
43
+ */
44
+ function turbopack(source) {
45
+ const callback = this.async();
46
+ const file = transform.stripQuery(this.resourcePath);
47
+ if (transform.isDeclarationFile(file) || nodeModulesPattern.test(file)) {
48
+ callback(undefined, source);
49
+ return;
50
+ }
51
+ transform.transformTtsc(file, source, options.resolveOptions(this.getOptions?.() ?? {}), undefined, transformCache).then((result) => callback(undefined, result?.code ?? source), (error) => callback(error));
52
+ }
53
+
54
+ exports.default = turbopack;
55
+ //# sourceMappingURL=turbopack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turbopack.js","sources":["../src/turbopack.ts"],"sourcesContent":[null],"names":["createTtscTransformCache","stripQuery","isDeclarationFile","transformTtsc","resolveOptions"],"mappings":";;;;;;;AAyBA;AACA,MAAM,kBAAkB,GAAG,oCAAoC;AAE/D;;;;;;AAMG;AACH,MAAM,cAAc,GAAGA,kCAAwB,EAAE;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;AACW,SAAU,SAAS,CAE/B,MAAc,EAAA;AAEd,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE;IAC7B,MAAM,IAAI,GAAGC,oBAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC1C,IAAA,IAAIC,2BAAiB,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC5D,QAAA,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B;IACF;IACAC,uBAAa,CACX,IAAI,EACJ,MAAM,EACNC,sBAAc,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC,EACzC,SAAS,EACT,cAAc,CACf,CAAC,IAAI,CACJ,CAAC,MAAM,KAAK,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,IAAI,MAAM,CAAC,EACvD,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,CAAC,CAC3B;AACH;;;;"}
@@ -0,0 +1,51 @@
1
+ import { resolveOptions } from './core/options.mjs';
2
+ import { stripQuery, isDeclarationFile, transformTtsc, createTtscTransformCache } from './core/transform.mjs';
3
+
4
+ /** Matches any path segment that is a `node_modules` directory (cross-platform). */
5
+ const nodeModulesPattern = /(?:^|[/\\])node_modules(?:[/\\]|$)/;
6
+ /**
7
+ * Per-process transform cache. Turbopack runs loaders in a worker pool and
8
+ * never signals build boundaries to a loader, so the cache lives for the
9
+ * worker's lifetime; entries self-invalidate by re-hashing the project's input
10
+ * files on every request (see `transformTtsc`), which is the same freshness
11
+ * rule the bundler-plugin adapters rely on between watch rebuilds.
12
+ */
13
+ const transformCache = createTtscTransformCache();
14
+ /**
15
+ * Standalone webpack-loader entrypoint for Turbopack.
16
+ *
17
+ * Turbopack cannot load unplugin-based plugins (no JS plugin API), but its
18
+ * `turbopack.rules` accept webpack loaders, and a ttsc transform is exactly
19
+ * loader-shaped: pure TypeScript source in, transformed source out. Wire it per
20
+ * extension:
21
+ *
22
+ * ```js
23
+ * // next.config.mjs
24
+ * const nextConfig = {
25
+ * turbopack: {
26
+ * rules: {
27
+ * "*.ts": { loaders: ["@ttsc/unplugin/turbopack"] },
28
+ * "*.tsx": { loaders: ["@ttsc/unplugin/turbopack"] },
29
+ * },
30
+ * },
31
+ * };
32
+ * ```
33
+ *
34
+ * Pass {@link TtscUnpluginOptions} through the rule's `options` object. The
35
+ * loader returns the source unchanged for declaration files, `node_modules`
36
+ * paths, and transforms that produce no change — mirroring the unplugin
37
+ * adapters' `transformInclude` filter, since a broad rule glob routes
38
+ * everything matching the extension through the loader.
39
+ */
40
+ function turbopack(source) {
41
+ const callback = this.async();
42
+ const file = stripQuery(this.resourcePath);
43
+ if (isDeclarationFile(file) || nodeModulesPattern.test(file)) {
44
+ callback(undefined, source);
45
+ return;
46
+ }
47
+ transformTtsc(file, source, resolveOptions(this.getOptions?.() ?? {}), undefined, transformCache).then((result) => callback(undefined, result?.code ?? source), (error) => callback(error));
48
+ }
49
+
50
+ export { turbopack as default };
51
+ //# sourceMappingURL=turbopack.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turbopack.mjs","sources":["../src/turbopack.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAyBA;AACA,MAAM,kBAAkB,GAAG,oCAAoC;AAE/D;;;;;;AAMG;AACH,MAAM,cAAc,GAAG,wBAAwB,EAAE;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;AACW,SAAU,SAAS,CAE/B,MAAc,EAAA;AAEd,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,EAAE;IAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;AAC1C,IAAA,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC5D,QAAA,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B;IACF;IACA,aAAa,CACX,IAAI,EACJ,MAAM,EACN,cAAc,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC,EACzC,SAAS,EACT,cAAc,CACf,CAAC,IAAI,CACJ,CAAC,MAAM,KAAK,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,IAAI,MAAM,CAAC,EACvD,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,CAAC,CAC3B;AACH;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttsc/unplugin",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "description": "Bundler adapters for ttsc plugins.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.mjs",
@@ -51,6 +51,11 @@
51
51
  "import": "./lib/rspack.mjs",
52
52
  "default": "./lib/rspack.js"
53
53
  },
54
+ "./turbopack": {
55
+ "types": "./lib/turbopack.d.ts",
56
+ "import": "./lib/turbopack.mjs",
57
+ "default": "./lib/turbopack.js"
58
+ },
54
59
  "./vite": {
55
60
  "types": "./lib/vite.d.ts",
56
61
  "import": "./lib/vite.mjs",
@@ -89,7 +94,7 @@
89
94
  "@rollup/plugin-node-resolve": "^16.0.3",
90
95
  "@rollup/plugin-typescript": "^12.3.0",
91
96
  "@types/node": "^25.3.0",
92
- "@typescript/native-preview": "7.0.0-dev.20260421.2",
97
+ "@typescript/native-preview": "7.0.0-dev.20260615.1",
93
98
  "esbuild": "^0.25.12",
94
99
  "rimraf": "^6.1.2",
95
100
  "rollup": "^4.60.3",
@@ -99,7 +104,7 @@
99
104
  "tslib": "^2.8.1",
100
105
  "typescript": "^6.0.3",
101
106
  "vite": "^7.1.12",
102
- "ttsc": "0.15.2"
107
+ "ttsc": "0.15.4"
103
108
  },
104
109
  "repository": {
105
110
  "type": "git",
package/src/core/index.ts CHANGED
@@ -67,7 +67,13 @@ const unpluginFactory: UnpluginFactory<
67
67
  if (!isTransformTarget(file)) {
68
68
  return undefined;
69
69
  }
70
- return transformTtsc(file, source, options, aliases, transformCache);
70
+ return transformTtsc(file, source, options, aliases, transformCache, {
71
+ // Register plugin-reported dependencies (the transform envelope's
72
+ // `dependencies` lists) so type-only inputs invalidate this module
73
+ // in watch mode; bundlers erase type-only imports from their own
74
+ // module graph and would otherwise serve stale generated code.
75
+ addWatchFile: (watched) => this.addWatchFile(watched),
76
+ });
71
77
  },
72
78
  };
73
79
  };
@@ -79,6 +85,7 @@ export type {
79
85
  TtscUnpluginCompilerOptionsJson,
80
86
  TtscUnpluginOptions,
81
87
  } from "./options";
88
+ export type { TtscTransformHooks } from "./transform";
82
89
  export { createTtscTransformCache, resolveOptions, transformTtsc, unplugin };
83
90
 
84
91
  export default unplugin;