ttsc 0.26.1 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/cmd/ttsc/api_transform.go +17 -3
- package/cmd/ttscgraph/auxiliary_identity_state_tracks_retargets_not_source_contents_test.go +85 -0
- package/cmd/ttscgraph/disk_realpath_other.go +16 -0
- package/cmd/ttscgraph/disk_realpath_windows.go +56 -0
- package/cmd/ttscgraph/serve.go +104 -35
- package/driver/diagnostics_preamble.go +284 -0
- package/driver/emit_plugin.go +71 -19
- package/driver/graph.go +64 -11
- package/driver/input_observation.go +273 -0
- package/driver/input_observation_test.go +149 -0
- package/driver/plugins.go +384 -4
- package/driver/program.go +81 -15
- package/driver/resolution_candidates.go +13 -5
- package/driver/rewrite.go +47 -4
- package/internal/graph/diagnostics.go +4 -3
- package/internal/graph/provenance.go +10 -1
- package/lib/TtscCompiler.d.ts +12 -11
- package/lib/TtscCompiler.js +44 -29
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/captureProcessOutput.js +2 -2
- package/lib/compiler/internal/captureProcessOutput.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +11 -3
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +2 -0
- package/lib/compiler/internal/resolveEmittedJavaScript.js +3 -0
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +29 -1
- package/lib/compiler/internal/runBuild.js +117 -32
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +9 -2
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +28 -0
- package/lib/compiler/internal/sharedHostHelpers.js +39 -0
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +12 -4
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.d.ts +3 -0
- package/lib/compiler/internal/transformProjectInMemory.js +239 -35
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/schema.js +33 -5
- package/lib/flags/schema.js.map +1 -1
- package/lib/internal/createCanonicalTempDirectory.d.ts +17 -0
- package/lib/internal/createCanonicalTempDirectory.js +42 -0
- package/lib/internal/createCanonicalTempDirectory.js.map +1 -0
- package/lib/internal/projectInputPathIdentity.d.ts +3 -0
- package/lib/internal/projectInputPathIdentity.js +11 -5
- package/lib/internal/projectInputPathIdentity.js.map +1 -1
- package/lib/internal/resolveNodeBinary.d.ts +14 -0
- package/lib/internal/resolveNodeBinary.js +150 -0
- package/lib/internal/resolveNodeBinary.js.map +1 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.d.ts +15 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.js +61 -0
- package/lib/internal/resolveSafeCacheCleanupTargets.js.map +1 -0
- package/lib/launcher/internal/assertNoSolutionBuild.d.ts +31 -0
- package/lib/launcher/internal/assertNoSolutionBuild.js +38 -0
- package/lib/launcher/internal/assertNoSolutionBuild.js.map +1 -0
- package/lib/launcher/internal/prepareExecution.d.ts +3 -0
- package/lib/launcher/internal/prepareExecution.js +73 -26
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +27 -13
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +18 -3
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +4 -0
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +37 -1
- package/lib/launcher/internal/runtimeHooks.js +660 -62
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +62 -8
- package/lib/plugin/internal/buildSourcePlugin.js +754 -72
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +17 -5
- package/lib/plugin/internal/loadProjectPlugins.js +1339 -77
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/register.d.ts +1 -0
- package/lib/register.js +46 -0
- package/lib/register.js.map +1 -0
- package/lib/structures/ITtscCompilerContext.d.ts +6 -3
- package/lib/structures/ITtscCompilerTransformation.d.ts +31 -0
- package/lib/structures/ITtscPlugin.d.ts +33 -0
- package/package.json +16 -9
- package/shim/checker/go.mod +9 -0
- package/shim/checker/go.sum +22 -0
- package/shim/checker/shim.go +75 -0
- package/shim/compiler/emit_sourcemap.go +56 -15
- package/shim/compiler/incremental.go +45 -8
- package/src/TtscCompiler.ts +55 -33
- package/src/compiler/internal/captureProcessOutput.ts +3 -2
- package/src/compiler/internal/compileProjectInMemory.ts +11 -3
- package/src/compiler/internal/resolveEmittedJavaScript.ts +6 -0
- package/src/compiler/internal/runBuild.ts +172 -36
- package/src/compiler/internal/runSingleFileEmit.ts +9 -2
- package/src/compiler/internal/sharedHostHelpers.ts +44 -0
- package/src/compiler/internal/startResidentTransform.ts +12 -3
- package/src/compiler/internal/transformProjectInMemory.ts +410 -39
- package/src/flags/schema.ts +35 -5
- package/src/internal/createCanonicalTempDirectory.ts +53 -0
- package/src/internal/projectInputPathIdentity.ts +17 -4
- package/src/internal/resolveNodeBinary.ts +173 -0
- package/src/internal/resolveSafeCacheCleanupTargets.ts +85 -0
- package/src/launcher/internal/assertNoSolutionBuild.ts +40 -0
- package/src/launcher/internal/prepareExecution.ts +78 -26
- package/src/launcher/internal/runTtsc.ts +26 -13
- package/src/launcher/internal/runTtscserver.ts +18 -3
- package/src/launcher/internal/runTtsx.ts +4 -0
- package/src/launcher/internal/runtimeHooks.ts +830 -66
- package/src/plugin/internal/buildSourcePlugin.ts +984 -79
- package/src/plugin/internal/loadProjectPlugins.ts +1718 -104
- package/src/register.ts +47 -0
- package/src/structures/ITtscCompilerContext.ts +6 -3
- package/src/structures/ITtscCompilerTransformation.ts +39 -0
- package/src/structures/ITtscPlugin.ts +36 -0
- package/tools/shim_audit/baseline.json +0 -1
- package/utility/host.go +9 -3
- package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +0 -5
- package/lib/internal/assertSafeExplicitCacheDirectory.js +0 -26
- package/lib/internal/assertSafeExplicitCacheDirectory.js.map +0 -1
- package/src/internal/assertSafeExplicitCacheDirectory.ts +0 -29
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type ProjectInputPathIdentityContext,
|
|
7
7
|
createProjectInputPathIdentityContext,
|
|
8
8
|
} from "../../internal/projectInputPathIdentity";
|
|
9
|
+
import { resolveNodeBinary } from "../../internal/resolveNodeBinary";
|
|
9
10
|
import {
|
|
10
11
|
hasProjectPluginEntries,
|
|
11
12
|
loadProjectPlugins,
|
|
@@ -26,7 +27,10 @@ import {
|
|
|
26
27
|
import { resolveBinary } from "./resolveBinary";
|
|
27
28
|
import { resolveTsgo } from "./resolveTsgo";
|
|
28
29
|
import {
|
|
30
|
+
TSGO_ARGS_ENV,
|
|
29
31
|
assertSharedHostCompatibility,
|
|
32
|
+
clearInheritedTsgoArgs,
|
|
33
|
+
inheritedSidecarEnv,
|
|
30
34
|
linkedTransformPlugins,
|
|
31
35
|
resolvePluginConfigDir,
|
|
32
36
|
selectSharedHostPlugin,
|
|
@@ -38,6 +42,34 @@ export type RunBuildOptions = TtscBuildOptions & {
|
|
|
38
42
|
forceListEmittedFiles?: boolean;
|
|
39
43
|
/** Keep every compiler-owned side product inside this private directory. */
|
|
40
44
|
isolateOutputsTo?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Hand tsgo the `rootDir` it would otherwise infer, for a build whose
|
|
47
|
+
* `outDir` this process injected rather than the project declaring it.
|
|
48
|
+
*
|
|
49
|
+
* Tsgo answers an inferred common source directory with TS5011 the moment an
|
|
50
|
+
* `outDir` is in play, so injecting one turns a project that declares no
|
|
51
|
+
* output at all — the `noEmit` check-only shape `tsgo`, `ttsc`, and `ttsc
|
|
52
|
+
* --emit` all accept — into one that must configure the layout of output the
|
|
53
|
+
* user never asked for and never sees (issue #1172).
|
|
54
|
+
*
|
|
55
|
+
* The pinned value is the one tsgo itself infers: with a config file in play
|
|
56
|
+
* its common source directory is that file's directory, never the computed
|
|
57
|
+
* common directory of the input files (`outputpaths.GetCommonSourceDirectory`
|
|
58
|
+
* consults the file list only for a config-less program). Pinning it
|
|
59
|
+
* therefore silences the demand without moving a single output, and it is the
|
|
60
|
+
* same source root `prepareExecution.ts::resolveRuntimeSourceRoot`,
|
|
61
|
+
* `runtimeHooks.ts::resolveDependencySourceRoot`, and
|
|
62
|
+
* `watchTopology.ts::inferPerSourceCompilerOutputs` already model on the
|
|
63
|
+
* JavaScript side.
|
|
64
|
+
*
|
|
65
|
+
* Ignored when the project declares its own `rootDir`: that project already
|
|
66
|
+
* satisfies tsgo, and overriding it would relocate the emit out from under
|
|
67
|
+
* every consumer that mirrors the declared root.
|
|
68
|
+
*
|
|
69
|
+
* Never set for a user-supplied `--outDir`. That outDir is the user's own
|
|
70
|
+
* request, and TS5011 is then tsgo's genuine answer to it.
|
|
71
|
+
*/
|
|
72
|
+
pinInferredRootDir?: boolean;
|
|
41
73
|
/**
|
|
42
74
|
* Receives selected native-plugin source roots after the project resolves.
|
|
43
75
|
* The watch launcher uses these roots to invalidate a sidecar when its Go
|
|
@@ -73,13 +105,18 @@ type BuildTiming = {
|
|
|
73
105
|
* `TTSC_NODE_BINARY` so child processes can re-invoke the same Node.js binary
|
|
74
106
|
* without searching `PATH`.
|
|
75
107
|
*/
|
|
76
|
-
function mergeEnv(
|
|
77
|
-
|
|
108
|
+
function mergeEnv(
|
|
109
|
+
extra?: NodeJS.ProcessEnv,
|
|
110
|
+
cwd: string = process.cwd(),
|
|
111
|
+
): NodeJS.ProcessEnv {
|
|
112
|
+
const env: NodeJS.ProcessEnv = {
|
|
78
113
|
...process.env,
|
|
79
|
-
|
|
114
|
+
...extra,
|
|
80
115
|
};
|
|
81
|
-
|
|
82
|
-
|
|
116
|
+
const node = resolveNodeBinary(env, cwd);
|
|
117
|
+
if (node === undefined) delete env.TTSC_NODE_BINARY;
|
|
118
|
+
else env.TTSC_NODE_BINARY = node;
|
|
119
|
+
return env;
|
|
83
120
|
}
|
|
84
121
|
|
|
85
122
|
function createBuildTiming(options: TtscCommonOptions): BuildTiming {
|
|
@@ -170,17 +207,29 @@ function nativePluginEnv(
|
|
|
170
207
|
extra: NodeJS.ProcessEnv | undefined,
|
|
171
208
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
172
209
|
plugin?: ITtscLoadedNativePlugin,
|
|
210
|
+
tsgoArgs?: string,
|
|
173
211
|
): NodeJS.ProcessEnv {
|
|
174
|
-
const env = mergeEnv(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
212
|
+
const env = mergeEnv(
|
|
213
|
+
{
|
|
214
|
+
...(execution.pluginConfigDir === undefined
|
|
215
|
+
? {}
|
|
216
|
+
: { TTSC_PLUGIN_CONFIG_DIR: execution.pluginConfigDir }),
|
|
217
|
+
TTSC_TSGO_BINARY: process.env.TTSC_TSGO_BINARY ?? execution.tsgo.binary,
|
|
218
|
+
TTSC_TTSX_BINARY:
|
|
219
|
+
process.env.TTSC_TTSX_BINARY ??
|
|
220
|
+
path.join(__dirname, "..", "..", "launcher", "ttsx.js"),
|
|
221
|
+
...extra,
|
|
222
|
+
},
|
|
223
|
+
execution.projectRoot,
|
|
224
|
+
);
|
|
225
|
+
// Forwarded tsgo argv is per-invocation state this host owns, exactly like
|
|
226
|
+
// the config anchor below: publish this run's payload, or drop whatever an
|
|
227
|
+
// ancestor ttsc process left behind when this lane forwards nothing.
|
|
228
|
+
if (tsgoArgs !== undefined) {
|
|
229
|
+
env[TSGO_ARGS_ENV] = tsgoArgs;
|
|
230
|
+
} else {
|
|
231
|
+
clearInheritedTsgoArgs(env, extra);
|
|
232
|
+
}
|
|
184
233
|
// The anchor is per-invocation state owned by this host: when this run
|
|
185
234
|
// declared none (and the caller's env does not name one), drop any value
|
|
186
235
|
// inherited from an ancestor ttsc process so a nested build never
|
|
@@ -363,8 +412,11 @@ export class ResidentCheckWatchSession {
|
|
|
363
412
|
stderr: "",
|
|
364
413
|
stdout: "",
|
|
365
414
|
};
|
|
366
|
-
const
|
|
367
|
-
|
|
415
|
+
const tsgoArgs = createNativeTsgoArgs(options);
|
|
416
|
+
const checks = planResidentCheckEntries(
|
|
417
|
+
execution.nativePlugins,
|
|
418
|
+
(plugin) => createNativeCheckArgs(execution, options, plugin),
|
|
419
|
+
tsgoArgs,
|
|
368
420
|
);
|
|
369
421
|
const request = residentCheckRequest(change, execution.projectRoot);
|
|
370
422
|
// Buffer the cycle for every resident plugin before running any of them.
|
|
@@ -383,6 +435,7 @@ export class ResidentCheckWatchSession {
|
|
|
383
435
|
"ttsc.check",
|
|
384
436
|
timing,
|
|
385
437
|
`ttsc check plugin ${plugin.name} time`,
|
|
438
|
+
tsgoArgs,
|
|
386
439
|
);
|
|
387
440
|
} else {
|
|
388
441
|
const startedAt = process.hrtime.bigint();
|
|
@@ -392,7 +445,7 @@ export class ResidentCheckWatchSession {
|
|
|
392
445
|
args: ["check-serve", ...args.slice(1)],
|
|
393
446
|
binary: plugin.binary,
|
|
394
447
|
cwd: execution.projectRoot,
|
|
395
|
-
env: nativePluginEnv(options.env, execution, plugin),
|
|
448
|
+
env: nativePluginEnv(options.env, execution, plugin, tsgoArgs),
|
|
396
449
|
});
|
|
397
450
|
this.processes.set(key, resident);
|
|
398
451
|
}
|
|
@@ -478,8 +531,9 @@ function residentCheckExecutionIsCompatible(
|
|
|
478
531
|
function residentCheckProcessKey(
|
|
479
532
|
plugin: ITtscLoadedNativePlugin,
|
|
480
533
|
args: readonly string[],
|
|
534
|
+
tsgoArgs?: string,
|
|
481
535
|
): string {
|
|
482
|
-
return `${plugin.binary}\0${plugin.name}\0${JSON.stringify(args)}`;
|
|
536
|
+
return `${plugin.binary}\0${plugin.name}\0${JSON.stringify(args)}\0${tsgoArgs ?? ""}`;
|
|
483
537
|
}
|
|
484
538
|
|
|
485
539
|
export type ResidentCheckEntryPlan = {
|
|
@@ -496,6 +550,11 @@ export type ResidentCheckEntryPlan = {
|
|
|
496
550
|
export function planResidentCheckEntries(
|
|
497
551
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
498
552
|
createArgs: (plugin: ITtscLoadedNativePlugin) => string[],
|
|
553
|
+
// Part of the process identity even though it never appears in argv: the
|
|
554
|
+
// forwarded tsgo payload rides the environment, and a resident process holds
|
|
555
|
+
// the compiler options it was started with. Two cycles that forward different
|
|
556
|
+
// flags must not share one warm Program.
|
|
557
|
+
tsgoArgs?: string,
|
|
499
558
|
): ResidentCheckEntryPlan[] {
|
|
500
559
|
return plugins
|
|
501
560
|
.filter((candidate) => candidate.stage === "check")
|
|
@@ -506,7 +565,7 @@ export function planResidentCheckEntries(
|
|
|
506
565
|
entryIndex,
|
|
507
566
|
key:
|
|
508
567
|
plugin.capabilities?.residentCheck === true
|
|
509
|
-
? residentCheckProcessKey(plugin, args)
|
|
568
|
+
? residentCheckProcessKey(plugin, args, tsgoArgs)
|
|
510
569
|
: undefined,
|
|
511
570
|
plugin,
|
|
512
571
|
};
|
|
@@ -802,7 +861,7 @@ function runProjectFreeTerminalFlag(
|
|
|
802
861
|
const tsgo = resolveTsgo({ ...options, cwd });
|
|
803
862
|
const res = spawnNative(tsgo.binary, [...(options.passthrough ?? [])], {
|
|
804
863
|
cwd,
|
|
805
|
-
env: mergeEnv(options.env),
|
|
864
|
+
env: mergeEnv(options.env, cwd),
|
|
806
865
|
encoding: "utf8",
|
|
807
866
|
});
|
|
808
867
|
if (res.error) {
|
|
@@ -1084,7 +1143,7 @@ function forwardsInternalShadowFlag(
|
|
|
1084
1143
|
* inside it via the `--plugins-json` flag.
|
|
1085
1144
|
*/
|
|
1086
1145
|
function buildWithNativeCompilerPlugins(
|
|
1087
|
-
options:
|
|
1146
|
+
options: RunBuildOptions,
|
|
1088
1147
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
1089
1148
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
1090
1149
|
timing: BuildTiming,
|
|
@@ -1098,6 +1157,7 @@ function buildWithNativeCompilerPlugins(
|
|
|
1098
1157
|
"ttsc.build",
|
|
1099
1158
|
timing,
|
|
1100
1159
|
transformHostTimingLabel(plugins),
|
|
1160
|
+
createNativeBuildTsgoArgs(execution, options),
|
|
1101
1161
|
);
|
|
1102
1162
|
}
|
|
1103
1163
|
|
|
@@ -1122,7 +1182,7 @@ function runTsgo(
|
|
|
1122
1182
|
],
|
|
1123
1183
|
{
|
|
1124
1184
|
cwd: execution.projectRoot,
|
|
1125
|
-
env: mergeEnv(options.env),
|
|
1185
|
+
env: mergeEnv(options.env, execution.projectRoot),
|
|
1126
1186
|
encoding: "utf8",
|
|
1127
1187
|
},
|
|
1128
1188
|
);
|
|
@@ -1156,7 +1216,7 @@ function runTsgoBuild(
|
|
|
1156
1216
|
): TtscBuildResult {
|
|
1157
1217
|
const res = spawnNative(execution.tsgo.binary, args, {
|
|
1158
1218
|
cwd: execution.projectRoot,
|
|
1159
|
-
env: mergeEnv(options.env),
|
|
1219
|
+
env: mergeEnv(options.env, execution.projectRoot),
|
|
1160
1220
|
encoding: "utf8",
|
|
1161
1221
|
});
|
|
1162
1222
|
if (res.error) {
|
|
@@ -1245,6 +1305,9 @@ function createTsgoBuildArgs(
|
|
|
1245
1305
|
if (options.forceRuntimeSourceMap === true) {
|
|
1246
1306
|
args.push("--sourceMap", "true");
|
|
1247
1307
|
}
|
|
1308
|
+
// Pushed before passthrough for the same reason: a user `--rootDir` still
|
|
1309
|
+
// wins over the value ttsc pins for its own injected `outDir`.
|
|
1310
|
+
args.push(...pinnedRootDirArgs(execution, options));
|
|
1248
1311
|
} else if (options.emit === false) {
|
|
1249
1312
|
args.push("--noEmit");
|
|
1250
1313
|
}
|
|
@@ -1264,6 +1327,37 @@ function createTsgoBuildArgs(
|
|
|
1264
1327
|
return args;
|
|
1265
1328
|
}
|
|
1266
1329
|
|
|
1330
|
+
/**
|
|
1331
|
+
* The explicit `--rootDir` a caller-injected `outDir` needs, or nothing.
|
|
1332
|
+
*
|
|
1333
|
+
* See {@link RunBuildOptions.pinInferredRootDir} for why an injected `outDir`
|
|
1334
|
+
* needs one at all. Three conditions gate it, and each one is load-bearing:
|
|
1335
|
+
*
|
|
1336
|
+
* - The caller injected the `outDir` itself, so a user `--outDir` keeps tsgo's
|
|
1337
|
+
* own TS5011 answer;
|
|
1338
|
+
* - This pass emits, because a no-emit pass has no layout to pin (tsgo skips the
|
|
1339
|
+
* check for `noEmit` too);
|
|
1340
|
+
* - The project declares no `rootDir` of its own, so a declared layout is never
|
|
1341
|
+
* overridden.
|
|
1342
|
+
*
|
|
1343
|
+
* `execution.projectRoot` is the directory of the tsconfig ttsc resolved and
|
|
1344
|
+
* hands tsgo as `-p`, which is exactly the directory tsgo infers, and it is
|
|
1345
|
+
* spelled the way tsgo will spell the input file names it compares against it —
|
|
1346
|
+
* both come from the same `fs.realpathSync` pass. Resolving it any further (a
|
|
1347
|
+
* Windows 8.3 expansion, say) would leave the comparison lexically mixed, and
|
|
1348
|
+
* `ContainsPath` is lexical: every input would count as outside `rootDir` and
|
|
1349
|
+
* tsgo would emit it beside the user's source instead of under `outDir`.
|
|
1350
|
+
*/
|
|
1351
|
+
function pinnedRootDirArgs(
|
|
1352
|
+
execution: ReturnType<typeof resolveExecutionContext>,
|
|
1353
|
+
options: RunBuildOptions,
|
|
1354
|
+
): string[] {
|
|
1355
|
+
if (options.pinInferredRootDir !== true) return [];
|
|
1356
|
+
if (options.emit !== true) return [];
|
|
1357
|
+
if (typeof execution.project.compilerOptions.rootDir === "string") return [];
|
|
1358
|
+
return ["--rootDir", execution.projectRoot];
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1267
1361
|
/**
|
|
1268
1362
|
* Return `["--pretty", "false"]` when structured diagnostics are requested so
|
|
1269
1363
|
* that the output can be parsed line-by-line, or an empty array otherwise.
|
|
@@ -1304,7 +1398,7 @@ function createTsgoThreadingArgs(options: TtscCommonOptions): string[] {
|
|
|
1304
1398
|
/** Build the argument list for a native plugin `build`/`check` invocation. */
|
|
1305
1399
|
function createNativeBuildArgs(
|
|
1306
1400
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
1307
|
-
options:
|
|
1401
|
+
options: RunBuildOptions,
|
|
1308
1402
|
plugins: readonly ITtscLoadedNativePlugin[],
|
|
1309
1403
|
): string[] {
|
|
1310
1404
|
const args = [
|
|
@@ -1339,10 +1433,23 @@ function createNativeBuildArgs(
|
|
|
1339
1433
|
args.push("--quiet");
|
|
1340
1434
|
}
|
|
1341
1435
|
}
|
|
1342
|
-
args.push(...createNativeTsgoArgs(options));
|
|
1343
1436
|
return args;
|
|
1344
1437
|
}
|
|
1345
1438
|
|
|
1439
|
+
/**
|
|
1440
|
+
* The forwarded-tsgo payload for a native `build`/`check` emit invocation.
|
|
1441
|
+
*
|
|
1442
|
+
* The sidecar builds its Program in-process, so the pinned `rootDir` has to
|
|
1443
|
+
* travel the same channel every other tsgo option takes to it — the host flag
|
|
1444
|
+
* set does not declare `--rootDir`, and `filterHostArgs` would strip it.
|
|
1445
|
+
*/
|
|
1446
|
+
function createNativeBuildTsgoArgs(
|
|
1447
|
+
execution: ReturnType<typeof resolveExecutionContext>,
|
|
1448
|
+
options: RunBuildOptions,
|
|
1449
|
+
): string | undefined {
|
|
1450
|
+
return createNativeTsgoArgs(options, pinnedRootDirArgs(execution, options));
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1346
1453
|
/** Build the argument list for a native plugin check/fix/format invocation. */
|
|
1347
1454
|
function createNativeCheckArgs(
|
|
1348
1455
|
execution: ReturnType<typeof resolveExecutionContext>,
|
|
@@ -1373,7 +1480,6 @@ function createNativeCheckArgs(
|
|
|
1373
1480
|
}
|
|
1374
1481
|
args.push(...createNativeCheckThreadingArgs(options, plugin));
|
|
1375
1482
|
args.push(...createNativeCheckDiagnosticsArgs(options, plugin));
|
|
1376
|
-
args.push(...createNativeTsgoArgs(options));
|
|
1377
1483
|
return args;
|
|
1378
1484
|
}
|
|
1379
1485
|
|
|
@@ -1483,20 +1589,48 @@ function transformHostTimingLabel(
|
|
|
1483
1589
|
|
|
1484
1590
|
/**
|
|
1485
1591
|
* Forward the tsgo flags ttsc did not recognize to a native sidecar as one
|
|
1486
|
-
* JSON-encoded
|
|
1487
|
-
*
|
|
1488
|
-
*
|
|
1489
|
-
*
|
|
1592
|
+
* JSON-encoded payload. The sidecar replays them through tsgo's own option
|
|
1593
|
+
* parser onto `CompilerOptions`, so a flag like `ttsc --strict` reaches a
|
|
1594
|
+
* plugin build the same way it reaches the plain tsgo lane.
|
|
1595
|
+
*
|
|
1596
|
+
* The payload travels in the `TTSC_TSGO_ARGS` environment variable, not on the
|
|
1597
|
+
* sidecar's command line. #113 shipped it as a `--tsgo-args` flag, which is an
|
|
1598
|
+
* addition to a plugin protocol third-party hosts had already frozen: a Go
|
|
1599
|
+
* `flag.FlagSet` created with `flag.ContinueOnError` treats an undeclared flag
|
|
1600
|
+
* as fatal, so every pre-#113 sidecar answered `flag provided but not defined:
|
|
1601
|
+
* -tsgo-args` and exited 2. That took down `ttsc --strict`, `ttsc
|
|
1602
|
+
* --declaration`, `ttsx --strict` and — because {@link isolatedTsgoOutputArgs}
|
|
1603
|
+
* makes this payload non-empty on its own — plain `ttsc <file.ts>`, on every
|
|
1604
|
+
* project carrying a typia/nestia-era transform host (issue #1188).
|
|
1605
|
+
*
|
|
1606
|
+
* The environment is the channel ttsc already uses for host-owned payloads that
|
|
1607
|
+
* must not collide with a third-party flag set (`TTSC_LINKED_PLUGINS_JSON`,
|
|
1608
|
+
* `TTSC_PLUGIN_CONFIG_DIR`). It reaches those hosts without any change on their
|
|
1609
|
+
* side, because `buildSourcePlugin.ts::sourceBuildWorkspaceReplacements` builds
|
|
1610
|
+
* every source plugin against the installed ttsc's own driver, and
|
|
1611
|
+
* `driver.LoadProgram` reads the variable whenever the caller supplied no
|
|
1612
|
+
* explicit argv. It is strictly better than the capability gate `ad3443a` used
|
|
1613
|
+
* for `--singleThreaded` / `--checkers`: that one drops the flag for hosts that
|
|
1614
|
+
* cannot take it, which is acceptable for a threading knob and not for
|
|
1615
|
+
* `--strict`.
|
|
1616
|
+
*
|
|
1617
|
+
* Returns the JSON payload, or `undefined` when this lane forwards nothing.
|
|
1490
1618
|
*/
|
|
1491
|
-
function createNativeTsgoArgs(
|
|
1619
|
+
function createNativeTsgoArgs(
|
|
1620
|
+
options: TtscCommonOptions,
|
|
1621
|
+
leading: readonly string[] = [],
|
|
1622
|
+
): string | undefined {
|
|
1492
1623
|
const passthrough = [
|
|
1624
|
+
// Ahead of the user's own flags, so the same precedence holds here as on
|
|
1625
|
+
// the direct tsgo lane: whatever the user forwarded wins.
|
|
1626
|
+
...leading,
|
|
1493
1627
|
...(nativeTsgoPassthroughArgs(options) ?? []),
|
|
1494
1628
|
...isolatedTsgoOutputArgs(options),
|
|
1495
1629
|
];
|
|
1496
1630
|
if (passthrough.length === 0) {
|
|
1497
|
-
return
|
|
1631
|
+
return undefined;
|
|
1498
1632
|
}
|
|
1499
|
-
return
|
|
1633
|
+
return JSON.stringify(passthrough);
|
|
1500
1634
|
}
|
|
1501
1635
|
|
|
1502
1636
|
function isolatedTsgoOutputArgs(options: TtscCommonOptions): string[] {
|
|
@@ -1605,6 +1739,7 @@ function runNativeCheckPlugins(
|
|
|
1605
1739
|
"ttsc.check",
|
|
1606
1740
|
timing,
|
|
1607
1741
|
`ttsc check plugin ${plugin.name} time`,
|
|
1742
|
+
createNativeTsgoArgs(options),
|
|
1608
1743
|
);
|
|
1609
1744
|
out = appendBuildOutput(out, result);
|
|
1610
1745
|
if (result.status !== 0) {
|
|
@@ -1876,11 +2011,12 @@ function runNativePluginCommand(
|
|
|
1876
2011
|
label: string,
|
|
1877
2012
|
timing: BuildTiming,
|
|
1878
2013
|
timingLabel: string,
|
|
2014
|
+
tsgoArgs?: string,
|
|
1879
2015
|
): TtscBuildResult {
|
|
1880
2016
|
const startedAt = process.hrtime.bigint();
|
|
1881
2017
|
const res = spawnNative(plugin.binary, args, {
|
|
1882
2018
|
cwd: execution.projectRoot,
|
|
1883
|
-
env: nativePluginEnv(options.env, execution, plugin),
|
|
2019
|
+
env: nativePluginEnv(options.env, execution, plugin, tsgoArgs),
|
|
1884
2020
|
encoding: "utf8",
|
|
1885
2021
|
});
|
|
1886
2022
|
recordTiming(timing, timingLabel, startedAt);
|
|
@@ -1974,7 +2110,7 @@ function resolveExecutionContext(
|
|
|
1974
2110
|
cacheDir: options.cacheDir ?? options.env?.TTSC_CACHE_DIR,
|
|
1975
2111
|
cwd,
|
|
1976
2112
|
entries: options.plugins,
|
|
1977
|
-
env:
|
|
2113
|
+
env: inheritedSidecarEnv(options.env),
|
|
1978
2114
|
onWatchInputs: options.onWatchInputs,
|
|
1979
2115
|
pluginConfigDir: options.pluginConfigDir,
|
|
1980
2116
|
projectRoot,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
|
|
4
|
+
import { createCanonicalTempDirectory } from "../../internal/createCanonicalTempDirectory";
|
|
5
5
|
import type { TtscSingleFileEmitOptions } from "../../structures/internal/TtscSingleFileEmitOptions";
|
|
6
6
|
import { readProjectConfig } from "./project/readProjectConfig";
|
|
7
7
|
import { resolveEmittedJavaScript } from "./resolveEmittedJavaScript";
|
|
@@ -32,7 +32,7 @@ export function runSingleFileEmit(options: TtscSingleFileEmitOptions): string {
|
|
|
32
32
|
});
|
|
33
33
|
const tsconfig = project.path;
|
|
34
34
|
const projectRoot = project.root;
|
|
35
|
-
const outDir =
|
|
35
|
+
const outDir = createCanonicalTempDirectory("ttsc-single-file-");
|
|
36
36
|
try {
|
|
37
37
|
const result = runBuild({
|
|
38
38
|
...options,
|
|
@@ -41,6 +41,13 @@ export function runSingleFileEmit(options: TtscSingleFileEmitOptions): string {
|
|
|
41
41
|
forceListEmittedFiles: true,
|
|
42
42
|
isolateOutputsTo: outDir,
|
|
43
43
|
outDir,
|
|
44
|
+
// The private temp directory above is an `outDir` this lane injected, not
|
|
45
|
+
// one the project declared, and tsgo answers an inferred common source
|
|
46
|
+
// directory with TS5011 as soon as any `outDir` is in play. Pinning the
|
|
47
|
+
// root tsgo would infer keeps `ttsc <file.ts>` working on a project that
|
|
48
|
+
// declares no output at all, and it is the same root
|
|
49
|
+
// `resolveEmittedJavaScript` mirrors below (issue #1172).
|
|
50
|
+
pinInferredRootDir: true,
|
|
44
51
|
resolvedProject: project,
|
|
45
52
|
tsconfig,
|
|
46
53
|
});
|
|
@@ -2,6 +2,50 @@ import path from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Environment channel carrying the JSON-encoded tsgo argv ttsc forwards to a
|
|
7
|
+
* native sidecar. Mirrors `driver.TsgoArgsEnv` on the Go side; see
|
|
8
|
+
* `runBuild.ts::createNativeTsgoArgs` for why the payload is not a CLI flag.
|
|
9
|
+
*/
|
|
10
|
+
export const TSGO_ARGS_ENV = "TTSC_TSGO_ARGS";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Drop a forwarded-tsgo payload this invocation did not publish itself.
|
|
14
|
+
*
|
|
15
|
+
* Every sidecar env starts from `process.env`, so a ttsc that is itself running
|
|
16
|
+
* inside a plugin sidecar — `@ttsc/lint` evaluating a config file through
|
|
17
|
+
* `ttsx`, for instance — would otherwise hand the outer run's `--strict` to its
|
|
18
|
+
* own sidecars, and `driver.LoadProgram` would apply it. The forwarded argv is
|
|
19
|
+
* per-invocation state the spawning host owns, the same rule
|
|
20
|
+
* `TTSC_PLUGIN_CONFIG_DIR` already follows. A caller that named the variable
|
|
21
|
+
* explicitly keeps it.
|
|
22
|
+
*/
|
|
23
|
+
export function clearInheritedTsgoArgs(
|
|
24
|
+
env: NodeJS.ProcessEnv,
|
|
25
|
+
callerEnv: NodeJS.ProcessEnv | undefined,
|
|
26
|
+
): void {
|
|
27
|
+
if (callerEnv?.[TSGO_ARGS_ENV] === undefined) {
|
|
28
|
+
delete env[TSGO_ARGS_ENV];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The `{ ...process.env, ...callerEnv }` a child process inherits, minus a
|
|
34
|
+
* forwarded-tsgo payload this lane never published.
|
|
35
|
+
*
|
|
36
|
+
* Use it at every spawn whose child can reach `driver.LoadProgram` — the
|
|
37
|
+
* `api-compile` / `api-transform` hosts, and the plugin loader, whose `ttsx`
|
|
38
|
+
* descriptor evaluation compiles a project of its own. One rule at every site
|
|
39
|
+
* beats four sites each reasoning about whether the variable could be present.
|
|
40
|
+
*/
|
|
41
|
+
export function inheritedSidecarEnv(
|
|
42
|
+
callerEnv: NodeJS.ProcessEnv | undefined,
|
|
43
|
+
): NodeJS.ProcessEnv {
|
|
44
|
+
const env: NodeJS.ProcessEnv = { ...process.env, ...callerEnv };
|
|
45
|
+
clearInheritedTsgoArgs(env, callerEnv);
|
|
46
|
+
return env;
|
|
47
|
+
}
|
|
48
|
+
|
|
5
49
|
/**
|
|
6
50
|
* Resolve the caller-declared plugin config anchor to an absolute path, or
|
|
7
51
|
* `undefined` when the caller did not declare one.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
|
|
3
|
+
import { resolveNodeBinary } from "../../internal/resolveNodeBinary";
|
|
3
4
|
import { loadProjectPlugins } from "../../plugin/internal/loadProjectPlugins";
|
|
4
5
|
import type { ITtscCompilerContext } from "../../structures/ITtscCompilerContext";
|
|
5
6
|
import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
|
|
@@ -9,6 +10,8 @@ import { resolveBinary } from "./resolveBinary";
|
|
|
9
10
|
import { resolveTsgo } from "./resolveTsgo";
|
|
10
11
|
import {
|
|
11
12
|
assertSharedHostCompatibility,
|
|
13
|
+
clearInheritedTsgoArgs,
|
|
14
|
+
inheritedSidecarEnv,
|
|
12
15
|
linkedTransformPlugins,
|
|
13
16
|
resolvePluginConfigDir,
|
|
14
17
|
selectSharedHostPlugin,
|
|
@@ -52,7 +55,7 @@ export function startResidentTransform(
|
|
|
52
55
|
cacheDir: context.cacheDir ?? context.env?.TTSC_CACHE_DIR,
|
|
53
56
|
cwd,
|
|
54
57
|
entries: context.plugins,
|
|
55
|
-
env:
|
|
58
|
+
env: inheritedSidecarEnv(context.env),
|
|
56
59
|
pluginConfigDir: context.pluginConfigDir,
|
|
57
60
|
projectRoot: context.projectRoot,
|
|
58
61
|
tsconfig: project.path,
|
|
@@ -79,7 +82,7 @@ export function startResidentTransform(
|
|
|
79
82
|
],
|
|
80
83
|
binary: host.binary,
|
|
81
84
|
cwd: project.root,
|
|
82
|
-
env: residentEnv(context, tsgoBinary, loaded.nativePlugins),
|
|
85
|
+
env: residentEnv(context, project.root, tsgoBinary, loaded.nativePlugins),
|
|
83
86
|
});
|
|
84
87
|
return { process: resident, projectRoot: project.root };
|
|
85
88
|
}
|
|
@@ -95,13 +98,13 @@ export function startResidentTransform(
|
|
|
95
98
|
*/
|
|
96
99
|
function residentEnv(
|
|
97
100
|
context: ITtscCompilerContext,
|
|
101
|
+
projectRoot: string,
|
|
98
102
|
tsgoBinary: string,
|
|
99
103
|
nativePlugins: readonly ITtscLoadedNativePlugin[],
|
|
100
104
|
): NodeJS.ProcessEnv {
|
|
101
105
|
const pluginConfigDir = resolvePluginConfigDir(context);
|
|
102
106
|
const env: NodeJS.ProcessEnv = {
|
|
103
107
|
...process.env,
|
|
104
|
-
TTSC_NODE_BINARY: process.env.TTSC_NODE_BINARY ?? process.execPath,
|
|
105
108
|
...(pluginConfigDir === undefined
|
|
106
109
|
? {}
|
|
107
110
|
: { TTSC_PLUGIN_CONFIG_DIR: pluginConfigDir }),
|
|
@@ -111,6 +114,9 @@ function residentEnv(
|
|
|
111
114
|
path.join(__dirname, "..", "..", "launcher", "ttsx.js"),
|
|
112
115
|
...context.env,
|
|
113
116
|
};
|
|
117
|
+
const node = resolveNodeBinary(env, projectRoot);
|
|
118
|
+
if (node === undefined) delete env.TTSC_NODE_BINARY;
|
|
119
|
+
else env.TTSC_NODE_BINARY = node;
|
|
114
120
|
// The anchor is per-invocation state owned by this host: when this run
|
|
115
121
|
// declared none (and the caller's env does not name one), drop any value
|
|
116
122
|
// inherited from an ancestor ttsc process so a nested build never
|
|
@@ -121,6 +127,9 @@ function residentEnv(
|
|
|
121
127
|
) {
|
|
122
128
|
delete env.TTSC_PLUGIN_CONFIG_DIR;
|
|
123
129
|
}
|
|
130
|
+
// This lane forwards no tsgo argv of its own, so anything inherited belongs
|
|
131
|
+
// to an outer ttsc run and must not reach the resident sidecar.
|
|
132
|
+
clearInheritedTsgoArgs(env, context.env);
|
|
124
133
|
const linked = linkedTransformPlugins(nativePlugins);
|
|
125
134
|
if (linked.length !== 0) {
|
|
126
135
|
env.TTSC_LINKED_PLUGINS_JSON = serializeNativePlugins(linked);
|