ttsc 0.7.2 → 0.8.0-dev.20260505

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.
Files changed (72) hide show
  1. package/README.md +5 -5
  2. package/cmd/platform/main.go +86 -76
  3. package/cmd/ttsc/api_compile.go +122 -105
  4. package/cmd/ttsc/api_transform.go +57 -49
  5. package/cmd/ttsc/build.go +116 -103
  6. package/cmd/ttsc/main.go +117 -117
  7. package/cmd/ttsc/main_test.go +191 -191
  8. package/driver/host.go +9 -9
  9. package/driver/program.go +285 -285
  10. package/driver/rewrite.go +266 -219
  11. package/lib/compiler/internal/compileProjectInMemory.js +3 -3
  12. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  13. package/lib/compiler/internal/resolveEmittedJavaScript.js +2 -1
  14. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  15. package/lib/compiler/internal/resolveTsgo.js.map +1 -1
  16. package/lib/compiler/internal/runBuild.js +47 -49
  17. package/lib/compiler/internal/runBuild.js.map +1 -1
  18. package/lib/compiler/internal/transformProjectInMemory.js +44 -4
  19. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  20. package/lib/launcher/internal/getCompilerVersionText.js +1 -2
  21. package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
  22. package/lib/launcher/internal/prepareExecution.js +6 -4
  23. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  24. package/lib/launcher/internal/runTtsc.js +49 -5
  25. package/lib/launcher/internal/runTtsc.js.map +1 -1
  26. package/lib/launcher/internal/runTtsx.js +7 -2
  27. package/lib/launcher/internal/runTtsx.js.map +1 -1
  28. package/lib/plugin/internal/buildSourcePlugin.js +6 -0
  29. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  30. package/lib/plugin/internal/loadProjectPlugins.js +55 -2
  31. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  32. package/lib/structures/ITtscPlugin.d.ts +19 -3
  33. package/lib/structures/ITtscPlugin.js +4 -0
  34. package/lib/structures/ITtscPlugin.js.map +1 -1
  35. package/lib/structures/TtscPluginStage.d.ts +4 -10
  36. package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +5 -0
  37. package/package.json +11 -10
  38. package/shim/ast/lint.go +172 -171
  39. package/shim/ast/shim.go +84 -83
  40. package/shim/bundled/shim.go +5 -1
  41. package/shim/checker/shim.go +79 -79
  42. package/shim/compiler/emit_hooks.go +494 -0
  43. package/shim/compiler/shim.go +16 -1
  44. package/shim/core/shim.go +13 -10
  45. package/shim/diagnosticwriter/lint.go +79 -79
  46. package/shim/diagnosticwriter/shim.go +19 -19
  47. package/shim/parser/shim.go +7 -1
  48. package/shim/scanner/shim.go +39 -1
  49. package/shim/tsoptions/shim.go +51 -1
  50. package/shim/tspath/shim.go +72 -1
  51. package/shim/vfs/cachedvfs/shim.go +1 -1
  52. package/shim/vfs/osvfs/shim.go +1 -1
  53. package/shim/vfs/shim.go +4 -1
  54. package/src/compiler/internal/compileProjectInMemory.ts +6 -3
  55. package/src/compiler/internal/resolveEmittedJavaScript.ts +2 -1
  56. package/src/compiler/internal/resolveTsgo.ts +0 -1
  57. package/src/compiler/internal/runBuild.ts +58 -86
  58. package/src/compiler/internal/transformProjectInMemory.ts +51 -6
  59. package/src/launcher/internal/getCompilerVersionText.ts +1 -2
  60. package/src/launcher/internal/prepareExecution.ts +6 -6
  61. package/src/launcher/internal/runTtsc.ts +52 -5
  62. package/src/launcher/internal/runTtsx.ts +16 -5
  63. package/src/plugin/internal/buildSourcePlugin.ts +30 -2
  64. package/src/plugin/internal/loadProjectPlugins.ts +81 -2
  65. package/src/structures/ITtscPlugin.ts +30 -3
  66. package/src/structures/TtscPluginStage.ts +4 -10
  67. package/src/structures/internal/ITtscLoadedNativePlugin.ts +5 -0
  68. package/test/compiler.test.ts +3 -3
  69. package/test/platform.test.ts +1 -3
  70. package/test/tsgo.test.ts +15 -7
  71. package/tools/gen_shims/main.go +409 -409
  72. package/utility/host.go +707 -0
@@ -2,6 +2,7 @@ import { spawnSync } from "node:child_process";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
 
5
+ import { TtscCompiler } from "../../TtscCompiler";
5
6
  import { resolveBinary } from "../../compiler/internal/resolveBinary";
6
7
  import { runBuild } from "../../compiler/internal/runBuild";
7
8
  import { runSingleFileEmit } from "../../compiler/internal/runSingleFileEmit";
@@ -35,6 +36,8 @@ export function runTtsc(
35
36
  return runCompatibleBuild(rest, true);
36
37
  case "clean":
37
38
  return runClean(rest);
39
+ case "prepare":
40
+ return runPrepare(rest);
38
41
  case "demo":
39
42
  return delegateToNative(argv);
40
43
  case "-p":
@@ -82,13 +85,41 @@ function runCompatibleBuild(
82
85
  return result.status;
83
86
  }
84
87
 
88
+ function runPrepare(argv: readonly string[]): number {
89
+ const options = parseProjectArgs(argv);
90
+ const cwd = path.resolve(options.cwd ?? process.cwd());
91
+ const compiler = new TtscCompiler({
92
+ cacheDir: options.cacheDir,
93
+ cwd,
94
+ tsconfig: options.tsconfig,
95
+ });
96
+ const prepared = compiler.prepare();
97
+ if (prepared.length === 0) {
98
+ const projectRoot = path.dirname(
99
+ resolveProjectConfig({
100
+ cwd,
101
+ tsconfig: options.tsconfig,
102
+ }),
103
+ );
104
+ process.stdout.write(
105
+ `ttsc: no source plugins found under ${formatProjectPath(cwd, projectRoot)}\n`,
106
+ );
107
+ return 0;
108
+ }
109
+ for (const target of prepared) {
110
+ process.stdout.write(`ttsc: prepared ${formatProjectPath(cwd, target)}\n`);
111
+ }
112
+ return 0;
113
+ }
114
+
85
115
  function runClean(argv: readonly string[]): number {
86
- const options = parseCleanArgs(argv);
116
+ const options = parseProjectArgs(argv);
87
117
  const cwd = path.resolve(options.cwd ?? process.cwd());
88
118
  const projectRoot = resolveCleanProjectRoot(cwd, options.tsconfig);
89
119
  const targets = [
90
120
  path.join(projectRoot, "node_modules", ".ttsc"),
91
121
  path.join(projectRoot, ".ttsc"),
122
+ ...(options.cacheDir ? [path.resolve(cwd, options.cacheDir)] : []),
92
123
  ...(process.env.TTSC_CACHE_DIR
93
124
  ? [path.resolve(process.env.TTSC_CACHE_DIR, "plugins")]
94
125
  : []),
@@ -106,7 +137,7 @@ function runClean(argv: readonly string[]): number {
106
137
  return 0;
107
138
  }
108
139
  for (const target of removed) {
109
- process.stdout.write(`ttsc: removed ${formatCleanPath(cwd, target)}\n`);
140
+ process.stdout.write(`ttsc: removed ${formatProjectPath(cwd, target)}\n`);
110
141
  }
111
142
  return 0;
112
143
  }
@@ -120,7 +151,7 @@ function resolveCleanProjectRoot(cwd: string, tsconfig?: string): string {
120
151
  }
121
152
  }
122
153
 
123
- function formatCleanPath(cwd: string, target: string): string {
154
+ function formatProjectPath(cwd: string, target: string): string {
124
155
  const relative = path.relative(cwd, target);
125
156
  if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
126
157
  return target;
@@ -174,7 +205,8 @@ function ensureExecutable(binary: string): void {
174
205
  }
175
206
  }
176
207
 
177
- function parseCleanArgs(argv: readonly string[]) {
208
+ function parseProjectArgs(argv: readonly string[]) {
209
+ let cacheDir: string | undefined;
178
210
  let cwd: string | undefined;
179
211
  let tsconfig: string | undefined;
180
212
 
@@ -185,6 +217,9 @@ function parseCleanArgs(argv: readonly string[]) {
185
217
  case "--cwd":
186
218
  cwd = takeValue(current, rest);
187
219
  break;
220
+ case "--cache-dir":
221
+ cacheDir = takeValue(current, rest);
222
+ break;
188
223
  case "-p":
189
224
  case "--tsconfig":
190
225
  case "--project":
@@ -193,6 +228,8 @@ function parseCleanArgs(argv: readonly string[]) {
193
228
  default:
194
229
  if (current.startsWith("--cwd=")) {
195
230
  cwd = current.slice("--cwd=".length);
231
+ } else if (current.startsWith("--cache-dir=")) {
232
+ cacheDir = current.slice("--cache-dir=".length);
196
233
  } else if (current.startsWith("--tsconfig=")) {
197
234
  tsconfig = current.slice("--tsconfig=".length);
198
235
  } else if (current.startsWith("--project=")) {
@@ -203,11 +240,12 @@ function parseCleanArgs(argv: readonly string[]) {
203
240
  break;
204
241
  }
205
242
  }
206
- return { cwd, tsconfig };
243
+ return { cacheDir, cwd, tsconfig };
207
244
  }
208
245
 
209
246
  function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
210
247
  let binary: string | undefined;
248
+ let cacheDir: string | undefined;
211
249
  let cwd: string | undefined;
212
250
  let emit: boolean | undefined = checkOnly ? false : undefined;
213
251
  const files: string[] = [];
@@ -254,6 +292,9 @@ function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
254
292
  case "--binary":
255
293
  binary = takeValue(current, rest);
256
294
  break;
295
+ case "--cache-dir":
296
+ cacheDir = takeValue(current, rest);
297
+ break;
257
298
  default:
258
299
  if (current.startsWith("--cwd=")) {
259
300
  cwd = current.slice("--cwd=".length);
@@ -270,6 +311,8 @@ function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
270
311
  current.slice("--preserveWatchOutput=".length) !== "false";
271
312
  } else if (current.startsWith("--binary=")) {
272
313
  binary = current.slice("--binary=".length);
314
+ } else if (current.startsWith("--cache-dir=")) {
315
+ cacheDir = current.slice("--cache-dir=".length);
273
316
  } else if (current === "--verbose") {
274
317
  quiet = false;
275
318
  } else if (current.startsWith("-")) {
@@ -282,6 +325,7 @@ function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
282
325
  }
283
326
  return {
284
327
  binary,
328
+ cacheDir,
285
329
  cwd,
286
330
  emit,
287
331
  files,
@@ -303,6 +347,7 @@ function printHelp(): void {
303
347
  " ttsc -p tsconfig.json",
304
348
  " ttsc --watch",
305
349
  " ttsc --noEmit",
350
+ " ttsc prepare [options]",
306
351
  " ttsc clean [options]",
307
352
  " ttsc version",
308
353
  " ttsc --help",
@@ -319,6 +364,7 @@ function printHelp(): void {
319
364
  " --quiet Keep build output quiet (default)",
320
365
  " --verbose Print the build summary and emitted files",
321
366
  " --binary <path> Use an explicit tsgo binary",
367
+ " --cache-dir <dir> Use this cache root for source-plugin builds",
322
368
  "",
323
369
  "Plugin contract:",
324
370
  " ttsc reads compilerOptions.plugins from tsconfig.json.",
@@ -328,6 +374,7 @@ function printHelp(): void {
328
374
  "Compatibility aliases:",
329
375
  " ttsc build [options] Same project build lane as `ttsc [options]`.",
330
376
  " ttsc check [options] Same as `ttsc --noEmit [options]`.",
377
+ " ttsc prepare [options] Build configured source-plugin binaries into cache.",
331
378
  " ttsc clean [options] Delete local source-plugin cache directories.",
332
379
  ].join("\n"),
333
380
  );
@@ -5,7 +5,9 @@ import * as path from "node:path";
5
5
  import { getCompilerVersionText } from "./getCompilerVersionText";
6
6
  import { prepareExecution } from "./prepareExecution";
7
7
 
8
- export function runTtsx(argv: readonly string[] = process.argv.slice(2)): number {
8
+ export function runTtsx(
9
+ argv: readonly string[] = process.argv.slice(2),
10
+ ): number {
9
11
  try {
10
12
  return run(argv);
11
13
  } catch (error) {
@@ -53,8 +55,10 @@ function formatError(error: unknown): string {
53
55
  function parseCLI(argv: readonly string[]) {
54
56
  const preload: string[] = [];
55
57
  const passthroughIndex = argv.indexOf("--");
56
- const head = passthroughIndex === -1 ? [...argv] : [...argv.slice(0, passthroughIndex)];
57
- const passthrough = passthroughIndex === -1 ? [] : [...argv.slice(passthroughIndex + 1)];
58
+ const head =
59
+ passthroughIndex === -1 ? [...argv] : [...argv.slice(0, passthroughIndex)];
60
+ const passthrough =
61
+ passthroughIndex === -1 ? [] : [...argv.slice(passthroughIndex + 1)];
58
62
 
59
63
  let binary: string | undefined;
60
64
  let cacheDir: string | undefined;
@@ -151,7 +155,11 @@ function printHelp(): void {
151
155
  }
152
156
 
153
157
  function resolvePreload(cwd: string, preload: string): string {
154
- if (preload.startsWith(".") || preload.startsWith("/") || preload.includes(path.sep)) {
158
+ if (
159
+ preload.startsWith(".") ||
160
+ preload.startsWith("/") ||
161
+ preload.includes(path.sep)
162
+ ) {
155
163
  return path.resolve(cwd, preload);
156
164
  }
157
165
  return preload;
@@ -180,7 +188,10 @@ function runPreparedEntry(
180
188
  );
181
189
  }
182
190
  const args = [
183
- ...parsed.preload.flatMap((preload) => ["-r", resolvePreload(cwd, preload)]),
191
+ ...parsed.preload.flatMap((preload) => [
192
+ "-r",
193
+ resolvePreload(cwd, preload),
194
+ ]),
184
195
  execution.entryFile,
185
196
  ...parsed.passthrough,
186
197
  ];
@@ -155,7 +155,9 @@ function writeGoWork(scratchDir: string, useDirs: readonly string[]): void {
155
155
  fs.writeFileSync(path.join(scratchDir, "go.work"), goWork, "utf8");
156
156
  }
157
157
 
158
- function sourceBuildWorkspaceReplacements(useDirs: readonly string[]): string[] {
158
+ function sourceBuildWorkspaceReplacements(
159
+ useDirs: readonly string[],
160
+ ): string[] {
159
161
  const ttscRoot = useDirs.find((dir) =>
160
162
  hasModulePath(dir, "github.com/samchon/ttsc/packages/ttsc"),
161
163
  );
@@ -308,7 +310,10 @@ function walkForGoMod(dir: string, out: string[]): void {
308
310
  }
309
311
  }
310
312
 
311
- function resolvePluginCacheRoot(projectRoot: string, cacheDir?: string): string {
313
+ function resolvePluginCacheRoot(
314
+ projectRoot: string,
315
+ cacheDir?: string,
316
+ ): string {
312
317
  if (cacheDir) {
313
318
  return path.resolve(cacheDir, "plugins");
314
319
  }
@@ -343,6 +348,20 @@ function resolveGoCompiler(): string {
343
348
  /* fall through */
344
349
  }
345
350
 
351
+ const platformPackage = path.resolve(
352
+ __dirname,
353
+ "..",
354
+ "..",
355
+ "..",
356
+ "..",
357
+ `ttsc-${process.platform}-${process.arch}`,
358
+ "bin",
359
+ "go",
360
+ "bin",
361
+ process.platform === "win32" ? "go.exe" : "go",
362
+ );
363
+ if (fs.existsSync(platformPackage)) return platformPackage;
364
+
346
365
  const local = path.resolve(
347
366
  __dirname,
348
367
  "..",
@@ -356,6 +375,15 @@ function resolveGoCompiler(): string {
356
375
  );
357
376
  if (fs.existsSync(local)) return local;
358
377
 
378
+ const homeSdk = path.join(
379
+ process.env.HOME ?? "",
380
+ "go-sdk",
381
+ "go",
382
+ "bin",
383
+ process.platform === "win32" ? "go.exe" : "go",
384
+ );
385
+ if (fs.existsSync(homeSdk)) return homeSdk;
386
+
359
387
  return "go";
360
388
  }
361
389
 
@@ -58,7 +58,9 @@ export function loadProjectPlugins(options: {
58
58
  const ttscVersion = readTtscVersion();
59
59
  const tsgoVersion = readTsgoVersion(context.projectRoot);
60
60
  plugins.forEach((plugin, index) => {
61
+ const stage = resolvePluginStage(plugin);
61
62
  validatePluginSource(plugin);
63
+ validatePluginHooks(plugin, stage);
62
64
  const binary = buildSourcePlugin({
63
65
  baseDir: context.projectRoot,
64
66
  cacheDir: options.cacheDir,
@@ -70,8 +72,10 @@ export function loadProjectPlugins(options: {
70
72
  nativePlugins.push({
71
73
  binary,
72
74
  config: entries[index]!,
75
+ hooks: plugin.hooks,
73
76
  name: plugin.name,
74
- stage: resolvePluginStage(plugin),
77
+ source: plugin.source,
78
+ stage,
75
79
  });
76
80
  });
77
81
  return {
@@ -88,6 +92,7 @@ function loadPluginEntry(
88
92
  if (typeof specifier !== "string" || specifier.length === 0) {
89
93
  throw new Error(`ttsc: plugin entry is missing a string "transform" field`);
90
94
  }
95
+ rejectUserPhaseOptions(specifier, entry);
91
96
 
92
97
  const request = resolvePluginRequest(specifier, context.projectRoot);
93
98
  const mod = require(request) as {
@@ -135,11 +140,37 @@ function rejectJsTransformHooks(specifier: string, candidate: object): void {
135
140
  }
136
141
  }
137
142
 
143
+ function rejectUserPhaseOptions(
144
+ specifier: string,
145
+ entry: ITtscProjectPluginConfig,
146
+ ): void {
147
+ for (const key of [
148
+ "after",
149
+ "afterDeclarations",
150
+ "before",
151
+ "phase",
152
+ "source:after",
153
+ ]) {
154
+ if (key in entry) {
155
+ throw new Error(
156
+ `ttsc: plugin entry for "${specifier}" uses unsupported ts-patch option ${JSON.stringify(key)}; ` +
157
+ "ttsc plugins declare source/declaration hooks in the package descriptor, not in user tsconfig",
158
+ );
159
+ }
160
+ }
161
+ }
162
+
138
163
  function resolvePluginStage(plugin: ITtscPlugin): TtscPluginStage {
139
164
  if (plugin.stage === undefined) {
140
165
  return "transform";
141
166
  }
142
167
  if (!isPluginStage(plugin.stage)) {
168
+ if (plugin.stage === "output") {
169
+ throw new Error(
170
+ `ttsc: plugin "${plugin.name}" requested removed stage "output"; ` +
171
+ "upgrade the plugin to a transform hook descriptor compatible with this ttsc version",
172
+ );
173
+ }
143
174
  throw new Error(
144
175
  `ttsc: plugin "${plugin.name}" requested unsupported stage ${JSON.stringify(plugin.stage)}`,
145
176
  );
@@ -153,8 +184,56 @@ function validatePluginSource(plugin: ITtscPlugin): void {
153
184
  }
154
185
  }
155
186
 
187
+ function validatePluginHooks(
188
+ plugin: ITtscPlugin,
189
+ stage: TtscPluginStage,
190
+ ): void {
191
+ const hooks = plugin.hooks;
192
+ if (hooks !== undefined && typeof hooks !== "object") {
193
+ throw new Error(`ttsc: plugin "${plugin.name}" hooks must be an object`);
194
+ }
195
+ if (stage === "check") {
196
+ if (hooks !== undefined && Object.keys(hooks).length !== 0) {
197
+ throw new Error(
198
+ `ttsc: check plugin "${plugin.name}" must not declare transform hooks`,
199
+ );
200
+ }
201
+ return;
202
+ }
203
+ if (hooks === undefined) {
204
+ throw new Error(
205
+ `ttsc: transform plugin "${plugin.name}" must declare source/declaration hooks in its package descriptor`,
206
+ );
207
+ }
208
+ for (const key of Object.keys(hooks)) {
209
+ if (key !== "source" && key !== "declaration") {
210
+ throw new Error(
211
+ `ttsc: plugin "${plugin.name}" requested unsupported hook ${JSON.stringify(key)}`,
212
+ );
213
+ }
214
+ }
215
+ if (hooks.source !== undefined && typeof hooks.source !== "boolean") {
216
+ throw new Error(
217
+ `ttsc: plugin "${plugin.name}" hooks.source must be boolean`,
218
+ );
219
+ }
220
+ if (
221
+ hooks.declaration !== undefined &&
222
+ typeof hooks.declaration !== "boolean"
223
+ ) {
224
+ throw new Error(
225
+ `ttsc: plugin "${plugin.name}" hooks.declaration must be boolean`,
226
+ );
227
+ }
228
+ if (hooks.source !== true && hooks.declaration !== true) {
229
+ throw new Error(
230
+ `ttsc: transform plugin "${plugin.name}" must enable at least one source/declaration hook`,
231
+ );
232
+ }
233
+ }
234
+
156
235
  function isPluginStage(value: string): value is TtscPluginStage {
157
- return value === "transform" || value === "check" || value === "output";
236
+ return value === "transform" || value === "check";
158
237
  }
159
238
 
160
239
  function resolvePluginRequest(specifier: string, projectRoot: string): string {
@@ -1,5 +1,20 @@
1
1
  import type { TtscPluginStage } from "./TtscPluginStage";
2
2
 
3
+ export interface ITtscPluginHooks {
4
+ /**
5
+ * Runs against TypeScript SourceFile AST before TypeScript-Go's built-in emit
6
+ * transforms. The Program/checker are created from the original source before
7
+ * this hook participates in emit.
8
+ */
9
+ source?: boolean;
10
+
11
+ /**
12
+ * Runs against declaration AST before declaration printing. This is a
13
+ * plugin-package capability, never a user-facing tsconfig phase option.
14
+ */
15
+ declaration?: boolean;
16
+ }
17
+
3
18
  /**
4
19
  * Runtime descriptor returned by a ttsc plugin module.
5
20
  *
@@ -48,11 +63,23 @@ export interface ITtscPlugin {
48
63
  /**
49
64
  * Pipeline stage implemented by the sidecar.
50
65
  *
51
- * Omit this field for normal compiler-transform plugins. Explicit stages are
52
- * intended for tools that only validate (`"check"`) or rewrite already
53
- * emitted files (`"output"`).
66
+ * Omit this field for normal compiler-transform plugins. The only explicit
67
+ * non-transform stage is `"check"`.
54
68
  *
55
69
  * @default "transform"
56
70
  */
57
71
  stage?: TtscPluginStage;
72
+
73
+ /** Native transform hook capabilities implemented by the plugin package. */
74
+ hooks?: ITtscPluginHooks;
75
+ }
76
+
77
+ export function defineTtscPlugin<T extends ITtscPlugin>(plugin: T): T;
78
+ export function defineTtscPlugin<TContext, T extends ITtscPlugin>(
79
+ factory: (context: TContext) => T,
80
+ ): (context: TContext) => T;
81
+ export function defineTtscPlugin(
82
+ value: ITtscPlugin | ((context: unknown) => ITtscPlugin),
83
+ ): ITtscPlugin | ((context: unknown) => ITtscPlugin) {
84
+ return value;
58
85
  }
@@ -1,18 +1,12 @@
1
1
  /**
2
2
  * Pipeline stage where a plugin's lazily built Go sidecar participates.
3
3
  *
4
- * - `"transform"`: owns the TypeScript transform/emit pass. This is the
5
- * default and is the right stage for compiler-transform plugins such as
6
- * typia-style source rewrites. During compilation, a transform sidecar
7
- * produces the project's emitted output. During
8
- * {@link TtscCompiler.transform}, the same sidecar may expose a
9
- * source-to-source `transform` command that returns transformed TypeScript
4
+ * - `"transform"`: participates in the TypeScript-Go transform path. Transform
5
+ * plugins declare their source/declaration hook capabilities in the plugin
6
+ * package descriptor and do not receive emitted JavaScript or emitted file
10
7
  * text.
11
8
  * - `"check"`: runs before emit and reports diagnostics only. Use this for
12
9
  * lint or validation plugins that should fail the compile before JavaScript
13
10
  * or declaration output is generated.
14
- * - `"output"`: runs after emit for each emitted output file. Use this for
15
- * post-processing plugins such as banner insertion, import-path rewriting,
16
- * or output stripping that operate on `.js`, `.d.ts`, or map files.
17
11
  */
18
- export type TtscPluginStage = "transform" | "check" | "output";
12
+ export type TtscPluginStage = "transform" | "check";
@@ -1,4 +1,5 @@
1
1
  import type { ITtscProjectPluginConfig } from "../ITtscProjectPluginConfig";
2
+ import type { ITtscPluginHooks } from "../ITtscPlugin";
2
3
  import type { TtscPluginStage } from "../TtscPluginStage";
3
4
 
4
5
  /** Native sidecar selected and built from one plugin descriptor. */
@@ -9,6 +10,10 @@ export interface ITtscLoadedNativePlugin {
9
10
  config: ITtscProjectPluginConfig;
10
11
  /** Stable plugin name used in diagnostics and native manifests. */
11
12
  name: string;
13
+ /** Go source directory selected by the plugin descriptor. */
14
+ source: string;
12
15
  /** Pipeline stage where the sidecar participates. */
13
16
  stage: TtscPluginStage;
17
+ /** Native transform hook capabilities declared by the plugin package. */
18
+ hooks?: ITtscPluginHooks;
14
19
  }
@@ -274,7 +274,7 @@ function createProject(options = {}) {
274
274
  function writeSourcePlugin(root) {
275
275
  fs.writeFileSync(
276
276
  path.join(root, "plugin.cjs"),
277
- 'module.exports = { name: "prepare-fixture", source: "./plugin-go" };\n',
277
+ 'module.exports = { name: "prepare-fixture", source: "./plugin-go", hooks: { source: true } };\n',
278
278
  "utf8",
279
279
  );
280
280
  fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
@@ -293,7 +293,7 @@ function writeSourcePlugin(root) {
293
293
  function writeBrokenTransformPlugin(root) {
294
294
  fs.writeFileSync(
295
295
  path.join(root, "plugin.cjs"),
296
- 'module.exports = { name: "broken-transform-fixture", source: "./plugin-go" };\n',
296
+ 'module.exports = { name: "broken-transform-fixture", source: "./plugin-go", hooks: { source: true } };\n',
297
297
  "utf8",
298
298
  );
299
299
  fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
@@ -327,7 +327,7 @@ function writeBrokenTransformPlugin(root) {
327
327
  function writeCompilerPlugin(root) {
328
328
  fs.writeFileSync(
329
329
  path.join(root, "plugin.cjs"),
330
- 'module.exports = { name: "compile-fixture", source: "./plugin-go" };\n',
330
+ 'module.exports = { name: "compile-fixture", source: "./plugin-go", hooks: { source: true } };\n',
331
331
  "utf8",
332
332
  );
333
333
  fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
@@ -1,8 +1,6 @@
1
1
  const assert = require("node:assert/strict");
2
2
  const test = require("node:test");
3
- const {
4
- resolveBinary,
5
- } = require("../lib/compiler/internal/resolveBinary.js");
3
+ const { resolveBinary } = require("../lib/compiler/internal/resolveBinary.js");
6
4
 
7
5
  test("resolveBinary prefers TTSC_BINARY absolute override", () => {
8
6
  const resolved = resolveBinary({
package/test/tsgo.test.ts CHANGED
@@ -20,12 +20,17 @@ test("resolveTsgo accepts TTSC_TSGO_BINARY as an explicit compiler", () => {
20
20
 
21
21
  test("resolveTsgo resolves the consumer native-preview platform package", () => {
22
22
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "ttsc-tsgo-test-"));
23
- const nativeRoot = path.join(root, "node_modules", "@typescript", "native-preview");
23
+ const nativeRoot = path.join(
24
+ root,
25
+ "node_modules",
26
+ "@typescript",
27
+ "native-preview",
28
+ );
24
29
  const platformRoot = path.join(
25
30
  root,
26
31
  "node_modules",
27
32
  "@typescript",
28
- "native-preview-linux-x64",
33
+ `native-preview-${process.platform}-${process.arch}`,
29
34
  );
30
35
  fs.mkdirSync(nativeRoot, { recursive: true });
31
36
  fs.mkdirSync(path.join(platformRoot, "lib"), { recursive: true });
@@ -41,21 +46,24 @@ test("resolveTsgo resolves the consumer native-preview platform package", () =>
41
46
  fs.writeFileSync(
42
47
  path.join(platformRoot, "package.json"),
43
48
  JSON.stringify({
44
- name: "@typescript/native-preview-linux-x64",
49
+ name: `@typescript/native-preview-${process.platform}-${process.arch}`,
45
50
  version: "7.0.0-dev.consumer",
46
51
  }),
47
52
  "utf8",
48
53
  );
49
- fs.writeFileSync(path.join(platformRoot, "lib", "tsgo"), "", "utf8");
54
+ const binary = path.join(
55
+ platformRoot,
56
+ "lib",
57
+ process.platform === "win32" ? "tsgo.exe" : "tsgo",
58
+ );
59
+ fs.writeFileSync(binary, "", "utf8");
50
60
 
51
61
  const resolved = resolveTsgo({
52
- arch: "x64",
53
62
  cwd: root,
54
63
  env: {},
55
- platform: "linux",
56
64
  });
57
65
 
58
66
  assert.equal(resolved.version, "7.0.0-dev.consumer");
59
67
  assert.equal(resolved.gitHead, "abc123");
60
- assert.equal(resolved.binary, path.join(platformRoot, "lib", "tsgo"));
68
+ assert.equal(resolved.binary, binary);
61
69
  });