ttsc 0.12.3 → 0.12.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.
Files changed (126) hide show
  1. package/cmd/platform/main.go +9 -0
  2. package/cmd/ttsc/api_compile.go +109 -101
  3. package/cmd/ttsc/api_compile_branches_test.go +55 -57
  4. package/cmd/ttsc/api_transform.go +54 -49
  5. package/cmd/ttsc/api_transform_branches_test.go +30 -32
  6. package/cmd/ttsc/build.go +111 -108
  7. package/cmd/ttsc/build_branches_test.go +95 -97
  8. package/cmd/ttsc/helpers_test.go +39 -28
  9. package/cmd/ttsc/main.go +111 -104
  10. package/cmd/ttsc/main_alias_branches_test.go +21 -23
  11. package/cmd/ttscserver/main.go +96 -90
  12. package/cmd/ttscserver/run_lsp_prefers_tsgo_flag_test.go +22 -22
  13. package/cmd/ttscserver/run_lsp_reports_server_error_test.go +22 -22
  14. package/cmd/ttscserver/run_lsp_uses_tsgo_environment_test.go +23 -23
  15. package/cmd/utility-host/main.go +30 -23
  16. package/driver/lsp.go +53 -7
  17. package/driver/plugins.go +88 -72
  18. package/driver/program.go +362 -339
  19. package/driver/rewrite.go +442 -380
  20. package/internal/lspserver/lsp_envelope.go +64 -64
  21. package/internal/lspserver/lsp_frame.go +60 -60
  22. package/internal/lspserver/lsp_plugin.go +57 -57
  23. package/internal/lspserver/lsp_proxy.go +265 -251
  24. package/internal/lspserver/lsp_server.go +155 -144
  25. package/lib/TtscCompiler.d.ts +7 -0
  26. package/lib/TtscCompiler.js +7 -0
  27. package/lib/TtscCompiler.js.map +1 -1
  28. package/lib/compiler/internal/buildNativeCompiler.d.ts +11 -1
  29. package/lib/compiler/internal/buildNativeCompiler.js +23 -3
  30. package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
  31. package/lib/compiler/internal/compileProjectInMemory.d.ts +9 -0
  32. package/lib/compiler/internal/compileProjectInMemory.js +36 -21
  33. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  34. package/lib/compiler/internal/paths.d.ts +27 -0
  35. package/lib/compiler/internal/paths.js +70 -0
  36. package/lib/compiler/internal/paths.js.map +1 -0
  37. package/lib/compiler/internal/project/readProjectConfig.d.ts +9 -1
  38. package/lib/compiler/internal/project/readProjectConfig.js +80 -1
  39. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
  40. package/lib/compiler/internal/project/resolveProjectConfig.d.ts +13 -1
  41. package/lib/compiler/internal/project/resolveProjectConfig.js +24 -1
  42. package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
  43. package/lib/compiler/internal/resolveBinary.d.ts +9 -1
  44. package/lib/compiler/internal/resolveBinary.js +17 -1
  45. package/lib/compiler/internal/resolveBinary.js.map +1 -1
  46. package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +16 -1
  47. package/lib/compiler/internal/resolveEmittedJavaScript.js +42 -10
  48. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  49. package/lib/compiler/internal/resolveTsgo.d.ts +21 -1
  50. package/lib/compiler/internal/resolveTsgo.js +23 -1
  51. package/lib/compiler/internal/resolveTsgo.js.map +1 -1
  52. package/lib/compiler/internal/runBuild.d.ts +19 -0
  53. package/lib/compiler/internal/runBuild.js +112 -46
  54. package/lib/compiler/internal/runBuild.js.map +1 -1
  55. package/lib/compiler/internal/runSingleFileEmit.d.ts +10 -1
  56. package/lib/compiler/internal/runSingleFileEmit.js +14 -1
  57. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  58. package/lib/compiler/internal/sharedHostHelpers.d.ts +5 -0
  59. package/lib/compiler/internal/sharedHostHelpers.js +6 -2
  60. package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
  61. package/lib/compiler/internal/spawnNative.d.ts +21 -0
  62. package/lib/compiler/internal/spawnNative.js +59 -0
  63. package/lib/compiler/internal/spawnNative.js.map +1 -0
  64. package/lib/compiler/internal/transformProjectInMemory.d.ts +15 -1
  65. package/lib/compiler/internal/transformProjectInMemory.js +57 -61
  66. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  67. package/lib/launcher/internal/getCompilerVersionText.js +7 -0
  68. package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
  69. package/lib/launcher/internal/prepareExecution.js +32 -0
  70. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  71. package/lib/launcher/internal/resolveCacheDir.d.ts +9 -0
  72. package/lib/launcher/internal/resolveCacheDir.js +22 -0
  73. package/lib/launcher/internal/resolveCacheDir.js.map +1 -0
  74. package/lib/launcher/internal/resolveTtscserverBinary.js +2 -0
  75. package/lib/launcher/internal/resolveTtscserverBinary.js.map +1 -1
  76. package/lib/launcher/internal/runTtsc.d.ts +10 -0
  77. package/lib/launcher/internal/runTtsc.js +22 -9
  78. package/lib/launcher/internal/runTtsc.js.map +1 -1
  79. package/lib/launcher/internal/runTtscserver.js +10 -35
  80. package/lib/launcher/internal/runTtscserver.js.map +1 -1
  81. package/lib/launcher/internal/runTtsx.d.ts +8 -0
  82. package/lib/launcher/internal/runTtsx.js +33 -7
  83. package/lib/launcher/internal/runTtsx.js.map +1 -1
  84. package/lib/plugin/internal/buildSourcePlugin.d.ts +38 -0
  85. package/lib/plugin/internal/buildSourcePlugin.js +40 -17
  86. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  87. package/lib/plugin/internal/loadProjectPlugins.d.ts +26 -0
  88. package/lib/plugin/internal/loadProjectPlugins.js +32 -18
  89. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  90. package/lib/structures/ITtscCompilerTransformation.d.ts +15 -2
  91. package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +0 -2
  92. package/package.json +9 -9
  93. package/shim/ast/shim.go +24 -0
  94. package/shim/checker/shim.go +35 -0
  95. package/shim/core/shim.go +17 -0
  96. package/shim/diagnosticwriter/shim.go +4 -0
  97. package/shim/lsp/shim.go +3 -3
  98. package/shim/printer/shim.go +20 -0
  99. package/src/TtscCompiler.ts +7 -0
  100. package/src/compiler/internal/buildNativeCompiler.ts +23 -3
  101. package/src/compiler/internal/compileProjectInMemory.ts +34 -25
  102. package/src/compiler/internal/paths.ts +68 -0
  103. package/src/compiler/internal/project/readProjectConfig.ts +86 -1
  104. package/src/compiler/internal/project/resolveProjectConfig.ts +24 -1
  105. package/src/compiler/internal/resolveBinary.ts +17 -1
  106. package/src/compiler/internal/resolveEmittedJavaScript.ts +43 -12
  107. package/src/compiler/internal/resolveTsgo.ts +29 -1
  108. package/src/compiler/internal/runBuild.ts +110 -55
  109. package/src/compiler/internal/runSingleFileEmit.ts +14 -1
  110. package/src/compiler/internal/sharedHostHelpers.ts +7 -7
  111. package/src/compiler/internal/spawnNative.ts +64 -0
  112. package/src/compiler/internal/transformProjectInMemory.ts +47 -67
  113. package/src/launcher/internal/getCompilerVersionText.ts +7 -0
  114. package/src/launcher/internal/prepareExecution.ts +32 -0
  115. package/src/launcher/internal/resolveCacheDir.ts +19 -0
  116. package/src/launcher/internal/resolveTtscserverBinary.ts +2 -0
  117. package/src/launcher/internal/runTtsc.ts +22 -10
  118. package/src/launcher/internal/runTtscserver.ts +9 -1
  119. package/src/launcher/internal/runTtsx.ts +33 -8
  120. package/src/plugin/internal/buildSourcePlugin.ts +40 -14
  121. package/src/plugin/internal/loadProjectPlugins.ts +42 -18
  122. package/src/structures/ITtscCompilerTransformation.ts +15 -2
  123. package/src/structures/ITtscPlugin.ts +0 -1
  124. package/src/structures/internal/TtscSingleFileEmitOptions.ts +0 -2
  125. package/tools/gen_shims/main.go +43 -8
  126. package/utility/host.go +294 -245
@@ -2,9 +2,10 @@ import fs from "node:fs";
2
2
  import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
4
 
5
+ import { findNearestGoMod } from "../../compiler/internal/paths";
5
6
  import { readProjectConfig } from "../../compiler/internal/project/readProjectConfig";
6
- import type { ITtscPluginContributor } from "../../structures/ITtscPluginContributor";
7
7
  import type { ITtscPlugin } from "../../structures/ITtscPlugin";
8
+ import type { ITtscPluginContributor } from "../../structures/ITtscPluginContributor";
8
9
  import type { ITtscPluginFactoryContext } from "../../structures/ITtscPluginFactoryContext";
9
10
  import type { ITtscProjectPluginConfig } from "../../structures/ITtscProjectPluginConfig";
10
11
  import type { TtscPluginStage } from "../../structures/TtscPluginStage";
@@ -30,6 +31,24 @@ type PackageManifest = {
30
31
  ttsc?: unknown;
31
32
  };
32
33
 
34
+ /**
35
+ * Resolve, load, and build all native plugin sidecars for a TypeScript project.
36
+ *
37
+ * Reads the project config, discovers plugin entries (from tsconfig and package
38
+ * auto-discovery), validates and composes their descriptors, then invokes
39
+ * `buildSourcePlugin` to compile each Go source package into a cached binary.
40
+ * Returns the ordered set of loaded native plugins alongside the parsed project
41
+ * config.
42
+ *
43
+ * @param options.binary - Absolute path to the ttsc native helper binary.
44
+ * @param options.cacheDir - Override the plugin binary cache directory.
45
+ * @param options.cwd - Working directory for resolving relative paths.
46
+ * @param options.entries - Explicit plugin entries; `false` disables all
47
+ * plugins (skips both tsconfig entries and package auto-discovery).
48
+ * @param options.file - Path to the tsconfig/jsconfig file.
49
+ * @param options.projectRoot - Override the project root directory.
50
+ * @param options.tsconfig - Alias for `file`.
51
+ */
33
52
  export function loadProjectPlugins(options: {
34
53
  binary: string;
35
54
  cacheDir?: string;
@@ -85,14 +104,21 @@ export function loadProjectPlugins(options: {
85
104
  validatePluginSource(plugin);
86
105
  const contributors = validatePluginContributors(plugin);
87
106
  const source = resolvePluginSource(plugin.source, context.projectRoot);
88
- const kind = resolveNativeSourceKind(source, plugin, entries[index]!.config, index);
107
+ const kind = resolveNativeSourceKind(
108
+ source,
109
+ plugin,
110
+ entries[index]!.config,
111
+ index,
112
+ );
89
113
  if (kind === "linked" && stage !== "transform") {
90
114
  throw new Error(
91
115
  `ttsc: plugin "${pluginLabel(plugin, entries[index]!.config, index)}" source is a linked Go package, but only transform-stage plugins can be linked into a compiler host`,
92
116
  );
93
117
  }
94
118
  const linkedContributorName =
95
- kind === "linked" ? `linked_${String(index).padStart(6, "0")}` : undefined;
119
+ kind === "linked"
120
+ ? `linked_${String(index).padStart(6, "0")}`
121
+ : undefined;
96
122
  return {
97
123
  contributors,
98
124
  config: entries[index]!.config,
@@ -261,6 +287,7 @@ function composePluginSources(
261
287
  return {
262
288
  ...plugin,
263
289
  source: aggregate.plugin.source,
290
+ contributors: aggregate.plugin.contributors,
264
291
  };
265
292
  });
266
293
  }
@@ -276,6 +303,14 @@ function matchesPluginAlias(
276
303
  );
277
304
  }
278
305
 
306
+ /**
307
+ * Return `true` when the project has at least one enabled plugin entry.
308
+ *
309
+ * Used by callers that need to skip plugin-specific work when no plugins are
310
+ * configured, without paying the full cost of `loadProjectPlugins`.
311
+ *
312
+ * @param entries - Explicit entries; `false` always returns `false`.
313
+ */
279
314
  export function hasProjectPluginEntries(
280
315
  project: ITtscParsedProjectConfig,
281
316
  entries?: readonly ITtscProjectPluginConfig[] | false,
@@ -610,7 +645,10 @@ function resolveNativeSourceKind(
610
645
  config: ITtscProjectPluginConfig,
611
646
  index: number,
612
647
  ): "executable" | "linked" {
613
- const packageDir = resolveGoPackageDir(source, pluginLabel(plugin, config, index));
648
+ const packageDir = resolveGoPackageDir(
649
+ source,
650
+ pluginLabel(plugin, config, index),
651
+ );
614
652
  if (findNearestGoMod(packageDir, GO_MOD_SEARCH_MAX_DEPTH) === null) {
615
653
  throw new Error(
616
654
  `ttsc: plugin "${pluginLabel(plugin, config, index)}" source must be inside a Go module with go.mod within ${GO_MOD_SEARCH_MAX_DEPTH} parent directories: ${source}`,
@@ -625,20 +663,6 @@ function resolveNativeSourceKind(
625
663
  return packageName === "main" ? "executable" : "linked";
626
664
  }
627
665
 
628
- function findNearestGoMod(from: string, maxDepth: number): string | null {
629
- let current = path.resolve(from);
630
- let depth = 0;
631
- while (true) {
632
- const candidate = path.join(current, "go.mod");
633
- if (fs.existsSync(candidate)) return candidate;
634
- if (depth >= maxDepth) return null;
635
- const parent = path.dirname(current);
636
- if (parent === current) return null;
637
- current = parent;
638
- depth += 1;
639
- }
640
- }
641
-
642
666
  function resolveGoPackageDir(source: string, label: string): string {
643
667
  if (!fs.existsSync(source)) {
644
668
  throw new Error(`ttsc: plugin "${label}" source does not exist: ${source}`);
@@ -22,7 +22,14 @@ export namespace ITtscCompilerTransformation {
22
22
  /** Non-fatal diagnostics reported during transformation. */
23
23
  diagnostics?: ITtscCompilerDiagnostic[];
24
24
 
25
- /** Transformed TypeScript source text keyed by project file path. */
25
+ /**
26
+ * Transformed TypeScript source text keyed by project-relative file path.
27
+ *
28
+ * Values are TypeScript source text, never JavaScript, declaration files,
29
+ * or source maps. When no transform sidecar is configured, this map
30
+ * contains the unmodified TypeScript files loaded by the TypeScript-Go
31
+ * Program.
32
+ */
26
33
  typescript: Record<string, string>;
27
34
  }
28
35
 
@@ -31,7 +38,13 @@ export namespace ITtscCompilerTransformation {
31
38
  /** Indicates that transformation completed with diagnostics. */
32
39
  type: "failure";
33
40
 
34
- /** Transformed or partially transformed TypeScript source text. */
41
+ /**
42
+ * Transformed or partially transformed TypeScript source text keyed by
43
+ * project-relative file path.
44
+ *
45
+ * May be empty or partial when diagnostics prevented the transform sidecar
46
+ * from completing its pass.
47
+ */
35
48
  typescript: Record<string, string>;
36
49
 
37
50
  /** Diagnostics reported during transformation. */
@@ -96,5 +96,4 @@ export interface ITtscPlugin {
96
96
  * unique within a single plugin build.
97
97
  */
98
98
  contributors?: ITtscPluginContributor[];
99
-
100
99
  }
@@ -10,6 +10,4 @@ export interface TtscSingleFileEmitOptions extends TtscCommonOptions {
10
10
  out?: string;
11
11
  /** Suppress summary banners from ttsc/native sidecars. Defaults to `true`. */
12
12
  quiet?: boolean;
13
- /** Normalize compiler output so diagnostics can be parsed structurally. */
14
- structuredDiagnostics?: boolean;
15
13
  }
@@ -56,13 +56,28 @@ var packagesToShim = []string{
56
56
  "vfs/osvfs",
57
57
  }
58
58
 
59
+ // ExtraShim is the schema for the per-shim-directory `extra-shim.json` file.
60
+ // It lets maintainers extend the generated output beyond what gen_shims can
61
+ // derive automatically from the public API surface.
59
62
  type ExtraShim struct {
60
- ExtraFunctions []string
61
- ExtraMethods map[string][]string
62
- ExtraFields map[string][]string
63
+ // ExtraFunctions lists unexported function names that should be shimmed via
64
+ // go:linkname in addition to the exported ones gen_shims discovers itself.
65
+ ExtraFunctions []string
66
+ // ExtraMethods maps type name → method names for unexported or
67
+ // otherwise-unlinkable methods that should be forwarded.
68
+ ExtraMethods map[string][]string
69
+ // ExtraFields maps type name → field names whose values should be exposed
70
+ // through unsafe pointer casts (used when go:linkname cannot reach them).
71
+ ExtraFields map[string][]string
72
+ // IgnoreFunctions lists exported function names that gen_shims should skip
73
+ // entirely, typically because the caller supplies a hand-written alternative.
63
74
  IgnoreFunctions []string
64
75
  }
65
76
 
77
+ // signatureHasUnexportedType reports whether any parameter of the function
78
+ // signature refers to an unexported named type (optionally through a pointer).
79
+ // Such functions cannot be linked safely because the shim package cannot
80
+ // reference the unexported type by name.
66
81
  func signatureHasUnexportedType(t types.Signature) bool {
67
82
  if params := t.Params(); params != nil {
68
83
  for v := range params.Variables() {
@@ -128,6 +143,9 @@ func main() {
128
143
  extraShim.IgnoreFunctions = []string{}
129
144
  }
130
145
 
146
+ // importedPackages tracks every package import the generated file needs.
147
+ // true = referenced by name (needs a named import).
148
+ // false = only needed for its side-effects (blank import "_").
131
149
  importedPackages := map[string]bool{}
132
150
  importPackage := func(path string, directly bool) {
133
151
  if directly {
@@ -137,12 +155,21 @@ func main() {
137
155
  }
138
156
  }
139
157
 
158
+ // qualifierOnlyPackageName records a direct import for every package the
159
+ // type-string references and returns just the package short name, producing
160
+ // output like `ast.Node` instead of a full path.
140
161
  var qualifierOnlyPackageName types.Qualifier = func(p *types.Package) string {
141
162
  importPackage(p.Path(), true)
142
163
  return p.Name()
143
164
  }
165
+ // qualifierEmptyPackageName omits the package qualifier entirely; used when
166
+ // writing the receiver type inside a go:linkname directive where the package
167
+ // prefix must not appear.
144
168
  var qualifierEmptyPackageName types.Qualifier = func(p *types.Package) string { return "" }
145
169
 
170
+ // emitGoLinknameDirective appends a `//go:linkname localName pkg.Func`
171
+ // pragma line to shimBuilder, registering unsafe and the source package as
172
+ // blank imports so the linker can resolve the symbol.
146
173
  emitGoLinknameDirective := func(localName string, fn *types.Func) {
147
174
  importPackage("unsafe", false)
148
175
  importPackage(pkg.Types.Path(), false)
@@ -161,6 +188,9 @@ func main() {
161
188
  shimBuilder.WriteByte('\n')
162
189
  }
163
190
 
191
+ // emitLinkedFunction emits a go:linkname directive and a matching func
192
+ // declaration for fn. Generic functions (TypeParams != nil) and functions
193
+ // with unexported parameter types are skipped (returns false).
164
194
  emitLinkedFunction := func(fn *types.Func) bool {
165
195
  if fn.Signature().TypeParams() != nil {
166
196
  return false
@@ -221,10 +251,9 @@ func main() {
221
251
  shimBuilder.WriteString("\n")
222
252
  }
223
253
 
224
- switch object.(type) {
254
+ switch typedObj := object.(type) {
225
255
  case *types.TypeName:
226
- typeName := object.(*types.TypeName)
227
- t := typeName.Type()
256
+ t := typedObj.Type()
228
257
  named, isNamed := t.(*types.Named)
229
258
  if isNamed {
230
259
  _, nameWithTypeParams, _ := strings.Cut(types.TypeString(named, qualifierOnlyPackageName), ".")
@@ -297,6 +326,10 @@ func main() {
297
326
  matchedExtraFields[name] = true
298
327
  mirrorStructName := "extra_" + name
299
328
 
329
+ // emitExtraStruct emits a mirror struct (`extra_<Name>`) whose field
330
+ // layout matches the unexported original so that unsafe.Pointer casts
331
+ // in the generated accessor functions are safe. Unexported pointer
332
+ // fields whose element type is also unexported are recursively mirrored.
300
333
  var emitExtraStruct func(name string, s *types.Struct)
301
334
  emitExtraStruct = func(name string, s *types.Struct) {
302
335
  shimBuilder.WriteString("type extra_")
@@ -384,12 +417,14 @@ func main() {
384
417
  printReexport("var")
385
418
  case *types.Func:
386
419
  if !slices.Contains(extraShim.IgnoreFunctions, name) {
387
- funcType := object.(*types.Func)
388
- emitLinkedFunction(funcType)
420
+ emitLinkedFunction(typedObj)
389
421
  }
390
422
  }
391
423
  }
392
424
 
425
+ // Verify that every extra function/method requested in extra-shim.json was
426
+ // actually found in the package. A missing symbol means the json file is
427
+ // stale relative to the upstream typescript-go API.
393
428
  exit := false
394
429
  for fnName, found := range matchedExtraFunctions {
395
430
  if found {