ttsc 0.6.0 → 0.7.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.
Files changed (261) hide show
  1. package/cmd/ttsc/api_compile.go +134 -0
  2. package/cmd/ttsc/build.go +1 -7
  3. package/cmd/ttsc/main.go +2 -2
  4. package/cmd/ttsc/transform.go +0 -6
  5. package/driver/program.go +11 -1
  6. package/lib/TtscCompiler.d.ts +76 -0
  7. package/lib/TtscCompiler.js +245 -0
  8. package/lib/TtscCompiler.js.map +1 -0
  9. package/lib/compiler/internal/buildNativeCompiler.d.ts +6 -0
  10. package/lib/compiler/internal/buildNativeCompiler.js +72 -0
  11. package/lib/compiler/internal/buildNativeCompiler.js.map +1 -0
  12. package/lib/compiler/internal/compileProjectInMemory.d.ts +7 -0
  13. package/lib/compiler/internal/compileProjectInMemory.js +176 -0
  14. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -0
  15. package/lib/compiler/internal/project/readProjectConfig.d.ts +4 -0
  16. package/lib/{project.js → compiler/internal/project/readProjectConfig.js} +12 -82
  17. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -0
  18. package/lib/compiler/internal/project/resolveProjectConfig.d.ts +3 -0
  19. package/lib/compiler/internal/project/resolveProjectConfig.js +94 -0
  20. package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -0
  21. package/lib/compiler/internal/resolveBinary.d.ts +4 -0
  22. package/lib/compiler/internal/resolveBinary.js +65 -0
  23. package/lib/compiler/internal/resolveBinary.js.map +1 -0
  24. package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +7 -0
  25. package/lib/compiler/internal/resolveEmittedJavaScript.js +118 -0
  26. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -0
  27. package/lib/compiler/internal/resolveTsgo.d.ts +20 -0
  28. package/lib/{tsgo.js → compiler/internal/resolveTsgo.js} +5 -10
  29. package/lib/compiler/internal/resolveTsgo.js.map +1 -0
  30. package/lib/compiler/internal/runBuild.d.ts +10 -0
  31. package/lib/compiler/internal/runBuild.js +480 -0
  32. package/lib/compiler/internal/runBuild.js.map +1 -0
  33. package/lib/compiler/internal/runTransform.d.ts +3 -0
  34. package/lib/compiler/internal/runTransform.js +100 -0
  35. package/lib/compiler/internal/runTransform.js.map +1 -0
  36. package/lib/index.d.ts +6 -15
  37. package/lib/index.js +6 -15
  38. package/lib/index.js.map +1 -1
  39. package/lib/launcher/internal/getCompilerVersionText.d.ts +3 -0
  40. package/lib/launcher/internal/getCompilerVersionText.js +71 -0
  41. package/lib/launcher/internal/getCompilerVersionText.js.map +1 -0
  42. package/lib/launcher/internal/prepareExecution.d.ts +10 -0
  43. package/lib/launcher/internal/prepareExecution.js +120 -0
  44. package/lib/launcher/internal/prepareExecution.js.map +1 -0
  45. package/lib/launcher/internal/runTtsc.d.ts +1 -0
  46. package/lib/{cli.js → launcher/internal/runTtsc.js} +48 -47
  47. package/lib/launcher/internal/runTtsc.js.map +1 -0
  48. package/lib/launcher/internal/runTtsx.d.ts +1 -0
  49. package/lib/{runner/cli.js → launcher/internal/runTtsx.js} +13 -35
  50. package/lib/launcher/internal/runTtsx.js.map +1 -0
  51. package/lib/launcher/ttsc.js +2 -2
  52. package/lib/launcher/ttsc.js.map +1 -1
  53. package/lib/launcher/ttsx.js +2 -2
  54. package/lib/launcher/ttsx.js.map +1 -1
  55. package/lib/plugin/internal/buildSourcePlugin.d.ts +12 -0
  56. package/lib/{source-build.js → plugin/internal/buildSourcePlugin.js} +77 -84
  57. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -0
  58. package/lib/plugin/internal/loadProjectPlugins.d.ts +14 -0
  59. package/lib/{plugin.js → plugin/internal/loadProjectPlugins.js} +38 -76
  60. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -0
  61. package/lib/structures/ITtscCompilerContext.d.ts +78 -0
  62. package/lib/structures/ITtscCompilerContext.js +3 -0
  63. package/lib/structures/ITtscCompilerContext.js.map +1 -0
  64. package/lib/structures/ITtscCompilerDiagnostic.d.ts +83 -0
  65. package/lib/structures/ITtscCompilerDiagnostic.js +3 -0
  66. package/lib/structures/ITtscCompilerDiagnostic.js.map +1 -0
  67. package/lib/structures/ITtscCompilerResult.d.ts +83 -0
  68. package/lib/structures/{ITtscCacheKeyInput.js → ITtscCompilerResult.js} +1 -1
  69. package/lib/structures/ITtscCompilerResult.js.map +1 -0
  70. package/lib/structures/ITtscPlugin.d.ts +52 -7
  71. package/lib/structures/ITtscPluginFactoryContext.d.ts +47 -0
  72. package/lib/structures/ITtscProjectPluginConfig.d.ts +41 -0
  73. package/lib/structures/TtscPluginStage.d.ts +15 -0
  74. package/lib/structures/{ITtscBuildResult.js → TtscPluginStage.js} +1 -1
  75. package/lib/structures/TtscPluginStage.js.map +1 -0
  76. package/lib/structures/index.d.ts +7 -0
  77. package/lib/structures/index.js +24 -0
  78. package/lib/structures/index.js.map +1 -0
  79. package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +13 -0
  80. package/lib/structures/internal/ITtscLoadedNativePlugin.js.map +1 -0
  81. package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +15 -0
  82. package/lib/structures/internal/ITtscParsedProjectConfig.js.map +1 -0
  83. package/lib/structures/internal/ITtscProjectLocatorOptions.d.ts +9 -0
  84. package/lib/structures/internal/ITtscProjectLocatorOptions.js.map +1 -0
  85. package/lib/structures/internal/TtscBuildOptions.d.ts +18 -0
  86. package/lib/structures/{ITtscBuildOptions.js → internal/TtscBuildOptions.js} +1 -1
  87. package/lib/structures/internal/TtscBuildOptions.js.map +1 -0
  88. package/lib/structures/internal/TtscBuildResult.d.ts +14 -0
  89. package/lib/structures/{ITtscCheckOptions.js → internal/TtscBuildResult.js} +1 -1
  90. package/lib/structures/internal/TtscBuildResult.js.map +1 -0
  91. package/lib/structures/internal/TtscCommonOptions.d.ts +27 -0
  92. package/lib/structures/{ITtscNativeSource.js → internal/TtscCommonOptions.js} +1 -1
  93. package/lib/structures/internal/TtscCommonOptions.js.map +1 -0
  94. package/lib/structures/internal/TtscTransformOptions.d.ts +14 -0
  95. package/lib/structures/internal/TtscTransformOptions.js +3 -0
  96. package/lib/structures/internal/TtscTransformOptions.js.map +1 -0
  97. package/package.json +9 -9
  98. package/src/TtscCompiler.ts +241 -0
  99. package/src/compiler/internal/buildNativeCompiler.ts +43 -0
  100. package/src/compiler/internal/compileProjectInMemory.ts +189 -0
  101. package/src/{project.ts → compiler/internal/project/readProjectConfig.ts} +36 -111
  102. package/src/compiler/internal/project/resolveProjectConfig.ts +67 -0
  103. package/src/compiler/internal/resolveBinary.ts +41 -0
  104. package/src/compiler/internal/resolveEmittedJavaScript.ts +102 -0
  105. package/src/{tsgo.ts → compiler/internal/resolveTsgo.ts} +20 -23
  106. package/src/compiler/internal/runBuild.ts +644 -0
  107. package/src/compiler/internal/runTransform.ts +69 -0
  108. package/src/index.ts +6 -15
  109. package/src/launcher/internal/getCompilerVersionText.ts +44 -0
  110. package/src/launcher/internal/prepareExecution.ts +115 -0
  111. package/src/{cli.ts → launcher/internal/runTtsc.ts} +61 -70
  112. package/src/{runner/cli.ts → launcher/internal/runTtsx.ts} +21 -49
  113. package/src/launcher/ttsc.ts +2 -2
  114. package/src/launcher/ttsx.ts +2 -2
  115. package/src/{source-build.ts → plugin/internal/buildSourcePlugin.ts} +121 -115
  116. package/src/plugin/internal/loadProjectPlugins.ts +214 -0
  117. package/src/structures/ITtscCompilerContext.ts +84 -0
  118. package/src/structures/ITtscCompilerDiagnostic.ts +91 -0
  119. package/src/structures/ITtscCompilerResult.ts +94 -0
  120. package/src/structures/ITtscPlugin.ts +54 -7
  121. package/src/structures/ITtscPluginFactoryContext.ts +51 -0
  122. package/src/structures/ITtscProjectPluginConfig.ts +43 -0
  123. package/src/structures/TtscPluginStage.ts +15 -0
  124. package/src/structures/index.ts +7 -0
  125. package/src/structures/internal/ITtscLoadedNativePlugin.ts +14 -0
  126. package/src/structures/internal/ITtscParsedProjectConfig.ts +16 -0
  127. package/src/structures/internal/ITtscProjectLocatorOptions.ts +9 -0
  128. package/src/structures/internal/TtscBuildOptions.ts +19 -0
  129. package/src/structures/internal/TtscBuildResult.ts +15 -0
  130. package/src/structures/internal/TtscCommonOptions.ts +28 -0
  131. package/src/structures/internal/TtscTransformOptions.ts +15 -0
  132. package/test/compiler.test.ts +234 -0
  133. package/test/platform.test.ts +1 -45
  134. package/test/project.test.ts +3 -1
  135. package/test/source-build.test.ts +33 -220
  136. package/test/tsgo.test.ts +1 -8
  137. package/lib/api.d.ts +0 -40
  138. package/lib/api.js +0 -680
  139. package/lib/api.js.map +0 -1
  140. package/lib/cli.d.ts +0 -1
  141. package/lib/cli.js.map +0 -1
  142. package/lib/native.d.ts +0 -8
  143. package/lib/native.js +0 -42
  144. package/lib/native.js.map +0 -1
  145. package/lib/platform.d.ts +0 -52
  146. package/lib/platform.js +0 -175
  147. package/lib/platform.js.map +0 -1
  148. package/lib/plugin.d.ts +0 -13
  149. package/lib/plugin.js.map +0 -1
  150. package/lib/project.d.ts +0 -14
  151. package/lib/project.js.map +0 -1
  152. package/lib/runner/cli.d.ts +0 -1
  153. package/lib/runner/cli.js.map +0 -1
  154. package/lib/runner/register.d.ts +0 -6
  155. package/lib/runner/register.js +0 -358
  156. package/lib/runner/register.js.map +0 -1
  157. package/lib/source-build.d.ts +0 -19
  158. package/lib/source-build.js.map +0 -1
  159. package/lib/structures/ITtscBuildOptions.d.ts +0 -14
  160. package/lib/structures/ITtscBuildOptions.js.map +0 -1
  161. package/lib/structures/ITtscBuildResult.d.ts +0 -6
  162. package/lib/structures/ITtscBuildResult.js.map +0 -1
  163. package/lib/structures/ITtscBuildSourcePluginOptions.d.ts +0 -8
  164. package/lib/structures/ITtscBuildSourcePluginOptions.js +0 -3
  165. package/lib/structures/ITtscBuildSourcePluginOptions.js.map +0 -1
  166. package/lib/structures/ITtscCacheKeyInput.d.ts +0 -7
  167. package/lib/structures/ITtscCacheKeyInput.js.map +0 -1
  168. package/lib/structures/ITtscCheckOptions.d.ts +0 -2
  169. package/lib/structures/ITtscCheckOptions.js.map +0 -1
  170. package/lib/structures/ITtscCommonOptions.d.ts +0 -22
  171. package/lib/structures/ITtscCommonOptions.js +0 -3
  172. package/lib/structures/ITtscCommonOptions.js.map +0 -1
  173. package/lib/structures/ITtscLoadPluginsOptions.d.ts +0 -8
  174. package/lib/structures/ITtscLoadPluginsOptions.js +0 -3
  175. package/lib/structures/ITtscLoadPluginsOptions.js.map +0 -1
  176. package/lib/structures/ITtscLoadedNativePlugin.d.ts +0 -7
  177. package/lib/structures/ITtscLoadedNativePlugin.js.map +0 -1
  178. package/lib/structures/ITtscLoadedPlugins.d.ts +0 -11
  179. package/lib/structures/ITtscLoadedPlugins.js +0 -3
  180. package/lib/structures/ITtscLoadedPlugins.js.map +0 -1
  181. package/lib/structures/ITtscNativeBackend.d.ts +0 -10
  182. package/lib/structures/ITtscNativeBackend.js +0 -3
  183. package/lib/structures/ITtscNativeBackend.js.map +0 -1
  184. package/lib/structures/ITtscNativePluginContractVersion.d.ts +0 -1
  185. package/lib/structures/ITtscNativePluginContractVersion.js +0 -3
  186. package/lib/structures/ITtscNativePluginContractVersion.js.map +0 -1
  187. package/lib/structures/ITtscNativePluginShape.d.ts +0 -8
  188. package/lib/structures/ITtscNativePluginShape.js +0 -3
  189. package/lib/structures/ITtscNativePluginShape.js.map +0 -1
  190. package/lib/structures/ITtscNativeRewriteMode.d.ts +0 -1
  191. package/lib/structures/ITtscNativeRewriteMode.js +0 -3
  192. package/lib/structures/ITtscNativeRewriteMode.js.map +0 -1
  193. package/lib/structures/ITtscNativeSource.d.ts +0 -4
  194. package/lib/structures/ITtscNativeSource.js.map +0 -1
  195. package/lib/structures/ITtscParsedProjectConfig.d.ts +0 -9
  196. package/lib/structures/ITtscParsedProjectConfig.js.map +0 -1
  197. package/lib/structures/ITtscPluginFactory.d.ts +0 -4
  198. package/lib/structures/ITtscPluginFactory.js +0 -3
  199. package/lib/structures/ITtscPluginFactory.js.map +0 -1
  200. package/lib/structures/ITtscPluginModule.d.ts +0 -3
  201. package/lib/structures/ITtscPluginModule.js +0 -3
  202. package/lib/structures/ITtscPluginModule.js.map +0 -1
  203. package/lib/structures/ITtscPreparedExecution.d.ts +0 -5
  204. package/lib/structures/ITtscPreparedExecution.js +0 -3
  205. package/lib/structures/ITtscPreparedExecution.js.map +0 -1
  206. package/lib/structures/ITtscProjectLocatorOptions.d.ts +0 -5
  207. package/lib/structures/ITtscProjectLocatorOptions.js.map +0 -1
  208. package/lib/structures/ITtscRegisterOptions.d.ts +0 -6
  209. package/lib/structures/ITtscRegisterOptions.js +0 -3
  210. package/lib/structures/ITtscRegisterOptions.js.map +0 -1
  211. package/lib/structures/ITtscResolveGoBinaryOptions.d.ts +0 -7
  212. package/lib/structures/ITtscResolveGoBinaryOptions.js +0 -3
  213. package/lib/structures/ITtscResolveGoBinaryOptions.js.map +0 -1
  214. package/lib/structures/ITtscResolveOptions.d.ts +0 -20
  215. package/lib/structures/ITtscResolveOptions.js +0 -3
  216. package/lib/structures/ITtscResolveOptions.js.map +0 -1
  217. package/lib/structures/ITtscResolvedTsgo.d.ts +0 -8
  218. package/lib/structures/ITtscResolvedTsgo.js +0 -3
  219. package/lib/structures/ITtscResolvedTsgo.js.map +0 -1
  220. package/lib/structures/ITtscTransformOptions.d.ts +0 -12
  221. package/lib/structures/ITtscTransformOptions.js +0 -3
  222. package/lib/structures/ITtscTransformOptions.js.map +0 -1
  223. package/lib/structures/ITtscTsgoResolveOptions.d.ts +0 -14
  224. package/lib/structures/ITtscTsgoResolveOptions.js +0 -3
  225. package/lib/structures/ITtscTsgoResolveOptions.js.map +0 -1
  226. package/lib/tsgo.d.ts +0 -6
  227. package/lib/tsgo.js.map +0 -1
  228. package/src/api.ts +0 -872
  229. package/src/native.ts +0 -64
  230. package/src/platform.ts +0 -151
  231. package/src/plugin.ts +0 -253
  232. package/src/runner/register.ts +0 -406
  233. package/src/structures/ITtscBuildOptions.ts +0 -19
  234. package/src/structures/ITtscBuildResult.ts +0 -6
  235. package/src/structures/ITtscBuildSourcePluginOptions.ts +0 -9
  236. package/src/structures/ITtscCacheKeyInput.ts +0 -7
  237. package/src/structures/ITtscCheckOptions.ts +0 -3
  238. package/src/structures/ITtscCommonOptions.ts +0 -23
  239. package/src/structures/ITtscLoadPluginsOptions.ts +0 -9
  240. package/src/structures/ITtscLoadedNativePlugin.ts +0 -8
  241. package/src/structures/ITtscLoadedPlugins.ts +0 -12
  242. package/src/structures/ITtscNativeBackend.ts +0 -11
  243. package/src/structures/ITtscNativePluginContractVersion.ts +0 -1
  244. package/src/structures/ITtscNativePluginShape.ts +0 -9
  245. package/src/structures/ITtscNativeRewriteMode.ts +0 -1
  246. package/src/structures/ITtscNativeSource.ts +0 -4
  247. package/src/structures/ITtscParsedProjectConfig.ts +0 -10
  248. package/src/structures/ITtscPluginFactory.ts +0 -7
  249. package/src/structures/ITtscPluginModule.ts +0 -4
  250. package/src/structures/ITtscPreparedExecution.ts +0 -5
  251. package/src/structures/ITtscProjectLocatorOptions.ts +0 -5
  252. package/src/structures/ITtscRegisterOptions.ts +0 -7
  253. package/src/structures/ITtscResolveGoBinaryOptions.ts +0 -7
  254. package/src/structures/ITtscResolveOptions.ts +0 -20
  255. package/src/structures/ITtscResolvedTsgo.ts +0 -8
  256. package/src/structures/ITtscTransformOptions.ts +0 -13
  257. package/src/structures/ITtscTsgoResolveOptions.ts +0 -14
  258. package/test/native.test.ts +0 -103
  259. /package/lib/structures/{ITtscLoadedNativePlugin.js → internal/ITtscLoadedNativePlugin.js} +0 -0
  260. /package/lib/structures/{ITtscParsedProjectConfig.js → internal/ITtscParsedProjectConfig.js} +0 -0
  261. /package/lib/structures/{ITtscProjectLocatorOptions.js → internal/ITtscProjectLocatorOptions.js} +0 -0
@@ -4,29 +4,37 @@ import * as fs from "node:fs";
4
4
  import { createRequire } from "node:module";
5
5
  import * as path from "node:path";
6
6
 
7
- import type { ITtscBuildSourcePluginOptions } from "./structures/ITtscBuildSourcePluginOptions";
8
- import type { ITtscResolveGoBinaryOptions } from "./structures/ITtscResolveGoBinaryOptions";
7
+ const GO_MOD_SEARCH_MAX_DEPTH = 3;
9
8
 
10
- export type { ITtscBuildSourcePluginOptions } from "./structures/ITtscBuildSourcePluginOptions";
11
- export type { ITtscResolveGoBinaryOptions } from "./structures/ITtscResolveGoBinaryOptions";
9
+ const SKIP_DIRS = new Set([
10
+ "node_modules",
11
+ ".git",
12
+ "dist",
13
+ "build",
14
+ "vendor",
15
+ "lib",
16
+ ]);
12
17
 
13
- export function buildSourcePlugin(opts: ITtscBuildSourcePluginOptions): string {
14
- const dir = path.isAbsolute(opts.source.dir)
15
- ? opts.source.dir
16
- : path.resolve(opts.baseDir, opts.source.dir);
17
- if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
18
- throw new Error(
19
- `ttsc: plugin "${opts.pluginName}" native.source.dir does not exist: ${dir}`,
20
- );
21
- }
22
- const entry = opts.source.entry ?? ".";
18
+ /** Build one Go source plugin into a cached executable. */
19
+ export function buildSourcePlugin(opts: {
20
+ source: string;
21
+ pluginName: string;
22
+ baseDir: string;
23
+ cacheDir?: string;
24
+ label?: string;
25
+ overlayDirs?: readonly string[];
26
+ quiet?: boolean;
27
+ ttscVersion: string;
28
+ tsgoVersion: string;
29
+ }): string {
30
+ const { dir, entry, source } = resolveSourceBuildTarget(opts);
23
31
  const key = computeCacheKey({
24
32
  dir,
25
33
  entry,
26
34
  ttscVersion: opts.ttscVersion,
27
35
  tsgoVersion: opts.tsgoVersion,
28
36
  });
29
- const root = resolvePluginCacheRoot(opts.baseDir);
37
+ const root = resolvePluginCacheRoot(opts.baseDir, opts.cacheDir);
30
38
  const cacheDir = path.join(root, key);
31
39
  const binaryName = process.platform === "win32" ? "plugin.exe" : "plugin";
32
40
  const binaryPath = path.join(cacheDir, binaryName);
@@ -34,9 +42,12 @@ export function buildSourcePlugin(opts: ITtscBuildSourcePluginOptions): string {
34
42
  return binaryPath;
35
43
  }
36
44
  fs.mkdirSync(cacheDir, { recursive: true });
37
- process.stderr.write(
38
- `ttsc: building source plugin "${opts.pluginName}" from ${dir} (this runs once per cache key)\n`,
39
- );
45
+ const label = opts.label ?? "source plugin";
46
+ if (opts.quiet !== true) {
47
+ process.stderr.write(
48
+ `ttsc: building ${label} "${opts.pluginName}" from ${source} (this runs once per cache key)\n`,
49
+ );
50
+ }
40
51
 
41
52
  const scratchDir = path.join(
42
53
  root,
@@ -44,7 +55,7 @@ export function buildSourcePlugin(opts: ITtscBuildSourcePluginOptions): string {
44
55
  );
45
56
  try {
46
57
  materializeScratchDir(dir, scratchDir);
47
- writeGoWork(scratchDir, findTtscOverlayDirs());
58
+ writeGoWork(scratchDir, opts.overlayDirs ?? findTtscOverlayDirs());
48
59
  const scratchBinaryName =
49
60
  process.platform === "win32" ? ".ttsc-plugin.exe" : ".ttsc-plugin";
50
61
  runGoBuild(scratchDir, entry, scratchBinaryName, opts.pluginName);
@@ -59,6 +70,66 @@ export function buildSourcePlugin(opts: ITtscBuildSourcePluginOptions): string {
59
70
  }
60
71
  }
61
72
 
73
+ function resolveSourceBuildTarget(opts: {
74
+ source: string;
75
+ pluginName: string;
76
+ baseDir: string;
77
+ }): {
78
+ dir: string;
79
+ entry: string;
80
+ source: string;
81
+ } {
82
+ const source = path.isAbsolute(opts.source)
83
+ ? opts.source
84
+ : path.resolve(opts.baseDir, opts.source);
85
+ if (!fs.existsSync(source)) {
86
+ throw new Error(
87
+ `ttsc: plugin "${opts.pluginName}" source does not exist: ${source}`,
88
+ );
89
+ }
90
+
91
+ const stat = fs.statSync(source);
92
+ const packageDir =
93
+ stat.isFile() && path.basename(source) === "go.mod"
94
+ ? path.dirname(source)
95
+ : stat.isDirectory()
96
+ ? source
97
+ : null;
98
+ if (packageDir === null) {
99
+ throw new Error(
100
+ `ttsc: plugin "${opts.pluginName}" source must be a Go package directory or go.mod file: ${source}`,
101
+ );
102
+ }
103
+
104
+ const goMod = findNearestGoMod(packageDir, GO_MOD_SEARCH_MAX_DEPTH);
105
+ if (goMod === null) {
106
+ throw new Error(
107
+ `ttsc: plugin "${opts.pluginName}" source must be inside a Go module with go.mod within ${GO_MOD_SEARCH_MAX_DEPTH} parent directories: ${source}`,
108
+ );
109
+ }
110
+ const dir = path.dirname(goMod);
111
+ const rel = path.relative(dir, packageDir).replace(/\\/g, "/");
112
+ return {
113
+ dir,
114
+ entry: rel === "" ? "." : `./${rel}`,
115
+ source,
116
+ };
117
+ }
118
+
119
+ function findNearestGoMod(from: string, maxDepth: number): string | null {
120
+ let current = path.resolve(from);
121
+ let depth = 0;
122
+ while (true) {
123
+ const candidate = path.join(current, "go.mod");
124
+ if (fs.existsSync(candidate)) return candidate;
125
+ if (depth >= maxDepth) return null;
126
+ const parent = path.dirname(current);
127
+ if (parent === current) return null;
128
+ current = parent;
129
+ depth += 1;
130
+ }
131
+ }
132
+
62
133
  function materializeScratchDir(source: string, scratch: string): void {
63
134
  fs.mkdirSync(scratch, { recursive: true });
64
135
  fs.cpSync(source, scratch, {
@@ -84,9 +155,7 @@ function writeGoWork(scratchDir: string, useDirs: readonly string[]): void {
84
155
  fs.writeFileSync(path.join(scratchDir, "go.work"), goWork, "utf8");
85
156
  }
86
157
 
87
- export function sourceBuildWorkspaceReplacements(
88
- useDirs: readonly string[],
89
- ): string[] {
158
+ function sourceBuildWorkspaceReplacements(useDirs: readonly string[]): string[] {
90
159
  const ttscRoot = useDirs.find((dir) =>
91
160
  hasModulePath(dir, "github.com/samchon/ttsc/packages/ttsc"),
92
161
  );
@@ -119,19 +188,15 @@ function runGoBuild(
119
188
  binaryName: string,
120
189
  pluginName: string,
121
190
  ): void {
122
- const goBinary = resolveGoBinary();
191
+ const goBinary = resolveGoCompiler();
123
192
  ensureExecutableGoToolchain(goBinary);
124
- const result = spawnSync(
125
- goBinary,
126
- ["build", "-o", binaryName, entry],
127
- {
128
- cwd,
129
- encoding: "utf8",
130
- env: goBuildEnv(goBinary),
131
- maxBuffer: 1024 * 1024 * 64,
132
- windowsHide: true,
133
- },
134
- );
193
+ const result = spawnSync(goBinary, ["build", "-o", binaryName, entry], {
194
+ cwd,
195
+ encoding: "utf8",
196
+ env: goBuildEnv(goBinary),
197
+ maxBuffer: 1024 * 1024 * 64,
198
+ windowsHide: true,
199
+ });
135
200
  if (result.error) {
136
201
  if ((result.error as NodeJS.ErrnoException).code === "ENOENT") {
137
202
  throw new Error(
@@ -206,23 +271,8 @@ function walkToolFiles(dir: string): string[] {
206
271
  return out;
207
272
  }
208
273
 
209
- export function goBinaryName(opts: ITtscResolveGoBinaryOptions = {}): string {
210
- return (opts.platform ?? process.platform) === "win32" ? "go.exe" : "go";
211
- }
212
-
213
- export function bundledGoPackageRequest(
214
- opts: ITtscResolveGoBinaryOptions = {},
215
- ): string {
216
- return `@ttsc/${goPlatformKey(opts)}/bin/go/bin/${goBinaryName(opts)}`;
217
- }
218
-
219
- let cachedOverlayDirs: readonly string[] | null = null;
220
-
221
274
  function findTtscOverlayDirs(): readonly string[] {
222
- if (cachedOverlayDirs !== null) {
223
- return cachedOverlayDirs;
224
- }
225
- const ttscRoot = path.resolve(__dirname, "..");
275
+ const ttscRoot = path.resolve(__dirname, "..", "..", "..");
226
276
  const dirs: string[] = [];
227
277
  if (fs.existsSync(path.join(ttscRoot, "go.mod"))) {
228
278
  dirs.push(ttscRoot);
@@ -232,7 +282,6 @@ function findTtscOverlayDirs(): readonly string[] {
232
282
  walkForGoMod(shimRoot, dirs);
233
283
  }
234
284
  dirs.sort();
235
- cachedOverlayDirs = dirs;
236
285
  return dirs;
237
286
  }
238
287
 
@@ -259,14 +308,13 @@ function walkForGoMod(dir: string, out: string[]): void {
259
308
  }
260
309
  }
261
310
 
262
- export function resolvePluginCacheRoot(projectRoot: string): string {
311
+ function resolvePluginCacheRoot(projectRoot: string, cacheDir?: string): string {
312
+ if (cacheDir) {
313
+ return path.resolve(cacheDir, "plugins");
314
+ }
263
315
  if (process.env.TTSC_CACHE_DIR) {
264
316
  return path.resolve(process.env.TTSC_CACHE_DIR, "plugins");
265
317
  }
266
- return resolveDefaultPluginCacheRoot(projectRoot);
267
- }
268
-
269
- export function resolveDefaultPluginCacheRoot(projectRoot: string): string {
270
318
  const root = path.resolve(projectRoot);
271
319
  const nodeModules = path.join(root, "node_modules");
272
320
  if (isDirectory(nodeModules)) {
@@ -275,18 +323,6 @@ export function resolveDefaultPluginCacheRoot(projectRoot: string): string {
275
323
  return path.join(root, ".ttsc", "plugins");
276
324
  }
277
325
 
278
- export function pluginCacheCleanupTargets(projectRoot: string): string[] {
279
- const root = path.resolve(projectRoot);
280
- const targets = [
281
- path.join(root, "node_modules", ".ttsc"),
282
- path.join(root, ".ttsc"),
283
- ];
284
- if (process.env.TTSC_CACHE_DIR) {
285
- targets.push(path.resolve(process.env.TTSC_CACHE_DIR, "plugins"));
286
- }
287
- return [...new Set(targets)];
288
- }
289
-
290
326
  function isDirectory(candidate: string): boolean {
291
327
  try {
292
328
  return fs.statSync(candidate).isDirectory();
@@ -295,61 +331,40 @@ function isDirectory(candidate: string): boolean {
295
331
  }
296
332
  }
297
333
 
298
- function resolveGoBinary(): string {
299
- return resolveGoCompiler();
300
- }
301
-
302
- export function resolveGoCompiler(
303
- opts: ITtscResolveGoBinaryOptions = {},
304
- ): string {
305
- const env = opts.env ?? process.env;
306
- const explicit = env.TTSC_GO_BINARY;
334
+ function resolveGoCompiler(): string {
335
+ const explicit = process.env.TTSC_GO_BINARY;
307
336
  if (explicit && explicit.length > 0) return explicit;
308
337
 
309
- const resolver =
310
- opts.resolver ??
311
- ((request: string) => createRequire(__filename).resolve(request));
312
338
  try {
313
- return resolver(bundledGoPackageRequest(opts));
339
+ return createRequire(__filename).resolve(
340
+ `@ttsc/${process.platform}-${process.arch}/bin/go/bin/${process.platform === "win32" ? "go.exe" : "go"}`,
341
+ );
314
342
  } catch {
315
343
  /* fall through */
316
344
  }
317
345
 
318
- if (opts.localGoLookup) {
319
- const local = opts.localGoLookup();
320
- if (local) return local;
321
- } else {
322
- const local = defaultLocalGoBinaryPath(opts);
323
- if (local) return local;
324
- }
325
-
326
- return "go";
327
- }
328
-
329
- function defaultLocalGoBinaryPath(opts: ITtscResolveGoBinaryOptions): string | null {
330
- const candidate = path.resolve(
346
+ const local = path.resolve(
331
347
  __dirname,
332
348
  "..",
349
+ "..",
350
+ "..",
351
+ "..",
333
352
  "native",
334
353
  "go",
335
354
  "bin",
336
- goBinaryName(opts),
355
+ process.platform === "win32" ? "go.exe" : "go",
337
356
  );
338
- return fs.existsSync(candidate) ? candidate : null;
339
- }
357
+ if (fs.existsSync(local)) return local;
340
358
 
341
- function goPlatformKey(opts: ITtscResolveGoBinaryOptions = {}): string {
342
- return `${opts.platform ?? process.platform}-${opts.arch ?? process.arch}`;
359
+ return "go";
343
360
  }
344
361
 
345
- interface ITtscSourceBuildCacheKeyInput {
362
+ function computeCacheKey(inputs: {
346
363
  dir: string;
347
364
  entry: string;
348
365
  ttscVersion: string;
349
366
  tsgoVersion: string;
350
- }
351
-
352
- export function computeCacheKey(inputs: ITtscSourceBuildCacheKeyInput): string {
367
+ }): string {
353
368
  const hash = crypto.createHash("sha256");
354
369
  hash.update(`ttsc=${inputs.ttscVersion}\n`);
355
370
  hash.update(`tsgo=${inputs.tsgoVersion}\n`);
@@ -363,23 +378,14 @@ export function computeCacheKey(inputs: ITtscSourceBuildCacheKeyInput): string {
363
378
  return hash.digest("hex").slice(0, 32);
364
379
  }
365
380
 
366
- const SKIP_DIRS = new Set([
367
- "node_modules",
368
- ".git",
369
- "dist",
370
- "build",
371
- "vendor",
372
- "lib",
373
- ]);
374
-
375
381
  function collectSourceFiles(root: string): string[] {
376
382
  const out: string[] = [];
377
- walk(root, root, out);
383
+ walk(root, out);
378
384
  out.sort();
379
385
  return out;
380
386
  }
381
387
 
382
- function walk(root: string, dir: string, out: string[]): void {
388
+ function walk(dir: string, out: string[]): void {
383
389
  let entries: fs.Dirent[];
384
390
  try {
385
391
  entries = fs.readdirSync(dir, { withFileTypes: true });
@@ -390,7 +396,7 @@ function walk(root: string, dir: string, out: string[]): void {
390
396
  if (SKIP_DIRS.has(entry.name)) continue;
391
397
  const full = path.join(dir, entry.name);
392
398
  if (entry.isDirectory()) {
393
- walk(root, full, out);
399
+ walk(full, out);
394
400
  continue;
395
401
  }
396
402
  if (!entry.isFile()) continue;
@@ -0,0 +1,214 @@
1
+ import { createRequire } from "node:module";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+
5
+ import { readProjectConfig } from "../../compiler/internal/project/readProjectConfig";
6
+ import type { ITtscPlugin } from "../../structures/ITtscPlugin";
7
+ import type { ITtscPluginFactoryContext } from "../../structures/ITtscPluginFactoryContext";
8
+ import type { ITtscProjectPluginConfig } from "../../structures/ITtscProjectPluginConfig";
9
+ import type { TtscPluginStage } from "../../structures/TtscPluginStage";
10
+ import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
11
+ import type { ITtscParsedProjectConfig } from "../../structures/internal/ITtscParsedProjectConfig";
12
+ import { buildSourcePlugin } from "./buildSourcePlugin";
13
+
14
+ type TtscPluginFactory<T = ITtscProjectPluginConfig> = (
15
+ context: ITtscPluginFactoryContext<T>,
16
+ ) => ITtscPlugin;
17
+
18
+ export function loadProjectPlugins(options: {
19
+ binary: string;
20
+ cacheDir?: string;
21
+ cwd?: string;
22
+ entries?: readonly ITtscProjectPluginConfig[] | false;
23
+ file?: string;
24
+ tsconfig?: string;
25
+ }): {
26
+ nativePlugins: ITtscLoadedNativePlugin[];
27
+ project: ITtscParsedProjectConfig;
28
+ } {
29
+ const project = readProjectConfig({
30
+ cwd: options.cwd,
31
+ file: options.file,
32
+ tsconfig: options.tsconfig,
33
+ });
34
+ const entries =
35
+ options.entries === false
36
+ ? []
37
+ : [...(options.entries ?? project.compilerOptions.plugins)].filter(
38
+ (entry) => entry.enabled !== false,
39
+ );
40
+ if (entries.length === 0) {
41
+ return {
42
+ nativePlugins: [],
43
+ project,
44
+ };
45
+ }
46
+
47
+ const context = {
48
+ binary: options.binary,
49
+ cwd: path.resolve(options.cwd ?? process.cwd()),
50
+ projectRoot: project.root,
51
+ tsconfig: project.path,
52
+ };
53
+ const plugins = entries.map((entry) =>
54
+ loadPluginEntry(entry, { ...context, plugin: entry }),
55
+ );
56
+
57
+ const nativePlugins: ITtscLoadedNativePlugin[] = [];
58
+ const ttscVersion = readTtscVersion();
59
+ const tsgoVersion = readTsgoVersion(context.projectRoot);
60
+ plugins.forEach((plugin, index) => {
61
+ validatePluginSource(plugin);
62
+ const binary = buildSourcePlugin({
63
+ baseDir: context.projectRoot,
64
+ cacheDir: options.cacheDir,
65
+ pluginName: plugin.name,
66
+ source: plugin.source,
67
+ ttscVersion,
68
+ tsgoVersion,
69
+ });
70
+ nativePlugins.push({
71
+ binary,
72
+ config: entries[index]!,
73
+ name: plugin.name,
74
+ stage: resolvePluginStage(plugin),
75
+ });
76
+ });
77
+ return {
78
+ nativePlugins,
79
+ project,
80
+ };
81
+ }
82
+
83
+ function loadPluginEntry(
84
+ entry: ITtscProjectPluginConfig,
85
+ context: ITtscPluginFactoryContext,
86
+ ): ITtscPlugin {
87
+ const specifier = entry.transform;
88
+ if (typeof specifier !== "string" || specifier.length === 0) {
89
+ throw new Error(`ttsc: plugin entry is missing a string "transform" field`);
90
+ }
91
+
92
+ const request = resolvePluginRequest(specifier, context.projectRoot);
93
+ const mod = require(request) as {
94
+ createTtscPlugin?: TtscPluginFactory;
95
+ default?: ITtscPlugin | TtscPluginFactory;
96
+ } & Partial<Record<"plugin", ITtscPlugin | TtscPluginFactory>>;
97
+ const candidate =
98
+ mod.createTtscPlugin ??
99
+ mod.default ??
100
+ mod.plugin ??
101
+ (mod as unknown as ITtscPlugin | TtscPluginFactory);
102
+ if (typeof candidate === "function") {
103
+ const plugin = candidate(context);
104
+ if (!isTtscPlugin(plugin)) {
105
+ throw new Error(
106
+ `ttsc: plugin "${specifier}" does not export a valid ttsc plugin`,
107
+ );
108
+ }
109
+ rejectJsTransformHooks(specifier, plugin);
110
+ return plugin;
111
+ }
112
+ if (isTtscPlugin(candidate)) {
113
+ rejectJsTransformHooks(specifier, candidate);
114
+ return candidate;
115
+ }
116
+ throw new Error(
117
+ `ttsc: plugin "${specifier}" does not export a valid ttsc plugin`,
118
+ );
119
+ }
120
+
121
+ function isTtscPlugin(value: unknown): value is ITtscPlugin {
122
+ return (
123
+ typeof value === "object" &&
124
+ value !== null &&
125
+ typeof (value as { name?: unknown }).name === "string"
126
+ );
127
+ }
128
+
129
+ function rejectJsTransformHooks(specifier: string, candidate: object): void {
130
+ if ("transformSource" in candidate || "transformOutput" in candidate) {
131
+ throw new Error(
132
+ `ttsc: plugin "${specifier}" declares unsupported JS transform hooks; ` +
133
+ "declare a native backend instead",
134
+ );
135
+ }
136
+ }
137
+
138
+ function resolvePluginStage(plugin: ITtscPlugin): TtscPluginStage {
139
+ if (plugin.stage === undefined) {
140
+ return "transform";
141
+ }
142
+ if (!isPluginStage(plugin.stage)) {
143
+ throw new Error(
144
+ `ttsc: plugin "${plugin.name}" requested unsupported stage ${JSON.stringify(plugin.stage)}`,
145
+ );
146
+ }
147
+ return plugin.stage;
148
+ }
149
+
150
+ function validatePluginSource(plugin: ITtscPlugin): void {
151
+ if (typeof plugin.source !== "string" || plugin.source.length === 0) {
152
+ throw new Error(`ttsc: plugin "${plugin.name}" must declare source`);
153
+ }
154
+ }
155
+
156
+ function isPluginStage(value: string): value is TtscPluginStage {
157
+ return value === "transform" || value === "check" || value === "output";
158
+ }
159
+
160
+ function resolvePluginRequest(specifier: string, projectRoot: string): string {
161
+ if (path.isAbsolute(specifier)) {
162
+ return specifier;
163
+ }
164
+ if (isRelativePluginSpecifier(specifier)) {
165
+ return path.resolve(projectRoot, specifier);
166
+ }
167
+ return require.resolve(specifier, { paths: [projectRoot] });
168
+ }
169
+
170
+ function isRelativePluginSpecifier(specifier: string): boolean {
171
+ return (
172
+ specifier === "." ||
173
+ specifier === ".." ||
174
+ specifier.startsWith("./") ||
175
+ specifier.startsWith("../") ||
176
+ specifier.startsWith(".\\") ||
177
+ specifier.startsWith("..\\")
178
+ );
179
+ }
180
+
181
+ let cachedTtscVersion: string | null = null;
182
+
183
+ function readTtscVersion(): string {
184
+ if (cachedTtscVersion !== null) {
185
+ return cachedTtscVersion;
186
+ }
187
+ try {
188
+ const file = path.resolve(__dirname, "..", "..", "..", "package.json");
189
+ const pkg = JSON.parse(fs.readFileSync(file, "utf8")) as {
190
+ version?: string;
191
+ };
192
+ cachedTtscVersion = pkg.version ?? "0.0.0";
193
+ } catch {
194
+ cachedTtscVersion = "0.0.0";
195
+ }
196
+ return cachedTtscVersion;
197
+ }
198
+
199
+ function readTsgoVersion(projectRoot: string): string {
200
+ try {
201
+ const projectRequire = createRequire(
202
+ path.join(projectRoot, "package.json"),
203
+ );
204
+ const pkgPath = projectRequire.resolve(
205
+ "@typescript/native-preview/package.json",
206
+ );
207
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8")) as {
208
+ version?: string;
209
+ };
210
+ return pkg.version ?? "unknown";
211
+ } catch {
212
+ return "unknown";
213
+ }
214
+ }
@@ -0,0 +1,84 @@
1
+ import type { ITtscProjectPluginConfig } from "./ITtscProjectPluginConfig";
2
+
3
+ /**
4
+ * Constructor context for {@link TtscCompiler}.
5
+ *
6
+ * Represents the project environment owned by a programmatic ttsc compiler
7
+ * instance. The context is fixed when the class is constructed: compile,
8
+ * prepare, and clean operations all use the same working directory, project
9
+ * config, native toolchain, environment, cache root, and plugin list.
10
+ *
11
+ * Keeping this context immutable prevents one `TtscCompiler` object from
12
+ * silently compiling different projects across calls. Create another compiler
13
+ * instance when any of these fields must change.
14
+ *
15
+ * @author Jeongho Nam - https://github.com/samchon
16
+ */
17
+ export interface ITtscCompilerContext {
18
+ /**
19
+ * The working directory for this compiler instance.
20
+ *
21
+ * Used to discover `tsconfig.json`, resolve relative `tsconfig` paths,
22
+ * resolve project source files, resolve plugin packages, and resolve relative
23
+ * cache paths.
24
+ *
25
+ * @default process.cwd()
26
+ */
27
+ cwd?: string;
28
+
29
+ /**
30
+ * The project configuration file for this compiler instance.
31
+ *
32
+ * Relative paths are resolved from {@link ITtscCompilerContext.cwd}. When this
33
+ * field is omitted, ttsc discovers the nearest owning `tsconfig.json` or
34
+ * `jsconfig.json` from the working directory.
35
+ */
36
+ tsconfig?: string;
37
+
38
+ /**
39
+ * Explicit TypeScript-Go executable for controlled embedding.
40
+ *
41
+ * Normal consumers should leave this unset. ttsc resolves the installed or
42
+ * bundled toolchain needed for each compile path. This field is intended for
43
+ * tests, pinned toolchains, and embedding environments that need plugin or
44
+ * CLI-compatible paths to use a specific TypeScript-Go binary.
45
+ *
46
+ * The no-plugin in-memory API path is hosted by ttsc's native compiler host
47
+ * so it can return structured diagnostics and output. Plugin-backed paths
48
+ * pass this binary through to the TypeScript-Go execution layer.
49
+ */
50
+ binary?: string;
51
+
52
+ /**
53
+ * Additional environment variables for child compiler processes.
54
+ *
55
+ * Values are merged over `process.env` before ttsc starts TypeScript-Go,
56
+ * native plugin binaries, or the native compiler host used by
57
+ * {@link TtscCompiler.compile}.
58
+ */
59
+ env?: NodeJS.ProcessEnv;
60
+
61
+ /**
62
+ * Root directory for compiled ttsc artifacts.
63
+ *
64
+ * Relative paths are resolved from {@link ITtscCompilerContext.cwd}. When
65
+ * omitted, ttsc uses its normal cache location: `TTSC_CACHE_DIR` when
66
+ * present, otherwise `node_modules/.ttsc` or `.ttsc` under the project root.
67
+ *
68
+ * The same cache stores source-plugin binaries and the lazily built native
69
+ * compiler host used for in-memory API compilation.
70
+ */
71
+ cacheDir?: string;
72
+
73
+ /**
74
+ * Plugin entries for this compiler instance.
75
+ *
76
+ * - `undefined`: read `compilerOptions.plugins` from the project config.
77
+ * - `false`: ignore project plugins for this compiler instance.
78
+ * - array: use these plugin entries instead of the project config entries.
79
+ *
80
+ * Plugin entries are resolved once per operation from this instance context.
81
+ * Per-call plugin overrides are intentionally not part of the public API.
82
+ */
83
+ plugins?: readonly ITtscProjectPluginConfig[] | false;
84
+ }