ttsc 0.12.2 → 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.
- package/cmd/platform/main.go +9 -0
- package/cmd/ttsc/api_compile.go +109 -101
- package/cmd/ttsc/api_compile_branches_test.go +55 -57
- package/cmd/ttsc/api_transform.go +54 -49
- package/cmd/ttsc/api_transform_branches_test.go +30 -32
- package/cmd/ttsc/build.go +111 -108
- package/cmd/ttsc/build_branches_test.go +95 -97
- package/cmd/ttsc/helpers_test.go +39 -28
- package/cmd/ttsc/main.go +111 -104
- package/cmd/ttsc/main_alias_branches_test.go +21 -23
- package/cmd/ttscserver/main.go +96 -90
- package/cmd/ttscserver/run_lsp_prefers_tsgo_flag_test.go +22 -22
- package/cmd/ttscserver/run_lsp_reports_server_error_test.go +22 -22
- package/cmd/ttscserver/run_lsp_uses_tsgo_environment_test.go +23 -23
- package/cmd/utility-host/main.go +30 -23
- package/driver/lsp.go +53 -7
- package/driver/plugins.go +88 -72
- package/driver/program.go +362 -339
- package/driver/rewrite.go +442 -380
- package/internal/lspserver/lsp_envelope.go +64 -64
- package/internal/lspserver/lsp_frame.go +60 -60
- package/internal/lspserver/lsp_plugin.go +57 -57
- package/internal/lspserver/lsp_proxy.go +265 -251
- package/internal/lspserver/lsp_server.go +155 -144
- package/lib/TtscCompiler.d.ts +7 -0
- package/lib/TtscCompiler.js +7 -0
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/buildNativeCompiler.d.ts +11 -1
- package/lib/compiler/internal/buildNativeCompiler.js +23 -3
- package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.d.ts +9 -0
- package/lib/compiler/internal/compileProjectInMemory.js +36 -21
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/paths.d.ts +27 -0
- package/lib/compiler/internal/paths.js +70 -0
- package/lib/compiler/internal/paths.js.map +1 -0
- package/lib/compiler/internal/project/readProjectConfig.d.ts +9 -1
- package/lib/compiler/internal/project/readProjectConfig.js +80 -1
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/project/resolveProjectConfig.d.ts +13 -1
- package/lib/compiler/internal/project/resolveProjectConfig.js +24 -1
- package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
- package/lib/compiler/internal/resolveBinary.d.ts +9 -1
- package/lib/compiler/internal/resolveBinary.js +17 -1
- package/lib/compiler/internal/resolveBinary.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +16 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.js +42 -10
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.d.ts +21 -1
- package/lib/compiler/internal/resolveTsgo.js +23 -1
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +19 -0
- package/lib/compiler/internal/runBuild.js +112 -46
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.d.ts +10 -1
- package/lib/compiler/internal/runSingleFileEmit.js +14 -1
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +5 -0
- package/lib/compiler/internal/sharedHostHelpers.js +6 -2
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/spawnNative.d.ts +21 -0
- package/lib/compiler/internal/spawnNative.js +59 -0
- package/lib/compiler/internal/spawnNative.js.map +1 -0
- package/lib/compiler/internal/transformProjectInMemory.d.ts +15 -1
- package/lib/compiler/internal/transformProjectInMemory.js +57 -61
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/launcher/internal/getCompilerVersionText.js +7 -0
- package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +32 -0
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/resolveCacheDir.d.ts +9 -0
- package/lib/launcher/internal/resolveCacheDir.js +22 -0
- package/lib/launcher/internal/resolveCacheDir.js.map +1 -0
- package/lib/launcher/internal/resolveTtscserverBinary.js +2 -0
- package/lib/launcher/internal/resolveTtscserverBinary.js.map +1 -1
- package/lib/launcher/internal/runTtsc.d.ts +10 -0
- package/lib/launcher/internal/runTtsc.js +101 -16
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +10 -35
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.d.ts +8 -0
- package/lib/launcher/internal/runTtsx.js +33 -7
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +38 -0
- package/lib/plugin/internal/buildSourcePlugin.js +40 -17
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +26 -0
- package/lib/plugin/internal/loadProjectPlugins.js +32 -18
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerTransformation.d.ts +15 -2
- package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +0 -2
- package/package.json +9 -9
- package/shim/ast/go.mod +9 -0
- package/shim/ast/go.sum +20 -0
- package/shim/ast/safe_text.go +86 -0
- package/shim/ast/shim.go +24 -0
- package/shim/ast/test/node_text_joins_multi_hop_qualified_name_test.go +32 -0
- package/shim/ast/test/node_text_joins_one_hop_qualified_name_test.go +31 -0
- package/shim/ast/test/node_text_returns_empty_for_nil_test.go +23 -0
- package/shim/ast/test/node_text_returns_identifier_text_test.go +27 -0
- package/shim/ast/test/node_text_skips_empty_qualified_left_test.go +30 -0
- package/shim/checker/shim.go +35 -0
- package/shim/core/shim.go +17 -0
- package/shim/diagnosticwriter/shim.go +4 -0
- package/shim/lsp/shim.go +3 -3
- package/shim/printer/shim.go +20 -0
- package/src/TtscCompiler.ts +7 -0
- package/src/compiler/internal/buildNativeCompiler.ts +23 -3
- package/src/compiler/internal/compileProjectInMemory.ts +34 -25
- package/src/compiler/internal/paths.ts +68 -0
- package/src/compiler/internal/project/readProjectConfig.ts +86 -1
- package/src/compiler/internal/project/resolveProjectConfig.ts +24 -1
- package/src/compiler/internal/resolveBinary.ts +17 -1
- package/src/compiler/internal/resolveEmittedJavaScript.ts +43 -12
- package/src/compiler/internal/resolveTsgo.ts +29 -1
- package/src/compiler/internal/runBuild.ts +110 -55
- package/src/compiler/internal/runSingleFileEmit.ts +14 -1
- package/src/compiler/internal/sharedHostHelpers.ts +7 -7
- package/src/compiler/internal/spawnNative.ts +64 -0
- package/src/compiler/internal/transformProjectInMemory.ts +47 -67
- package/src/launcher/internal/getCompilerVersionText.ts +7 -0
- package/src/launcher/internal/prepareExecution.ts +32 -0
- package/src/launcher/internal/resolveCacheDir.ts +19 -0
- package/src/launcher/internal/resolveTtscserverBinary.ts +2 -0
- package/src/launcher/internal/runTtsc.ts +120 -20
- package/src/launcher/internal/runTtscserver.ts +9 -1
- package/src/launcher/internal/runTtsx.ts +33 -8
- package/src/plugin/internal/buildSourcePlugin.ts +40 -14
- package/src/plugin/internal/loadProjectPlugins.ts +42 -18
- package/src/structures/ITtscCompilerTransformation.ts +15 -2
- package/src/structures/ITtscPlugin.ts +0 -1
- package/src/structures/internal/TtscSingleFileEmitOptions.ts +0 -2
- package/tools/gen_shims/main.go +43 -8
- package/utility/host.go +294 -245
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
1
|
import path from "node:path";
|
|
5
2
|
|
|
6
3
|
import { loadProjectPlugins } from "../../plugin/internal/loadProjectPlugins";
|
|
@@ -17,8 +14,13 @@ import {
|
|
|
17
14
|
linkedTransformPlugins,
|
|
18
15
|
selectSharedHostPlugin,
|
|
19
16
|
} from "./sharedHostHelpers";
|
|
17
|
+
import { outputText, spawnNative } from "./spawnNative";
|
|
20
18
|
|
|
21
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Merge extra environment variables over `process.env`, always injecting
|
|
21
|
+
* `TTSC_NODE_BINARY` so child processes can re-invoke the same Node.js binary
|
|
22
|
+
* without searching `PATH`.
|
|
23
|
+
*/
|
|
22
24
|
function mergeEnv(extra?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
|
23
25
|
const base = {
|
|
24
26
|
...process.env,
|
|
@@ -28,6 +30,12 @@ function mergeEnv(extra?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
|
|
|
28
30
|
return { ...base, ...extra };
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Build the environment for a native plugin spawn. Injects `TTSC_TSGO_BINARY`
|
|
35
|
+
* and `TTSC_TTSX_BINARY` alongside the base env from `mergeEnv`. For
|
|
36
|
+
* transform-stage plugins, also passes `TTSC_LINKED_PLUGINS_JSON` containing
|
|
37
|
+
* any linked sources so they run inside the same process as the host plugin.
|
|
38
|
+
*/
|
|
31
39
|
function nativePluginEnv(
|
|
32
40
|
extra: NodeJS.ProcessEnv | undefined,
|
|
33
41
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
@@ -49,54 +57,6 @@ function nativePluginEnv(
|
|
|
49
57
|
return env;
|
|
50
58
|
}
|
|
51
59
|
|
|
52
|
-
function spawnBinary(
|
|
53
|
-
binary: string,
|
|
54
|
-
args: readonly string[],
|
|
55
|
-
options: {
|
|
56
|
-
cwd?: string;
|
|
57
|
-
env?: NodeJS.ProcessEnv;
|
|
58
|
-
encoding?: BufferEncoding;
|
|
59
|
-
},
|
|
60
|
-
) {
|
|
61
|
-
const viaNode = /\.(?:[cm]?js|ts)$/i.test(binary);
|
|
62
|
-
if (!viaNode) {
|
|
63
|
-
ensureExecutable(binary);
|
|
64
|
-
}
|
|
65
|
-
return spawnSync(
|
|
66
|
-
viaNode ? process.execPath : binary,
|
|
67
|
-
viaNode ? [binary, ...args] : [...args],
|
|
68
|
-
{
|
|
69
|
-
cwd: options.cwd,
|
|
70
|
-
env: options.env,
|
|
71
|
-
encoding: options.encoding,
|
|
72
|
-
maxBuffer: 1024 * 1024 * 256,
|
|
73
|
-
windowsHide: true,
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function ensureExecutable(binary: string): void {
|
|
79
|
-
if (process.platform === "win32") {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
try {
|
|
83
|
-
const mode = fs.statSync(binary).mode & 0o777;
|
|
84
|
-
if ((mode & 0o111) !== 0) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
fs.chmodSync(binary, mode | 0o755);
|
|
88
|
-
} catch {
|
|
89
|
-
/* keep the original spawn error path */
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function outputText(value: string | Buffer | null | undefined): string {
|
|
94
|
-
if (value == null) {
|
|
95
|
-
return "";
|
|
96
|
-
}
|
|
97
|
-
return typeof value === "string" ? value : value.toString("utf8");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
60
|
/**
|
|
101
61
|
* Run `ttsc` against a tsconfig. Returns once the binary exits so the CLI can
|
|
102
62
|
* decide how to surface diagnostics. Does not throw on non-zero exit.
|
|
@@ -199,6 +159,11 @@ export function runBuild(
|
|
|
199
159
|
return runTsgoBuild(execution, options, args);
|
|
200
160
|
}
|
|
201
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Dispatch a build through the shared-host native plugin. The host plugin is
|
|
164
|
+
* the one that owns the process (non-linked); all other transform plugins ride
|
|
165
|
+
* inside it via the `--plugins-json` flag.
|
|
166
|
+
*/
|
|
202
167
|
function buildWithNativeCompilerPlugins(
|
|
203
168
|
options: TtscBuildOptions,
|
|
204
169
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
@@ -214,12 +179,16 @@ function buildWithNativeCompilerPlugins(
|
|
|
214
179
|
);
|
|
215
180
|
}
|
|
216
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Run `tsgo -p <tsconfig> [extraArgs]` and return the normalized result. Used
|
|
184
|
+
* for the no-emit type-check pass that precedes file emission.
|
|
185
|
+
*/
|
|
217
186
|
function runTsgo(
|
|
218
187
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
219
188
|
extraArgs: readonly string[],
|
|
220
189
|
options: NonNullable<Parameters<typeof runBuild>[0]>,
|
|
221
190
|
): TtscBuildResult {
|
|
222
|
-
const res =
|
|
191
|
+
const res = spawnNative(
|
|
223
192
|
execution.tsgo.binary,
|
|
224
193
|
[
|
|
225
194
|
"-p",
|
|
@@ -251,12 +220,17 @@ function runTsgo(
|
|
|
251
220
|
);
|
|
252
221
|
}
|
|
253
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Run `tsgo` with the full emit arguments and parse `TSFILE:` lines from stdout
|
|
225
|
+
* into `emittedFiles`. The TSFILE lines are stripped before the result is
|
|
226
|
+
* returned so they do not appear in the user-facing output.
|
|
227
|
+
*/
|
|
254
228
|
function runTsgoBuild(
|
|
255
229
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
256
230
|
options: NonNullable<Parameters<typeof runBuild>[0]>,
|
|
257
231
|
args: readonly string[],
|
|
258
232
|
): TtscBuildResult {
|
|
259
|
-
const res =
|
|
233
|
+
const res = spawnNative(execution.tsgo.binary, args, {
|
|
260
234
|
cwd: execution.projectRoot,
|
|
261
235
|
env: mergeEnv(options.env),
|
|
262
236
|
encoding: "utf8",
|
|
@@ -284,6 +258,7 @@ function runTsgoBuild(
|
|
|
284
258
|
);
|
|
285
259
|
}
|
|
286
260
|
|
|
261
|
+
/** Build the argument list for a direct `tsgo` build invocation. */
|
|
287
262
|
function createTsgoBuildArgs(
|
|
288
263
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
289
264
|
options: NonNullable<Parameters<typeof runBuild>[0]>,
|
|
@@ -305,10 +280,15 @@ function createTsgoBuildArgs(
|
|
|
305
280
|
return args;
|
|
306
281
|
}
|
|
307
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Return `["--pretty", "false"]` when structured diagnostics are requested so
|
|
285
|
+
* that the output can be parsed line-by-line, or an empty array otherwise.
|
|
286
|
+
*/
|
|
308
287
|
function createTsgoDiagnosticArgs(options: TtscCommonOptions): string[] {
|
|
309
288
|
return options.structuredDiagnostics === true ? ["--pretty", "false"] : [];
|
|
310
289
|
}
|
|
311
290
|
|
|
291
|
+
/** Build the argument list for a native plugin `build`/`check` invocation. */
|
|
312
292
|
function createNativeBuildArgs(
|
|
313
293
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
314
294
|
options: TtscBuildOptions,
|
|
@@ -336,6 +316,7 @@ function createNativeBuildArgs(
|
|
|
336
316
|
return args;
|
|
337
317
|
}
|
|
338
318
|
|
|
319
|
+
/** Build the argument list for a native plugin check/fix/format invocation. */
|
|
339
320
|
function createNativeCheckArgs(
|
|
340
321
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
341
322
|
options: TtscBuildOptions,
|
|
@@ -369,6 +350,10 @@ function nativeCheckSubcommand(options: TtscBuildOptions): string {
|
|
|
369
350
|
return "check";
|
|
370
351
|
}
|
|
371
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Serialize the plugin list to a compact JSON string for `--plugins-json=`.
|
|
355
|
+
* Only the fields the native binary protocol requires are included.
|
|
356
|
+
*/
|
|
372
357
|
function serializeNativePlugins(
|
|
373
358
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
374
359
|
): string {
|
|
@@ -381,6 +366,10 @@ function serializeNativePlugins(
|
|
|
381
366
|
);
|
|
382
367
|
}
|
|
383
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Run every check-stage plugin in order, short-circuiting on the first non-zero
|
|
371
|
+
* exit. Aggregates diagnostics and output across all check plugins.
|
|
372
|
+
*/
|
|
384
373
|
function runNativeCheckPlugins(
|
|
385
374
|
options: TtscBuildOptions,
|
|
386
375
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
@@ -409,6 +398,11 @@ function runNativeCheckPlugins(
|
|
|
409
398
|
return out;
|
|
410
399
|
}
|
|
411
400
|
|
|
401
|
+
/**
|
|
402
|
+
* Spawn a single native plugin binary with the given args and return the
|
|
403
|
+
* normalized build result. `label` is used in the thrown error message so the
|
|
404
|
+
* caller's context (e.g. `"ttsc.check"` or `"ttsc.build"`) is preserved.
|
|
405
|
+
*/
|
|
412
406
|
function runNativePluginCommand(
|
|
413
407
|
plugin: ITtscLoadedNativePlugin,
|
|
414
408
|
args: readonly string[],
|
|
@@ -416,7 +410,7 @@ function runNativePluginCommand(
|
|
|
416
410
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
417
411
|
label: string,
|
|
418
412
|
): TtscBuildResult {
|
|
419
|
-
const res =
|
|
413
|
+
const res = spawnNative(plugin.binary, args, {
|
|
420
414
|
cwd: execution.projectRoot,
|
|
421
415
|
env: nativePluginEnv(options.env, execution, plugin),
|
|
422
416
|
encoding: "utf8",
|
|
@@ -436,6 +430,14 @@ function runNativePluginCommand(
|
|
|
436
430
|
);
|
|
437
431
|
}
|
|
438
432
|
|
|
433
|
+
/**
|
|
434
|
+
* Merge two `TtscBuildResult` values into one.
|
|
435
|
+
*
|
|
436
|
+
* - `status`: the right status wins unless it is 0 (failure propagates).
|
|
437
|
+
* - `diagnostics`: concatenated left then right.
|
|
438
|
+
* - `emittedFiles`: right wins when present, otherwise left is kept.
|
|
439
|
+
* - `stdout`/`stderr`: concatenated left then right.
|
|
440
|
+
*/
|
|
439
441
|
export function appendBuildOutput(
|
|
440
442
|
left: TtscBuildResult,
|
|
441
443
|
right: TtscBuildResult,
|
|
@@ -450,6 +452,11 @@ export function appendBuildOutput(
|
|
|
450
452
|
});
|
|
451
453
|
}
|
|
452
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Resolve all runtime context needed for a build: cwd, tsconfig path, project
|
|
457
|
+
* root, tsgo binary location, and the loaded native plugin list. Centralised
|
|
458
|
+
* here so every code path in `runBuild` shares the same resolution logic.
|
|
459
|
+
*/
|
|
453
460
|
function resolveExecutionContext(
|
|
454
461
|
options: TtscCommonOptions & { tsconfig?: string },
|
|
455
462
|
) {
|
|
@@ -480,6 +487,10 @@ function resolveExecutionContext(
|
|
|
480
487
|
};
|
|
481
488
|
}
|
|
482
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Extract `TSFILE: <path>` lines from tsgo stdout and return the absolute
|
|
492
|
+
* paths. tsgo emits these when `--listEmittedFiles` is passed.
|
|
493
|
+
*/
|
|
483
494
|
function parseEmittedFiles(stdout: string): string[] {
|
|
484
495
|
const out: string[] = [];
|
|
485
496
|
for (const line of stdout.split(/\r?\n/)) {
|
|
@@ -491,6 +502,10 @@ function parseEmittedFiles(stdout: string): string[] {
|
|
|
491
502
|
return out;
|
|
492
503
|
}
|
|
493
504
|
|
|
505
|
+
/**
|
|
506
|
+
* Remove `TSFILE:` lines from tsgo stdout so they do not appear in the
|
|
507
|
+
* user-facing output after they have been parsed into `emittedFiles`.
|
|
508
|
+
*/
|
|
494
509
|
function stripEmittedFileLines(stdout: string): string {
|
|
495
510
|
return stdout
|
|
496
511
|
.split(/\r?\n/)
|
|
@@ -499,10 +514,21 @@ function stripEmittedFileLines(stdout: string): string {
|
|
|
499
514
|
.replace(/\n+$/, "");
|
|
500
515
|
}
|
|
501
516
|
|
|
517
|
+
/**
|
|
518
|
+
* `TtscBuildResult` with `diagnostics` made optional. Used internally when
|
|
519
|
+
* diagnostics are parsed lazily from stdout/stderr by `normalizeBuildOutput`.
|
|
520
|
+
*/
|
|
502
521
|
type PartialBuildResult = Omit<TtscBuildResult, "diagnostics"> & {
|
|
503
522
|
diagnostics?: ITtscCompilerDiagnostic[];
|
|
504
523
|
};
|
|
505
524
|
|
|
525
|
+
/**
|
|
526
|
+
* Normalise a raw spawn result into a `TtscBuildResult`.
|
|
527
|
+
*
|
|
528
|
+
* When `diagnostics` is absent they are parsed from the text output. When the
|
|
529
|
+
* process exited non-zero but stderr is empty and stdout is non-empty, stdout
|
|
530
|
+
* is moved to stderr so the error is visible to callers who only check stderr.
|
|
531
|
+
*/
|
|
506
532
|
export function normalizeBuildOutput(
|
|
507
533
|
result: PartialBuildResult,
|
|
508
534
|
cwd?: string,
|
|
@@ -524,6 +550,11 @@ export function normalizeBuildOutput(
|
|
|
524
550
|
};
|
|
525
551
|
}
|
|
526
552
|
|
|
553
|
+
/**
|
|
554
|
+
* Parse structured diagnostics from the combined stderr+stdout text when the
|
|
555
|
+
* caller did not supply pre-parsed diagnostics. ANSI escape codes are stripped
|
|
556
|
+
* and `TSFILE:` / `Found N errors` summary lines are skipped.
|
|
557
|
+
*/
|
|
527
558
|
function parseCompilerDiagnostics(
|
|
528
559
|
result: Pick<TtscBuildResult, "stderr" | "stdout">,
|
|
529
560
|
cwd: string | undefined,
|
|
@@ -553,6 +584,16 @@ function parseCompilerDiagnostics(
|
|
|
553
584
|
return out;
|
|
554
585
|
}
|
|
555
586
|
|
|
587
|
+
/**
|
|
588
|
+
* Try to parse a single line as a TypeScript compiler diagnostic in one of
|
|
589
|
+
* three formats:
|
|
590
|
+
*
|
|
591
|
+
* - `file:line:col - category TSxxxx: message` (colon-separated, tsgo style)
|
|
592
|
+
* - `file(line,col): category TSxxxx: message` (paren style, classic tsc)
|
|
593
|
+
* - `category TSxxxx: message` (global, no file)
|
|
594
|
+
*
|
|
595
|
+
* Returns `null` when the line does not match any format.
|
|
596
|
+
*/
|
|
556
597
|
function parseDiagnosticLine(
|
|
557
598
|
line: string,
|
|
558
599
|
cwd: string | undefined,
|
|
@@ -599,6 +640,10 @@ function parseDiagnosticLine(
|
|
|
599
640
|
};
|
|
600
641
|
}
|
|
601
642
|
|
|
643
|
+
/**
|
|
644
|
+
* Return an absolute file path. When `file` is already absolute it is returned
|
|
645
|
+
* unchanged; relative paths are resolved against `cwd` when available.
|
|
646
|
+
*/
|
|
602
647
|
function normalizeDiagnosticFile(
|
|
603
648
|
file: string,
|
|
604
649
|
cwd: string | undefined,
|
|
@@ -609,6 +654,11 @@ function normalizeDiagnosticFile(
|
|
|
609
654
|
return path.resolve(cwd, file);
|
|
610
655
|
}
|
|
611
656
|
|
|
657
|
+
/**
|
|
658
|
+
* Map a raw category string (`"error"`, `"warning"`, `"suggestion"`,
|
|
659
|
+
* `"message"`) to the canonical `ITtscCompilerDiagnostic.Category`. Any
|
|
660
|
+
* unrecognised value is coerced to `"error"`.
|
|
661
|
+
*/
|
|
612
662
|
function normalizeDiagnosticCategory(
|
|
613
663
|
value: string,
|
|
614
664
|
): ITtscCompilerDiagnostic.Category {
|
|
@@ -620,10 +670,15 @@ function normalizeDiagnosticCategory(
|
|
|
620
670
|
: "error";
|
|
621
671
|
}
|
|
622
672
|
|
|
673
|
+
/**
|
|
674
|
+
* Parse a diagnostic code as a number when it is all digits (TS numeric codes
|
|
675
|
+
* like `2322`), or keep it as a string for plugin-defined alphanumeric codes.
|
|
676
|
+
*/
|
|
623
677
|
function normalizeDiagnosticCode(value: string): number | string {
|
|
624
678
|
return /^\d+$/.test(value) ? Number(value) : value;
|
|
625
679
|
}
|
|
626
680
|
|
|
681
|
+
/** Strip ANSI escape sequences from `text` for line-by-line diagnostic parsing. */
|
|
627
682
|
function stripAnsi(text: string): string {
|
|
628
683
|
return text.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
|
|
629
684
|
}
|
|
@@ -7,7 +7,16 @@ import { resolveProjectConfig } from "./project/resolveProjectConfig";
|
|
|
7
7
|
import { resolveEmittedJavaScript } from "./resolveEmittedJavaScript";
|
|
8
8
|
import { runBuild } from "./runBuild";
|
|
9
9
|
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Emit one source file by building its project into a temporary directory.
|
|
12
|
+
*
|
|
13
|
+
* The full project is compiled with `forceListEmittedFiles` so that the emitted
|
|
14
|
+
* file list is available for `resolveEmittedJavaScript`. The temp directory is
|
|
15
|
+
* always cleaned up in the `finally` block, even on error.
|
|
16
|
+
*
|
|
17
|
+
* @returns The transformed JavaScript source text.
|
|
18
|
+
* @throws When the build exits non-zero or no output is produced for the file.
|
|
19
|
+
*/
|
|
11
20
|
export function runSingleFileEmit(options: TtscSingleFileEmitOptions): string {
|
|
12
21
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
13
22
|
const sourceFile = realpathIfExists(
|
|
@@ -64,6 +73,10 @@ export function runSingleFileEmit(options: TtscSingleFileEmitOptions): string {
|
|
|
64
73
|
}
|
|
65
74
|
}
|
|
66
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Resolve symlinks on `file` when it exists; return the original path when the
|
|
78
|
+
* file is not yet on disk (e.g. a synthetic path used in tests).
|
|
79
|
+
*/
|
|
67
80
|
function realpathIfExists(file: string): string {
|
|
68
81
|
try {
|
|
69
82
|
return fs.realpathSync(file);
|
|
@@ -4,9 +4,7 @@ import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoa
|
|
|
4
4
|
* Reports whether the given transform source is linked into another compiler
|
|
5
5
|
* host instead of owning the process itself.
|
|
6
6
|
*/
|
|
7
|
-
export function isLinkedTransform(
|
|
8
|
-
plugin: ITtscLoadedNativePlugin,
|
|
9
|
-
): boolean {
|
|
7
|
+
export function isLinkedTransform(plugin: ITtscLoadedNativePlugin): boolean {
|
|
10
8
|
return plugin.stage === "transform" && plugin.kind === "linked";
|
|
11
9
|
}
|
|
12
10
|
|
|
@@ -59,12 +57,14 @@ export function assertSharedHostCompatibility(
|
|
|
59
57
|
export function selectSharedHostPlugin(
|
|
60
58
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
61
59
|
): ITtscLoadedNativePlugin {
|
|
62
|
-
return (
|
|
63
|
-
plugins.find((plugin) => !isLinkedTransform(plugin)) ??
|
|
64
|
-
plugins[0]!
|
|
65
|
-
);
|
|
60
|
+
return plugins.find((plugin) => !isLinkedTransform(plugin)) ?? plugins[0]!;
|
|
66
61
|
}
|
|
67
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Return every plugin whose transform source is linked into another host binary
|
|
65
|
+
* rather than owning the process. The host binary passes these via
|
|
66
|
+
* `TTSC_LINKED_PLUGINS_JSON` so their Go code runs inside the same process.
|
|
67
|
+
*/
|
|
68
68
|
export function linkedTransformPlugins(
|
|
69
69
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
70
70
|
): ITtscLoadedNativePlugin[] {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Spawn a native binary (or a Node.js script when the path has a JS/TS
|
|
6
|
+
* extension) with the given args and return the `spawnSync` result. Sets a
|
|
7
|
+
* generous 256 MiB output buffer so large projects do not truncate.
|
|
8
|
+
*
|
|
9
|
+
* When `options.encoding` is omitted it defaults to `"utf8"`. Pass an explicit
|
|
10
|
+
* value when the caller needs a different encoding or raw `Buffer` output.
|
|
11
|
+
*/
|
|
12
|
+
export function spawnNative(
|
|
13
|
+
binary: string,
|
|
14
|
+
args: readonly string[],
|
|
15
|
+
options: {
|
|
16
|
+
cwd?: string;
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
encoding?: BufferEncoding;
|
|
19
|
+
},
|
|
20
|
+
) {
|
|
21
|
+
const viaNode = /\.(?:[cm]?js|ts)$/i.test(binary);
|
|
22
|
+
if (!viaNode) {
|
|
23
|
+
ensureExecutable(binary);
|
|
24
|
+
}
|
|
25
|
+
return spawnSync(
|
|
26
|
+
viaNode ? process.execPath : binary,
|
|
27
|
+
viaNode ? [binary, ...args] : [...args],
|
|
28
|
+
{
|
|
29
|
+
cwd: options.cwd,
|
|
30
|
+
encoding: options.encoding ?? "utf8",
|
|
31
|
+
env: options.env,
|
|
32
|
+
maxBuffer: 1024 * 1024 * 256,
|
|
33
|
+
windowsHide: true,
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Ensure the binary has the executable bit set on POSIX systems. Silently skips
|
|
40
|
+
* on Windows and swallows `chmod` errors to let the original spawn error
|
|
41
|
+
* surface instead of masking it with a permission error.
|
|
42
|
+
*/
|
|
43
|
+
export function ensureExecutable(binary: string): void {
|
|
44
|
+
if (process.platform === "win32") {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const mode = fs.statSync(binary).mode & 0o777;
|
|
49
|
+
if ((mode & 0o111) !== 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
fs.chmodSync(binary, mode | 0o755);
|
|
53
|
+
} catch {
|
|
54
|
+
/* keep the original spawn error path */
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Coerce a `spawnSync` output value to a plain string, defaulting to `""`. */
|
|
59
|
+
export function outputText(value: string | Buffer | null | undefined): string {
|
|
60
|
+
if (value == null) {
|
|
61
|
+
return "";
|
|
62
|
+
}
|
|
63
|
+
return typeof value === "string" ? value : value.toString("utf8");
|
|
64
|
+
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import fs from "node:fs";
|
|
3
1
|
import path from "node:path";
|
|
4
2
|
|
|
5
3
|
import {
|
|
@@ -12,6 +10,7 @@ import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoa
|
|
|
12
10
|
import type { ITtscParsedProjectConfig } from "../../structures/internal/ITtscParsedProjectConfig";
|
|
13
11
|
import type { TtscBuildResult } from "../../structures/internal/TtscBuildResult";
|
|
14
12
|
import { buildNativeCompiler } from "./buildNativeCompiler";
|
|
13
|
+
import { packageRootDir } from "./paths";
|
|
15
14
|
import { readProjectConfig } from "./project/readProjectConfig";
|
|
16
15
|
import { resolveBinary } from "./resolveBinary";
|
|
17
16
|
import { resolveTsgo } from "./resolveTsgo";
|
|
@@ -21,8 +20,23 @@ import {
|
|
|
21
20
|
linkedTransformPlugins,
|
|
22
21
|
selectSharedHostPlugin,
|
|
23
22
|
} from "./sharedHostHelpers";
|
|
23
|
+
import { outputText, spawnNative } from "./spawnNative";
|
|
24
24
|
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Transform a project and capture TypeScript source output in memory.
|
|
27
|
+
*
|
|
28
|
+
* When no plugins are configured the fast path spawns the native ttsc compiler
|
|
29
|
+
* host (`cmd/ttsc api-transform`) which returns a JSON map of transformed
|
|
30
|
+
* TypeScript sources. When plugins are present:
|
|
31
|
+
*
|
|
32
|
+
* 1. Check-stage plugins run first and abort on failure.
|
|
33
|
+
* 2. If there are no transform-stage plugins the host is used as the transformer.
|
|
34
|
+
* 3. If transform plugins exist they are dispatched through the shared-host binary
|
|
35
|
+
* with linked plugins passed via `TTSC_LINKED_PLUGINS_JSON`.
|
|
36
|
+
*
|
|
37
|
+
* @returns A `{ result, typescript }` pair where `typescript` maps output paths
|
|
38
|
+
* to their transformed TypeScript source text.
|
|
39
|
+
*/
|
|
26
40
|
export function transformProjectInMemory(options: ITtscCompilerContext): {
|
|
27
41
|
result: TtscBuildResult;
|
|
28
42
|
typescript: Record<string, string>;
|
|
@@ -39,6 +53,7 @@ export function transformProjectInMemory(options: ITtscCompilerContext): {
|
|
|
39
53
|
return transformProjectWithNativeHost(options, project);
|
|
40
54
|
}
|
|
41
55
|
|
|
56
|
+
/** Return true when the project or the call-level options declare any plugins. */
|
|
42
57
|
function hasConfiguredPlugins(
|
|
43
58
|
options: ITtscCompilerContext,
|
|
44
59
|
project: ITtscParsedProjectConfig,
|
|
@@ -46,6 +61,11 @@ function hasConfiguredPlugins(
|
|
|
46
61
|
return hasProjectPluginEntries(project, options.plugins);
|
|
47
62
|
}
|
|
48
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Transform via the built-in native compiler host (`cmd/ttsc api-transform`).
|
|
66
|
+
* Used when no user plugins are configured, or as the fallback transformer when
|
|
67
|
+
* check-stage plugins pass and no transform-stage plugins are declared.
|
|
68
|
+
*/
|
|
49
69
|
function transformProjectWithNativeHost(
|
|
50
70
|
options: ITtscCompilerContext,
|
|
51
71
|
project: ITtscParsedProjectConfig,
|
|
@@ -160,6 +180,10 @@ function transformProjectWithPlugins(
|
|
|
160
180
|
};
|
|
161
181
|
}
|
|
162
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Run every check-stage plugin in sequence, short-circuiting on the first
|
|
185
|
+
* failure. Returns the aggregated `TtscBuildResult` (status 0 when all pass).
|
|
186
|
+
*/
|
|
163
187
|
function runNativeChecks(
|
|
164
188
|
options: ITtscCompilerContext,
|
|
165
189
|
project: ITtscParsedProjectConfig,
|
|
@@ -204,6 +228,7 @@ function runNativeChecks(
|
|
|
204
228
|
return result;
|
|
205
229
|
}
|
|
206
230
|
|
|
231
|
+
/** Build the CLI argument list for the `transform` subcommand. */
|
|
207
232
|
function createNativeTransformArgs(
|
|
208
233
|
project: ITtscParsedProjectConfig,
|
|
209
234
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
@@ -216,6 +241,7 @@ function createNativeTransformArgs(
|
|
|
216
241
|
];
|
|
217
242
|
}
|
|
218
243
|
|
|
244
|
+
/** Build the CLI argument list for the `check` subcommand. */
|
|
219
245
|
function createNativeCheckArgs(
|
|
220
246
|
project: ITtscParsedProjectConfig,
|
|
221
247
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
@@ -228,6 +254,10 @@ function createNativeCheckArgs(
|
|
|
228
254
|
];
|
|
229
255
|
}
|
|
230
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Serialize the plugin list to a JSON string for `--plugins-json=`. Only the
|
|
259
|
+
* fields the native binary needs are included to keep the arg short.
|
|
260
|
+
*/
|
|
231
261
|
function serializeNativePlugins(
|
|
232
262
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
233
263
|
): string {
|
|
@@ -240,6 +270,12 @@ function serializeNativePlugins(
|
|
|
240
270
|
);
|
|
241
271
|
}
|
|
242
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Build the environment for a native plugin spawn. Injects `TTSC_NODE_BINARY`,
|
|
275
|
+
* `TTSC_TSGO_BINARY`, and `TTSC_TTSX_BINARY` so the sidecar can re-invoke
|
|
276
|
+
* Node.js or tsgo without searching PATH. For transform plugins, also passes
|
|
277
|
+
* `TTSC_LINKED_PLUGINS_JSON` when linked sources are present.
|
|
278
|
+
*/
|
|
243
279
|
function nativePluginEnv(
|
|
244
280
|
options: ITtscCompilerContext,
|
|
245
281
|
projectRoot: string,
|
|
@@ -265,53 +301,13 @@ function nativePluginEnv(
|
|
|
265
301
|
return env;
|
|
266
302
|
}
|
|
267
303
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
) {
|
|
276
|
-
const viaNode = /\.(?:[cm]?js|ts)$/i.test(binary);
|
|
277
|
-
if (!viaNode) {
|
|
278
|
-
ensureExecutable(binary);
|
|
279
|
-
}
|
|
280
|
-
return spawnSync(
|
|
281
|
-
viaNode ? process.execPath : binary,
|
|
282
|
-
viaNode ? [binary, ...args] : [...args],
|
|
283
|
-
{
|
|
284
|
-
cwd: options.cwd,
|
|
285
|
-
encoding: "utf8",
|
|
286
|
-
env: options.env,
|
|
287
|
-
maxBuffer: 1024 * 1024 * 256,
|
|
288
|
-
windowsHide: true,
|
|
289
|
-
},
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function ensureExecutable(binary: string): void {
|
|
294
|
-
if (process.platform === "win32") {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
try {
|
|
298
|
-
const mode = fs.statSync(binary).mode & 0o777;
|
|
299
|
-
if ((mode & 0o111) !== 0) {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
fs.chmodSync(binary, mode | 0o755);
|
|
303
|
-
} catch {
|
|
304
|
-
/* keep the original spawn error path */
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function outputText(value: string | Buffer | null | undefined): string {
|
|
309
|
-
if (value == null) {
|
|
310
|
-
return "";
|
|
311
|
-
}
|
|
312
|
-
return typeof value === "string" ? value : value.toString("utf8");
|
|
313
|
-
}
|
|
314
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Parse the JSON envelope written by the native transform host to stdout.
|
|
306
|
+
*
|
|
307
|
+
* The `typescript` field must be a `Record<string, string>`. Any other shape is
|
|
308
|
+
* treated as a protocol error and throws with the stderr/stdout context. JSON
|
|
309
|
+
* parse errors are also wrapped with the same context message.
|
|
310
|
+
*/
|
|
315
311
|
function parseNativeTransformOutput(
|
|
316
312
|
stdout: string,
|
|
317
313
|
stderr: string,
|
|
@@ -344,6 +340,7 @@ function parseNativeTransformOutput(
|
|
|
344
340
|
}
|
|
345
341
|
}
|
|
346
342
|
|
|
343
|
+
/** Type guard: true when `value` is a non-null, non-array object of strings. */
|
|
347
344
|
function isTextRecord(value: unknown): value is Record<string, string> {
|
|
348
345
|
return (
|
|
349
346
|
typeof value === "object" &&
|
|
@@ -352,20 +349,3 @@ function isTextRecord(value: unknown): value is Record<string, string> {
|
|
|
352
349
|
Object.values(value).every((entry) => typeof entry === "string")
|
|
353
350
|
);
|
|
354
351
|
}
|
|
355
|
-
|
|
356
|
-
function packageRootDir(): string {
|
|
357
|
-
let current = path.resolve(__dirname);
|
|
358
|
-
while (true) {
|
|
359
|
-
if (
|
|
360
|
-
fs.existsSync(path.join(current, "package.json")) &&
|
|
361
|
-
fs.existsSync(path.join(current, "go.mod"))
|
|
362
|
-
) {
|
|
363
|
-
return fs.realpathSync.native?.(current) ?? fs.realpathSync(current);
|
|
364
|
-
}
|
|
365
|
-
const parent = path.dirname(current);
|
|
366
|
-
if (parent === current) {
|
|
367
|
-
throw new Error("ttsc: package root not found for native compiler build");
|
|
368
|
-
}
|
|
369
|
-
current = parent;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
@@ -23,6 +23,7 @@ export function getCompilerVersionText(
|
|
|
23
23
|
return `ttsc ${readOwnPackageVersion()} (${outputText(res.stdout).trim()})`;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/** Coerce a spawnSync stdio field (string | Buffer | null) to a plain string. */
|
|
26
27
|
function outputText(value: string | Buffer | null | undefined): string {
|
|
27
28
|
if (value == null) {
|
|
28
29
|
return "";
|
|
@@ -30,6 +31,12 @@ function outputText(value: string | Buffer | null | undefined): string {
|
|
|
30
31
|
return typeof value === "string" ? value : value.toString("utf8");
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Read the `version` field from the `@ttsc/ttsc` package.json that sits three
|
|
36
|
+
* directories above the compiled launcher output (`lib/launcher/internal/`).
|
|
37
|
+
* Returns `"0.0.0"` on any I/O or parse failure so the banner is always safe to
|
|
38
|
+
* display.
|
|
39
|
+
*/
|
|
33
40
|
function readOwnPackageVersion(): string {
|
|
34
41
|
try {
|
|
35
42
|
const file = path.resolve(__dirname, "..", "..", "..", "package.json");
|