ttsc 0.8.0 → 0.9.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 (84) hide show
  1. package/README.md +75 -66
  2. package/cmd/ttsc/api_compile.go +5 -1
  3. package/driver/program.go +23 -1
  4. package/driver/rewrite.go +126 -9
  5. package/driver/rewrite_test.go +52 -0
  6. package/lib/TtscCompiler.js +28 -46
  7. package/lib/TtscCompiler.js.map +1 -1
  8. package/lib/compiler/internal/buildNativeCompiler.js +8 -38
  9. package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
  10. package/lib/compiler/internal/compileProjectInMemory.js +36 -63
  11. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  12. package/lib/compiler/internal/project/readProjectConfig.js +108 -60
  13. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
  14. package/lib/compiler/internal/project/resolveProjectConfig.js +15 -45
  15. package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
  16. package/lib/compiler/internal/resolveBinary.js +10 -40
  17. package/lib/compiler/internal/resolveBinary.js.map +1 -1
  18. package/lib/compiler/internal/resolveEmittedJavaScript.js +21 -48
  19. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  20. package/lib/compiler/internal/resolveTsgo.js +14 -44
  21. package/lib/compiler/internal/resolveTsgo.js.map +1 -1
  22. package/lib/compiler/internal/runBuild.d.ts +7 -0
  23. package/lib/compiler/internal/runBuild.js +47 -66
  24. package/lib/compiler/internal/runBuild.js.map +1 -1
  25. package/lib/compiler/internal/runSingleFileEmit.js +18 -48
  26. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  27. package/lib/compiler/internal/transformProjectInMemory.js +41 -75
  28. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  29. package/lib/launcher/internal/getCompilerVersionText.js +7 -37
  30. package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
  31. package/lib/launcher/internal/prepareExecution.js +48 -69
  32. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  33. package/lib/launcher/internal/runTtsc.js +53 -64
  34. package/lib/launcher/internal/runTtsc.js.map +1 -1
  35. package/lib/launcher/internal/runTtsx.js +328 -57
  36. package/lib/launcher/internal/runTtsx.js.map +1 -1
  37. package/lib/plugin/internal/buildSourcePlugin.d.ts +8 -0
  38. package/lib/plugin/internal/buildSourcePlugin.js +179 -125
  39. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  40. package/lib/plugin/internal/loadProjectPlugins.d.ts +2 -0
  41. package/lib/plugin/internal/loadProjectPlugins.js +197 -9
  42. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  43. package/lib/structures/ITtscCompilerContext.d.ts +16 -3
  44. package/lib/structures/ITtscCompilerResult.d.ts +4 -0
  45. package/lib/structures/ITtscCompilerTransformation.d.ts +2 -0
  46. package/lib/structures/ITtscPluginFactoryContext.d.ts +6 -3
  47. package/lib/structures/ITtscProjectPluginConfig.d.ts +8 -7
  48. package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +2 -0
  49. package/lib/structures/internal/ITtscProjectLocatorOptions.d.ts +2 -0
  50. package/lib/structures/internal/TtscCommonOptions.d.ts +2 -0
  51. package/package.json +9 -14
  52. package/shim/diagnosticwriter/lint.go +8 -0
  53. package/src/TtscCompiler.ts +20 -5
  54. package/src/compiler/internal/buildNativeCompiler.ts +2 -2
  55. package/src/compiler/internal/compileProjectInMemory.ts +21 -16
  56. package/src/compiler/internal/project/readProjectConfig.ts +134 -35
  57. package/src/compiler/internal/project/resolveProjectConfig.ts +2 -2
  58. package/src/compiler/internal/resolveBinary.ts +2 -2
  59. package/src/compiler/internal/resolveEmittedJavaScript.ts +11 -7
  60. package/src/compiler/internal/resolveTsgo.ts +2 -2
  61. package/src/compiler/internal/runBuild.ts +34 -21
  62. package/src/compiler/internal/runSingleFileEmit.ts +3 -3
  63. package/src/compiler/internal/transformProjectInMemory.ts +37 -37
  64. package/src/launcher/internal/getCompilerVersionText.ts +2 -2
  65. package/src/launcher/internal/prepareExecution.ts +14 -4
  66. package/src/launcher/internal/runTtsc.ts +30 -4
  67. package/src/launcher/internal/runTtsx.ts +377 -26
  68. package/src/plugin/internal/buildSourcePlugin.ts +127 -32
  69. package/src/plugin/internal/loadProjectPlugins.ts +266 -10
  70. package/src/structures/ITtscCompilerContext.ts +17 -3
  71. package/src/structures/ITtscCompilerResult.ts +5 -0
  72. package/src/structures/ITtscCompilerTransformation.ts +3 -0
  73. package/src/structures/ITtscPluginFactoryContext.ts +6 -3
  74. package/src/structures/ITtscProjectPluginConfig.ts +8 -7
  75. package/src/structures/internal/ITtscParsedProjectConfig.ts +2 -0
  76. package/src/structures/internal/ITtscProjectLocatorOptions.ts +2 -0
  77. package/src/structures/internal/TtscCommonOptions.ts +2 -0
  78. package/utility/host.go +610 -18
  79. package/utility/host_test.go +162 -0
  80. package/test/compiler.test.ts +0 -422
  81. package/test/platform.test.ts +0 -12
  82. package/test/project.test.ts +0 -197
  83. package/test/source-build.test.ts +0 -45
  84. package/test/tsgo.test.ts +0 -69
@@ -0,0 +1,162 @@
1
+ package utility
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+ )
9
+
10
+ func TestFilterHostArgsKeepsUtilityFlagsAndDropsHostOnlyFlags(t *testing.T) {
11
+ got := filterHostArgs([]string{
12
+ "--cwd", "/workspace/project",
13
+ "--cache-dir", ".ttsc",
14
+ "--emit",
15
+ "--binary=/tmp/tsgo",
16
+ "--plugins-json", "[]",
17
+ "src/main.ts",
18
+ "--",
19
+ "--cwd", "ignored",
20
+ })
21
+ want := []string{
22
+ "--cwd", "/workspace/project",
23
+ "--emit",
24
+ "--plugins-json", "[]",
25
+ "src/main.ts",
26
+ }
27
+ if !equalStringSlices(got, want) {
28
+ t.Fatalf("filtered args mismatch:\nwant: %#v\n got: %#v", want, got)
29
+ }
30
+ }
31
+
32
+ func TestParseBannerFormatsAndSanitizesJSDoc(t *testing.T) {
33
+ banner, err := parseBanner(map[string]any{
34
+ "text": "first\r\nsecond */\n\n",
35
+ }, t.TempDir(), "tsconfig.json")
36
+ if err != nil {
37
+ t.Fatal(err)
38
+ }
39
+ if !strings.Contains(banner, " * first\n * second * /\n") {
40
+ t.Fatalf("banner was not normalized and sanitized:\n%s", banner)
41
+ }
42
+ if strings.Contains(banner, "second */") {
43
+ t.Fatalf("banner must not preserve raw JSDoc terminator:\n%s", banner)
44
+ }
45
+ if !strings.HasSuffix(banner, "*/\n") {
46
+ t.Fatalf("banner must end with a closed JSDoc block:\n%s", banner)
47
+ }
48
+ }
49
+
50
+ func TestFindBannerConfigFileUsesTsconfigDirectoryWhenOutsideCwd(t *testing.T) {
51
+ cwd := seedHostTestProject(t, map[string]string{
52
+ "banner.config.cjs": `module.exports = { text: "cwd banner" };` + "\n",
53
+ })
54
+ wrapper := seedHostTestProject(t, map[string]string{
55
+ "banner.config.cjs": `module.exports = { text: "wrapper banner" };` + "\n",
56
+ "tsconfig.json": "{}",
57
+ })
58
+
59
+ discovered, err := findBannerConfigFile(cwd, filepath.Join(wrapper, "tsconfig.json"))
60
+ if err != nil {
61
+ t.Fatalf("findBannerConfigFile: %v", err)
62
+ }
63
+ if discovered != filepath.Join(wrapper, "banner.config.cjs") {
64
+ t.Fatalf("unexpected discovery path: %s", discovered)
65
+ }
66
+ }
67
+
68
+ func TestResolveBannerTextRejectsEmptyObjectText(t *testing.T) {
69
+ _, err := resolveBannerText(map[string]any{
70
+ "text": " ",
71
+ }, t.TempDir(), "tsconfig.json")
72
+ if err == nil || !strings.Contains(err.Error(), "non-empty string") {
73
+ t.Fatalf("expected non-empty string error, got %v", err)
74
+ }
75
+ }
76
+
77
+ func TestPathsRewriterResolvesIndexAndModuleExtensions(t *testing.T) {
78
+ root := normalizePath(t.TempDir())
79
+ source := normalizePath(filepath.Join(root, "src", "consumer", "main.ts"))
80
+ index := normalizePath(filepath.Join(root, "src", "modules", "index.ts"))
81
+ module := normalizePath(filepath.Join(root, "src", "modules", "esm.mts"))
82
+ rewriter := &pathsRewriter{
83
+ basePath: root,
84
+ outDir: normalizePath(filepath.Join(root, "dist")),
85
+ rootDir: normalizePath(filepath.Join(root, "src")),
86
+ patterns: []pathsPattern{
87
+ {pattern: "@lib/*", targets: []string{"src/modules/*"}},
88
+ },
89
+ sourceFiles: map[string]string{
90
+ index: index,
91
+ stripKnownSourceExtension(index): index,
92
+ module: module,
93
+ stripKnownSourceExtension(module): module,
94
+ },
95
+ }
96
+
97
+ rewritten, ok := rewriter.rewrite(source, "@lib")
98
+ if ok || rewritten != "@lib" {
99
+ t.Fatalf("non-matching pattern should stay unchanged, got %q ok=%v", rewritten, ok)
100
+ }
101
+
102
+ rewritten, ok = rewriter.rewrite(source, "@lib/index")
103
+ if !ok || rewritten != "../modules/index.js" {
104
+ t.Fatalf("index rewrite mismatch: %q ok=%v", rewritten, ok)
105
+ }
106
+
107
+ rewritten, ok = rewriter.rewrite(source, "@lib/esm")
108
+ if !ok || rewritten != "../modules/esm.mjs" {
109
+ t.Fatalf("module extension rewrite mismatch: %q ok=%v", rewritten, ok)
110
+ }
111
+ }
112
+
113
+ func TestStripConfigurationDefaultsAndValidation(t *testing.T) {
114
+ strip, err := parseStrip(map[string]any{})
115
+ if err != nil {
116
+ t.Fatal(err)
117
+ }
118
+ if !strip.stripDebugger || !strip.matchesCall("console.log") || !strip.matchesCall("assert.equal") {
119
+ t.Fatalf("default strip config did not enable expected patterns: %#v", strip)
120
+ }
121
+ if strip.matchesCall("console.info") || strip.matchesCall("assert") {
122
+ t.Fatalf("default strip config matched too broadly")
123
+ }
124
+
125
+ if _, err := parseStrip(map[string]any{"statements": []any{"debugger", "with"}}); err == nil {
126
+ t.Fatal("unsupported statement pattern must fail")
127
+ }
128
+ if _, err := parseCallPattern("assert.*.deep"); err == nil {
129
+ t.Fatal("middle wildcard call pattern must fail")
130
+ }
131
+ }
132
+
133
+ func TestSourceExtensionHelpersPreferCompoundExtensions(t *testing.T) {
134
+ cases := map[string]string{
135
+ "types.d.ts": "types",
136
+ "types.d.mts": "types",
137
+ "module.test.ts": "module.test",
138
+ "entry.jsx": "entry",
139
+ }
140
+ for input, want := range cases {
141
+ t.Run(input, func(t *testing.T) {
142
+ if got := stripKnownSourceExtension(input); got != want {
143
+ t.Fatalf("stripKnownSourceExtension(%q) = %q, want %q", input, got, want)
144
+ }
145
+ })
146
+ }
147
+ }
148
+
149
+ func seedHostTestProject(t *testing.T, files map[string]string) string {
150
+ t.Helper()
151
+ root := t.TempDir()
152
+ for name, text := range files {
153
+ file := filepath.Join(root, filepath.FromSlash(name))
154
+ if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil {
155
+ t.Fatal(err)
156
+ }
157
+ if err := os.WriteFile(file, []byte(text), 0o644); err != nil {
158
+ t.Fatal(err)
159
+ }
160
+ }
161
+ return root
162
+ }
@@ -1,422 +0,0 @@
1
- const assert = require("node:assert/strict");
2
- const fs = require("node:fs");
3
- const os = require("node:os");
4
- const path = require("node:path");
5
- const test = require("node:test");
6
-
7
- const { TtscCompiler } = require("../lib/index.js");
8
- const { resolveTsgo } = require("../lib/compiler/internal/resolveTsgo.js");
9
- const tsgo = resolveTsgo({ cwd: path.resolve(__dirname, "..") }).binary;
10
-
11
- test("TtscCompiler.compile returns output without writing project files", () => {
12
- const root = createProject();
13
- const compiler = new TtscCompiler({
14
- binary: tsgo,
15
- cwd: root,
16
- plugins: false,
17
- });
18
-
19
- const result = compiler.compile();
20
-
21
- assert.equal(result.type, "success");
22
- assert.match(result.output["dist/main.js"], /api-ok/);
23
- assert.match(result.output["dist/main.js"], /console\.log\(\s*message\s*\)/);
24
- assert.match(result.output["dist/main.d.ts"], /declare const message/);
25
- assert.match(result.output["dist/main.js.map"], /"version":3/);
26
- assert.match(result.output["dist/main.d.ts.map"], /"version":3/);
27
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
28
- });
29
-
30
- test("TtscCompiler can disable project plugin loading", () => {
31
- const root = createProject({
32
- plugins: [{ transform: "./missing-plugin.cjs" }],
33
- });
34
- const compiler = new TtscCompiler({
35
- binary: tsgo,
36
- cwd: root,
37
- plugins: false,
38
- });
39
-
40
- const result = compiler.compile();
41
-
42
- assert.equal(result.type, "success");
43
- });
44
-
45
- test("TtscCompiler.compile applies configured source plugins without project output", () => {
46
- const root = createProject({
47
- plugins: [{ transform: "./plugin.cjs" }],
48
- source: 'export const value = goUpper("plugin");\nconsole.log(value);\n',
49
- });
50
- writeCompilerPlugin(root);
51
- const compiler = new TtscCompiler({ binary: tsgo, cwd: root });
52
-
53
- const result = compiler.compile();
54
-
55
- assert.equal(result.type, "success");
56
- assert.match(result.output["dist/main.js"], /PLUGIN/);
57
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
58
- });
59
-
60
- test("TtscCompiler.transform returns TypeScript source without project files", () => {
61
- const root = createProject();
62
- const compiler = new TtscCompiler({
63
- binary: tsgo,
64
- cwd: root,
65
- plugins: false,
66
- });
67
-
68
- const result = compiler.transform();
69
-
70
- assert.equal(result.type, "success");
71
- assert.match(
72
- result.typescript["src/main.ts"],
73
- /const message: string = "api-ok"/,
74
- );
75
- assert.match(
76
- result.typescript["src/main.ts"],
77
- /console\.log\(\s*message\s*\)/,
78
- );
79
- assert.equal(result.typescript["dist/main.js"], undefined);
80
- assert.equal(result.typescript["dist/main.d.ts"], undefined);
81
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
82
- });
83
-
84
- test("TtscCompiler.transform returns every included TypeScript source file", () => {
85
- const root = createProject({
86
- files: {
87
- "src/helpers.ts":
88
- "export const helper = (value: string): string => value.toUpperCase();\n",
89
- "src/nested/model.ts": "export interface Model { value: string }\n",
90
- },
91
- source:
92
- 'import { helper } from "./helpers";\nconst message: string = helper("api-ok");\nconsole.log(message);\n',
93
- });
94
- const compiler = new TtscCompiler({
95
- binary: tsgo,
96
- cwd: root,
97
- plugins: false,
98
- });
99
-
100
- const result = compiler.transform();
101
-
102
- assert.equal(result.type, "success");
103
- assert.match(result.typescript["src/main.ts"], /helper\("api-ok"\)/);
104
- assert.match(result.typescript["src/helpers.ts"], /toUpperCase/);
105
- assert.match(result.typescript["src/nested/model.ts"], /interface Model/);
106
- for (const key of Object.keys(result.typescript)) {
107
- assert.equal(key.startsWith("dist/"), false);
108
- assert.equal(/\.(?:js|cjs|mjs|d\.ts|map)$/.test(key), false);
109
- }
110
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
111
- });
112
-
113
- test("TtscCompiler.transform applies configured source plugins to TypeScript output", () => {
114
- const root = createProject({
115
- plugins: [{ transform: "./plugin.cjs" }],
116
- source: 'export const value = goUpper("plugin");\nconsole.log(value);\n',
117
- });
118
- writeCompilerPlugin(root);
119
- const compiler = new TtscCompiler({ binary: tsgo, cwd: root });
120
-
121
- const result = compiler.transform();
122
-
123
- assert.equal(result.type, "success");
124
- assert.match(
125
- result.typescript["src/main.ts"],
126
- /export const value = "PLUGIN"/,
127
- );
128
- assert.match(result.typescript["src/main.ts"], /console\.log\(value\)/);
129
- assert.equal(result.typescript["dist/main.js"], undefined);
130
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
131
- });
132
-
133
- test("TtscCompiler.transform rejects plugin output that is not TypeScript source", () => {
134
- const root = createProject({
135
- plugins: [{ transform: "./plugin.cjs" }],
136
- source: 'export const value = goUpper("plugin");\nconsole.log(value);\n',
137
- });
138
- writeBrokenTransformPlugin(root);
139
- const compiler = new TtscCompiler({ binary: tsgo, cwd: root });
140
-
141
- const result = compiler.transform();
142
-
143
- assert.equal(result.type, "exception");
144
- assert.match(result.error.message, /did not return a TypeScript source map/);
145
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
146
- });
147
-
148
- test("TtscCompiler.transform returns failure on compiler diagnostics", () => {
149
- const root = createProject({
150
- source: 'const value: number = "not-a-number";\nconsole.log(value);\n',
151
- });
152
- const compiler = new TtscCompiler({
153
- binary: tsgo,
154
- cwd: root,
155
- plugins: false,
156
- });
157
-
158
- const result = compiler.transform();
159
-
160
- assert.equal(result.type, "failure");
161
- assert.equal(result.diagnostics[0].code, 2322);
162
- assert.match(result.typescript["src/main.ts"], /not-a-number/);
163
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
164
- });
165
-
166
- test("TtscCompiler.compile returns structured diagnostics", () => {
167
- const root = createProject({
168
- source: 'const value: number = "not-a-number";\nconsole.log(value);\n',
169
- });
170
- const compiler = new TtscCompiler({
171
- binary: tsgo,
172
- cwd: root,
173
- plugins: false,
174
- });
175
-
176
- const result = compiler.compile();
177
-
178
- assert.equal(result.type, "failure");
179
- assert.equal(result.diagnostics.length, 1);
180
- assert.equal(result.diagnostics[0].category, "error");
181
- assert.equal(result.diagnostics[0].code, 2322);
182
- assert.equal(typeof result.diagnostics[0].start, "number");
183
- assert.equal(typeof result.diagnostics[0].length, "number");
184
- assert.equal(result.diagnostics[0].line, 1);
185
- assert.equal(result.diagnostics[0].character, 7);
186
- assert.equal(result.diagnostics[0].file.endsWith("src/main.ts"), true);
187
- assert.match(result.diagnostics[0].messageText, /not assignable/);
188
- assert.equal(typeof result.output, "object");
189
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
190
- });
191
-
192
- test("TtscCompiler.compile does not accept per-call context overrides", () => {
193
- const root = createProject();
194
- const other = createProject({
195
- plugins: [{ transform: "./missing-plugin.cjs" }],
196
- });
197
- const compiler = new TtscCompiler({
198
- binary: tsgo,
199
- cwd: root,
200
- plugins: false,
201
- });
202
-
203
- const result = compiler.compile({
204
- binary: path.join(other, "missing-tsgo"),
205
- cwd: other,
206
- plugins: [{ transform: "./missing-plugin.cjs" }],
207
- });
208
-
209
- assert.equal(result.type, "success");
210
- assert.match(result.output["dist/main.js"], /api-ok/);
211
- assert.equal(fs.existsSync(path.join(root, "dist")), false);
212
- assert.equal(fs.existsSync(path.join(other, "dist")), false);
213
- });
214
-
215
- test("TtscCompiler.prepare builds source plugins and clean removes context cache", () => {
216
- const root = createProject({
217
- plugins: [{ transform: "./plugin.cjs" }],
218
- });
219
- writeSourcePlugin(root);
220
- const cacheDir = path.join(root, ".cache", "ttsc");
221
- const compiler = new TtscCompiler({ binary: tsgo, cacheDir, cwd: root });
222
-
223
- const prepared = compiler.prepare();
224
-
225
- assert.equal(prepared.length, 1);
226
- assert.equal(fs.existsSync(prepared[0]), true);
227
- assert.equal(prepared[0].startsWith(path.join(cacheDir, "plugins")), true);
228
-
229
- const removed = compiler.clean();
230
-
231
- assert.deepEqual(removed, [cacheDir]);
232
- assert.equal(fs.existsSync(cacheDir), false);
233
- });
234
-
235
- function createProject(options = {}) {
236
- const root = fs.mkdtempSync(path.join(os.tmpdir(), "ttsc-compiler-api-"));
237
- fs.mkdirSync(path.join(root, "src"), { recursive: true });
238
- fs.writeFileSync(
239
- path.join(root, "src", "main.ts"),
240
- options.source ??
241
- 'const message: string = "api-ok";\nconsole.log(message);\n',
242
- "utf8",
243
- );
244
- for (const [file, content] of Object.entries(options.files ?? {})) {
245
- const location = path.join(root, file);
246
- fs.mkdirSync(path.dirname(location), { recursive: true });
247
- fs.writeFileSync(location, content, "utf8");
248
- }
249
- fs.writeFileSync(
250
- path.join(root, "tsconfig.json"),
251
- JSON.stringify(
252
- {
253
- compilerOptions: {
254
- target: "ES2022",
255
- module: "commonjs",
256
- strict: true,
257
- outDir: "dist",
258
- declaration: true,
259
- declarationMap: true,
260
- rootDir: "src",
261
- sourceMap: true,
262
- plugins: options.plugins,
263
- },
264
- include: ["src"],
265
- },
266
- null,
267
- 2,
268
- ),
269
- "utf8",
270
- );
271
- return root;
272
- }
273
-
274
- function writeSourcePlugin(root) {
275
- fs.writeFileSync(
276
- path.join(root, "plugin.cjs"),
277
- 'module.exports = { name: "prepare-fixture", source: "./plugin-go" };\n',
278
- "utf8",
279
- );
280
- fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
281
- fs.writeFileSync(
282
- path.join(root, "plugin-go", "go.mod"),
283
- "module example.com/preparefixture\n\ngo 1.26\n",
284
- "utf8",
285
- );
286
- fs.writeFileSync(
287
- path.join(root, "plugin-go", "main.go"),
288
- "package main\n\nfunc main() {}\n",
289
- "utf8",
290
- );
291
- }
292
-
293
- function writeBrokenTransformPlugin(root) {
294
- fs.writeFileSync(
295
- path.join(root, "plugin.cjs"),
296
- 'module.exports = { name: "broken-transform-fixture", source: "./plugin-go" };\n',
297
- "utf8",
298
- );
299
- fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
300
- fs.writeFileSync(
301
- path.join(root, "plugin-go", "go.mod"),
302
- "module example.com/brokentransformfixture\n\ngo 1.26\n",
303
- "utf8",
304
- );
305
- fs.writeFileSync(
306
- path.join(root, "plugin-go", "main.go"),
307
- [
308
- "package main",
309
- "",
310
- "import (",
311
- '\t"fmt"',
312
- '\t"os"',
313
- ")",
314
- "",
315
- "func main() {",
316
- '\tif len(os.Args) > 1 && os.Args[1] == "transform" {',
317
- '\t\tfmt.Println(`{"output":{"dist/main.js":"console.log(\\"wrong\\");\\n"}}`)',
318
- "\t\treturn",
319
- "\t}",
320
- "}",
321
- "",
322
- ].join("\n"),
323
- "utf8",
324
- );
325
- }
326
-
327
- function writeCompilerPlugin(root) {
328
- fs.writeFileSync(
329
- path.join(root, "plugin.cjs"),
330
- 'module.exports = { name: "compile-fixture", source: "./plugin-go" };\n',
331
- "utf8",
332
- );
333
- fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
334
- fs.writeFileSync(
335
- path.join(root, "plugin-go", "go.mod"),
336
- "module example.com/compilefixture\n\ngo 1.26\n",
337
- "utf8",
338
- );
339
- fs.writeFileSync(
340
- path.join(root, "plugin-go", "main.go"),
341
- [
342
- "package main",
343
- "",
344
- "import (",
345
- '\t"encoding/json"',
346
- '\t"flag"',
347
- '\t"fmt"',
348
- '\t"os"',
349
- '\t"path/filepath"',
350
- '\t"strings"',
351
- ")",
352
- "",
353
- "func main() { os.Exit(run(os.Args[1:])) }",
354
- "",
355
- "func run(args []string) int {",
356
- "\tif len(args) == 0 { return 2 }",
357
- "\tswitch args[0] {",
358
- '\tcase "build":',
359
- "\t\treturn build(args[1:])",
360
- '\tcase "transform":',
361
- "\t\treturn transformSource(args[1:])",
362
- '\tcase "check", "version":',
363
- "\t\treturn 0",
364
- "\tdefault:",
365
- "\t\treturn 2",
366
- "\t}",
367
- "}",
368
- "",
369
- "func build(args []string) int {",
370
- '\tfs := flag.NewFlagSet("build", flag.ContinueOnError)',
371
- "\tfs.SetOutput(os.Stderr)",
372
- '\tcwd := fs.String("cwd", "", "")',
373
- '\toutDir := fs.String("outDir", "dist", "")',
374
- '\t_ = fs.String("tsconfig", "", "")',
375
- '\t_ = fs.String("plugins-json", "", "")',
376
- '\t_ = fs.Bool("emit", false, "")',
377
- '\t_ = fs.Bool("quiet", false, "")',
378
- '\t_ = fs.Bool("verbose", false, "")',
379
- '\t_ = fs.Bool("noEmit", false, "")',
380
- "\tif err := fs.Parse(args); err != nil { return 2 }",
381
- "\troot := *cwd",
382
- '\tif root == "" { root, _ = os.Getwd() }',
383
- '\tinput, err := os.ReadFile(filepath.Join(root, "src", "main.ts"))',
384
- "\tif err != nil { fmt.Fprintln(os.Stderr, err); return 2 }",
385
- '\tvalue := "PLUGIN"',
386
- '\tif !strings.Contains(string(input), `goUpper("plugin")`) { value = "UNKNOWN" }',
387
- '\toutput := fmt.Sprintf("\\"use strict\\";\\nObject.defineProperty(exports, \\"__esModule\\", { value: true });\\nexports.value = void 0;\\nconst value = %q;\\nexports.value = value;\\nconsole.log(value);\\n", value)',
388
- '\tfile := filepath.Join(*outDir, "main.js")',
389
- '\tif !filepath.IsAbs(*outDir) { file = filepath.Join(root, *outDir, "main.js") }',
390
- "\tif err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil { fmt.Fprintln(os.Stderr, err); return 2 }",
391
- "\tif err := os.WriteFile(file, []byte(output), 0o644); err != nil { fmt.Fprintln(os.Stderr, err); return 2 }",
392
- "\treturn 0",
393
- "}",
394
- "",
395
- "type transformResult struct {",
396
- '\tTypeScript map[string]string `json:"typescript"`',
397
- "}",
398
- "",
399
- "func transformSource(args []string) int {",
400
- '\tfs := flag.NewFlagSet("transform", flag.ContinueOnError)',
401
- "\tfs.SetOutput(os.Stderr)",
402
- '\tcwd := fs.String("cwd", "", "")',
403
- '\t_ = fs.String("tsconfig", "", "")',
404
- '\t_ = fs.String("plugins-json", "", "")',
405
- "\tif err := fs.Parse(args); err != nil { return 2 }",
406
- "\troot := *cwd",
407
- '\tif root == "" { root, _ = os.Getwd() }',
408
- '\tinput, err := os.ReadFile(filepath.Join(root, "src", "main.ts"))',
409
- "\tif err != nil { fmt.Fprintln(os.Stderr, err); return 2 }",
410
- '\tvalue := "PLUGIN"',
411
- '\tif !strings.Contains(string(input), `goUpper("plugin")`) { value = "UNKNOWN" }',
412
- '\toutput := fmt.Sprintf("export const value = %q;\\nconsole.log(value);\\n", value)',
413
- '\tdata, err := json.Marshal(transformResult{TypeScript: map[string]string{"src/main.ts": output}})',
414
- "\tif err != nil { fmt.Fprintln(os.Stderr, err); return 2 }",
415
- "\tfmt.Fprintln(os.Stdout, string(data))",
416
- "\treturn 0",
417
- "}",
418
- "",
419
- ].join("\n"),
420
- "utf8",
421
- );
422
- }
@@ -1,12 +0,0 @@
1
- const assert = require("node:assert/strict");
2
- const test = require("node:test");
3
- const { resolveBinary } = require("../lib/compiler/internal/resolveBinary.js");
4
-
5
- test("resolveBinary prefers TTSC_BINARY absolute override", () => {
6
- const resolved = resolveBinary({
7
- env: {
8
- TTSC_BINARY: "/tmp/custom-ttsc",
9
- },
10
- });
11
- assert.equal(resolved, "/tmp/custom-ttsc");
12
- });