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
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { Worker } from "node:worker_threads";
|
|
3
|
+
|
|
4
|
+
import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
5
|
+
import { workerModuleUrl } from "../../../internal/workerModuleUrl";
|
|
6
|
+
import type { PluginContentIdentities } from "../../../plugin/internal/source/PluginContentIdentities";
|
|
7
|
+
import type { ITtscProjectInputSnapshot } from "../../../structures/internal/ITtscProjectInputSnapshot";
|
|
8
|
+
import type { WatchTopologyWorkerProtocol } from "./WatchTopologyWorkerProtocol";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Keep one watch topology and its native subscriptions on a worker thread.
|
|
12
|
+
*
|
|
13
|
+
* Case-policy probes, content digests and compiler listings must retain their
|
|
14
|
+
* actual observations. Replacing them with path-only case caches or size/mtime
|
|
15
|
+
* digests can miss directory replacements and source edits. They instead run
|
|
16
|
+
* off the launcher's loop so their cost cannot delay resident-host retirement
|
|
17
|
+
* or queued build decisions (#1758). This moves the cost; it does not remove
|
|
18
|
+
* it. Options and publications are cloned, while callbacks stay on the caller.
|
|
19
|
+
*
|
|
20
|
+
* Await a publication before the build reads its inputs. Moving that baseline
|
|
21
|
+
* past the build could absorb an intervening edit (#1728). Callback messages
|
|
22
|
+
* and completion replies share one FIFO channel, so whenIdle completes after
|
|
23
|
+
* the notifications its barrier observed have reached the launcher (#1756).
|
|
24
|
+
*
|
|
25
|
+
* @evidence contracts/common.md#principled-implementation A dedicated supported worker executes the unchanged topology algorithm on selected cloneable data while callbacks remain caller-owned; worker events and correlated replies settle actual operations, and one FIFO channel orders callbacks before completion.
|
|
26
|
+
* @evidence contracts/common.md#clear-and-simple-design The facade separates option capture, reply dispatch and worker lifetime; the synchronous core retains filesystem policy and watcher ownership.
|
|
27
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Existing native case observations, compiler membership and content proofs remain authoritative. The explicit worker factory supplies transport without replacing globals, and the default starts the actual packaged CommonJS entry without a synchronous barrier or metadata shortcut.
|
|
28
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains off-thread cost, baseline-before-build ordering, FIFO replies and lifetime failures; constructor prose identifies data capture, callback ownership and the optional factory.
|
|
29
|
+
* @evidence contracts/portability.md#os-neutral-implementation Native joins locate the packaged CommonJS entry, and the supported module bootstrap loads it through createRequire while retaining Node-owned inherited execution options and loader hooks. Structured cloning preserves maps and bigint device references; SidecarEnvironment merges native environment names before startup.
|
|
30
|
+
* @evidence contracts/performance.md#efficient-algorithms One thread serves the topology lifetime. Construction copies fixed option references before cloning, with costs for option/environment bytes and module initialization; each operation clones its publication bytes and adds one pending entry while the core retains native costs.
|
|
31
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Construction starts a fresh worker lifetime; that worker retains current registrations, listing premises and baselines across requests, but completion grants no reuse for another filesystem generation.
|
|
32
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources One referenced worker, listeners, exit promise and uncapped pending map belong to the facade; creation failure precedes ownership transfer. Replies prune entries and failure rejects all entries. Close joins worker exit after native subscription close; failed close terminates and joins the thread while retaining error. Requests have no implicit deadline.
|
|
33
|
+
*/
|
|
34
|
+
export class AsyncWatchTopology {
|
|
35
|
+
private readonly worker: Worker;
|
|
36
|
+
private readonly exited: Promise<void>;
|
|
37
|
+
private readonly pending = new Map<
|
|
38
|
+
number,
|
|
39
|
+
{ resolve(): void; reject(error: unknown): void }
|
|
40
|
+
>();
|
|
41
|
+
private sequence = 0;
|
|
42
|
+
private failure: unknown;
|
|
43
|
+
private failed = false;
|
|
44
|
+
private terminating = false;
|
|
45
|
+
private closing: Promise<void> | undefined;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Capture data options and start the worker; callbacks remain caller-owned.
|
|
49
|
+
* The optional factory observes worker transport without replacing globals.
|
|
50
|
+
*/
|
|
51
|
+
public constructor(
|
|
52
|
+
options: WatchTopologyWorkerProtocol.Options,
|
|
53
|
+
private readonly callbacks: WatchTopologyWorkerProtocol.Callbacks,
|
|
54
|
+
createWorker: (options: WatchTopologyWorkerProtocol.Options) => Worker = (
|
|
55
|
+
selected,
|
|
56
|
+
) =>
|
|
57
|
+
new Worker(
|
|
58
|
+
workerModuleUrl(
|
|
59
|
+
path.join(
|
|
60
|
+
__dirname,
|
|
61
|
+
`watchTopologyWorker${path.extname(__filename)}`,
|
|
62
|
+
),
|
|
63
|
+
),
|
|
64
|
+
{
|
|
65
|
+
env: SidecarEnvironment.merge(process.env, selected.env),
|
|
66
|
+
workerData: selected,
|
|
67
|
+
},
|
|
68
|
+
),
|
|
69
|
+
) {
|
|
70
|
+
// Callers also carry build callbacks. Select only the core's data options:
|
|
71
|
+
// sending the invocation wholesale would attempt to clone those functions.
|
|
72
|
+
const {
|
|
73
|
+
binary,
|
|
74
|
+
compilerArgsCwd,
|
|
75
|
+
compilerProjectSelections,
|
|
76
|
+
cwd,
|
|
77
|
+
emit,
|
|
78
|
+
env,
|
|
79
|
+
files,
|
|
80
|
+
outDir,
|
|
81
|
+
passthrough,
|
|
82
|
+
pinCompilerProject,
|
|
83
|
+
projectRoot,
|
|
84
|
+
tsconfig,
|
|
85
|
+
} = options;
|
|
86
|
+
this.worker = createWorker({
|
|
87
|
+
binary,
|
|
88
|
+
compilerArgsCwd,
|
|
89
|
+
compilerProjectSelections,
|
|
90
|
+
cwd,
|
|
91
|
+
emit,
|
|
92
|
+
env,
|
|
93
|
+
files,
|
|
94
|
+
outDir,
|
|
95
|
+
passthrough,
|
|
96
|
+
pinCompilerProject,
|
|
97
|
+
projectRoot,
|
|
98
|
+
tsconfig,
|
|
99
|
+
});
|
|
100
|
+
this.worker.on("message", (reply: WatchTopologyWorkerProtocol.Reply) => {
|
|
101
|
+
if ("id" in reply) {
|
|
102
|
+
const waiting = this.pending.get(reply.id);
|
|
103
|
+
if (waiting === undefined) return;
|
|
104
|
+
this.pending.delete(reply.id);
|
|
105
|
+
if (reply.ok) waiting.resolve();
|
|
106
|
+
else waiting.reject(reply.error);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
switch (reply.event) {
|
|
110
|
+
case "input":
|
|
111
|
+
this.callbacks.onInputChange(reply.change);
|
|
112
|
+
break;
|
|
113
|
+
case "topology":
|
|
114
|
+
this.callbacks.onTopologyChange();
|
|
115
|
+
break;
|
|
116
|
+
case "error":
|
|
117
|
+
this.callbacks.onError(reply.location, reply.error);
|
|
118
|
+
break;
|
|
119
|
+
case "roots":
|
|
120
|
+
this.callbacks.onProjectInputWatchRoots?.(reply.roots);
|
|
121
|
+
break;
|
|
122
|
+
case "unavailable":
|
|
123
|
+
this.callbacks.onProjectInputWatchUnavailable?.(reply.roots);
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
this.worker.on("error", (error) => this.fail(error));
|
|
128
|
+
this.exited = new Promise<void>((resolve) => {
|
|
129
|
+
this.worker.once("exit", (code) => {
|
|
130
|
+
if (
|
|
131
|
+
this.closing === undefined ||
|
|
132
|
+
this.pending.size !== 0 ||
|
|
133
|
+
(code !== 0 && !this.terminating)
|
|
134
|
+
)
|
|
135
|
+
this.fail(
|
|
136
|
+
new Error(`ttsc: watch topology worker exited with code ${code}`),
|
|
137
|
+
);
|
|
138
|
+
resolve();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Reconcile actual compiler membership and wait for its publication.
|
|
145
|
+
*
|
|
146
|
+
* @evidence contracts/common.md#principled-implementation The worker executes the core's actual refresh before replying, so completion does not stand for a predicted membership.
|
|
147
|
+
* @evidence contracts/common.md#clear-and-simple-design This operation frames one refresh and delegates transport correlation to request.
|
|
148
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Membership still comes from the core's native compiler-input reader.
|
|
149
|
+
* @evidence contracts/common.md#meaningful-documentation Prose states the membership and publication boundary.
|
|
150
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The method frames a boolean; the worker and core own native execution.
|
|
151
|
+
* @evidence contracts/performance.md#efficient-algorithms Fixed-size framing adds one pending entry; the core retains listing, traversal and hashing costs off-thread.
|
|
152
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Every requested refresh executes; listing reuse remains the core's decision.
|
|
153
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Correlation remains live until reply or worker failure; no deadline is imposed.
|
|
154
|
+
*/
|
|
155
|
+
public refresh(notify: boolean): Promise<void> {
|
|
156
|
+
return this.request({ method: "refresh", notify });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Capture plugin baselines before the caller starts reading or building.
|
|
161
|
+
*
|
|
162
|
+
* @evidence contracts/common.md#principled-implementation Awaited completion follows the core's baseline capture and preserves the supplied record store's separability references through structured cloning.
|
|
163
|
+
* @evidence contracts/common.md#clear-and-simple-design One publication carries inputs and their existing proof store together.
|
|
164
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The actual content identity owner still judges every record; transport invents no digest or metadata equivalence.
|
|
165
|
+
* @evidence contracts/common.md#meaningful-documentation Prose states the required pre-build ordering.
|
|
166
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Paths and bigint maps are cloned as data; the core owns native interpretation.
|
|
167
|
+
* @evidence contracts/performance.md#efficient-algorithms Framing is fixed structural work and cloning visits input paths and record references; digest and registration work stays with the core.
|
|
168
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each publication reaches the core, which owns baseline and listing reuse premises.
|
|
169
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Publication data and one pending correlation remain live through completion or worker failure without a size or deadline cap.
|
|
170
|
+
*/
|
|
171
|
+
public setExtraInputs(
|
|
172
|
+
inputs: readonly string[],
|
|
173
|
+
identities?: PluginContentIdentities.Store,
|
|
174
|
+
): Promise<void> {
|
|
175
|
+
return this.request({ method: "setExtraInputs", inputs, identities });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Capture rule-input baselines before the caller consumes those inputs.
|
|
180
|
+
*
|
|
181
|
+
* @evidence contracts/common.md#principled-implementation Completion follows actual declaration normalization, population capture and subscription reconciliation in the core.
|
|
182
|
+
* @evidence contracts/common.md#clear-and-simple-design One operation carries the complete declared snapshot without splitting population and baseline ownership.
|
|
183
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The core retains missing-path, alias and empty-population semantics; transport filters no inputs.
|
|
184
|
+
* @evidence contracts/common.md#meaningful-documentation Prose states capture timing relative to consumption.
|
|
185
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The snapshot crosses as data; the core owns filesystem identity and case policy.
|
|
186
|
+
* @evidence contracts/performance.md#efficient-algorithms Cloning visits the snapshot's path text; matching, fingerprinting and registrations keep their owning core costs.
|
|
187
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work The core decides whether a publication is equivalent; transport reuses no earlier result.
|
|
188
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Snapshot bytes and one pending correlation remain live until reply or worker failure without a population cap.
|
|
189
|
+
*/
|
|
190
|
+
public setProjectInputs(inputs: ITtscProjectInputSnapshot): Promise<void> {
|
|
191
|
+
return this.request({ method: "setProjectInputs", inputs });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Wait for delivered topology work and its preceding callback messages.
|
|
196
|
+
*
|
|
197
|
+
* @evidence contracts/common.md#principled-implementation The worker's core barrier observes its scheduled owners, and callbacks sent before the completion reply arrive first on the same FIFO channel.
|
|
198
|
+
* @evidence contracts/common.md#clear-and-simple-design One request exposes the core's complete queue ownership instead of duplicating queue flags here.
|
|
199
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Actual queue completion replaces elapsed quiet-time estimates.
|
|
200
|
+
* @evidence contracts/common.md#meaningful-documentation Prose identifies delivered work and callback ordering.
|
|
201
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The operation uses portable MessagePort ordering without a native path or process call.
|
|
202
|
+
* @evidence contracts/performance.md#efficient-algorithms Fixed-size framing adds one correlation; the core checks flags per yielded turn and still pays its pending operations' costs.
|
|
203
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each barrier observes current pending work rather than a previous receipt.
|
|
204
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources One request remains live until idle, close or failure; continuous new work can keep it pending without an implicit deadline.
|
|
205
|
+
*/
|
|
206
|
+
public whenIdle(): Promise<void> {
|
|
207
|
+
return this.request({ method: "whenIdle" });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Close subscriptions and join the thread. Repeated calls share retirement;
|
|
212
|
+
* close or worker failures remain rejection even after thread termination.
|
|
213
|
+
*
|
|
214
|
+
* @evidence contracts/common.md#principled-implementation Successful close follows core subscription release, outstanding barrier answers and actual worker exit; failed close terminates and joins the thread while preserving rejection.
|
|
215
|
+
* @evidence contracts/common.md#clear-and-simple-design One retained promise owns idempotent shutdown and finishClose owns its two retirement paths.
|
|
216
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Shutdown joins actual thread exit rather than treating a posted close as completion.
|
|
217
|
+
* @evidence contracts/common.md#meaningful-documentation Prose states joined completion, repeated-call sharing and failure retention.
|
|
218
|
+
* @evidence contracts/portability.md#os-neutral-implementation Node's supported worker exit and termination APIs own thread retirement; the core owns backend subscription closure.
|
|
219
|
+
* @evidence contracts/performance.md#efficient-algorithms One close message and shared promise add fixed structural work; subscription traversal, outstanding replies and thread retirement retain delegated costs.
|
|
220
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Every repeated close shares this lifetime's single retirement result, including rejection.
|
|
221
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Closure rejects new requests and joins the worker; pending requests settle by replies or terminal failure. Native FSEvents stop errors are suppressed by its existing backend, so thread joining alone cannot certify that optional binding's physical cleanup.
|
|
222
|
+
*/
|
|
223
|
+
public close(): Promise<void> {
|
|
224
|
+
this.closing ??= this.finishClose();
|
|
225
|
+
return this.closing;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private async finishClose(): Promise<void> {
|
|
229
|
+
try {
|
|
230
|
+
await this.request({ method: "close" });
|
|
231
|
+
} catch (error) {
|
|
232
|
+
this.terminating = true;
|
|
233
|
+
await this.worker.terminate();
|
|
234
|
+
await this.exited;
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
await this.exited;
|
|
238
|
+
if (this.failed) throw this.failure;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private request(
|
|
242
|
+
operation: WatchTopologyWorkerProtocol.Operation,
|
|
243
|
+
): Promise<void> {
|
|
244
|
+
if (this.failed) return Promise.reject(this.failure);
|
|
245
|
+
if (this.closing !== undefined)
|
|
246
|
+
return Promise.reject(new Error("ttsc: watch topology is closing"));
|
|
247
|
+
const id = ++this.sequence;
|
|
248
|
+
return new Promise<void>((resolve, reject) => {
|
|
249
|
+
this.pending.set(id, { reject, resolve });
|
|
250
|
+
try {
|
|
251
|
+
this.worker.postMessage({ ...operation, id });
|
|
252
|
+
} catch (error) {
|
|
253
|
+
this.pending.delete(id);
|
|
254
|
+
reject(error);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private fail(error: unknown): void {
|
|
260
|
+
if (this.failed) return;
|
|
261
|
+
this.failed = true;
|
|
262
|
+
this.failure = error;
|
|
263
|
+
for (const waiting of this.pending.values()) waiting.reject(error);
|
|
264
|
+
this.pending.clear();
|
|
265
|
+
this.callbacks.onFailure(error);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waits for an owner's idle observation without losing changes during that
|
|
3
|
+
* observation. The owner announces every scheduling and terminal transition.
|
|
4
|
+
*
|
|
5
|
+
* Elapsed silence cannot certify idle: a queued build or an asynchronous input
|
|
6
|
+
* decision can remain silent until it starts. A changed revision therefore
|
|
7
|
+
* requires another observation, even when the earlier one reported idle.
|
|
8
|
+
*
|
|
9
|
+
* @evidence contracts/common.md#principled-implementation A monotonic revision detects transitions across an asynchronous idle query; wait registration and the final revision comparison share one JavaScript turn, preventing a lost wake.
|
|
10
|
+
* @evidence contracts/common.md#clear-and-simple-design The owner supplies its actual idle predicate and announces state changes; this class owns only revision validation and waiting callbacks.
|
|
11
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts No timeout, retry limit, process hook or consumer-specific decision substitutes for the owner's state.
|
|
12
|
+
* @evidence contracts/common.md#meaningful-documentation Prose defines idle-query ownership and why silent queued work and intervening changes require a fresh observation; methods describe notification and failure effects.
|
|
13
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Revisions and promises have no native path, filesystem or process boundary.
|
|
14
|
+
* @evidence contracts/performance.md#efficient-algorithms Each transition visits current waiters once; each observation is constant bookkeeping plus the supplied owner's work, without polling.
|
|
15
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each wait observes mutable owner state independently; no computed result is cached across transitions.
|
|
16
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources A non-idle wait registers one callback until the next transition; an in-flight idle query or publication retains its call closure until settlement. Errors reject directly. The owner must announce terminal transitions so registered callbacks can recheck and reject. Concurrent caller population has no fixed cap.
|
|
17
|
+
*/
|
|
18
|
+
export class WatchSettlement {
|
|
19
|
+
private revision = 0;
|
|
20
|
+
private readonly waiters = new Set<() => void>();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Announces a scheduling or terminal transition and releases current waits.
|
|
24
|
+
*
|
|
25
|
+
* @evidence contracts/common.md#principled-implementation Advancing the revision invalidates queries already in flight, and releasing the current callback population permits each pending wait to query again.
|
|
26
|
+
* @evidence contracts/common.md#clear-and-simple-design One notification handles both ordinary scheduling and terminal transitions without interpreting the owner's state.
|
|
27
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Callbacks observe a real owner transition without polling or replacing owner operations.
|
|
28
|
+
* @evidence contracts/common.md#meaningful-documentation The prose states which transitions callers announce and that current waits are released.
|
|
29
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation This in-memory notification has no native boundary.
|
|
30
|
+
* @evidence contracts/performance.md#efficient-algorithms Copying and waking current callbacks costs linear time and temporary space in pending waits.
|
|
31
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This effectful transition does not compute a reusable result.
|
|
32
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Clearing the set releases its references before callbacks run; each resumed wait owns any later registration.
|
|
33
|
+
*/
|
|
34
|
+
public changed(): void {
|
|
35
|
+
++this.revision;
|
|
36
|
+
const waiters = [...this.waiters];
|
|
37
|
+
this.waiters.clear();
|
|
38
|
+
for (const wake of waiters) wake();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Publishes and resolves after an idle query spans no transition; errors
|
|
43
|
+
* reject. The owner must reject its query after shutdown and announce that
|
|
44
|
+
* shutdown. Publication starts in the same turn as the final revision check.
|
|
45
|
+
*
|
|
46
|
+
* @evidence contracts/common.md#principled-implementation The revision comparison validates the complete awaited observation; publication starts synchronously after that comparison, and a non-idle result registers its wake in the same turn, so neither path loses an intervening transition.
|
|
47
|
+
* @evidence contracts/common.md#clear-and-simple-design The loop retries only after a real transition and delegates all idle and terminal meaning to the supplied owner query.
|
|
48
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts No elapsed silence, deadline or fixed retry count stands for the owner's actual pending work.
|
|
49
|
+
* @evidence contracts/common.md#meaningful-documentation The prose describes successful observation, same-turn publication, error propagation and the terminal notification obligation.
|
|
50
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Awaiting an owner query imposes no native path or process policy.
|
|
51
|
+
* @evidence contracts/performance.md#efficient-algorithms Each query adds constant revision bookkeeping and at most one callback; query work belongs to the supplied owner, and no timer polls state.
|
|
52
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Queries observe mutable state and are not cached across transitions.
|
|
53
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources A non-idle observation retains one resolver until changed clears it; successful and failed queries retain no registered callback, while an in-flight query or publication retains this call until settlement. Terminal wake and rejection are the owner's obligation.
|
|
54
|
+
*/
|
|
55
|
+
public async wait(
|
|
56
|
+
idle: () => Promise<boolean>,
|
|
57
|
+
publish: () => void | Promise<void> = () => {},
|
|
58
|
+
): Promise<void> {
|
|
59
|
+
for (;;) {
|
|
60
|
+
const revision = this.revision;
|
|
61
|
+
const observed = await idle();
|
|
62
|
+
if (revision !== this.revision) continue;
|
|
63
|
+
if (observed) return await publish();
|
|
64
|
+
await new Promise<void>((resolve) => this.waiters.add(resolve));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -7,6 +7,7 @@ import { CompilerProjectSelection } from "../../../compiler/internal/project/Com
|
|
|
7
7
|
import { readJsoncFile } from "../../../compiler/internal/project/readJsoncFile";
|
|
8
8
|
import { readProjectConfig } from "../../../compiler/internal/project/readProjectConfig";
|
|
9
9
|
import { resolveTsgo } from "../../../compiler/internal/resolveTsgo";
|
|
10
|
+
import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
10
11
|
import { spawnNative } from "../../../compiler/internal/spawnNative";
|
|
11
12
|
import { normalizeCompilerEnumValue } from "../../../flags/normalizeCompilerEnumValue";
|
|
12
13
|
import { readCompilerOptionValues } from "../../../flags/readCompilerOptionValues";
|
|
@@ -64,7 +65,7 @@ import { watchDirectory } from "./watchDirectory";
|
|
|
64
65
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain membership authority, plugin fingerprinting, publication races, physical registration and public lifecycle operations following the documentation skill. Parameters identify each supplied operation and native default beside the constructor. Project-input attribution: Native paragraphs explain stale attention, directory causality, accompanying resolution digests and unselected immediate entries.
|
|
65
66
|
* @evidence contracts/portability.md#os-neutral-implementation Native paths use Node APIs and registration uses realpath; compiler/plugin maps preserve lexical aliases and fold only measured insensitive ASCII components. Project inputs use physical identities, while unknown/native Unicode relations remain conservative event candidates rather than identity proof. Registration paths and read options are passed unchanged; compiler-input readers supply absolute membership paths without replacing the topology's native identity policy. Project-input attribution: The supplied filesystem identity transaction establishes selected names and ancestry without an OS-wide case assumption or lexical alias guess.
|
|
66
67
|
*
|
|
67
|
-
* @evidence contracts/performance.md#efficient-algorithms Identity-keyed maps separate membership, baselines and handle registries; reconciliation delegates project/config discovery, native compiler listing, filesystem traversal/hashing and backend callbacks, with costs described by its members. Construction retains operation references and empty indexes without a filesystem observation or build. Attribution indexed visits additionally pay path/key text, ancestor and native identity work; shared ancestor keys avoid repeating the same walk within a transaction.
|
|
68
|
+
* @evidence contracts/performance.md#efficient-algorithms Identity-keyed maps separate membership, baselines and handle registries; reconciliation delegates project/config discovery, native compiler listing, filesystem traversal/hashing and backend callbacks, with costs described by its members. A directory-triggered refresh additionally visits R active reload files even on failure and compares their metadata/owner snapshots, reading bytes only when those snapshots changed. Changed-owner and notification arrays and a reported-key set require O(R) references; moved owners share one existing watcher synchronization and post-registration reconciliation, whose selected-file traversal remains part of the operation. No additional compiler listing is requested. Construction retains operation references and empty indexes without a filesystem observation or build. Attribution indexed visits additionally pay path/key text, ancestor and native identity work; shared ancestor keys avoid repeating the same walk within a transaction.
|
|
68
69
|
* @evidence contracts/performance.md#reuse-equivalent-work Current membership, content baselines and live registrations belong to one topology; reconciliation owners decide their reuse against fresh premises. Supplied operation identities are retained without assuming changed inputs remain equivalent. Each project's last compiler listing is kept with its arguments and answers only a plugin-input change, which cannot move Program membership; every other refresh lists again. Notifications delivered in one poll iteration are decided together in the check phase, so one change lists and rescans once. Project-input attribution: This classifier borrows one scan's deltas and identity transaction without retaining cross-event answers.
|
|
69
70
|
* @evidence contracts/performance.md#bound-retention-and-release-resources Current and pending maps and live subscriptions remain topology-owned without a population cap; compiler listings are replaced by each resolution and hold only its projects; reconciliation attempts obsolete handle retirement. Constructor acquires no handle; directory arrays and attribution deltas are call-local. close invokes supplied close methods but does not await backend closure, and a thrown close can interrupt later map cleanup; retained snapshots remain until the facade is released.
|
|
70
71
|
*/
|
|
@@ -216,6 +217,39 @@ export class WatchTopology {
|
|
|
216
217
|
this.refreshCompilerInputs(notify, false);
|
|
217
218
|
}
|
|
218
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Wait until delivered notifications and registration reconciliation finish.
|
|
222
|
+
*
|
|
223
|
+
* A completed build does not imply a quiet topology: its final refresh can
|
|
224
|
+
* queue another decision and another build (#1756). Yield through the check
|
|
225
|
+
* phase before inspecting every scheduled owner so a decision queued by
|
|
226
|
+
* another decision remains part of this barrier. Later filesystem changes
|
|
227
|
+
* belong to a later barrier; this does not freeze the filesystem.
|
|
228
|
+
*
|
|
229
|
+
* @evidence contracts/common.md#principled-implementation A check-phase observation follows delivered events, and every notification, recovery and registration queue must be empty before completion.
|
|
230
|
+
* @evidence contracts/common.md#clear-and-simple-design The topology owns the barrier because it alone owns all five scheduled queues.
|
|
231
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Queue state establishes completion without a quiet-time estimate or an invented filesystem snapshot.
|
|
232
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose distinguishes delivered work from later mutations and explains the post-build queued-decision race.
|
|
233
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The barrier observes owned JavaScript queues without a separate native operation.
|
|
234
|
+
* @evidence contracts/performance.md#efficient-algorithms Each check turn inspects five flags and two map sizes; notification processing retains its owning traversal and native-operation costs.
|
|
235
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call observes current work rather than reusing an earlier completion.
|
|
236
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources One immediate callback and promise remain live per waiting call; continuous new work can prevent completion and no deadline is imposed.
|
|
237
|
+
*/
|
|
238
|
+
public async whenIdle(): Promise<void> {
|
|
239
|
+
do {
|
|
240
|
+
await new Promise<void>((resolve) => setImmediate(resolve));
|
|
241
|
+
} while (
|
|
242
|
+
!this.closed &&
|
|
243
|
+
(this.notificationsScheduled ||
|
|
244
|
+
this.pluginNotificationsScheduled ||
|
|
245
|
+
this.compilerPostRegistrationReconciliationScheduled ||
|
|
246
|
+
this.projectInputRecoveryScheduled ||
|
|
247
|
+
this.projectInputPostRegistrationReconciliationScheduled ||
|
|
248
|
+
this.pendingNotifications.size !== 0 ||
|
|
249
|
+
this.pendingPluginNotifications.size !== 0)
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
219
253
|
/**
|
|
220
254
|
* @param reuseListings Answer each project's membership with its last listing
|
|
221
255
|
* under the same arguments instead of asking the compiler again. Only a
|
|
@@ -1711,6 +1745,15 @@ export class WatchTopology {
|
|
|
1711
1745
|
* Refresh compiler membership once for every directory a decision asked
|
|
1712
1746
|
* about. A failed refresh still reports, once each, the reload inputs every
|
|
1713
1747
|
* requested change names.
|
|
1748
|
+
*
|
|
1749
|
+
* A replacement can be delivered under only its vanished temporary name,
|
|
1750
|
+
* including when its malformed bytes prevent refresh. Reconcile active
|
|
1751
|
+
* reload-file snapshots on either outcome, deduplicate failed-refresh
|
|
1752
|
+
* recovery against actual reported movement, and preserve the original
|
|
1753
|
+
* refresh error after recovery. Batch moved owners through the existing rearm
|
|
1754
|
+
* operation before notifying, because a POSIX per-file handle still owns the
|
|
1755
|
+
* old inode. Unchanged snapshots stay quiet unless the existing
|
|
1756
|
+
* failed-refresh selector explicitly names or cannot find the reload input.
|
|
1714
1757
|
*/
|
|
1715
1758
|
private refreshFromDirectories(refreshes: readonly DirectoryRefresh[]): void {
|
|
1716
1759
|
for (const { changed } of refreshes) {
|
|
@@ -1723,23 +1766,50 @@ export class WatchTopology {
|
|
|
1723
1766
|
this.observedDirectories.set(this.pathKey(changed), changed);
|
|
1724
1767
|
}
|
|
1725
1768
|
}
|
|
1769
|
+
let refreshFailure: { error: unknown } | undefined;
|
|
1726
1770
|
try {
|
|
1727
1771
|
this.refresh(true);
|
|
1728
1772
|
} catch (error) {
|
|
1773
|
+
refreshFailure = { error };
|
|
1774
|
+
}
|
|
1775
|
+
try {
|
|
1776
|
+
if (this.closed) return;
|
|
1777
|
+
const changed: string[] = [];
|
|
1778
|
+
const rearm: string[] = [];
|
|
1729
1779
|
const reported = new Set<string>();
|
|
1730
|
-
for (const
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1780
|
+
for (const reload of this.reloadFiles.values()) {
|
|
1781
|
+
if (this.closed) return;
|
|
1782
|
+
const movement = this.compilerFileMovement(reload);
|
|
1783
|
+
if (movement.owner) rearm.push(reload);
|
|
1784
|
+
if (this.compilerMovementReports(reload, movement))
|
|
1785
|
+
changed.push(reload);
|
|
1786
|
+
}
|
|
1787
|
+
if (rearm.length !== 0) this.rearmFileWatchers(rearm, true);
|
|
1788
|
+
for (const reload of changed) {
|
|
1789
|
+
if (this.closed) return;
|
|
1790
|
+
reported.add(this.pathKey(reload));
|
|
1791
|
+
this.reportCompilerFileChange(reload);
|
|
1792
|
+
}
|
|
1793
|
+
if (refreshFailure !== undefined) {
|
|
1794
|
+
for (const { changed } of refreshes) {
|
|
1795
|
+
for (const reload of reloadInputsForFailedTopologyRefresh(
|
|
1796
|
+
this.reloadFiles.values(),
|
|
1797
|
+
changed,
|
|
1798
|
+
this.lexicalIdentities,
|
|
1799
|
+
)) {
|
|
1800
|
+
if (this.closed) return;
|
|
1801
|
+
const key = this.pathKey(reload);
|
|
1802
|
+
if (reported.has(key)) continue;
|
|
1803
|
+
reported.add(key);
|
|
1804
|
+
this.callbacks.onInputChange({ kind: "config", path: reload });
|
|
1805
|
+
}
|
|
1740
1806
|
}
|
|
1741
1807
|
}
|
|
1808
|
+
} catch (error) {
|
|
1742
1809
|
this.callbacks.onError(refreshes[0]!.location, error);
|
|
1810
|
+
} finally {
|
|
1811
|
+
if (refreshFailure !== undefined)
|
|
1812
|
+
this.callbacks.onError(refreshes[0]!.location, refreshFailure.error);
|
|
1743
1813
|
}
|
|
1744
1814
|
}
|
|
1745
1815
|
|
|
@@ -2203,10 +2273,11 @@ function listCompilerInputs(
|
|
|
2203
2273
|
project: ITtscParsedProjectConfig,
|
|
2204
2274
|
options: WatchTopologyOptions,
|
|
2205
2275
|
): string[] {
|
|
2276
|
+
const env = SidecarEnvironment.merge(process.env, options.env);
|
|
2206
2277
|
const tsgo = resolveTsgo({
|
|
2207
2278
|
binary: options.binary,
|
|
2208
2279
|
cwd: project.root,
|
|
2209
|
-
env
|
|
2280
|
+
env,
|
|
2210
2281
|
});
|
|
2211
2282
|
const result = spawnNative(
|
|
2212
2283
|
tsgo.binary,
|
|
@@ -2221,7 +2292,7 @@ function listCompilerInputs(
|
|
|
2221
2292
|
],
|
|
2222
2293
|
{
|
|
2223
2294
|
cwd: options.compilerArgsCwd ?? project.root,
|
|
2224
|
-
env
|
|
2295
|
+
env,
|
|
2225
2296
|
encoding: "utf8",
|
|
2226
2297
|
},
|
|
2227
2298
|
);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { PluginContentIdentities } from "../../../plugin/internal/source/PluginContentIdentities";
|
|
2
|
+
import type { ITtscProjectInputSnapshot } from "../../../structures/internal/ITtscProjectInputSnapshot";
|
|
3
|
+
import type { WatchInputChange } from "./WatchInputChange";
|
|
4
|
+
import type { WatchTopology } from "./WatchTopology";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cloned requests and ordered notifications of one watch topology worker.
|
|
8
|
+
*
|
|
9
|
+
* @evidence contracts/common.md#principled-implementation Discriminated messages preserve operation arguments and separate callbacks from request completion; bigint reference maps retain the record store's separability evidence through structured cloning.
|
|
10
|
+
* @evidence contracts/common.md#clear-and-simple-design One internal protocol serves the facade and its worker without transferring callback functions.
|
|
11
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Messages carry actual topology operations and observations rather than predicted decisions.
|
|
12
|
+
* @evidence contracts/common.md#meaningful-documentation Members identify correlation, callback ordering and the cloneable option boundary.
|
|
13
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The types describe structured messages; execution owns native paths and workers.
|
|
14
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms These types execute no algorithm.
|
|
15
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work The protocol grants no result reuse.
|
|
16
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The types acquire no resources; the facade owns in-flight messages.
|
|
17
|
+
*/
|
|
18
|
+
export namespace WatchTopologyWorkerProtocol {
|
|
19
|
+
/**
|
|
20
|
+
* Only the core's selected data options cross the worker boundary.
|
|
21
|
+
*
|
|
22
|
+
* @evidence contracts/common.md#principled-implementation Deriving the data type from the core constructor keeps option meaning with its owner.
|
|
23
|
+
* @evidence contracts/common.md#clear-and-simple-design One alias serves both ends of the worker's startup payload.
|
|
24
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The facade explicitly selects these fields without transferring invocation callbacks.
|
|
25
|
+
* @evidence contracts/common.md#meaningful-documentation Prose identifies the cloneable startup boundary.
|
|
26
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation This alias executes no native operation.
|
|
27
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms The alias chooses no algorithm.
|
|
28
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work The type grants no reuse.
|
|
29
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The type acquires no resource; the facade owns startup cloning.
|
|
30
|
+
*/
|
|
31
|
+
export type Options = ConstructorParameters<typeof WatchTopology>[0];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Callback implementations remain on the launcher thread.
|
|
35
|
+
*
|
|
36
|
+
* @evidence contracts/common.md#principled-implementation Core callbacks retain their meanings; actual worker error or unexpected exit invokes separate terminal notification because authority was lost, requiring the launcher to retire its session.
|
|
37
|
+
* @evidence contracts/common.md#clear-and-simple-design One structural intersection adds a dedicated terminal callback beside recoverable subscription events.
|
|
38
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Callbacks report actual observations and authority loss without continuing to claim coverage after thread death.
|
|
39
|
+
* @evidence contracts/common.md#meaningful-documentation Prose identifies launcher-thread callbacks and the receiving owner's required retirement after terminal loss.
|
|
40
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation These signatures perform no native operation.
|
|
41
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms Callback signatures choose no algorithm.
|
|
42
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Callback declarations grant no event reuse; terminal failure belongs to one lifecycle.
|
|
43
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Signatures acquire no resources; callback implementations own session retention and cleanup.
|
|
44
|
+
*/
|
|
45
|
+
export type Callbacks = ConstructorParameters<typeof WatchTopology>[1] & {
|
|
46
|
+
/** Terminal thread loss requires the launcher to retire its watch session. */
|
|
47
|
+
onFailure(error: unknown): void;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* An operation carries only the arguments its core member consumes.
|
|
52
|
+
*
|
|
53
|
+
* @evidence contracts/common.md#principled-implementation Discriminated method names pair each actual operation with its required payload.
|
|
54
|
+
* @evidence contracts/common.md#clear-and-simple-design One union describes the core's five transport operations.
|
|
55
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Publications retain complete input snapshots and source proof stores without filtering.
|
|
56
|
+
* @evidence contracts/common.md#meaningful-documentation Prose identifies argument ownership and discriminated payloads.
|
|
57
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The union executes no native operation.
|
|
58
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms The type chooses no algorithm.
|
|
59
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work The payload grants no result reuse.
|
|
60
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Transport and core owners retain cloned payloads rather than this type.
|
|
61
|
+
*/
|
|
62
|
+
export type Operation =
|
|
63
|
+
| { method: "refresh"; notify: boolean }
|
|
64
|
+
| {
|
|
65
|
+
method: "setExtraInputs";
|
|
66
|
+
inputs: readonly string[];
|
|
67
|
+
identities?: PluginContentIdentities.Store;
|
|
68
|
+
}
|
|
69
|
+
| { method: "setProjectInputs"; inputs: ITtscProjectInputSnapshot }
|
|
70
|
+
| { method: "whenIdle" }
|
|
71
|
+
| { method: "close" };
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Each operation receives its own correlated completion or failure.
|
|
75
|
+
*
|
|
76
|
+
* @evidence contracts/common.md#principled-implementation A per-facade monotonic id distinguishes concurrent pending operations.
|
|
77
|
+
* @evidence contracts/common.md#clear-and-simple-design Correlation is one field intersected with the operation union.
|
|
78
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts An id identifies the actual request rather than an assumed ordered result.
|
|
79
|
+
* @evidence contracts/common.md#meaningful-documentation Prose states correlation and terminal outcomes.
|
|
80
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The representation performs no native operation.
|
|
81
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms This type runs no algorithm.
|
|
82
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Request identity grants no reuse.
|
|
83
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The facade owns pending correlation entries.
|
|
84
|
+
*/
|
|
85
|
+
export type Request = { id: number } & Operation;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Callbacks and answers use one FIFO port, preserving their causal order.
|
|
89
|
+
*
|
|
90
|
+
* @evidence contracts/common.md#principled-implementation Event tags distinguish callbacks from correlated success or failure, and one MessagePort orders callback transmission before operation completion.
|
|
91
|
+
* @evidence contracts/common.md#clear-and-simple-design One union carries observed changes, coverage reports, recoverable errors and request outcomes.
|
|
92
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Failures retain serialized causes and actual observed input paths; no expected response replaces them.
|
|
93
|
+
* @evidence contracts/common.md#meaningful-documentation Prose states causal FIFO ordering.
|
|
94
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The union describes portable message data without a native operation.
|
|
95
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms The type chooses no algorithm.
|
|
96
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each message belongs to its actual event or operation.
|
|
97
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Message and correlation retention belongs to worker and facade implementations.
|
|
98
|
+
*/
|
|
99
|
+
export type Reply =
|
|
100
|
+
| { id: number; ok: true }
|
|
101
|
+
| { id: number; ok: false; error: unknown }
|
|
102
|
+
| { event: "input"; change: WatchInputChange }
|
|
103
|
+
| { event: "topology" }
|
|
104
|
+
| { event: "error"; location: string; error: unknown }
|
|
105
|
+
| { event: "roots" | "unavailable"; roots: readonly string[] };
|
|
106
|
+
}
|