ttsc 0.12.3 → 0.12.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +22 -9
- 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/shim.go +24 -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 +22 -10
- 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
|
@@ -3,7 +3,19 @@ import path from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import type { ITtscProjectLocatorOptions } from "../../../structures/internal/ITtscProjectLocatorOptions";
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the tsconfig/jsconfig that owns a ttsc invocation.
|
|
8
|
+
*
|
|
9
|
+
* Resolution order:
|
|
10
|
+
*
|
|
11
|
+
* 1. `opts.tsconfig` — resolved absolute and checked for existence.
|
|
12
|
+
* 2. `opts.file` — the nearest ancestor config that contains the file is found by
|
|
13
|
+
* walking up from the file's directory.
|
|
14
|
+
* 3. `opts.cwd` — the nearest ancestor config walking up from cwd.
|
|
15
|
+
*
|
|
16
|
+
* Always returns a real (symlink-resolved) absolute path. Throws when no config
|
|
17
|
+
* is found or the explicitly supplied path does not exist.
|
|
18
|
+
*/
|
|
7
19
|
export function resolveProjectConfig(
|
|
8
20
|
opts: ITtscProjectLocatorOptions = {},
|
|
9
21
|
): string {
|
|
@@ -29,10 +41,15 @@ export function resolveProjectConfig(
|
|
|
29
41
|
return resolveRealPath(found);
|
|
30
42
|
}
|
|
31
43
|
|
|
44
|
+
/** Resolve `target` against `cwd` when it is not already absolute. */
|
|
32
45
|
function resolveAbsolutePath(cwd: string, target: string): string {
|
|
33
46
|
return path.isAbsolute(target) ? target : path.resolve(cwd, target);
|
|
34
47
|
}
|
|
35
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Resolve symlinks on `location`, returning the original path when
|
|
51
|
+
* `realpathSync` fails (e.g. when the file does not yet exist).
|
|
52
|
+
*/
|
|
36
53
|
function resolveRealPath(location: string): string {
|
|
37
54
|
try {
|
|
38
55
|
return fs.realpathSync(location);
|
|
@@ -41,6 +58,11 @@ function resolveRealPath(location: string): string {
|
|
|
41
58
|
}
|
|
42
59
|
}
|
|
43
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Walk up the directory tree from `from`, returning the first directory that
|
|
63
|
+
* contains a file whose name is in `names`. Returns `null` when the filesystem
|
|
64
|
+
* root is reached without finding a match.
|
|
65
|
+
*/
|
|
44
66
|
function findUp(from: string, names: readonly string[]): string | null {
|
|
45
67
|
let current = path.resolve(from);
|
|
46
68
|
while (true) {
|
|
@@ -58,6 +80,7 @@ function findUp(from: string, names: readonly string[]): string | null {
|
|
|
58
80
|
}
|
|
59
81
|
}
|
|
60
82
|
|
|
83
|
+
/** Return true when `location` exists and is a directory. */
|
|
61
84
|
function isDirectory(location: string): boolean {
|
|
62
85
|
try {
|
|
63
86
|
return fs.statSync(location).isDirectory();
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the ttsc helper binary path, or null when unavailable.
|
|
6
|
+
*
|
|
7
|
+
* Resolution order:
|
|
8
|
+
*
|
|
9
|
+
* 1. `TTSC_BINARY` env var — must be an absolute path when set.
|
|
10
|
+
* 2. The per-platform npm package `@ttsc/<platform>-<arch>/bin/ttsc[.exe]`.
|
|
11
|
+
* 3. A `ttsc-native[.exe]` sibling of this package's root (dev/CI layout).
|
|
12
|
+
*/
|
|
5
13
|
export function resolveBinary(
|
|
6
14
|
opts: { env?: NodeJS.ProcessEnv } = {},
|
|
7
15
|
): string | null {
|
|
@@ -24,6 +32,10 @@ export function resolveBinary(
|
|
|
24
32
|
return null;
|
|
25
33
|
}
|
|
26
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Return the path to the dev-layout `ttsc-native[.exe]` binary adjacent to the
|
|
37
|
+
* package root, or null when the file does not exist.
|
|
38
|
+
*/
|
|
27
39
|
function defaultLocalBinaryPath(): string | null {
|
|
28
40
|
const root = packageRootDir();
|
|
29
41
|
const candidate = path.resolve(
|
|
@@ -35,6 +47,10 @@ function defaultLocalBinaryPath(): string | null {
|
|
|
35
47
|
return fs.existsSync(candidate) ? candidate : null;
|
|
36
48
|
}
|
|
37
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Return the real, absolute path of the `packages/ttsc` package root by walking
|
|
52
|
+
* two levels up from `__dirname` (which lives in `src/compiler/internal`).
|
|
53
|
+
*/
|
|
38
54
|
function packageRootDir(): string {
|
|
39
55
|
const moduleDir = path.resolve(__dirname, "..", "..");
|
|
40
56
|
return fs.realpathSync.native?.(moduleDir) ?? fs.realpathSync(moduleDir);
|
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import { isOutsideRelativePath } from "./paths";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Locate the JavaScript file emitted for a TypeScript source file.
|
|
8
|
+
*
|
|
9
|
+
* Resolution strategy:
|
|
10
|
+
*
|
|
11
|
+
* 1. Try to derive the exact output path by mirroring the source's relative
|
|
12
|
+
* position inside `projectRoot` into `outDir`, applying the correct JS
|
|
13
|
+
* extension (`.js` / `.mjs` / `.cjs`). Use this path if it exists on disk.
|
|
14
|
+
* 2. Fall back to scoring each candidate in `emittedFiles` (or a recursive
|
|
15
|
+
* directory scan of `outDir`) by the number of trailing path-stem segments
|
|
16
|
+
* shared with the source file name, and pick the highest-scoring existing
|
|
17
|
+
* file.
|
|
18
|
+
*
|
|
19
|
+
* Returns `null` when no matching output file is found on disk.
|
|
20
|
+
*/
|
|
5
21
|
export function resolveEmittedJavaScript(options: {
|
|
22
|
+
/** Pre-computed list of emitted paths; when absent `outDir` is scanned. */
|
|
6
23
|
emittedFiles?: readonly string[];
|
|
7
24
|
outDir: string;
|
|
8
25
|
projectRoot: string;
|
|
@@ -31,6 +48,11 @@ export function resolveEmittedJavaScript(options: {
|
|
|
31
48
|
return best && fs.existsSync(best) ? best : null;
|
|
32
49
|
}
|
|
33
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Derive the exact output path for `sourceFile` by mirroring its position
|
|
53
|
+
* relative to `projectRoot` into `outDir`. Returns `null` when the source is
|
|
54
|
+
* not inside the project root or when the path cannot be determined.
|
|
55
|
+
*/
|
|
34
56
|
function resolveExactEmittedFile(
|
|
35
57
|
outDir: string,
|
|
36
58
|
projectRoot: string,
|
|
@@ -47,6 +69,11 @@ function resolveExactEmittedFile(
|
|
|
47
69
|
);
|
|
48
70
|
}
|
|
49
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Recursively enumerate every JavaScript output file under `root`. Uses an
|
|
74
|
+
* explicit stack instead of recursion to avoid call-stack overflow on deep
|
|
75
|
+
* directory trees. Non-existent roots are silently skipped.
|
|
76
|
+
*/
|
|
50
77
|
function listJavaScriptFiles(root: string): string[] {
|
|
51
78
|
const out: string[] = [];
|
|
52
79
|
const stack = [root];
|
|
@@ -65,15 +92,22 @@ function listJavaScriptFiles(root: string): string[] {
|
|
|
65
92
|
return out;
|
|
66
93
|
}
|
|
67
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Count the number of consecutive trailing path-stem segments that `outPath`
|
|
97
|
+
* and `srcPath` share when both are stripped of their extensions and normalised
|
|
98
|
+
* to forward slashes.
|
|
99
|
+
*
|
|
100
|
+
* Example: `dist/lib/foo.js` vs `src/lib/foo.ts` → 2 (`lib`, `foo`).
|
|
101
|
+
*/
|
|
68
102
|
function sharedSourceStemSegments(outPath: string, srcPath: string): number {
|
|
69
|
-
const
|
|
103
|
+
const stripExtAndSplit = (location: string): string[] => {
|
|
70
104
|
const normalized = location.replace(/\\/g, "/");
|
|
71
105
|
return normalized
|
|
72
106
|
.slice(0, normalized.length - path.extname(normalized).length)
|
|
73
107
|
.split("/");
|
|
74
108
|
};
|
|
75
|
-
const a =
|
|
76
|
-
const b =
|
|
109
|
+
const a = stripExtAndSplit(outPath);
|
|
110
|
+
const b = stripExtAndSplit(srcPath);
|
|
77
111
|
const count = Math.min(a.length, b.length);
|
|
78
112
|
let shared = 0;
|
|
79
113
|
for (let i = 1; i <= count; i += 1) {
|
|
@@ -83,14 +117,10 @@ function sharedSourceStemSegments(outPath: string, srcPath: string): number {
|
|
|
83
117
|
return shared;
|
|
84
118
|
}
|
|
85
119
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
path.isAbsolute(relative)
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Map a TypeScript source extension to its JavaScript output counterpart.
|
|
122
|
+
* `.mts` → `.mjs`, `.cts` → `.cjs`, everything else → `.js`.
|
|
123
|
+
*/
|
|
94
124
|
function emittedJavaScriptExtension(filename: string): string {
|
|
95
125
|
switch (path.extname(filename).toLowerCase()) {
|
|
96
126
|
case ".mts":
|
|
@@ -102,6 +132,7 @@ function emittedJavaScriptExtension(filename: string): string {
|
|
|
102
132
|
}
|
|
103
133
|
}
|
|
104
134
|
|
|
135
|
+
/** Return true when `filename` has a `.js`, `.mjs`, or `.cjs` extension. */
|
|
105
136
|
function isJavaScriptOutput(filename: string): boolean {
|
|
106
137
|
return /\.(?:[cm]?js)$/i.test(filename);
|
|
107
138
|
}
|
|
@@ -2,12 +2,32 @@ import fs from "node:fs";
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the consumer project's TypeScript-Go preview binary and metadata.
|
|
7
|
+
*
|
|
8
|
+
* Resolution order:
|
|
9
|
+
*
|
|
10
|
+
* 1. `opts.binary` or `TTSC_TSGO_BINARY` env var — must be an existing absolute
|
|
11
|
+
* path; returns `{ binary, packageJson: "", packageRoot, version: "custom"
|
|
12
|
+
* }`.
|
|
13
|
+
* 2. `@typescript/native-preview` resolved from the project `cwd`.
|
|
14
|
+
* 3. `@typescript/native-preview` resolved from `opts.resolveFrom` (for test
|
|
15
|
+
* harnesses and embedders that anchor to a different directory).
|
|
16
|
+
*
|
|
17
|
+
* Throws a descriptive error when the package or platform binary is missing so
|
|
18
|
+
* callers never have to reason about undefined binary paths.
|
|
19
|
+
*/
|
|
6
20
|
export function resolveTsgo(
|
|
7
21
|
opts: {
|
|
22
|
+
/** Explicit path to a tsgo binary; bypasses package resolution. */
|
|
8
23
|
binary?: string;
|
|
24
|
+
/** Directory from which to discover `@typescript/native-preview`. */
|
|
9
25
|
cwd?: string;
|
|
10
26
|
env?: NodeJS.ProcessEnv;
|
|
27
|
+
/**
|
|
28
|
+
* Fallback resolution anchor used when the package is not found at `cwd`.
|
|
29
|
+
* Useful in test harnesses that install the package into a different tree.
|
|
30
|
+
*/
|
|
11
31
|
resolveFrom?: string;
|
|
12
32
|
} = {},
|
|
13
33
|
) {
|
|
@@ -28,6 +48,8 @@ export function resolveTsgo(
|
|
|
28
48
|
}
|
|
29
49
|
|
|
30
50
|
const cwd = path.resolve(opts.cwd ?? process.cwd());
|
|
51
|
+
// Resolve the package.json of @typescript/native-preview.
|
|
52
|
+
// Try cwd first, then the optional resolveFrom anchor.
|
|
31
53
|
let packageJson: string;
|
|
32
54
|
packageJson =
|
|
33
55
|
resolveNativePreviewPackageJson(path.join(cwd, "package.json")) ??
|
|
@@ -84,6 +106,11 @@ export function resolveTsgo(
|
|
|
84
106
|
};
|
|
85
107
|
}
|
|
86
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Attempt to resolve the `package.json` of `@typescript/native-preview`
|
|
111
|
+
* starting from `from` (a package.json path or directory). Returns `undefined`
|
|
112
|
+
* when the package is not resolvable from that location.
|
|
113
|
+
*/
|
|
87
114
|
function resolveNativePreviewPackageJson(from: string): string | undefined {
|
|
88
115
|
try {
|
|
89
116
|
return createRequire(from).resolve(
|
|
@@ -94,6 +121,7 @@ function resolveNativePreviewPackageJson(from: string): string | undefined {
|
|
|
94
121
|
}
|
|
95
122
|
}
|
|
96
123
|
|
|
124
|
+
/** Parse a JSON file and return the result as a plain object. */
|
|
97
125
|
function readPackageJson(file: string): Record<string, unknown> {
|
|
98
126
|
return JSON.parse(fs.readFileSync(file, "utf8")) as Record<string, unknown>;
|
|
99
127
|
}
|
|
@@ -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[] {
|