ttsc 0.31.1 → 0.31.3
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/compiler/internal/build/BuildExecution.d.ts +6 -3
- package/lib/compiler/internal/build/BuildExecution.js +40 -12
- package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
- package/lib/compiler/internal/build/RunBuildOptions.d.ts +2 -1
- package/lib/compiler/internal/startResidentTransform.js +5 -4
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +9 -7
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/internal/javascriptRuntimeCapabilities.d.ts +13 -4
- package/lib/internal/javascriptRuntimeCapabilities.js +56 -6
- package/lib/internal/javascriptRuntimeCapabilities.js.map +1 -1
- package/lib/internal/pluginSource.d.ts +1 -0
- package/lib/internal/pluginSource.js +1 -0
- package/lib/internal/pluginSource.js.map +1 -1
- package/lib/internal/resolveNodeBinary.d.ts +6 -1
- package/lib/internal/resolveNodeBinary.js +6 -2
- package/lib/internal/resolveNodeBinary.js.map +1 -1
- package/lib/internal/runtimeExecutableIdentity.d.ts +22 -13
- package/lib/internal/runtimeExecutableIdentity.js +192 -102
- package/lib/internal/runtimeExecutableIdentity.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +2 -2
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +58 -4
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.d.ts +5 -1
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js +7 -2
- package/lib/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.js.map +1 -1
- package/lib/launcher/internal/ttscserver/runTtscserver.js +8 -1
- package/lib/launcher/internal/ttscserver/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/watch/WatchTopology.d.ts +20 -3
- package/lib/launcher/internal/watch/WatchTopology.js +31 -9
- package/lib/launcher/internal/watch/WatchTopology.js.map +1 -1
- package/lib/plugin/internal/CapabilityResolutionFormat.d.ts +21 -62
- package/lib/plugin/internal/CapabilityResolutionFormat.js +15 -106
- package/lib/plugin/internal/CapabilityResolutionFormat.js.map +1 -1
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.d.ts +6 -0
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js +4 -4
- package/lib/plugin/internal/load/PluginDescriptorEvaluationCache.js.map +1 -1
- package/lib/plugin/internal/load/loadProjectPlugins.d.ts +17 -3
- package/lib/plugin/internal/load/loadProjectPlugins.js +86 -23
- package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
- package/lib/plugin/internal/readCapabilityResolution.d.ts +6 -0
- package/lib/plugin/internal/readCapabilityResolution.js +8 -5
- package/lib/plugin/internal/readCapabilityResolution.js.map +1 -1
- package/lib/plugin/internal/source/GoEnvironmentReading.d.ts +9 -3
- package/lib/plugin/internal/source/GoEnvironmentReading.js +53 -7
- package/lib/plugin/internal/source/GoEnvironmentReading.js.map +1 -1
- package/lib/plugin/internal/source/NativeSourcePackages.d.ts +44 -6
- package/lib/plugin/internal/source/NativeSourcePackages.js +150 -8
- package/lib/plugin/internal/source/NativeSourcePackages.js.map +1 -1
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.d.ts +21 -3
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js +32 -7
- package/lib/plugin/internal/source/PluginBuildEnvironmentReadings.js.map +1 -1
- package/lib/plugin/internal/source/PluginContentIdentities.d.ts +265 -0
- package/lib/plugin/internal/source/PluginContentIdentities.js +452 -0
- package/lib/plugin/internal/source/PluginContentIdentities.js.map +1 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.d.ts +63 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.js +128 -0
- package/lib/plugin/internal/source/PluginLoadAnswers.js.map +1 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.d.ts +10 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js +12 -0
- package/lib/plugin/internal/source/SourceBuildCacheLayout.js.map +1 -1
- package/lib/plugin/internal/source/SourcePluginWorkspace.d.ts +13 -2
- package/lib/plugin/internal/source/SourcePluginWorkspace.js +140 -4
- package/lib/plugin/internal/source/SourcePluginWorkspace.js.map +1 -1
- package/lib/plugin/internal/source/buildSourcePlugin.d.ts +15 -2
- package/lib/plugin/internal/source/buildSourcePlugin.js +27 -4
- package/lib/plugin/internal/source/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/source/computeCacheKey.d.ts +21 -5
- package/lib/plugin/internal/source/computeCacheKey.js +71 -29
- package/lib/plugin/internal/source/computeCacheKey.js.map +1 -1
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.d.ts +7 -3
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.js +74 -35
- package/lib/plugin/internal/source/hashPluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildEnvironment.d.ts +8 -3
- package/lib/plugin/internal/source/pluginBuildEnvironment.js +8 -4
- package/lib/plugin/internal/source/pluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js +12 -2
- package/lib/plugin/internal/source/pluginBuildEnvironmentWorker.js.map +1 -1
- package/lib/plugin/internal/source/pluginBuildVersions.d.ts +2 -2
- package/lib/plugin/internal/source/pluginBuildVersions.js +4 -17
- package/lib/plugin/internal/source/pluginBuildVersions.js.map +1 -1
- package/lib/plugin/internal/source/pluginSourceState.d.ts +6 -2
- package/lib/plugin/internal/source/pluginSourceState.js +20 -8
- package/lib/plugin/internal/source/pluginSourceState.js.map +1 -1
- package/lib/plugin/internal/source/pluginSourceStateHolds.d.ts +7 -2
- package/lib/plugin/internal/source/pluginSourceStateHolds.js +12 -7
- package/lib/plugin/internal/source/pluginSourceStateHolds.js.map +1 -1
- package/lib/plugin/internal/source/processPluginBuildEnvironment.d.ts +7 -2
- package/lib/plugin/internal/source/processPluginBuildEnvironment.js +8 -3
- package/lib/plugin/internal/source/processPluginBuildEnvironment.js.map +1 -1
- package/lib/plugin/internal/source/provenPluginSourceDigest.d.ts +28 -0
- package/lib/plugin/internal/source/provenPluginSourceDigest.js +41 -0
- package/lib/plugin/internal/source/provenPluginSourceDigest.js.map +1 -0
- package/lib/plugin/internal/source/pruneCacheFileRoot.d.ts +3 -2
- package/lib/plugin/internal/source/pruneCacheFileRoot.js +3 -2
- package/lib/plugin/internal/source/pruneCacheFileRoot.js.map +1 -1
- package/lib/plugin/internal/source/ttscPackageVersion.d.ts +26 -0
- package/lib/plugin/internal/source/ttscPackageVersion.js +47 -0
- package/lib/plugin/internal/source/ttscPackageVersion.js.map +1 -0
- package/lib/plugin/internal/writeCapabilityResolution.d.ts +6 -0
- package/lib/plugin/internal/writeCapabilityResolution.js +11 -7
- package/lib/plugin/internal/writeCapabilityResolution.js.map +1 -1
- package/lib/plugin/resolveCapabilityPlugins.js +67 -15
- package/lib/plugin/resolveCapabilityPlugins.js.map +1 -1
- package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +5 -1
- package/package.json +8 -8
- package/src/compiler/internal/build/BuildExecution.ts +48 -14
- package/src/compiler/internal/build/RunBuildOptions.ts +2 -1
- package/src/compiler/internal/startResidentTransform.ts +12 -3
- package/src/compiler/internal/transformProjectInMemory.ts +10 -2
- package/src/internal/javascriptRuntimeCapabilities.ts +71 -5
- package/src/internal/pluginSource.ts +1 -0
- package/src/internal/resolveNodeBinary.ts +12 -1
- package/src/internal/runtimeExecutableIdentity.ts +227 -141
- package/src/launcher/internal/runTtsc.ts +6 -2
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +68 -3
- package/src/launcher/internal/ttscserver/captureLSPPluginSelectionInputs.ts +11 -2
- package/src/launcher/internal/ttscserver/runTtscserver.ts +18 -1
- package/src/launcher/internal/watch/WatchTopology.ts +38 -9
- package/src/plugin/internal/CapabilityResolutionFormat.ts +23 -107
- package/src/plugin/internal/load/PluginDescriptorEvaluationCache.ts +14 -4
- package/src/plugin/internal/load/loadProjectPlugins.ts +226 -98
- package/src/plugin/internal/readCapabilityResolution.ts +17 -6
- package/src/plugin/internal/source/GoEnvironmentReading.ts +74 -5
- package/src/plugin/internal/source/NativeSourcePackages.ts +262 -5
- package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +41 -5
- package/src/plugin/internal/source/PluginContentIdentities.ts +563 -0
- package/src/plugin/internal/source/PluginLoadAnswers.ts +151 -0
- package/src/plugin/internal/source/SourceBuildCacheLayout.ts +14 -0
- package/src/plugin/internal/source/SourcePluginWorkspace.ts +176 -2
- package/src/plugin/internal/source/buildSourcePlugin.ts +43 -3
- package/src/plugin/internal/source/computeCacheKey.ts +103 -47
- package/src/plugin/internal/source/hashPluginBuildEnvironment.ts +144 -29
- package/src/plugin/internal/source/pluginBuildEnvironment.ts +9 -2
- package/src/plugin/internal/source/pluginBuildEnvironmentWorker.ts +18 -2
- package/src/plugin/internal/source/pluginBuildVersions.ts +5 -26
- package/src/plugin/internal/source/pluginSourceState.ts +28 -12
- package/src/plugin/internal/source/pluginSourceStateHolds.ts +15 -8
- package/src/plugin/internal/source/processPluginBuildEnvironment.ts +8 -2
- package/src/plugin/internal/source/provenPluginSourceDigest.ts +45 -0
- package/src/plugin/internal/source/pruneCacheFileRoot.ts +3 -2
- package/src/plugin/internal/source/ttscPackageVersion.ts +45 -0
- package/src/plugin/internal/writeCapabilityResolution.ts +29 -8
- package/src/plugin/resolveCapabilityPlugins.ts +87 -13
- package/src/structures/internal/TtscSingleFileEmitOptions.ts +8 -1
|
@@ -22,9 +22,12 @@ import type { ITtscParsedProjectConfig } from "../../../structures/internal/ITts
|
|
|
22
22
|
import { pluginDescriptorFailureReason } from "../pluginDescriptorFailureReason";
|
|
23
23
|
import { pluginDescriptorProcessFailure } from "../pluginDescriptorProcessFailure";
|
|
24
24
|
import { NativeSourcePackages } from "../source/NativeSourcePackages";
|
|
25
|
+
import type { PluginBuildEnvironmentWitness } from "../source/PluginBuildEnvironmentWitness";
|
|
26
|
+
import { PluginContentIdentities } from "../source/PluginContentIdentities";
|
|
25
27
|
import { SourcePluginWorkspace } from "../source/SourcePluginWorkspace";
|
|
26
28
|
import { buildSourcePlugin } from "../source/buildSourcePlugin";
|
|
27
29
|
import { isPathWithin } from "../source/isPathWithin";
|
|
30
|
+
import { pluginBuildEnvironment } from "../source/pluginBuildEnvironment";
|
|
28
31
|
import { pluginBuildVersions } from "../source/pluginBuildVersions";
|
|
29
32
|
import { pluginModuleReplaceDirectories } from "../source/pluginModuleReplaceDirectories";
|
|
30
33
|
import { pluginSourceState } from "../source/pluginSourceState";
|
|
@@ -99,7 +102,7 @@ import { visitImportMappedCandidates } from "./visitImportMappedCandidates";
|
|
|
99
102
|
* @evidence contracts/common.md#meaningful-documentation Native JSDoc explains result provenance, environment and path options; helper comments explain input races, conservative proof omission, fallback authority and cleanup. Member/tag spacing and separated concepts follow the documentation skill.
|
|
100
103
|
* @evidence contracts/portability.md#os-neutral-implementation Native path/file-URL conversion, createRequire and hidden spawn with explicit argv/environment implement OS-neutral selection and process execution. Physical identities are preserved separately from lexical candidates; Bun-specific differences are capability decisions, not OS guesses.
|
|
101
104
|
* @evidence contracts/performance.md#efficient-algorithms Input merging and conflicts use Sets/maps and sorted path populations, with path/key/value byte costs. Discovery can repeat config/manifest/candidate reads and full hashes; descriptor work includes runtime probes, full observation/JSON processing and possibly synchronous evaluation. Watch-only preliminary publication can temporarily digest/watch the full admitted module as well as its package before kind is known; callbacks delegate topology reconciliation. Load-local replacement readings serve preliminary and final publication. Package selection groups equivalent module contexts and batches entries through Go list without dependency compilation; per-load selected-tool manifest readers share overlay readings. Builds delegate source/environment hashing, copying, cold materialized ownership admission and Go execution; per-load digest maps share selected work. Composition can be quadratic in configured plugins/aliases, and native lookup/file/output bytes are not bounded by plugin count alone.
|
|
102
|
-
* @evidence contracts/performance.md#reuse-equivalent-work Descriptor hits require the cache's context/environment/runtime/version identity and matching recorded projections, subject to producer declarations and sequential-observation limits. Per-load source/environment maps share directory-keyed digests and one selected transform host serves linked contributors;
|
|
105
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Descriptor hits require the cache's context/environment/runtime/version identity and matching recorded projections, subject to producer declarations and sequential-observation limits. Per-load source/environment maps share directory-keyed digests between package selection and builds, and one selected transform host serves linked contributors. Across processes, the record store opened here proves unchanged sources, toolchain and runtime from separable metadata and answers equal package selections and runtime probes (#1721, #1722, #1723); a store whose root lies inside a plugin source is withdrawn before any source is proven. These identities do not certify every undeclared read or atomic filesystem stability.
|
|
103
106
|
* @evidence contracts/performance.md#bound-retention-and-release-resources Finally restores injected environment locators, attempts evaluator directory removal and closes direct-evaluator diagnostic descriptors. Close/removal can fail; synchronous completion concerns the selected evaluator and does not certify arbitrary descendants are gone. Generation maps/results scale with observed data, and disk diagnostics/result/observation files have no independent byte ceiling here. Default disk pruning has its own interval/protection/failure policy; explicit roots remain caller-owned.
|
|
104
107
|
*/
|
|
105
108
|
export function loadProjectPlugins(options: {
|
|
@@ -121,8 +124,20 @@ export function loadProjectPlugins(options: {
|
|
|
121
124
|
/** Explicit project config, resolved from cwd. */
|
|
122
125
|
file?: string;
|
|
123
126
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
127
|
+
/**
|
|
128
|
+
* Record store the caller already opened for this invocation, so its later
|
|
129
|
+
* native spawns share it; the loader opens its own when omitted.
|
|
130
|
+
*/
|
|
131
|
+
identities?: PluginContentIdentities.Store;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Observe plugin build roots before building, including failed builds, with
|
|
135
|
+
* the record store that proves their states (#1728).
|
|
136
|
+
*/
|
|
137
|
+
onWatchInputs?: (
|
|
138
|
+
inputs: readonly string[],
|
|
139
|
+
identities?: PluginContentIdentities.Store,
|
|
140
|
+
) => void;
|
|
126
141
|
|
|
127
142
|
/** Caller-selected anchor for plugin-owned configuration discovery. */
|
|
128
143
|
pluginConfigDir?: string;
|
|
@@ -168,6 +183,12 @@ export function loadProjectPlugins(options: {
|
|
|
168
183
|
*/
|
|
169
184
|
observationsComplete?: false;
|
|
170
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Record store this load proved its inputs through, for the invocation's
|
|
188
|
+
* later native spawns (#1723); absent when the project loads no plugin.
|
|
189
|
+
*/
|
|
190
|
+
identities?: PluginContentIdentities.Store;
|
|
191
|
+
|
|
171
192
|
/** Check-stage entries followed by transform-stage entries in stable order. */
|
|
172
193
|
nativePlugins: ITtscLoadedNativePlugin[];
|
|
173
194
|
|
|
@@ -234,91 +255,111 @@ export function loadProjectPlugins(options: {
|
|
|
234
255
|
};
|
|
235
256
|
// Where isolated descriptor evaluations keep their answers across launches
|
|
236
257
|
// (`PluginDescriptorEvaluationCache`).
|
|
258
|
+
// WARNING (#1721, #1722, #1723): a warm load must prove its unchanged inputs
|
|
259
|
+
// from this store, not re-read them. Every launch is a new process, so any
|
|
260
|
+
// module-level memo of this load's work dies with it; a 27 s warm typia
|
|
261
|
+
// launch whose native build took 0.28 s is what that looked like.
|
|
262
|
+
const identities =
|
|
263
|
+
options.identities ??
|
|
264
|
+
PluginContentIdentities.open({
|
|
265
|
+
projectRoot: project.root,
|
|
266
|
+
cacheDir: options.cacheDir,
|
|
267
|
+
env: effectiveEnv,
|
|
268
|
+
});
|
|
237
269
|
const descriptorCache: DescriptorCacheOptions = {
|
|
238
270
|
cacheDir: options.cacheDir,
|
|
271
|
+
identities,
|
|
239
272
|
version: pluginBuildVersions(project.root).ttsc,
|
|
240
273
|
};
|
|
241
|
-
const loadedEntries = withPluginLoaderEnv(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
274
|
+
const loadedEntries = withPluginLoaderEnv(
|
|
275
|
+
() =>
|
|
276
|
+
entries.map((entry) => {
|
|
277
|
+
const specifier = entry.config.transform;
|
|
278
|
+
if (typeof specifier !== "string" || specifier.length === 0) {
|
|
279
|
+
throw new Error(
|
|
280
|
+
`ttsc: plugin entry is missing a string "transform" field`,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
const entryParent = path.join(entry.baseDir, "package.json");
|
|
284
|
+
const probedCandidates = collectModuleResolutionCandidates(
|
|
285
|
+
specifier,
|
|
286
|
+
entryParent,
|
|
287
|
+
undefined,
|
|
247
288
|
);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
(
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
289
|
+
// Capture every candidate before resolution chooses the descriptor entry.
|
|
290
|
+
// A post-resolution snapshot could bless a higher-priority file created
|
|
291
|
+
// after the resolver had already selected the old entry.
|
|
292
|
+
const probedCandidateHashes = hashHostInputPaths(probedCandidates);
|
|
293
|
+
const probedCandidateRealpaths =
|
|
294
|
+
realpathHostInputPaths(probedCandidates);
|
|
295
|
+
const request = PluginPackageResolution.resolvePluginRequest(
|
|
296
|
+
specifier,
|
|
297
|
+
entry.baseDir,
|
|
298
|
+
);
|
|
299
|
+
// Keep the candidates of the search roots up to the one the entry
|
|
300
|
+
// resolved in: the lookup never read the roots after it
|
|
301
|
+
// (`moduleResolutionBaseSelects`).
|
|
302
|
+
const read = new Set(
|
|
303
|
+
collectModuleResolutionCandidates(
|
|
304
|
+
specifier,
|
|
305
|
+
entryParent,
|
|
306
|
+
request,
|
|
307
|
+
).map((candidate) => path.resolve(candidate)),
|
|
308
|
+
);
|
|
309
|
+
const entryCandidates = probedCandidates.filter((candidate) =>
|
|
310
|
+
read.has(path.resolve(candidate)),
|
|
311
|
+
);
|
|
312
|
+
const entryCandidateHashes = pickHostInputEntries(
|
|
313
|
+
probedCandidateHashes,
|
|
314
|
+
entryCandidates,
|
|
315
|
+
);
|
|
316
|
+
const entryCandidateRealpaths = pickHostInputEntries(
|
|
317
|
+
probedCandidateRealpaths,
|
|
318
|
+
entryCandidates,
|
|
319
|
+
);
|
|
320
|
+
const loaded = loadPluginEntry(
|
|
321
|
+
entry.config,
|
|
322
|
+
{ ...context, plugin: entry.config },
|
|
323
|
+
request,
|
|
324
|
+
effectiveEnv,
|
|
325
|
+
descriptorCache,
|
|
326
|
+
);
|
|
327
|
+
const loadedHostInputHashes = mergeObservedHostInputHashes(
|
|
328
|
+
loaded.hostInputHashes,
|
|
329
|
+
hashHostInputPaths(Object.keys(loaded.hostInputHashes)),
|
|
330
|
+
);
|
|
331
|
+
const loadedHostInputRealpaths = mergeObservedHostInputRealpaths(
|
|
332
|
+
loaded.hostInputRealpaths,
|
|
333
|
+
realpathHostInputPaths(Object.keys(loaded.hostInputRealpaths)),
|
|
334
|
+
);
|
|
335
|
+
const hostInputHashes = mergeObservedHostInputHashes(
|
|
336
|
+
entryCandidateHashes,
|
|
337
|
+
loadedHostInputHashes,
|
|
338
|
+
);
|
|
339
|
+
const hostInputRealpaths = mergeObservedHostInputRealpaths(
|
|
340
|
+
entryCandidateRealpaths,
|
|
341
|
+
loadedHostInputRealpaths,
|
|
342
|
+
);
|
|
343
|
+
for (const input of loaded.hostInputs) {
|
|
344
|
+
const absolute = path.resolve(input);
|
|
345
|
+
if (
|
|
346
|
+
!Object.prototype.hasOwnProperty.call(
|
|
347
|
+
loadedHostInputHashes,
|
|
348
|
+
absolute,
|
|
349
|
+
)
|
|
350
|
+
) {
|
|
351
|
+
delete hostInputHashes[absolute];
|
|
352
|
+
}
|
|
312
353
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
|
|
354
|
+
return {
|
|
355
|
+
...loaded,
|
|
356
|
+
hostInputHashes,
|
|
357
|
+
hostInputRealpaths,
|
|
358
|
+
hostInputs: [...loaded.hostInputs, ...entryCandidates],
|
|
359
|
+
request,
|
|
360
|
+
};
|
|
361
|
+
}),
|
|
362
|
+
identities,
|
|
322
363
|
);
|
|
323
364
|
const plugins = composePluginSources(
|
|
324
365
|
entries,
|
|
@@ -342,6 +383,33 @@ export function loadProjectPlugins(options: {
|
|
|
342
383
|
...candidate,
|
|
343
384
|
...resolvePluginGoModule(candidate.source, candidate.label),
|
|
344
385
|
}));
|
|
386
|
+
// One reading of each source directory, shared by package selection and
|
|
387
|
+
// every build below and reported as the state the binaries were keyed on.
|
|
388
|
+
const sourceDigests = new Map<string, string>();
|
|
389
|
+
// And one reading of the environment each build directory is keyed on, which
|
|
390
|
+
// a plugin module root's state reports as it is.
|
|
391
|
+
const environmentDigests = new Map<string, string>();
|
|
392
|
+
// With the witness of each such reading, so a build of a directory package
|
|
393
|
+
// selection already read keys on that reading instead of probing Go again.
|
|
394
|
+
const environmentWitnesses = new Map<
|
|
395
|
+
string,
|
|
396
|
+
PluginBuildEnvironmentWitness.Record
|
|
397
|
+
>();
|
|
398
|
+
const readings = {
|
|
399
|
+
sources: sourceDigests,
|
|
400
|
+
environments: environmentDigests,
|
|
401
|
+
witnesses: environmentWitnesses,
|
|
402
|
+
};
|
|
403
|
+
// Records describing sources must never land inside one, so the store is
|
|
404
|
+
// admitted for source proofs only once every source of the load is known.
|
|
405
|
+
const sourceIdentities = PluginContentIdentities.outside(identities, [
|
|
406
|
+
...candidates.flatMap((candidate) => [
|
|
407
|
+
candidate.moduleRoot,
|
|
408
|
+
candidate.packageDir,
|
|
409
|
+
...(candidate.contributors ?? []).map((input) => input.source),
|
|
410
|
+
]),
|
|
411
|
+
...SourcePluginWorkspace.findTtscOverlayDirs(),
|
|
412
|
+
]);
|
|
345
413
|
// One fixed-effective-environment load owns manifest syntax sharing from the
|
|
346
414
|
// first watch query through metadata and builds. Do not allocate this after
|
|
347
415
|
// watch projection: that silently repeats selected-Go work (#1712).
|
|
@@ -363,7 +431,10 @@ export function loadProjectPlugins(options: {
|
|
|
363
431
|
])
|
|
364
432
|
.filter(reportsPluginSource),
|
|
365
433
|
);
|
|
366
|
-
|
|
434
|
+
// WARNING (#1728): hand the watch owner this load's store with the roots.
|
|
435
|
+
// It baselines each root before any build reads it; without the store it
|
|
436
|
+
// read every source the load proves from records a moment later.
|
|
437
|
+
options.onWatchInputs([...interests].sort(), sourceIdentities);
|
|
367
438
|
const initialSize = interests.size;
|
|
368
439
|
for (const candidate of candidates) {
|
|
369
440
|
// Nested source-only proposals replace the outer root manifests. Do not
|
|
@@ -378,7 +449,7 @@ export function loadProjectPlugins(options: {
|
|
|
378
449
|
if (reportsPluginSource(directory)) interests.add(directory);
|
|
379
450
|
}
|
|
380
451
|
if (interests.size !== initialSize)
|
|
381
|
-
options.onWatchInputs([...interests].sort());
|
|
452
|
+
options.onWatchInputs([...interests].sort(), sourceIdentities);
|
|
382
453
|
}
|
|
383
454
|
const proposals = NativeSourcePackages.propose(
|
|
384
455
|
candidates.map((candidate) => ({
|
|
@@ -387,6 +458,8 @@ export function loadProjectPlugins(options: {
|
|
|
387
458
|
})),
|
|
388
459
|
effectiveEnv,
|
|
389
460
|
packageReaders,
|
|
461
|
+
sourceIdentities,
|
|
462
|
+
readings,
|
|
390
463
|
);
|
|
391
464
|
const records = candidates.map(
|
|
392
465
|
({ plugin, index, stage, contributors, source, packageDir }) => {
|
|
@@ -465,6 +538,7 @@ export function loadProjectPlugins(options: {
|
|
|
465
538
|
watchReplacements,
|
|
466
539
|
packageReaders,
|
|
467
540
|
),
|
|
541
|
+
sourceIdentities,
|
|
468
542
|
);
|
|
469
543
|
const linkedContributors = records
|
|
470
544
|
.filter((record) => record.stage === "transform")
|
|
@@ -519,6 +593,8 @@ export function loadProjectPlugins(options: {
|
|
|
519
593
|
pluginName: host.label,
|
|
520
594
|
env: effectiveEnv,
|
|
521
595
|
readers: packageReaders,
|
|
596
|
+
identities: sourceIdentities,
|
|
597
|
+
readings,
|
|
522
598
|
packages: [
|
|
523
599
|
...hostEntries,
|
|
524
600
|
...linkedContributors.map((input) => ({
|
|
@@ -554,6 +630,8 @@ export function loadProjectPlugins(options: {
|
|
|
554
630
|
standaloneCandidates,
|
|
555
631
|
effectiveEnv,
|
|
556
632
|
packageReaders,
|
|
633
|
+
sourceIdentities,
|
|
634
|
+
readings,
|
|
557
635
|
);
|
|
558
636
|
standaloneCandidates.forEach((candidate, index) => {
|
|
559
637
|
NativeSourcePackages.kind(
|
|
@@ -574,12 +652,6 @@ export function loadProjectPlugins(options: {
|
|
|
574
652
|
}))
|
|
575
653
|
: []),
|
|
576
654
|
];
|
|
577
|
-
// One reading of each source directory, shared by every build below and
|
|
578
|
-
// reported as the state the binaries were keyed on.
|
|
579
|
-
const sourceDigests = new Map<string, string>();
|
|
580
|
-
// And one reading of the environment each build directory is keyed on, which
|
|
581
|
-
// a plugin module root's state reports as it is.
|
|
582
|
-
const environmentDigests = new Map<string, string>();
|
|
583
655
|
const builtTransformHosts = new Map<object, string>();
|
|
584
656
|
for (const record of transformHosts) {
|
|
585
657
|
builtTransformHosts.set(
|
|
@@ -590,10 +662,12 @@ export function loadProjectPlugins(options: {
|
|
|
590
662
|
contributors: mergeContributors(record.contributors, hostContributors),
|
|
591
663
|
env: effectiveEnv,
|
|
592
664
|
goModReaders: packageReaders,
|
|
665
|
+
identities: sourceIdentities,
|
|
593
666
|
pluginName: record.label,
|
|
594
667
|
packageOwnership: packageOwnership(record.source, record.label, true),
|
|
595
668
|
source: record.source,
|
|
596
669
|
environmentDigests,
|
|
670
|
+
environmentWitnesses,
|
|
597
671
|
sourceDigests,
|
|
598
672
|
ttscVersion,
|
|
599
673
|
tsgoVersion,
|
|
@@ -608,6 +682,7 @@ export function loadProjectPlugins(options: {
|
|
|
608
682
|
contributors: linkedContributors,
|
|
609
683
|
env: effectiveEnv,
|
|
610
684
|
goModReaders: packageReaders,
|
|
685
|
+
identities: sourceIdentities,
|
|
611
686
|
label: "linked plugin host",
|
|
612
687
|
pluginName: "linked-plugin-host",
|
|
613
688
|
source: path.join(ttscPackageRoot(), "cmd", "utility-host"),
|
|
@@ -617,6 +692,7 @@ export function loadProjectPlugins(options: {
|
|
|
617
692
|
true,
|
|
618
693
|
),
|
|
619
694
|
environmentDigests,
|
|
695
|
+
environmentWitnesses,
|
|
620
696
|
sourceDigests,
|
|
621
697
|
ttscVersion,
|
|
622
698
|
tsgoVersion,
|
|
@@ -638,6 +714,7 @@ export function loadProjectPlugins(options: {
|
|
|
638
714
|
contributors: record.contributors,
|
|
639
715
|
env: effectiveEnv,
|
|
640
716
|
goModReaders: packageReaders,
|
|
717
|
+
identities: sourceIdentities,
|
|
641
718
|
pluginName: record.label,
|
|
642
719
|
packageOwnership: packageOwnership(
|
|
643
720
|
record.source,
|
|
@@ -646,6 +723,7 @@ export function loadProjectPlugins(options: {
|
|
|
646
723
|
),
|
|
647
724
|
source: record.source,
|
|
648
725
|
environmentDigests,
|
|
726
|
+
environmentWitnesses,
|
|
649
727
|
sourceDigests,
|
|
650
728
|
ttscVersion,
|
|
651
729
|
tsgoVersion,
|
|
@@ -697,6 +775,7 @@ export function loadProjectPlugins(options: {
|
|
|
697
775
|
entry.observationsComplete && declaresHostInputReads(entry.plugin),
|
|
698
776
|
),
|
|
699
777
|
discoveryInputsComplete: project.configInputsComplete === true,
|
|
778
|
+
...(identities === undefined ? {} : { identities }),
|
|
700
779
|
nativePlugins: orderNativePlugins(nativePlugins),
|
|
701
780
|
...(loadedEntries.some((entry) => !entry.observationsComplete)
|
|
702
781
|
? { observationsComplete: false as const }
|
|
@@ -712,9 +791,14 @@ export function loadProjectPlugins(options: {
|
|
|
712
791
|
pluginSourceState(directory, {
|
|
713
792
|
env: effectiveEnv,
|
|
714
793
|
sourceDigest,
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
794
|
+
environment:
|
|
795
|
+
environmentDigests.get(directory) ??
|
|
796
|
+
pluginBuildEnvironment(
|
|
797
|
+
directory,
|
|
798
|
+
effectiveEnv,
|
|
799
|
+
undefined,
|
|
800
|
+
sourceIdentities,
|
|
801
|
+
),
|
|
718
802
|
}),
|
|
719
803
|
]),
|
|
720
804
|
),
|
|
@@ -1290,7 +1374,12 @@ function loadPluginDescriptor(
|
|
|
1290
1374
|
) {
|
|
1291
1375
|
throw error;
|
|
1292
1376
|
}
|
|
1293
|
-
const loaded = loadDescriptorViaTtsx(
|
|
1377
|
+
const loaded = loadDescriptorViaTtsx(
|
|
1378
|
+
request,
|
|
1379
|
+
context,
|
|
1380
|
+
effectiveEnv,
|
|
1381
|
+
descriptorCache.identities,
|
|
1382
|
+
);
|
|
1294
1383
|
if (loaded === undefined) {
|
|
1295
1384
|
throw error;
|
|
1296
1385
|
}
|
|
@@ -1303,6 +1392,9 @@ interface DescriptorCacheOptions {
|
|
|
1303
1392
|
/** The plugin cache directory the caller selected, if any. */
|
|
1304
1393
|
cacheDir: string | undefined;
|
|
1305
1394
|
|
|
1395
|
+
/** Record store that proves the evaluating runtimes from metadata (#1723). */
|
|
1396
|
+
identities: PluginContentIdentities.Store | undefined;
|
|
1397
|
+
|
|
1306
1398
|
/** This ttsc build's version. */
|
|
1307
1399
|
version: string;
|
|
1308
1400
|
}
|
|
@@ -1352,21 +1444,28 @@ function loadCommonJsDescriptor(
|
|
|
1352
1444
|
runtime,
|
|
1353
1445
|
effectiveEnv,
|
|
1354
1446
|
context.projectRoot,
|
|
1447
|
+
descriptorCache.identities,
|
|
1355
1448
|
);
|
|
1356
1449
|
const node =
|
|
1357
1450
|
!runtimeCapabilities.bun &&
|
|
1358
1451
|
runtimeCapabilities.registerHooks &&
|
|
1359
1452
|
runtimeCapabilities.executable !== undefined
|
|
1360
1453
|
? runtimeCapabilities.executable
|
|
1361
|
-
: resolveNodeBinary(
|
|
1454
|
+
: resolveNodeBinary(
|
|
1455
|
+
effectiveEnv,
|
|
1456
|
+
context.projectRoot,
|
|
1457
|
+
descriptorCache.identities,
|
|
1458
|
+
);
|
|
1362
1459
|
const cacheAuthority = {
|
|
1363
1460
|
additionalRuntime: node,
|
|
1364
1461
|
cacheDir: descriptorCache.cacheDir,
|
|
1462
|
+
identities: descriptorCache.identities,
|
|
1365
1463
|
context,
|
|
1366
1464
|
// Everything the child receives besides the per-evaluation output paths.
|
|
1367
1465
|
env: {
|
|
1368
1466
|
...effectiveEnv,
|
|
1369
1467
|
...(node === undefined ? {} : { TTSC_NODE_BINARY: node }),
|
|
1468
|
+
...descriptorRecordRoot(descriptorCache.identities),
|
|
1370
1469
|
TTSC_TTSX_BINARY: ttsx,
|
|
1371
1470
|
},
|
|
1372
1471
|
projectRoot: context.projectRoot,
|
|
@@ -1456,6 +1555,7 @@ function loadCommonJsDescriptor(
|
|
|
1456
1555
|
// The direct evaluator may be Bun, but ttsx and native config
|
|
1457
1556
|
// loaders require a real Node runtime with synchronous hooks.
|
|
1458
1557
|
...(node === undefined ? {} : { TTSC_NODE_BINARY: node }),
|
|
1558
|
+
...descriptorRecordRoot(descriptorCache.identities),
|
|
1459
1559
|
TTSC_TTSX_BINARY: ttsx,
|
|
1460
1560
|
TTSC_PLUGIN_CONTEXT: JSON.stringify(context),
|
|
1461
1561
|
TTSC_PLUGIN_DESCRIPTOR_LOAD: "1",
|
|
@@ -1840,11 +1940,12 @@ function loadDescriptorViaTtsx(
|
|
|
1840
1940
|
request: string,
|
|
1841
1941
|
context: ITtscPluginFactoryContext,
|
|
1842
1942
|
effectiveEnv: NodeJS.ProcessEnv,
|
|
1943
|
+
identities: PluginContentIdentities.Store | undefined,
|
|
1843
1944
|
): IsolatedPluginDescriptor | undefined {
|
|
1844
1945
|
// Binary discovery prefers the instance environment, then the ambient
|
|
1845
1946
|
// process.env (where `withPluginLoaderEnv` injects ttsc's own node/ttsx paths
|
|
1846
1947
|
// just before this runs), then the running interpreter.
|
|
1847
|
-
const node = resolveNodeBinary(effectiveEnv, context.projectRoot);
|
|
1948
|
+
const node = resolveNodeBinary(effectiveEnv, context.projectRoot, identities);
|
|
1848
1949
|
const ttsx = effectiveEnv.TTSC_TTSX_BINARY ?? process.env.TTSC_TTSX_BINARY;
|
|
1849
1950
|
if (node === undefined || ttsx === undefined || ttsx.length === 0) {
|
|
1850
1951
|
return undefined;
|
|
@@ -1883,6 +1984,7 @@ function loadDescriptorViaTtsx(
|
|
|
1883
1984
|
// may recurse into further descriptor loads) finds them even when the
|
|
1884
1985
|
// instance-env snapshot predates `withPluginLoaderEnv`.
|
|
1885
1986
|
TTSC_NODE_BINARY: node,
|
|
1987
|
+
...descriptorRecordRoot(identities),
|
|
1886
1988
|
TTSC_TTSX_BINARY: ttsx,
|
|
1887
1989
|
TTSC_PLUGIN_CONTEXT: JSON.stringify({
|
|
1888
1990
|
binary: context.binary,
|
|
@@ -1967,6 +2069,20 @@ interface TtsxDescriptorResolutionRecord {
|
|
|
1967
2069
|
unstable?: boolean;
|
|
1968
2070
|
}
|
|
1969
2071
|
|
|
2072
|
+
/**
|
|
2073
|
+
* The private variable that hands a descriptor evaluator the plugin cache root
|
|
2074
|
+
* this load's record store selected, so the child proves the compiler it runs
|
|
2075
|
+
* from that root's records instead of streaming it (#1726) and never selects a
|
|
2076
|
+
* cache root of its own. Absent without a store.
|
|
2077
|
+
*/
|
|
2078
|
+
function descriptorRecordRoot(
|
|
2079
|
+
identities: PluginContentIdentities.Store | undefined,
|
|
2080
|
+
): { TTSC_PLUGIN_RECORD_ROOT?: string } {
|
|
2081
|
+
return identities === undefined
|
|
2082
|
+
? {}
|
|
2083
|
+
: { TTSC_PLUGIN_RECORD_ROOT: identities.root };
|
|
2084
|
+
}
|
|
2085
|
+
|
|
1970
2086
|
/**
|
|
1971
2087
|
* Expand the ttsx runtime's selected module edges into the same exact and
|
|
1972
2088
|
* missing resolution inputs used by the direct isolated evaluator.
|
|
@@ -2038,6 +2154,15 @@ function readTtsxDescriptorInputs(
|
|
|
2038
2154
|
(signatures.has(resolved) &&
|
|
2039
2155
|
signatures.get(resolved) !== record.signature)
|
|
2040
2156
|
) {
|
|
2157
|
+
E2ETrace.capabilityResolution(
|
|
2158
|
+
"plugin-descriptor-input-signature-moved",
|
|
2159
|
+
{
|
|
2160
|
+
resolved,
|
|
2161
|
+
first: signatures.get(resolved),
|
|
2162
|
+
later:
|
|
2163
|
+
typeof record.signature === "string" ? record.signature : null,
|
|
2164
|
+
},
|
|
2165
|
+
);
|
|
2041
2166
|
hashes.delete(resolved);
|
|
2042
2167
|
realpaths.delete(resolved);
|
|
2043
2168
|
signatures.delete(resolved);
|
|
@@ -2115,10 +2240,13 @@ function errorMessage(error: unknown): string {
|
|
|
2115
2240
|
return error instanceof Error ? error.message : String(error);
|
|
2116
2241
|
}
|
|
2117
2242
|
|
|
2118
|
-
function withPluginLoaderEnv<T>(
|
|
2243
|
+
function withPluginLoaderEnv<T>(
|
|
2244
|
+
run: () => T,
|
|
2245
|
+
identities: PluginContentIdentities.Store | undefined,
|
|
2246
|
+
): T {
|
|
2119
2247
|
const previousNode = process.env.TTSC_NODE_BINARY;
|
|
2120
2248
|
const previousTtsx = process.env.TTSC_TTSX_BINARY;
|
|
2121
|
-
const node = resolveNodeBinary({}, process.cwd());
|
|
2249
|
+
const node = resolveNodeBinary({}, process.cwd(), identities);
|
|
2122
2250
|
if (process.env.TTSC_NODE_BINARY === undefined && node !== undefined) {
|
|
2123
2251
|
process.env.TTSC_NODE_BINARY = node;
|
|
2124
2252
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
|
|
3
4
|
import { CapabilityResolutionFormat } from "./CapabilityResolutionFormat";
|
|
4
5
|
import type { ITtscCapabilityPluginSource } from "./ITtscCapabilityPluginSource";
|
|
5
6
|
import type { ITtscCapabilityResolutionEntry } from "./ITtscCapabilityResolutionEntry";
|
|
6
7
|
import { hashHostInputPaths } from "./load/hashHostInputPaths";
|
|
7
8
|
import { realpathHostInputPaths } from "./load/realpathHostInputPaths";
|
|
9
|
+
import { PluginContentIdentities } from "./source/PluginContentIdentities";
|
|
8
10
|
import { pluginSourceFilesSignature } from "./source/pluginSourceFilesSignature";
|
|
9
11
|
import { pluginSourceStateHolds } from "./source/pluginSourceStateHolds";
|
|
10
12
|
import { recordCacheFileUse } from "./source/recordCacheFileUse";
|
|
@@ -52,6 +54,12 @@ export function readCapabilityResolution(options: {
|
|
|
52
54
|
|
|
53
55
|
/** Environment selecting the cache root; ambient process env when omitted. */
|
|
54
56
|
env?: NodeJS.ProcessEnv;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Record store of the project's plugin cache, which proves the runtime and
|
|
60
|
+
* the plugin sources and SDK from metadata instead of their bytes (#1725).
|
|
61
|
+
*/
|
|
62
|
+
identities?: PluginContentIdentities.Store;
|
|
55
63
|
}): ITtscCapabilityResolutionEntry | null {
|
|
56
64
|
const file = CapabilityResolutionFormat.resolutionFile(options);
|
|
57
65
|
if (file === null) return null;
|
|
@@ -83,12 +91,14 @@ export function readCapabilityResolution(options: {
|
|
|
83
91
|
// old one still exists.
|
|
84
92
|
const sources = Object.entries(entry.pluginSources);
|
|
85
93
|
const evidence = sources.some(([, source]) => source.signature !== undefined)
|
|
86
|
-
?
|
|
87
|
-
|
|
94
|
+
? PluginContentIdentities.sourceEvidence(
|
|
95
|
+
PluginContentIdentities.mintReference(path.dirname(file)),
|
|
88
96
|
)
|
|
89
97
|
: undefined;
|
|
98
|
+
const projectRoot = path.resolve(options.cwd);
|
|
90
99
|
for (const [directory, source] of sources)
|
|
91
|
-
if (!pluginSourceProven(directory, source, evidence))
|
|
100
|
+
if (!pluginSourceProven(directory, source, evidence, projectRoot))
|
|
101
|
+
return null;
|
|
92
102
|
for (const plugin of entry.plugins)
|
|
93
103
|
if (!fs.existsSync(plugin.binary)) return null;
|
|
94
104
|
recordCacheFileUse(file);
|
|
@@ -108,8 +118,9 @@ function pluginSourceProven(
|
|
|
108
118
|
directory: string,
|
|
109
119
|
source: ITtscCapabilityPluginSource,
|
|
110
120
|
evidence:
|
|
111
|
-
| ReturnType<typeof
|
|
121
|
+
| ReturnType<typeof PluginContentIdentities.sourceEvidence>
|
|
112
122
|
| undefined,
|
|
123
|
+
projectRoot: string,
|
|
113
124
|
): boolean {
|
|
114
125
|
try {
|
|
115
126
|
const now =
|
|
@@ -123,8 +134,8 @@ function pluginSourceProven(
|
|
|
123
134
|
now.separable &&
|
|
124
135
|
now.signature === source.signature &&
|
|
125
136
|
source.digest !== undefined
|
|
126
|
-
? { sourceDigest: source.digest }
|
|
127
|
-
: {},
|
|
137
|
+
? { projectRoot, sourceDigest: source.digest }
|
|
138
|
+
: { projectRoot },
|
|
128
139
|
);
|
|
129
140
|
} catch {
|
|
130
141
|
return false;
|