ttsc 0.7.2 → 0.8.0-dev.20260505
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/README.md +5 -5
- package/cmd/platform/main.go +86 -76
- package/cmd/ttsc/api_compile.go +122 -105
- package/cmd/ttsc/api_transform.go +57 -49
- package/cmd/ttsc/build.go +116 -103
- package/cmd/ttsc/main.go +117 -117
- package/cmd/ttsc/main_test.go +191 -191
- package/driver/host.go +9 -9
- package/driver/program.go +285 -285
- package/driver/rewrite.go +266 -219
- package/lib/compiler/internal/compileProjectInMemory.js +3 -3
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.js +2 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runBuild.js +47 -49
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +44 -4
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/launcher/internal/getCompilerVersionText.js +1 -2
- package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +6 -4
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +49 -5
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +7 -2
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.js +6 -0
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.js +55 -2
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscPlugin.d.ts +19 -3
- package/lib/structures/ITtscPlugin.js +4 -0
- package/lib/structures/ITtscPlugin.js.map +1 -1
- package/lib/structures/TtscPluginStage.d.ts +4 -10
- package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +5 -0
- package/package.json +11 -10
- package/shim/ast/lint.go +172 -171
- package/shim/ast/shim.go +84 -83
- package/shim/bundled/shim.go +5 -1
- package/shim/checker/shim.go +79 -79
- package/shim/compiler/emit_hooks.go +494 -0
- package/shim/compiler/shim.go +16 -1
- package/shim/core/shim.go +13 -10
- package/shim/diagnosticwriter/lint.go +79 -79
- package/shim/diagnosticwriter/shim.go +19 -19
- package/shim/parser/shim.go +7 -1
- package/shim/scanner/shim.go +39 -1
- package/shim/tsoptions/shim.go +51 -1
- package/shim/tspath/shim.go +72 -1
- package/shim/vfs/cachedvfs/shim.go +1 -1
- package/shim/vfs/osvfs/shim.go +1 -1
- package/shim/vfs/shim.go +4 -1
- package/src/compiler/internal/compileProjectInMemory.ts +6 -3
- package/src/compiler/internal/resolveEmittedJavaScript.ts +2 -1
- package/src/compiler/internal/resolveTsgo.ts +0 -1
- package/src/compiler/internal/runBuild.ts +58 -86
- package/src/compiler/internal/transformProjectInMemory.ts +51 -6
- package/src/launcher/internal/getCompilerVersionText.ts +1 -2
- package/src/launcher/internal/prepareExecution.ts +6 -6
- package/src/launcher/internal/runTtsc.ts +52 -5
- package/src/launcher/internal/runTtsx.ts +16 -5
- package/src/plugin/internal/buildSourcePlugin.ts +30 -2
- package/src/plugin/internal/loadProjectPlugins.ts +81 -2
- package/src/structures/ITtscPlugin.ts +30 -3
- package/src/structures/TtscPluginStage.ts +4 -10
- package/src/structures/internal/ITtscLoadedNativePlugin.ts +5 -0
- package/test/compiler.test.ts +3 -3
- package/test/platform.test.ts +1 -3
- package/test/tsgo.test.ts +15 -7
- package/tools/gen_shims/main.go +409 -409
- package/utility/host.go +707 -0
|
@@ -2,6 +2,7 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
|
|
5
|
+
import { TtscCompiler } from "../../TtscCompiler";
|
|
5
6
|
import { resolveBinary } from "../../compiler/internal/resolveBinary";
|
|
6
7
|
import { runBuild } from "../../compiler/internal/runBuild";
|
|
7
8
|
import { runSingleFileEmit } from "../../compiler/internal/runSingleFileEmit";
|
|
@@ -35,6 +36,8 @@ export function runTtsc(
|
|
|
35
36
|
return runCompatibleBuild(rest, true);
|
|
36
37
|
case "clean":
|
|
37
38
|
return runClean(rest);
|
|
39
|
+
case "prepare":
|
|
40
|
+
return runPrepare(rest);
|
|
38
41
|
case "demo":
|
|
39
42
|
return delegateToNative(argv);
|
|
40
43
|
case "-p":
|
|
@@ -82,13 +85,41 @@ function runCompatibleBuild(
|
|
|
82
85
|
return result.status;
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
function runPrepare(argv: readonly string[]): number {
|
|
89
|
+
const options = parseProjectArgs(argv);
|
|
90
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
91
|
+
const compiler = new TtscCompiler({
|
|
92
|
+
cacheDir: options.cacheDir,
|
|
93
|
+
cwd,
|
|
94
|
+
tsconfig: options.tsconfig,
|
|
95
|
+
});
|
|
96
|
+
const prepared = compiler.prepare();
|
|
97
|
+
if (prepared.length === 0) {
|
|
98
|
+
const projectRoot = path.dirname(
|
|
99
|
+
resolveProjectConfig({
|
|
100
|
+
cwd,
|
|
101
|
+
tsconfig: options.tsconfig,
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
process.stdout.write(
|
|
105
|
+
`ttsc: no source plugins found under ${formatProjectPath(cwd, projectRoot)}\n`,
|
|
106
|
+
);
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
for (const target of prepared) {
|
|
110
|
+
process.stdout.write(`ttsc: prepared ${formatProjectPath(cwd, target)}\n`);
|
|
111
|
+
}
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
85
115
|
function runClean(argv: readonly string[]): number {
|
|
86
|
-
const options =
|
|
116
|
+
const options = parseProjectArgs(argv);
|
|
87
117
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
88
118
|
const projectRoot = resolveCleanProjectRoot(cwd, options.tsconfig);
|
|
89
119
|
const targets = [
|
|
90
120
|
path.join(projectRoot, "node_modules", ".ttsc"),
|
|
91
121
|
path.join(projectRoot, ".ttsc"),
|
|
122
|
+
...(options.cacheDir ? [path.resolve(cwd, options.cacheDir)] : []),
|
|
92
123
|
...(process.env.TTSC_CACHE_DIR
|
|
93
124
|
? [path.resolve(process.env.TTSC_CACHE_DIR, "plugins")]
|
|
94
125
|
: []),
|
|
@@ -106,7 +137,7 @@ function runClean(argv: readonly string[]): number {
|
|
|
106
137
|
return 0;
|
|
107
138
|
}
|
|
108
139
|
for (const target of removed) {
|
|
109
|
-
process.stdout.write(`ttsc: removed ${
|
|
140
|
+
process.stdout.write(`ttsc: removed ${formatProjectPath(cwd, target)}\n`);
|
|
110
141
|
}
|
|
111
142
|
return 0;
|
|
112
143
|
}
|
|
@@ -120,7 +151,7 @@ function resolveCleanProjectRoot(cwd: string, tsconfig?: string): string {
|
|
|
120
151
|
}
|
|
121
152
|
}
|
|
122
153
|
|
|
123
|
-
function
|
|
154
|
+
function formatProjectPath(cwd: string, target: string): string {
|
|
124
155
|
const relative = path.relative(cwd, target);
|
|
125
156
|
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
126
157
|
return target;
|
|
@@ -174,7 +205,8 @@ function ensureExecutable(binary: string): void {
|
|
|
174
205
|
}
|
|
175
206
|
}
|
|
176
207
|
|
|
177
|
-
function
|
|
208
|
+
function parseProjectArgs(argv: readonly string[]) {
|
|
209
|
+
let cacheDir: string | undefined;
|
|
178
210
|
let cwd: string | undefined;
|
|
179
211
|
let tsconfig: string | undefined;
|
|
180
212
|
|
|
@@ -185,6 +217,9 @@ function parseCleanArgs(argv: readonly string[]) {
|
|
|
185
217
|
case "--cwd":
|
|
186
218
|
cwd = takeValue(current, rest);
|
|
187
219
|
break;
|
|
220
|
+
case "--cache-dir":
|
|
221
|
+
cacheDir = takeValue(current, rest);
|
|
222
|
+
break;
|
|
188
223
|
case "-p":
|
|
189
224
|
case "--tsconfig":
|
|
190
225
|
case "--project":
|
|
@@ -193,6 +228,8 @@ function parseCleanArgs(argv: readonly string[]) {
|
|
|
193
228
|
default:
|
|
194
229
|
if (current.startsWith("--cwd=")) {
|
|
195
230
|
cwd = current.slice("--cwd=".length);
|
|
231
|
+
} else if (current.startsWith("--cache-dir=")) {
|
|
232
|
+
cacheDir = current.slice("--cache-dir=".length);
|
|
196
233
|
} else if (current.startsWith("--tsconfig=")) {
|
|
197
234
|
tsconfig = current.slice("--tsconfig=".length);
|
|
198
235
|
} else if (current.startsWith("--project=")) {
|
|
@@ -203,11 +240,12 @@ function parseCleanArgs(argv: readonly string[]) {
|
|
|
203
240
|
break;
|
|
204
241
|
}
|
|
205
242
|
}
|
|
206
|
-
return { cwd, tsconfig };
|
|
243
|
+
return { cacheDir, cwd, tsconfig };
|
|
207
244
|
}
|
|
208
245
|
|
|
209
246
|
function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
|
|
210
247
|
let binary: string | undefined;
|
|
248
|
+
let cacheDir: string | undefined;
|
|
211
249
|
let cwd: string | undefined;
|
|
212
250
|
let emit: boolean | undefined = checkOnly ? false : undefined;
|
|
213
251
|
const files: string[] = [];
|
|
@@ -254,6 +292,9 @@ function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
|
|
|
254
292
|
case "--binary":
|
|
255
293
|
binary = takeValue(current, rest);
|
|
256
294
|
break;
|
|
295
|
+
case "--cache-dir":
|
|
296
|
+
cacheDir = takeValue(current, rest);
|
|
297
|
+
break;
|
|
257
298
|
default:
|
|
258
299
|
if (current.startsWith("--cwd=")) {
|
|
259
300
|
cwd = current.slice("--cwd=".length);
|
|
@@ -270,6 +311,8 @@ function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
|
|
|
270
311
|
current.slice("--preserveWatchOutput=".length) !== "false";
|
|
271
312
|
} else if (current.startsWith("--binary=")) {
|
|
272
313
|
binary = current.slice("--binary=".length);
|
|
314
|
+
} else if (current.startsWith("--cache-dir=")) {
|
|
315
|
+
cacheDir = current.slice("--cache-dir=".length);
|
|
273
316
|
} else if (current === "--verbose") {
|
|
274
317
|
quiet = false;
|
|
275
318
|
} else if (current.startsWith("-")) {
|
|
@@ -282,6 +325,7 @@ function parseBuildArgs(argv: readonly string[], checkOnly: boolean) {
|
|
|
282
325
|
}
|
|
283
326
|
return {
|
|
284
327
|
binary,
|
|
328
|
+
cacheDir,
|
|
285
329
|
cwd,
|
|
286
330
|
emit,
|
|
287
331
|
files,
|
|
@@ -303,6 +347,7 @@ function printHelp(): void {
|
|
|
303
347
|
" ttsc -p tsconfig.json",
|
|
304
348
|
" ttsc --watch",
|
|
305
349
|
" ttsc --noEmit",
|
|
350
|
+
" ttsc prepare [options]",
|
|
306
351
|
" ttsc clean [options]",
|
|
307
352
|
" ttsc version",
|
|
308
353
|
" ttsc --help",
|
|
@@ -319,6 +364,7 @@ function printHelp(): void {
|
|
|
319
364
|
" --quiet Keep build output quiet (default)",
|
|
320
365
|
" --verbose Print the build summary and emitted files",
|
|
321
366
|
" --binary <path> Use an explicit tsgo binary",
|
|
367
|
+
" --cache-dir <dir> Use this cache root for source-plugin builds",
|
|
322
368
|
"",
|
|
323
369
|
"Plugin contract:",
|
|
324
370
|
" ttsc reads compilerOptions.plugins from tsconfig.json.",
|
|
@@ -328,6 +374,7 @@ function printHelp(): void {
|
|
|
328
374
|
"Compatibility aliases:",
|
|
329
375
|
" ttsc build [options] Same project build lane as `ttsc [options]`.",
|
|
330
376
|
" ttsc check [options] Same as `ttsc --noEmit [options]`.",
|
|
377
|
+
" ttsc prepare [options] Build configured source-plugin binaries into cache.",
|
|
331
378
|
" ttsc clean [options] Delete local source-plugin cache directories.",
|
|
332
379
|
].join("\n"),
|
|
333
380
|
);
|
|
@@ -5,7 +5,9 @@ import * as path from "node:path";
|
|
|
5
5
|
import { getCompilerVersionText } from "./getCompilerVersionText";
|
|
6
6
|
import { prepareExecution } from "./prepareExecution";
|
|
7
7
|
|
|
8
|
-
export function runTtsx(
|
|
8
|
+
export function runTtsx(
|
|
9
|
+
argv: readonly string[] = process.argv.slice(2),
|
|
10
|
+
): number {
|
|
9
11
|
try {
|
|
10
12
|
return run(argv);
|
|
11
13
|
} catch (error) {
|
|
@@ -53,8 +55,10 @@ function formatError(error: unknown): string {
|
|
|
53
55
|
function parseCLI(argv: readonly string[]) {
|
|
54
56
|
const preload: string[] = [];
|
|
55
57
|
const passthroughIndex = argv.indexOf("--");
|
|
56
|
-
const head =
|
|
57
|
-
|
|
58
|
+
const head =
|
|
59
|
+
passthroughIndex === -1 ? [...argv] : [...argv.slice(0, passthroughIndex)];
|
|
60
|
+
const passthrough =
|
|
61
|
+
passthroughIndex === -1 ? [] : [...argv.slice(passthroughIndex + 1)];
|
|
58
62
|
|
|
59
63
|
let binary: string | undefined;
|
|
60
64
|
let cacheDir: string | undefined;
|
|
@@ -151,7 +155,11 @@ function printHelp(): void {
|
|
|
151
155
|
}
|
|
152
156
|
|
|
153
157
|
function resolvePreload(cwd: string, preload: string): string {
|
|
154
|
-
if (
|
|
158
|
+
if (
|
|
159
|
+
preload.startsWith(".") ||
|
|
160
|
+
preload.startsWith("/") ||
|
|
161
|
+
preload.includes(path.sep)
|
|
162
|
+
) {
|
|
155
163
|
return path.resolve(cwd, preload);
|
|
156
164
|
}
|
|
157
165
|
return preload;
|
|
@@ -180,7 +188,10 @@ function runPreparedEntry(
|
|
|
180
188
|
);
|
|
181
189
|
}
|
|
182
190
|
const args = [
|
|
183
|
-
...parsed.preload.flatMap((preload) => [
|
|
191
|
+
...parsed.preload.flatMap((preload) => [
|
|
192
|
+
"-r",
|
|
193
|
+
resolvePreload(cwd, preload),
|
|
194
|
+
]),
|
|
184
195
|
execution.entryFile,
|
|
185
196
|
...parsed.passthrough,
|
|
186
197
|
];
|
|
@@ -155,7 +155,9 @@ function writeGoWork(scratchDir: string, useDirs: readonly string[]): void {
|
|
|
155
155
|
fs.writeFileSync(path.join(scratchDir, "go.work"), goWork, "utf8");
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
function sourceBuildWorkspaceReplacements(
|
|
158
|
+
function sourceBuildWorkspaceReplacements(
|
|
159
|
+
useDirs: readonly string[],
|
|
160
|
+
): string[] {
|
|
159
161
|
const ttscRoot = useDirs.find((dir) =>
|
|
160
162
|
hasModulePath(dir, "github.com/samchon/ttsc/packages/ttsc"),
|
|
161
163
|
);
|
|
@@ -308,7 +310,10 @@ function walkForGoMod(dir: string, out: string[]): void {
|
|
|
308
310
|
}
|
|
309
311
|
}
|
|
310
312
|
|
|
311
|
-
function resolvePluginCacheRoot(
|
|
313
|
+
function resolvePluginCacheRoot(
|
|
314
|
+
projectRoot: string,
|
|
315
|
+
cacheDir?: string,
|
|
316
|
+
): string {
|
|
312
317
|
if (cacheDir) {
|
|
313
318
|
return path.resolve(cacheDir, "plugins");
|
|
314
319
|
}
|
|
@@ -343,6 +348,20 @@ function resolveGoCompiler(): string {
|
|
|
343
348
|
/* fall through */
|
|
344
349
|
}
|
|
345
350
|
|
|
351
|
+
const platformPackage = path.resolve(
|
|
352
|
+
__dirname,
|
|
353
|
+
"..",
|
|
354
|
+
"..",
|
|
355
|
+
"..",
|
|
356
|
+
"..",
|
|
357
|
+
`ttsc-${process.platform}-${process.arch}`,
|
|
358
|
+
"bin",
|
|
359
|
+
"go",
|
|
360
|
+
"bin",
|
|
361
|
+
process.platform === "win32" ? "go.exe" : "go",
|
|
362
|
+
);
|
|
363
|
+
if (fs.existsSync(platformPackage)) return platformPackage;
|
|
364
|
+
|
|
346
365
|
const local = path.resolve(
|
|
347
366
|
__dirname,
|
|
348
367
|
"..",
|
|
@@ -356,6 +375,15 @@ function resolveGoCompiler(): string {
|
|
|
356
375
|
);
|
|
357
376
|
if (fs.existsSync(local)) return local;
|
|
358
377
|
|
|
378
|
+
const homeSdk = path.join(
|
|
379
|
+
process.env.HOME ?? "",
|
|
380
|
+
"go-sdk",
|
|
381
|
+
"go",
|
|
382
|
+
"bin",
|
|
383
|
+
process.platform === "win32" ? "go.exe" : "go",
|
|
384
|
+
);
|
|
385
|
+
if (fs.existsSync(homeSdk)) return homeSdk;
|
|
386
|
+
|
|
359
387
|
return "go";
|
|
360
388
|
}
|
|
361
389
|
|
|
@@ -58,7 +58,9 @@ export function loadProjectPlugins(options: {
|
|
|
58
58
|
const ttscVersion = readTtscVersion();
|
|
59
59
|
const tsgoVersion = readTsgoVersion(context.projectRoot);
|
|
60
60
|
plugins.forEach((plugin, index) => {
|
|
61
|
+
const stage = resolvePluginStage(plugin);
|
|
61
62
|
validatePluginSource(plugin);
|
|
63
|
+
validatePluginHooks(plugin, stage);
|
|
62
64
|
const binary = buildSourcePlugin({
|
|
63
65
|
baseDir: context.projectRoot,
|
|
64
66
|
cacheDir: options.cacheDir,
|
|
@@ -70,8 +72,10 @@ export function loadProjectPlugins(options: {
|
|
|
70
72
|
nativePlugins.push({
|
|
71
73
|
binary,
|
|
72
74
|
config: entries[index]!,
|
|
75
|
+
hooks: plugin.hooks,
|
|
73
76
|
name: plugin.name,
|
|
74
|
-
|
|
77
|
+
source: plugin.source,
|
|
78
|
+
stage,
|
|
75
79
|
});
|
|
76
80
|
});
|
|
77
81
|
return {
|
|
@@ -88,6 +92,7 @@ function loadPluginEntry(
|
|
|
88
92
|
if (typeof specifier !== "string" || specifier.length === 0) {
|
|
89
93
|
throw new Error(`ttsc: plugin entry is missing a string "transform" field`);
|
|
90
94
|
}
|
|
95
|
+
rejectUserPhaseOptions(specifier, entry);
|
|
91
96
|
|
|
92
97
|
const request = resolvePluginRequest(specifier, context.projectRoot);
|
|
93
98
|
const mod = require(request) as {
|
|
@@ -135,11 +140,37 @@ function rejectJsTransformHooks(specifier: string, candidate: object): void {
|
|
|
135
140
|
}
|
|
136
141
|
}
|
|
137
142
|
|
|
143
|
+
function rejectUserPhaseOptions(
|
|
144
|
+
specifier: string,
|
|
145
|
+
entry: ITtscProjectPluginConfig,
|
|
146
|
+
): void {
|
|
147
|
+
for (const key of [
|
|
148
|
+
"after",
|
|
149
|
+
"afterDeclarations",
|
|
150
|
+
"before",
|
|
151
|
+
"phase",
|
|
152
|
+
"source:after",
|
|
153
|
+
]) {
|
|
154
|
+
if (key in entry) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`ttsc: plugin entry for "${specifier}" uses unsupported ts-patch option ${JSON.stringify(key)}; ` +
|
|
157
|
+
"ttsc plugins declare source/declaration hooks in the package descriptor, not in user tsconfig",
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
138
163
|
function resolvePluginStage(plugin: ITtscPlugin): TtscPluginStage {
|
|
139
164
|
if (plugin.stage === undefined) {
|
|
140
165
|
return "transform";
|
|
141
166
|
}
|
|
142
167
|
if (!isPluginStage(plugin.stage)) {
|
|
168
|
+
if (plugin.stage === "output") {
|
|
169
|
+
throw new Error(
|
|
170
|
+
`ttsc: plugin "${plugin.name}" requested removed stage "output"; ` +
|
|
171
|
+
"upgrade the plugin to a transform hook descriptor compatible with this ttsc version",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
143
174
|
throw new Error(
|
|
144
175
|
`ttsc: plugin "${plugin.name}" requested unsupported stage ${JSON.stringify(plugin.stage)}`,
|
|
145
176
|
);
|
|
@@ -153,8 +184,56 @@ function validatePluginSource(plugin: ITtscPlugin): void {
|
|
|
153
184
|
}
|
|
154
185
|
}
|
|
155
186
|
|
|
187
|
+
function validatePluginHooks(
|
|
188
|
+
plugin: ITtscPlugin,
|
|
189
|
+
stage: TtscPluginStage,
|
|
190
|
+
): void {
|
|
191
|
+
const hooks = plugin.hooks;
|
|
192
|
+
if (hooks !== undefined && typeof hooks !== "object") {
|
|
193
|
+
throw new Error(`ttsc: plugin "${plugin.name}" hooks must be an object`);
|
|
194
|
+
}
|
|
195
|
+
if (stage === "check") {
|
|
196
|
+
if (hooks !== undefined && Object.keys(hooks).length !== 0) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`ttsc: check plugin "${plugin.name}" must not declare transform hooks`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (hooks === undefined) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`ttsc: transform plugin "${plugin.name}" must declare source/declaration hooks in its package descriptor`,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
for (const key of Object.keys(hooks)) {
|
|
209
|
+
if (key !== "source" && key !== "declaration") {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`ttsc: plugin "${plugin.name}" requested unsupported hook ${JSON.stringify(key)}`,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (hooks.source !== undefined && typeof hooks.source !== "boolean") {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`ttsc: plugin "${plugin.name}" hooks.source must be boolean`,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
if (
|
|
221
|
+
hooks.declaration !== undefined &&
|
|
222
|
+
typeof hooks.declaration !== "boolean"
|
|
223
|
+
) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
`ttsc: plugin "${plugin.name}" hooks.declaration must be boolean`,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
if (hooks.source !== true && hooks.declaration !== true) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`ttsc: transform plugin "${plugin.name}" must enable at least one source/declaration hook`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
156
235
|
function isPluginStage(value: string): value is TtscPluginStage {
|
|
157
|
-
return value === "transform" || value === "check"
|
|
236
|
+
return value === "transform" || value === "check";
|
|
158
237
|
}
|
|
159
238
|
|
|
160
239
|
function resolvePluginRequest(specifier: string, projectRoot: string): string {
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import type { TtscPluginStage } from "./TtscPluginStage";
|
|
2
2
|
|
|
3
|
+
export interface ITtscPluginHooks {
|
|
4
|
+
/**
|
|
5
|
+
* Runs against TypeScript SourceFile AST before TypeScript-Go's built-in emit
|
|
6
|
+
* transforms. The Program/checker are created from the original source before
|
|
7
|
+
* this hook participates in emit.
|
|
8
|
+
*/
|
|
9
|
+
source?: boolean;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Runs against declaration AST before declaration printing. This is a
|
|
13
|
+
* plugin-package capability, never a user-facing tsconfig phase option.
|
|
14
|
+
*/
|
|
15
|
+
declaration?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
/**
|
|
4
19
|
* Runtime descriptor returned by a ttsc plugin module.
|
|
5
20
|
*
|
|
@@ -48,11 +63,23 @@ export interface ITtscPlugin {
|
|
|
48
63
|
/**
|
|
49
64
|
* Pipeline stage implemented by the sidecar.
|
|
50
65
|
*
|
|
51
|
-
* Omit this field for normal compiler-transform plugins.
|
|
52
|
-
*
|
|
53
|
-
* emitted files (`"output"`).
|
|
66
|
+
* Omit this field for normal compiler-transform plugins. The only explicit
|
|
67
|
+
* non-transform stage is `"check"`.
|
|
54
68
|
*
|
|
55
69
|
* @default "transform"
|
|
56
70
|
*/
|
|
57
71
|
stage?: TtscPluginStage;
|
|
72
|
+
|
|
73
|
+
/** Native transform hook capabilities implemented by the plugin package. */
|
|
74
|
+
hooks?: ITtscPluginHooks;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function defineTtscPlugin<T extends ITtscPlugin>(plugin: T): T;
|
|
78
|
+
export function defineTtscPlugin<TContext, T extends ITtscPlugin>(
|
|
79
|
+
factory: (context: TContext) => T,
|
|
80
|
+
): (context: TContext) => T;
|
|
81
|
+
export function defineTtscPlugin(
|
|
82
|
+
value: ITtscPlugin | ((context: unknown) => ITtscPlugin),
|
|
83
|
+
): ITtscPlugin | ((context: unknown) => ITtscPlugin) {
|
|
84
|
+
return value;
|
|
58
85
|
}
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pipeline stage where a plugin's lazily built Go sidecar participates.
|
|
3
3
|
*
|
|
4
|
-
* - `"transform"`:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* produces the project's emitted output. During
|
|
8
|
-
* {@link TtscCompiler.transform}, the same sidecar may expose a
|
|
9
|
-
* source-to-source `transform` command that returns transformed TypeScript
|
|
4
|
+
* - `"transform"`: participates in the TypeScript-Go transform path. Transform
|
|
5
|
+
* plugins declare their source/declaration hook capabilities in the plugin
|
|
6
|
+
* package descriptor and do not receive emitted JavaScript or emitted file
|
|
10
7
|
* text.
|
|
11
8
|
* - `"check"`: runs before emit and reports diagnostics only. Use this for
|
|
12
9
|
* lint or validation plugins that should fail the compile before JavaScript
|
|
13
10
|
* or declaration output is generated.
|
|
14
|
-
* - `"output"`: runs after emit for each emitted output file. Use this for
|
|
15
|
-
* post-processing plugins such as banner insertion, import-path rewriting,
|
|
16
|
-
* or output stripping that operate on `.js`, `.d.ts`, or map files.
|
|
17
11
|
*/
|
|
18
|
-
export type TtscPluginStage = "transform" | "check"
|
|
12
|
+
export type TtscPluginStage = "transform" | "check";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ITtscProjectPluginConfig } from "../ITtscProjectPluginConfig";
|
|
2
|
+
import type { ITtscPluginHooks } from "../ITtscPlugin";
|
|
2
3
|
import type { TtscPluginStage } from "../TtscPluginStage";
|
|
3
4
|
|
|
4
5
|
/** Native sidecar selected and built from one plugin descriptor. */
|
|
@@ -9,6 +10,10 @@ export interface ITtscLoadedNativePlugin {
|
|
|
9
10
|
config: ITtscProjectPluginConfig;
|
|
10
11
|
/** Stable plugin name used in diagnostics and native manifests. */
|
|
11
12
|
name: string;
|
|
13
|
+
/** Go source directory selected by the plugin descriptor. */
|
|
14
|
+
source: string;
|
|
12
15
|
/** Pipeline stage where the sidecar participates. */
|
|
13
16
|
stage: TtscPluginStage;
|
|
17
|
+
/** Native transform hook capabilities declared by the plugin package. */
|
|
18
|
+
hooks?: ITtscPluginHooks;
|
|
14
19
|
}
|
package/test/compiler.test.ts
CHANGED
|
@@ -274,7 +274,7 @@ function createProject(options = {}) {
|
|
|
274
274
|
function writeSourcePlugin(root) {
|
|
275
275
|
fs.writeFileSync(
|
|
276
276
|
path.join(root, "plugin.cjs"),
|
|
277
|
-
'module.exports = { name: "prepare-fixture", source: "./plugin-go" };\n',
|
|
277
|
+
'module.exports = { name: "prepare-fixture", source: "./plugin-go", hooks: { source: true } };\n',
|
|
278
278
|
"utf8",
|
|
279
279
|
);
|
|
280
280
|
fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
|
|
@@ -293,7 +293,7 @@ function writeSourcePlugin(root) {
|
|
|
293
293
|
function writeBrokenTransformPlugin(root) {
|
|
294
294
|
fs.writeFileSync(
|
|
295
295
|
path.join(root, "plugin.cjs"),
|
|
296
|
-
'module.exports = { name: "broken-transform-fixture", source: "./plugin-go" };\n',
|
|
296
|
+
'module.exports = { name: "broken-transform-fixture", source: "./plugin-go", hooks: { source: true } };\n',
|
|
297
297
|
"utf8",
|
|
298
298
|
);
|
|
299
299
|
fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
|
|
@@ -327,7 +327,7 @@ function writeBrokenTransformPlugin(root) {
|
|
|
327
327
|
function writeCompilerPlugin(root) {
|
|
328
328
|
fs.writeFileSync(
|
|
329
329
|
path.join(root, "plugin.cjs"),
|
|
330
|
-
'module.exports = { name: "compile-fixture", source: "./plugin-go" };\n',
|
|
330
|
+
'module.exports = { name: "compile-fixture", source: "./plugin-go", hooks: { source: true } };\n',
|
|
331
331
|
"utf8",
|
|
332
332
|
);
|
|
333
333
|
fs.mkdirSync(path.join(root, "plugin-go"), { recursive: true });
|
package/test/platform.test.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
const assert = require("node:assert/strict");
|
|
2
2
|
const test = require("node:test");
|
|
3
|
-
const {
|
|
4
|
-
resolveBinary,
|
|
5
|
-
} = require("../lib/compiler/internal/resolveBinary.js");
|
|
3
|
+
const { resolveBinary } = require("../lib/compiler/internal/resolveBinary.js");
|
|
6
4
|
|
|
7
5
|
test("resolveBinary prefers TTSC_BINARY absolute override", () => {
|
|
8
6
|
const resolved = resolveBinary({
|
package/test/tsgo.test.ts
CHANGED
|
@@ -20,12 +20,17 @@ test("resolveTsgo accepts TTSC_TSGO_BINARY as an explicit compiler", () => {
|
|
|
20
20
|
|
|
21
21
|
test("resolveTsgo resolves the consumer native-preview platform package", () => {
|
|
22
22
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), "ttsc-tsgo-test-"));
|
|
23
|
-
const nativeRoot = path.join(
|
|
23
|
+
const nativeRoot = path.join(
|
|
24
|
+
root,
|
|
25
|
+
"node_modules",
|
|
26
|
+
"@typescript",
|
|
27
|
+
"native-preview",
|
|
28
|
+
);
|
|
24
29
|
const platformRoot = path.join(
|
|
25
30
|
root,
|
|
26
31
|
"node_modules",
|
|
27
32
|
"@typescript",
|
|
28
|
-
|
|
33
|
+
`native-preview-${process.platform}-${process.arch}`,
|
|
29
34
|
);
|
|
30
35
|
fs.mkdirSync(nativeRoot, { recursive: true });
|
|
31
36
|
fs.mkdirSync(path.join(platformRoot, "lib"), { recursive: true });
|
|
@@ -41,21 +46,24 @@ test("resolveTsgo resolves the consumer native-preview platform package", () =>
|
|
|
41
46
|
fs.writeFileSync(
|
|
42
47
|
path.join(platformRoot, "package.json"),
|
|
43
48
|
JSON.stringify({
|
|
44
|
-
name:
|
|
49
|
+
name: `@typescript/native-preview-${process.platform}-${process.arch}`,
|
|
45
50
|
version: "7.0.0-dev.consumer",
|
|
46
51
|
}),
|
|
47
52
|
"utf8",
|
|
48
53
|
);
|
|
49
|
-
|
|
54
|
+
const binary = path.join(
|
|
55
|
+
platformRoot,
|
|
56
|
+
"lib",
|
|
57
|
+
process.platform === "win32" ? "tsgo.exe" : "tsgo",
|
|
58
|
+
);
|
|
59
|
+
fs.writeFileSync(binary, "", "utf8");
|
|
50
60
|
|
|
51
61
|
const resolved = resolveTsgo({
|
|
52
|
-
arch: "x64",
|
|
53
62
|
cwd: root,
|
|
54
63
|
env: {},
|
|
55
|
-
platform: "linux",
|
|
56
64
|
});
|
|
57
65
|
|
|
58
66
|
assert.equal(resolved.version, "7.0.0-dev.consumer");
|
|
59
67
|
assert.equal(resolved.gitHead, "abc123");
|
|
60
|
-
assert.equal(resolved.binary,
|
|
68
|
+
assert.equal(resolved.binary, binary);
|
|
61
69
|
});
|