ttsc 0.32.0 → 0.32.1
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/lib/TtscCompiler.js +1 -1
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/ResidentCheckProcess.d.ts +74 -96
- package/lib/compiler/internal/ResidentCheckProcess.js +150 -335
- package/lib/compiler/internal/ResidentCheckProcess.js.map +1 -1
- package/lib/compiler/internal/ResidentCheckProcessHost.d.ts +127 -0
- package/lib/compiler/internal/ResidentCheckProcessHost.js +447 -0
- package/lib/compiler/internal/ResidentCheckProcessHost.js.map +1 -0
- package/lib/compiler/internal/ResidentCheckProcessProtocol.d.ts +64 -0
- package/lib/compiler/internal/ResidentCheckProcessProtocol.js +3 -0
- package/lib/compiler/internal/ResidentCheckProcessProtocol.js.map +1 -0
- package/lib/compiler/internal/build/BuildExecution.d.ts +103 -1
- package/lib/compiler/internal/build/BuildExecution.js +91 -11
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/build/ResidentCheckWatchSession.d.ts +16 -11
- package/lib/compiler/internal/build/ResidentCheckWatchSession.js +37 -21
- package/lib/compiler/internal/build/ResidentCheckWatchSession.js.map +1 -1
- package/lib/compiler/internal/build/RunBuildOptions.d.ts +6 -5
- package/lib/compiler/internal/build/WatchInputPublication.d.ts +59 -0
- package/lib/compiler/internal/build/WatchInputPublication.js +93 -0
- package/lib/compiler/internal/build/WatchInputPublication.js.map +1 -0
- package/lib/compiler/internal/build/runBuild.d.ts +29 -2
- package/lib/compiler/internal/build/runBuild.js +45 -19
- package/lib/compiler/internal/build/runBuild.js.map +1 -1
- package/lib/compiler/internal/buildNativeCompiler.d.ts +2 -0
- package/lib/compiler/internal/buildNativeCompiler.js +1 -0
- package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +4 -2
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/resolveOwningProjectConfig.d.ts +7 -2
- package/lib/compiler/internal/project/resolveOwningProjectConfig.js +6 -3
- package/lib/compiler/internal/project/resolveOwningProjectConfig.js.map +1 -1
- package/lib/compiler/internal/readEffectiveCompilerOptions.js +1 -1
- package/lib/compiler/internal/readEffectiveCompilerOptions.js.map +1 -1
- package/lib/compiler/internal/resolveBinary.d.ts +1 -0
- package/lib/compiler/internal/resolveBinary.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.d.ts +6 -0
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.d.ts +28 -1
- package/lib/compiler/internal/runSingleFileEmit.js +120 -86
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +8 -2
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +11 -3
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/transformProjectInWorker.d.ts +1 -1
- package/lib/compiler/internal/transformProjectInWorker.js +3 -2
- package/lib/compiler/internal/transformProjectInWorker.js.map +1 -1
- package/lib/internal/workerModuleUrl.d.ts +28 -0
- package/lib/internal/workerModuleUrl.js +40 -0
- package/lib/internal/workerModuleUrl.js.map +1 -0
- package/lib/launcher/internal/buildSingleRootProject.js +2 -1
- package/lib/launcher/internal/buildSingleRootProject.js.map +1 -1
- package/lib/launcher/internal/getCompilerVersionText.js +3 -2
- package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +2 -1
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +91 -41
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runtime/CommonJsRuntimeSource.d.ts +10 -6
- package/lib/launcher/internal/runtime/CommonJsRuntimeSource.js +11 -9
- package/lib/launcher/internal/runtime/CommonJsRuntimeSource.js.map +1 -1
- package/lib/launcher/internal/runtime/advertiseTypeScriptExtensions.d.ts +20 -0
- package/lib/launcher/internal/runtime/advertiseTypeScriptExtensions.js +27 -0
- package/lib/launcher/internal/runtime/advertiseTypeScriptExtensions.js.map +1 -0
- package/lib/launcher/internal/runtime/installRuntimeHooks.d.ts +5 -3
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +7 -3
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/watch/AsyncWatchTopology.d.ts +113 -0
- package/lib/launcher/internal/watch/AsyncWatchTopology.js +232 -0
- package/lib/launcher/internal/watch/AsyncWatchTopology.js.map +1 -0
- package/lib/launcher/internal/watch/WatchSettlement.d.ts +49 -0
- package/lib/launcher/internal/watch/WatchSettlement.js +70 -0
- package/lib/launcher/internal/watch/WatchSettlement.js.map +1 -0
- package/lib/launcher/internal/watch/WatchTopology.d.ts +29 -1
- package/lib/launcher/internal/watch/WatchTopology.js +86 -10
- package/lib/launcher/internal/watch/WatchTopology.js.map +1 -1
- package/lib/launcher/internal/watch/WatchTopologyWorkerProtocol.d.ts +121 -0
- package/lib/launcher/internal/watch/WatchTopologyWorkerProtocol.js +3 -0
- package/lib/launcher/internal/watch/WatchTopologyWorkerProtocol.js.map +1 -0
- package/lib/launcher/internal/watch/serveWatchTopologyWorker.d.ts +19 -0
- package/lib/launcher/internal/watch/serveWatchTopologyWorker.js +62 -0
- package/lib/launcher/internal/watch/serveWatchTopologyWorker.js.map +1 -0
- package/lib/launcher/internal/watch/watchTopologyWorker.d.ts +1 -0
- package/lib/launcher/internal/watch/watchTopologyWorker.js +22 -0
- package/lib/launcher/internal/watch/watchTopologyWorker.js.map +1 -0
- package/lib/plugin/CapabilityPluginResolver.d.ts +1 -1
- package/lib/plugin/CapabilityPluginResolver.js +3 -2
- package/lib/plugin/CapabilityPluginResolver.js.map +1 -1
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.d.ts +15 -12
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js +13 -11
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js.map +1 -1
- package/lib/plugin/internal/load/PluginPackageResolution.d.ts +2 -2
- package/lib/plugin/internal/load/PluginPackageResolution.js +13 -7
- package/lib/plugin/internal/load/PluginPackageResolution.js.map +1 -1
- package/lib/plugin/internal/load/ProjectPluginEntries.d.ts +23 -7
- package/lib/plugin/internal/load/ProjectPluginEntries.js +36 -14
- package/lib/plugin/internal/load/ProjectPluginEntries.js.map +1 -1
- package/lib/plugin/internal/load/collectProjectHostInputs.d.ts +3 -1
- package/lib/plugin/internal/load/collectProjectHostInputs.js +5 -2
- package/lib/plugin/internal/load/collectProjectHostInputs.js.map +1 -1
- package/lib/plugin/internal/load/hasProjectPluginEntries.d.ts +3 -1
- package/lib/plugin/internal/load/hasProjectPluginEntries.js +4 -2
- package/lib/plugin/internal/load/hasProjectPluginEntries.js.map +1 -1
- package/lib/plugin/internal/load/loadProjectPlugins.d.ts +36 -5
- package/lib/plugin/internal/load/loadProjectPlugins.js +466 -416
- package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/internal/load/pluginResolutionFailure.d.ts +18 -0
- package/lib/plugin/internal/load/pluginResolutionFailure.js +32 -0
- package/lib/plugin/internal/load/pluginResolutionFailure.js.map +1 -0
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.d.ts +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js +3 -2
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +12 -12
- package/lib/structures/ITtscPlugin.d.ts +7 -5
- package/lib/structures/ITtscPluginFactoryContext.d.ts +9 -8
- package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +12 -6
- package/package.json +9 -9
- package/src/TtscCompiler.ts +1 -1
- package/src/compiler/internal/ResidentCheckProcess.ts +159 -374
- package/src/compiler/internal/ResidentCheckProcessHost.ts +502 -0
- package/src/compiler/internal/ResidentCheckProcessProtocol.ts +53 -0
- package/src/compiler/internal/build/BuildExecution.ts +118 -9
- package/src/compiler/internal/build/ResidentCheckWatchSession.ts +41 -24
- package/src/compiler/internal/build/RunBuildOptions.ts +9 -5
- package/src/compiler/internal/build/WatchInputPublication.ts +106 -0
- package/src/compiler/internal/build/runBuild.ts +58 -34
- package/src/compiler/internal/buildNativeCompiler.ts +4 -0
- package/src/compiler/internal/compileProjectInMemory.ts +8 -2
- package/src/compiler/internal/project/resolveOwningProjectConfig.ts +16 -5
- package/src/compiler/internal/readEffectiveCompilerOptions.ts +1 -1
- package/src/compiler/internal/resolveBinary.ts +4 -1
- package/src/compiler/internal/resolveTsgo.ts +7 -0
- package/src/compiler/internal/runSingleFileEmit.ts +139 -99
- package/src/compiler/internal/startResidentTransform.ts +9 -2
- package/src/compiler/internal/transformProjectInMemory.ts +12 -3
- package/src/compiler/internal/transformProjectInWorker.ts +10 -2
- package/src/internal/workerModuleUrl.ts +34 -0
- package/src/launcher/internal/buildSingleRootProject.ts +2 -0
- package/src/launcher/internal/getCompilerVersionText.ts +3 -2
- package/src/launcher/internal/prepareExecution.ts +2 -0
- package/src/launcher/internal/runTtsc.ts +123 -45
- package/src/launcher/internal/runtime/CommonJsRuntimeSource.ts +11 -9
- package/src/launcher/internal/runtime/advertiseTypeScriptExtensions.ts +25 -0
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +7 -3
- package/src/launcher/internal/watch/AsyncWatchTopology.ts +267 -0
- package/src/launcher/internal/watch/WatchSettlement.ts +67 -0
- package/src/launcher/internal/watch/WatchTopology.ts +84 -13
- package/src/launcher/internal/watch/WatchTopologyWorkerProtocol.ts +106 -0
- package/src/launcher/internal/watch/serveWatchTopologyWorker.ts +75 -0
- package/src/launcher/internal/watch/watchTopologyWorker.ts +29 -0
- package/src/plugin/CapabilityPluginResolver.ts +9 -2
- package/src/plugin/internal/load/PluginDescriptorEvaluationCache.ts +17 -12
- package/src/plugin/internal/load/PluginPackageResolution.ts +14 -9
- package/src/plugin/internal/load/ProjectPluginEntries.ts +40 -15
- package/src/plugin/internal/load/collectProjectHostInputs.ts +7 -1
- package/src/plugin/internal/load/hasProjectPluginEntries.ts +8 -3
- package/src/plugin/internal/load/loadProjectPlugins.ts +672 -594
- package/src/plugin/internal/load/pluginResolutionFailure.ts +37 -0
- package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +8 -2
- package/src/structures/ITtscCompilerContext.ts +12 -12
- package/src/structures/ITtscPlugin.ts +7 -5
- package/src/structures/ITtscPluginFactoryContext.ts +9 -8
- package/src/structures/internal/TtscSingleFileEmitOptions.ts +22 -11
|
@@ -52,6 +52,8 @@ import { selectReferencedProject } from "./selectReferencedProject";
|
|
|
52
52
|
* @param props.tsconfig - The config project discovery found for the file.
|
|
53
53
|
* @param props.file - The file whose project is asked for.
|
|
54
54
|
* @param props.binary - An explicit TypeScript-Go binary, when one was given.
|
|
55
|
+
* @param props.env - Complete environment shared by compiler selection and
|
|
56
|
+
* root-file expansion; omission inherits the current process environment.
|
|
55
57
|
* @param props.onConfig - Called with every config this reads, so a caller that
|
|
56
58
|
* fingerprints its inputs can record them.
|
|
57
59
|
* @evidence contracts/common.md#principled-implementation Successful compiler showConfig supplies root membership observations, best-effort filesystem identity compares aliases, and visited identity keys terminate repeated graph states while declaration-order DFS selects the first observed containing project. Failed observations preserve the discovered fallback without certifying membership.
|
|
@@ -76,13 +78,17 @@ export function resolveOwningProjectConfig(props: {
|
|
|
76
78
|
*/
|
|
77
79
|
binary?: string;
|
|
78
80
|
|
|
81
|
+
/** Complete environment for compiler selection and root-file expansion. */
|
|
82
|
+
env?: NodeJS.ProcessEnv;
|
|
83
|
+
|
|
79
84
|
/** Observe each directly read config, including ones with no reference edges. */
|
|
80
85
|
onConfig?: (config: string) => void;
|
|
81
86
|
|
|
82
87
|
/**
|
|
83
88
|
* Expanded root files kept across lookups, by config path, for a caller whose
|
|
84
|
-
* selected builds already hold for the same
|
|
85
|
-
* project once per process
|
|
89
|
+
* selected builds and compiler environment already hold for the same
|
|
90
|
+
* lifetime: ttsx builds each owning project once per process
|
|
91
|
+
* (samchon/ttsc#1747).
|
|
86
92
|
*/
|
|
87
93
|
expansions?: Map<string, { files: readonly string[]; takenAt: number }>;
|
|
88
94
|
}): string {
|
|
@@ -128,7 +134,7 @@ export function resolveOwningProjectConfig(props: {
|
|
|
128
134
|
|
|
129
135
|
/** Expand `config` now, and keep the expansion when the caller asked to. */
|
|
130
136
|
function expand(config: string): RootFiles {
|
|
131
|
-
const roots = rootFiles(config, props.binary);
|
|
137
|
+
const roots = rootFiles(config, props.binary, props.env);
|
|
132
138
|
props.expansions?.set(config, roots);
|
|
133
139
|
return roots;
|
|
134
140
|
}
|
|
@@ -214,14 +220,19 @@ interface RootFiles {
|
|
|
214
220
|
* include approximation or permanent failed answer substitutes for compiler
|
|
215
221
|
* behavior.
|
|
216
222
|
*/
|
|
217
|
-
function rootFiles(
|
|
223
|
+
function rootFiles(
|
|
224
|
+
config: string,
|
|
225
|
+
binary: string | undefined,
|
|
226
|
+
env: NodeJS.ProcessEnv | undefined,
|
|
227
|
+
): RootFiles {
|
|
218
228
|
const takenAt = Date.now();
|
|
219
229
|
let files: string[] = [];
|
|
220
230
|
try {
|
|
221
231
|
const directory = path.dirname(config);
|
|
222
|
-
const tsgo = resolveTsgo({ binary, cwd: directory });
|
|
232
|
+
const tsgo = resolveTsgo({ binary, cwd: directory, env });
|
|
223
233
|
const result = spawnNative(tsgo.binary, ["-p", config, "--showConfig"], {
|
|
224
234
|
cwd: directory,
|
|
235
|
+
env,
|
|
225
236
|
encoding: "utf8",
|
|
226
237
|
});
|
|
227
238
|
if (result.status === 0) {
|
|
@@ -84,7 +84,7 @@ export function readEffectiveCompilerOptions(
|
|
|
84
84
|
} catch {
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
|
-
const tsgo = resolveTsgo({ cwd: project.root, binary });
|
|
87
|
+
const tsgo = resolveTsgo({ cwd: project.root, binary, env });
|
|
88
88
|
const result = spawnNative(
|
|
89
89
|
tsgo.binary,
|
|
90
90
|
["-p", project.path, ...passthrough, "-p", project.path, "--showConfig"],
|
|
@@ -29,7 +29,10 @@ import { SidecarEnvironment } from "./sharedHost/SidecarEnvironment";
|
|
|
29
29
|
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Resolution owns no persistent map, descriptor or task and returns only the selected path spelling.
|
|
30
30
|
*/
|
|
31
31
|
export function resolveBinary(
|
|
32
|
-
opts: {
|
|
32
|
+
opts: {
|
|
33
|
+
/** Complete selection environment; omission reads the current process. */
|
|
34
|
+
env?: NodeJS.ProcessEnv;
|
|
35
|
+
} = {},
|
|
33
36
|
): string | null {
|
|
34
37
|
const env = opts.env ?? process.env;
|
|
35
38
|
const explicit = SidecarEnvironment.read(env, "TTSC_BINARY");
|
|
@@ -41,6 +41,13 @@ export function resolveTsgo(
|
|
|
41
41
|
|
|
42
42
|
/** Directory from which to discover `typescript`. */
|
|
43
43
|
cwd?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Complete environment for executable selection; omission reads the current
|
|
47
|
+
* process environment. Public compiler owners merge caller overrides before
|
|
48
|
+
* invoking this resolver, retaining their original overlay for channel
|
|
49
|
+
* ownership.
|
|
50
|
+
*/
|
|
44
51
|
env?: NodeJS.ProcessEnv;
|
|
45
52
|
|
|
46
53
|
/**
|
|
@@ -4,10 +4,12 @@ import path from "node:path";
|
|
|
4
4
|
import { createCanonicalTempDirectory } from "../../internal/createCanonicalTempDirectory";
|
|
5
5
|
import type { TtscSingleFileEmitOptions } from "../../structures/internal/TtscSingleFileEmitOptions";
|
|
6
6
|
import { EmitOwnershipIndex } from "./EmitOwnershipIndex";
|
|
7
|
+
import { WatchInputPublication } from "./build/WatchInputPublication";
|
|
7
8
|
import { runBuild } from "./build/runBuild";
|
|
8
9
|
import { CompilerProjectSelection } from "./project/CompilerProjectSelection";
|
|
9
10
|
import { readProjectConfig } from "./project/readProjectConfig";
|
|
10
11
|
import { readEffectiveCompilerOptions } from "./readEffectiveCompilerOptions";
|
|
12
|
+
import { SidecarEnvironment } from "./sharedHost/SidecarEnvironment";
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Emit one source file by building its project into a temporary directory.
|
|
@@ -24,7 +26,8 @@ import { readEffectiveCompilerOptions } from "./readEffectiveCompilerOptions";
|
|
|
24
26
|
* argument cwd with public output planning. Response freshness is checked
|
|
25
27
|
* before native work and publication; these sequential checks do not pin bytes
|
|
26
28
|
* atomically. Callers without that record retain explicit config/nearest-file
|
|
27
|
-
* discovery.
|
|
29
|
+
* discovery. Watch-input handlers must complete synchronously; use
|
|
30
|
+
* {@link runSingleFileEmit.async} for promise-returning handlers.
|
|
28
31
|
*
|
|
29
32
|
* @returns The transformed JavaScript source text.
|
|
30
33
|
* @throws When the build exits non-zero, proves no JavaScript for the requested
|
|
@@ -44,110 +47,147 @@ export function runSingleFileEmit(
|
|
|
44
47
|
options: TtscSingleFileEmitOptions,
|
|
45
48
|
selection?: ReturnType<typeof CompilerProjectSelection.read>,
|
|
46
49
|
): string {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
options
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
CompilerProjectSelection.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
50
|
+
return WatchInputPublication.run(runSingleFileEmit.steps(options, selection));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Keep synchronous and awaited single-file emission on one temporary lifetime.
|
|
55
|
+
*
|
|
56
|
+
* @evidence contracts/common.md#principled-implementation Both entries share project/root selection, producing build, response freshness, provenance lookup and temporary-output cleanup; awaited completion joins every nested publication before compilation and output selection.
|
|
57
|
+
* @evidence contracts/common.md#clear-and-simple-design One generator owns project emission, optional public output and cleanup for both completion modes; the companion adds a runner without another output-selection implementation.
|
|
58
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Pending registration cannot authorize a build, and rejected publication reaches the same temporary cleanup path. Completion mode preserves response checks and provenance instead of reconstructing source ownership from filenames.
|
|
59
|
+
* @evidence contracts/common.md#meaningful-documentation Each entry states completion mode and the shared temporary lifetime; sequence prose requires rejection delivery into its finally path, while the primary entry documents output selection and cleanup failures.
|
|
60
|
+
* @evidence contracts/portability.md#os-neutral-implementation The shared sequence retains existing native source/output identity, cwd bases and private-directory handling across suspension without another native boundary.
|
|
61
|
+
* @evidence contracts/performance.md#efficient-algorithms One project selection and full-project build serve one provenance lookup; each handoff is awaited once with no additional source or output traversal.
|
|
62
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each sequence owns fresh compiler effects rather than an output cache or shared generation; higher-level owners decide equivalent build reuse.
|
|
63
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources One accepted private output directory spans nested handoff and build work, and the existing finally path removes it on success or failure and preserves cleanup error aggregation.
|
|
64
|
+
*/
|
|
65
|
+
export namespace runSingleFileEmit {
|
|
66
|
+
/**
|
|
67
|
+
* Await watch-input registration before emitting and selecting one source's
|
|
68
|
+
* JavaScript. Rejected publication follows the same temporary cleanup path.
|
|
69
|
+
*/
|
|
70
|
+
export function async(
|
|
71
|
+
options: TtscSingleFileEmitOptions,
|
|
72
|
+
selection?: ReturnType<typeof CompilerProjectSelection.read>,
|
|
73
|
+
): Promise<string> {
|
|
74
|
+
return WatchInputPublication.runAsync(steps(options, selection));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Emit through one selected project while suspending at watch handoffs.
|
|
79
|
+
* Internal completion runners must deliver rejection into this sequence so
|
|
80
|
+
* its finally block retains temporary-output cleanup ownership.
|
|
81
|
+
*/
|
|
82
|
+
export function* steps(
|
|
83
|
+
options: TtscSingleFileEmitOptions,
|
|
84
|
+
selection?: ReturnType<typeof CompilerProjectSelection.read>,
|
|
85
|
+
): WatchInputPublication.Sequence<string> {
|
|
86
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
87
|
+
const sourceFile = realpathIfExists(
|
|
88
|
+
path.isAbsolute(options.file)
|
|
89
|
+
? options.file
|
|
90
|
+
: path.resolve(cwd, options.file),
|
|
91
|
+
);
|
|
92
|
+
const project =
|
|
93
|
+
selection?.project ??
|
|
94
|
+
readProjectConfig({
|
|
95
|
+
cwd,
|
|
96
|
+
file: options.file,
|
|
97
|
+
projectRoot: options.projectRoot,
|
|
98
|
+
tsconfig: options.tsconfig,
|
|
99
|
+
});
|
|
100
|
+
const tsconfig = project.path;
|
|
101
|
+
const compilerArgsCwd = selection?.compilerArgsCwd ?? project.root;
|
|
102
|
+
if (selection !== undefined)
|
|
103
|
+
CompilerProjectSelection.assertCurrent(selection);
|
|
104
|
+
// The root tsgo lays the outputs against: a `--rootDir` forwarded on the
|
|
105
|
+
// command line, which reaches it after the config; otherwise the declared
|
|
106
|
+
// one, which `readProjectConfig` already absolutized; otherwise the project's
|
|
107
|
+
// own directory, which `pinInferredRootDir` hands it below.
|
|
108
|
+
const effective = readEffectiveCompilerOptions(
|
|
109
|
+
project,
|
|
110
|
+
options.passthrough,
|
|
111
|
+
options.binary,
|
|
112
|
+
SidecarEnvironment.merge(process.env, options.env),
|
|
89
113
|
compilerArgsCwd,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// one the project declared, and tsgo answers an inferred common source
|
|
96
|
-
// directory with TS5011 as soon as any `outDir` is in play. Pinning the
|
|
97
|
-
// root tsgo would infer keeps `ttsc <file.ts>` working on a project that
|
|
98
|
-
// declares no output at all, while the producing invocation reports its
|
|
99
|
-
// actual source/output ownership separately.
|
|
100
|
-
pinInferredRootDir: true,
|
|
101
|
-
resolvedProject: project,
|
|
102
|
-
tsconfig,
|
|
103
|
-
});
|
|
104
|
-
if (result.status !== 0) {
|
|
105
|
-
throw new Error(
|
|
106
|
-
"ttsc single-file emit exited " +
|
|
107
|
-
result.status +
|
|
108
|
-
"\n" +
|
|
109
|
-
(result.stderr || result.stdout),
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
const emitted = new EmitOwnershipIndex({
|
|
113
|
-
emitDir: outDir,
|
|
114
|
-
rootDir,
|
|
115
|
-
emittedSources: result.emittedSources,
|
|
116
|
-
emittedSourceProofFailures: result.emittedSourceProofFailures,
|
|
117
|
-
outputs: EmitOwnershipIndex.listOutputs(outDir),
|
|
118
|
-
}).find(sourceFile);
|
|
119
|
-
if (emitted === null) {
|
|
120
|
-
throw new Error(
|
|
121
|
-
`ttsc single-file emit: ${tsconfig} emitted no JavaScript owned by ${sourceFile}; check that the project includes the source and its options permit JavaScript emission`,
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
const transformed = fs.readFileSync(emitted, "utf8");
|
|
114
|
+
)?.("rootDir");
|
|
115
|
+
const rootDir =
|
|
116
|
+
typeof effective === "string"
|
|
117
|
+
? path.resolve(compilerArgsCwd, effective)
|
|
118
|
+
: project.root;
|
|
125
119
|
if (selection !== undefined)
|
|
126
120
|
CompilerProjectSelection.assertCurrent(selection);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
: path.resolve(cwd, options.out);
|
|
131
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
132
|
-
fs.writeFileSync(target, transformed, "utf8");
|
|
133
|
-
}
|
|
134
|
-
return transformed;
|
|
135
|
-
} catch (error) {
|
|
136
|
-
failed = true;
|
|
137
|
-
failure = error;
|
|
138
|
-
throw error;
|
|
139
|
-
} finally {
|
|
121
|
+
const outDir = createCanonicalTempDirectory("ttsc-single-file-");
|
|
122
|
+
let failed = false;
|
|
123
|
+
let failure: unknown;
|
|
140
124
|
try {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
125
|
+
const result = yield* runBuild.steps({
|
|
126
|
+
...options,
|
|
127
|
+
cwd,
|
|
128
|
+
compilerArgsCwd,
|
|
129
|
+
emit: true,
|
|
130
|
+
forceEmitProvenance: true,
|
|
131
|
+
isolateOutputsTo: outDir,
|
|
132
|
+
outDir,
|
|
133
|
+
// The private temp directory above is an `outDir` this lane injected, not
|
|
134
|
+
// one the project declared, and tsgo answers an inferred common source
|
|
135
|
+
// directory with TS5011 as soon as any `outDir` is in play. Pinning the
|
|
136
|
+
// root tsgo would infer keeps `ttsc <file.ts>` working on a project that
|
|
137
|
+
// declares no output at all, while the producing invocation reports its
|
|
138
|
+
// actual source/output ownership separately.
|
|
139
|
+
pinInferredRootDir: true,
|
|
140
|
+
resolvedProject: project,
|
|
141
|
+
tsconfig,
|
|
142
|
+
});
|
|
143
|
+
if (result.status !== 0) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
"ttsc single-file emit exited " +
|
|
146
|
+
result.status +
|
|
147
|
+
"\n" +
|
|
148
|
+
(result.stderr || result.stdout),
|
|
148
149
|
);
|
|
149
150
|
}
|
|
150
|
-
|
|
151
|
+
const emitted = new EmitOwnershipIndex({
|
|
152
|
+
emitDir: outDir,
|
|
153
|
+
rootDir,
|
|
154
|
+
emittedSources: result.emittedSources,
|
|
155
|
+
emittedSourceProofFailures: result.emittedSourceProofFailures,
|
|
156
|
+
outputs: EmitOwnershipIndex.listOutputs(outDir),
|
|
157
|
+
}).find(sourceFile);
|
|
158
|
+
if (emitted === null) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`ttsc single-file emit: ${tsconfig} emitted no JavaScript owned by ${sourceFile}; check that the project includes the source and its options permit JavaScript emission`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
const transformed = fs.readFileSync(emitted, "utf8");
|
|
164
|
+
if (selection !== undefined)
|
|
165
|
+
CompilerProjectSelection.assertCurrent(selection);
|
|
166
|
+
if (options.out) {
|
|
167
|
+
const target = path.isAbsolute(options.out)
|
|
168
|
+
? options.out
|
|
169
|
+
: path.resolve(cwd, options.out);
|
|
170
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
171
|
+
fs.writeFileSync(target, transformed, "utf8");
|
|
172
|
+
}
|
|
173
|
+
return transformed;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
failed = true;
|
|
176
|
+
failure = error;
|
|
177
|
+
throw error;
|
|
178
|
+
} finally {
|
|
179
|
+
try {
|
|
180
|
+
fs.rmSync(outDir, { recursive: true, force: true });
|
|
181
|
+
} catch (cleanupError) {
|
|
182
|
+
if (failed) {
|
|
183
|
+
throw new AggregateError(
|
|
184
|
+
[failure, cleanupError],
|
|
185
|
+
"ttsc: single-file emission and temporary output cleanup failed",
|
|
186
|
+
{ cause: failure },
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
throw cleanupError;
|
|
190
|
+
}
|
|
151
191
|
}
|
|
152
192
|
}
|
|
153
193
|
}
|
|
@@ -62,7 +62,10 @@ export function startResidentTransform(
|
|
|
62
62
|
tsconfig: context.tsconfig,
|
|
63
63
|
});
|
|
64
64
|
const loaded = loadProjectPlugins({
|
|
65
|
-
binary:
|
|
65
|
+
binary:
|
|
66
|
+
resolveBinary({
|
|
67
|
+
env: SidecarEnvironment.merge(process.env, context.env),
|
|
68
|
+
}) ?? "",
|
|
66
69
|
cacheDir:
|
|
67
70
|
context.cacheDir ??
|
|
68
71
|
SidecarEnvironment.read(context.env, "TTSC_CACHE_DIR"),
|
|
@@ -85,7 +88,11 @@ export function startResidentTransform(
|
|
|
85
88
|
assertSharedHostCompatibility(transformers, "source-to-source");
|
|
86
89
|
|
|
87
90
|
const host = selectSharedHostPlugin(transformers);
|
|
88
|
-
const tsgoBinary = resolveTsgo({
|
|
91
|
+
const tsgoBinary = resolveTsgo({
|
|
92
|
+
...context,
|
|
93
|
+
cwd: project.root,
|
|
94
|
+
env: SidecarEnvironment.merge(process.env, context.env),
|
|
95
|
+
}).binary;
|
|
89
96
|
const resident = new ResidentTransformProcess({
|
|
90
97
|
args: [
|
|
91
98
|
"serve",
|
|
@@ -109,7 +109,10 @@ export function transformProjectInMemory(options: ITtscCompilerContext): {
|
|
|
109
109
|
} {
|
|
110
110
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
111
111
|
const loaded = loadProjectPlugins({
|
|
112
|
-
binary:
|
|
112
|
+
binary:
|
|
113
|
+
resolveBinary({
|
|
114
|
+
env: SidecarEnvironment.merge(process.env, options.env),
|
|
115
|
+
}) ?? "",
|
|
113
116
|
cacheDir:
|
|
114
117
|
options.cacheDir ??
|
|
115
118
|
SidecarEnvironment.read(options.env, "TTSC_CACHE_DIR"),
|
|
@@ -188,11 +191,13 @@ function transformProjectWithNativeHost(
|
|
|
188
191
|
baseline?.hostInputs ?? [],
|
|
189
192
|
projectHostInputs,
|
|
190
193
|
);
|
|
194
|
+
const env = inheritedSidecarEnv(options.env);
|
|
191
195
|
const binary = buildNativeCompiler({
|
|
192
196
|
cacheBaseDir: project.root,
|
|
193
197
|
cacheDir:
|
|
194
198
|
options.cacheDir ??
|
|
195
199
|
SidecarEnvironment.read(options.env, "TTSC_CACHE_DIR"),
|
|
200
|
+
env,
|
|
196
201
|
packageRoot: packageRootDir(),
|
|
197
202
|
});
|
|
198
203
|
const res = spawnNative(
|
|
@@ -200,7 +205,7 @@ function transformProjectWithNativeHost(
|
|
|
200
205
|
["api-transform", "--cwd", project.root, "--tsconfig", project.path],
|
|
201
206
|
{
|
|
202
207
|
cwd: project.root,
|
|
203
|
-
env
|
|
208
|
+
env,
|
|
204
209
|
},
|
|
205
210
|
);
|
|
206
211
|
if (res.error) {
|
|
@@ -295,7 +300,11 @@ function transformProjectWithPlugins(
|
|
|
295
300
|
const tsgoBinary =
|
|
296
301
|
loaded.nativePlugins.length === 0
|
|
297
302
|
? ""
|
|
298
|
-
: resolveTsgo({
|
|
303
|
+
: resolveTsgo({
|
|
304
|
+
...options,
|
|
305
|
+
cwd: project.root,
|
|
306
|
+
env: SidecarEnvironment.merge(process.env, options.env),
|
|
307
|
+
}).binary;
|
|
299
308
|
const checked = runNativeChecks(
|
|
300
309
|
options,
|
|
301
310
|
project,
|
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { Worker } from "node:worker_threads";
|
|
4
4
|
|
|
5
5
|
import { CompilerContextSnapshot } from "../../internal/CompilerContextSnapshot";
|
|
6
|
+
import { workerModuleUrl } from "../../internal/workerModuleUrl";
|
|
6
7
|
import type { ITtscCompilerContext } from "../../structures/ITtscCompilerContext";
|
|
7
8
|
import type { TransformProjectWorkerReply } from "./TransformProjectWorkerReply";
|
|
8
9
|
import type { TransformProjectWorkerRequest } from "./TransformProjectWorkerRequest";
|
|
@@ -50,7 +51,7 @@ import type { transformProjectInMemory } from "./transformProjectInMemory";
|
|
|
50
51
|
* @evidence contracts/common.md#clear-and-simple-design The public operation owns checkout, exclusive event listeners and return to the idle pool; two private helpers isolate idle-worker retirement from active request settlement.
|
|
51
52
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Blocking work runs in a supported worker boundary rather than rewriting the caller's environment around synchronous work; failures preserve real exceptions and do not substitute measured or expected results.
|
|
52
53
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain why all transform phases move off-thread, environment isolation, warm reuse and retained-population limits following the documentation skill.
|
|
53
|
-
* @evidence contracts/portability.md#os-neutral-implementation
|
|
54
|
+
* @evidence contracts/portability.md#os-neutral-implementation A supported module URL requires the native CommonJS source or emitted worker entry while Node retains inherited execution options and preload hooks. The environment snapshot uses native name identity; Windows worker copies are case-sensitive, so canonical merging prevents aliases from defeating caller overrides inside the worker.
|
|
54
55
|
* @evidence contracts/performance.md#efficient-algorithms Pool checkout removes one entry and listeners; environment merge and plugin JSON serialization visit caller data before structured cloning, whose cost includes context, serialized payload and environment bytes. Caller JSON conversion can add arbitrary work. Idle-worker retirement searches/compacts at most the pool budget; worker startup and native transform costs remain delegated, and output cloning is transport work rather than a second transform.
|
|
55
56
|
* @evidence contracts/performance.md#reuse-equivalent-work An exclusively checked-out warm worker reuses the loader's input-validated caches; each request adopts its complete current environment and still executes the transform, so thread reuse is not an unsupported response cache.
|
|
56
57
|
* @evidence contracts/performance.md#bound-retention-and-release-resources At most the module-initialization CPU budget remains in the idle pool with event-loop references removed. Excess/failed workers receive unawaited termination requests; retiring native threads are not covered by the reusable-entry count. Terminal settlement removes active listeners, while pooled module caches retain their owning data policy. Active requests and live transforms have no concurrency cap or implicit deadline.
|
|
@@ -65,7 +66,14 @@ export function transformProjectInWorker(
|
|
|
65
66
|
};
|
|
66
67
|
const worker =
|
|
67
68
|
takeIdleWorker() ??
|
|
68
|
-
new Worker(
|
|
69
|
+
new Worker(
|
|
70
|
+
workerModuleUrl(
|
|
71
|
+
path.join(
|
|
72
|
+
__dirname,
|
|
73
|
+
`transformProjectWorker${path.extname(__filename)}`,
|
|
74
|
+
),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
69
77
|
worker.ref();
|
|
70
78
|
return new Promise((resolve, reject) => {
|
|
71
79
|
let settled = false;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Load an owned CommonJS worker through a module URL while retaining Node's
|
|
5
|
+
* inherited execution options and preload hooks.
|
|
6
|
+
*
|
|
7
|
+
* A parent launched with --input-type interprets stdin or evaluated source.
|
|
8
|
+
* With a preload, module resolution rejects that inherited option at a file
|
|
9
|
+
* worker entry before the worker can start. A supported data URL supplies
|
|
10
|
+
* module source that requires the real entry. Setting execArgv instead would
|
|
11
|
+
* replace Node's inherited-option handling and can reject otherwise valid
|
|
12
|
+
* process options such as --max-old-space-size. createRequire preserves the
|
|
13
|
+
* entry's CommonJS resolution, including literal POSIX backslashes that file
|
|
14
|
+
* URL imports reject as encoded separators. The worker entry must use the
|
|
15
|
+
* package's CommonJS source or emitted format.
|
|
16
|
+
*
|
|
17
|
+
* @param filename Native entry path, resolved from cwd when relative.
|
|
18
|
+
* @returns A data URL accepted by the Worker constructor; it owns no thread.
|
|
19
|
+
* @evidence contracts/common.md#principled-implementation Node documents data URL worker entries and inherited options; a module-source entry requires the selected CommonJS owner without applying the parent's stdin-only input type to that file's initial module resolution.
|
|
20
|
+
* @evidence contracts/common.md#clear-and-simple-design One URL constructor owns the bootstrap representation while callers retain worker options, thread lifetime and actual entry selection.
|
|
21
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Supported createRequire loads the actual CommonJS owner; no flags are guessed, stripped or replaced and no foreign process state is changed.
|
|
22
|
+
* @evidence contracts/common.md#meaningful-documentation Prose explains the stdin inheritance failure, the explicit-execArgv hazard, CommonJS entry requirements and the native path input.
|
|
23
|
+
* @evidence contracts/portability.md#os-neutral-implementation Native path resolution and createRequire retain filesystem path spelling, including POSIX literal backslashes; JSON string encoding and data URL encoding separate that path from JavaScript and URL syntax without routing it through ESM file-URL separator rules.
|
|
24
|
+
* @evidence contracts/performance.md#efficient-algorithms Native path resolution, string encoding and data URL construction each visit entry-path text; the returned URL and its module source occupy linear space in that text.
|
|
25
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call represents its selected entry and retains no computed answer.
|
|
26
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources This operation returns a URL without acquiring a worker, file handle or persistent state; the caller owns the URL and thread.
|
|
27
|
+
* @see https://nodejs.org/api/worker_threads.html#new-workerfilename-options
|
|
28
|
+
* @see https://nodejs.org/api/cli.html#--input-typetype
|
|
29
|
+
*/
|
|
30
|
+
export function workerModuleUrl(filename: string): URL {
|
|
31
|
+
const entry = JSON.stringify(path.resolve(filename));
|
|
32
|
+
const source = `import { createRequire } from "node:module"; createRequire(${entry})(${entry});`;
|
|
33
|
+
return new URL(`data:text/javascript,${encodeURIComponent(source)}`);
|
|
34
|
+
}
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { runBuild } from "../../compiler/internal/build/runBuild";
|
|
5
5
|
import { readProjectConfig } from "../../compiler/internal/project/readProjectConfig";
|
|
6
6
|
import { readEffectiveCompilerOptions } from "../../compiler/internal/readEffectiveCompilerOptions";
|
|
7
|
+
import { SidecarEnvironment } from "../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
7
8
|
import { createFilesystemPathIdentityContext } from "../../internal/pathIdentity/createFilesystemPathIdentityContext";
|
|
8
9
|
import type { TtscBuildResult } from "../../structures/internal/TtscBuildResult";
|
|
9
10
|
import type { TtscCommonOptions } from "../../structures/internal/TtscCommonOptions";
|
|
@@ -186,6 +187,7 @@ export function buildSingleRootProject(props: {
|
|
|
186
187
|
project,
|
|
187
188
|
options.passthrough,
|
|
188
189
|
options.binary,
|
|
190
|
+
SidecarEnvironment.merge(process.env, options.env),
|
|
189
191
|
);
|
|
190
192
|
const result = runBuild({
|
|
191
193
|
binary: options.binary,
|
|
@@ -24,10 +24,11 @@ import type { TtscCommonOptions } from "../../structures/internal/TtscCommonOpti
|
|
|
24
24
|
export function getCompilerVersionText(
|
|
25
25
|
options: TtscCommonOptions = {},
|
|
26
26
|
): string {
|
|
27
|
-
const
|
|
27
|
+
const env = SidecarEnvironment.merge(process.env, options.env);
|
|
28
|
+
const tsgo = resolveTsgo({ ...options, env });
|
|
28
29
|
const res = spawnNative(tsgo.binary, ["--version"], {
|
|
29
30
|
cwd: options.cwd,
|
|
30
|
-
env
|
|
31
|
+
env,
|
|
31
32
|
});
|
|
32
33
|
if (res.error || res.status !== 0) {
|
|
33
34
|
throw new Error(
|
|
@@ -324,6 +324,7 @@ function createProjectContext(
|
|
|
324
324
|
project,
|
|
325
325
|
options.passthrough,
|
|
326
326
|
options.binary,
|
|
327
|
+
env,
|
|
327
328
|
);
|
|
328
329
|
const privateEmitRootDir = resolveRuntimeSourceRoot(
|
|
329
330
|
project,
|
|
@@ -440,6 +441,7 @@ function discoverOwningProject(
|
|
|
440
441
|
});
|
|
441
442
|
const owning = resolveOwningProjectConfig({
|
|
442
443
|
binary: options.binary,
|
|
444
|
+
env: SidecarEnvironment.merge(process.env, options.env),
|
|
443
445
|
file,
|
|
444
446
|
tsconfig: nearest.path,
|
|
445
447
|
});
|