ttsc 0.31.6 → 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/cmd/ttsc/compiler_argument_cwd_test.go +38 -38
- package/cmd/ttscserver/main.go +2 -12
- package/cmd/ttscserver/resolve_launch_uses_native_flag_authority_test.go +7 -7
- package/driver/lsp.go +4 -43
- package/driver/rewrite.go +1 -1
- package/internal/e2etrace/completion_hints.go +3 -3
- package/internal/e2etrace/completion_hints_test.go +26 -12
- package/internal/graph/build.go +5 -6
- package/internal/graph/graph.go +3 -3
- package/internal/graph/line_model.go +2 -35
- package/internal/lspserver/lsp_clean_didopen_refreshes_compiler_state_test.go +13 -36
- package/internal/lspserver/lsp_hints_refresh_ignores_a_superseded_generation_test.go +9 -3
- package/internal/lspserver/lsp_plugin.go +19 -0
- package/internal/lspserver/lsp_proxy.go +9 -129
- package/internal/lspserver/lsp_server.go +0 -8
- package/internal/lspserver/lsp_watched_file_changes_reach_compiler_caches_test.go +6 -36
- package/internal/sourceprocess/windows_target_owns_suspended_admission_test.go +5 -5
- 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 +92 -12
- 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/TsgoArguments.js.map +1 -1
- 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/CompilerProjectSelection.d.ts +9 -8
- package/lib/compiler/internal/project/CompilerProjectSelection.js +11 -9
- package/lib/compiler/internal/project/CompilerProjectSelection.js.map +1 -1
- package/lib/compiler/internal/project/resolveOwningProjectConfig.d.ts +25 -8
- package/lib/compiler/internal/project/resolveOwningProjectConfig.js +26 -14
- 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 +32 -4
- package/lib/compiler/internal/runSingleFileEmit.js +124 -89
- 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/flags/ParseOptions.d.ts +2 -2
- package/lib/internal/E2ETrace.js.map +1 -1
- package/lib/internal/OwnedNativeProcess.d.ts +2 -2
- package/lib/internal/OwnedNativeProcess.js +2 -2
- package/lib/internal/SourceNativeRetirement.d.ts +8 -7
- package/lib/internal/SourceNativeRetirement.js +19 -10
- package/lib/internal/SourceNativeRetirement.js.map +1 -1
- package/lib/internal/TtsxNodeOptions.d.ts +79 -0
- package/lib/internal/TtsxNodeOptions.js +121 -0
- package/lib/internal/TtsxNodeOptions.js.map +1 -0
- package/lib/internal/javascriptRuntimeCapabilities.js +4 -1
- package/lib/internal/javascriptRuntimeCapabilities.js.map +1 -1
- package/lib/internal/parseWindowsDirectoryCaseSensitivity.d.ts +5 -5
- package/lib/internal/parseWindowsDirectoryCaseSensitivity.js +5 -5
- package/lib/internal/pathIdentity/createCaseSensitivityObservations.d.ts +35 -0
- package/lib/internal/pathIdentity/createCaseSensitivityObservations.js +209 -0
- package/lib/internal/pathIdentity/createCaseSensitivityObservations.js.map +1 -0
- package/lib/internal/pathIdentity/createFilesystemPathIdentityContext.js +2 -143
- package/lib/internal/pathIdentity/createFilesystemPathIdentityContext.js.map +1 -1
- package/lib/internal/projectInputPathIdentity.d.ts +1 -0
- package/lib/internal/projectInputPathIdentity.js +1 -0
- package/lib/internal/projectInputPathIdentity.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/parseTtsxCLI.d.ts +5 -4
- package/lib/launcher/internal/parseTtsxCLI.js +5 -4
- package/lib/launcher/internal/parseTtsxCLI.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/resolveSingleFileOutput.d.ts +8 -9
- package/lib/launcher/internal/resolveSingleFileOutput.js +8 -9
- package/lib/launcher/internal/resolveSingleFileOutput.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/runTtsx.js +5 -2
- package/lib/launcher/internal/runTtsx.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/RuntimeEntrySources.d.ts +40 -0
- package/lib/launcher/internal/runtime/RuntimeEntrySources.js +57 -0
- package/lib/launcher/internal/runtime/RuntimeEntrySources.js.map +1 -0
- package/lib/launcher/internal/runtime/RuntimeProjectOwnership.d.ts +5 -4
- package/lib/launcher/internal/runtime/RuntimeProjectOwnership.js +8 -6
- package/lib/launcher/internal/runtime/RuntimeProjectOwnership.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/commonJsExportNames.d.ts +2 -1
- package/lib/launcher/internal/runtime/commonJsExportNames.js +2 -1
- package/lib/launcher/internal/runtime/commonJsExportNames.js.map +1 -1
- package/lib/launcher/internal/runtime/installRuntimeHooks.d.ts +5 -3
- package/lib/launcher/internal/runtime/installRuntimeHooks.js +42 -12
- package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/runtime/resolveRuntimeCleanTargets.js +3 -1
- package/lib/launcher/internal/runtime/resolveRuntimeCleanTargets.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 +103 -13
- package/lib/launcher/internal/watch/WatchTopology.js +380 -95
- 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/projectInputReloadEventShouldNotify.d.ts +4 -1
- package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.js +3 -2
- package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.js.map +1 -1
- 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 +477 -421
- 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/load/resolveNativeSource.js +2 -3
- package/lib/plugin/internal/load/resolveNativeSource.js.map +1 -1
- 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/plugin/internal/source/pluginModuleReplaceDirectories.d.ts +4 -1
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js +9 -2
- package/lib/plugin/internal/source/pluginModuleReplaceDirectories.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/TtscCommonOptions.d.ts +2 -2
- 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 +123 -11
- package/src/compiler/internal/build/ResidentCheckWatchSession.ts +41 -24
- package/src/compiler/internal/build/RunBuildOptions.ts +9 -5
- package/src/compiler/internal/build/TsgoArguments.ts +4 -1
- 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/CompilerProjectSelection.ts +14 -14
- package/src/compiler/internal/project/resolveOwningProjectConfig.ts +42 -16
- 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 +145 -101
- 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/flags/ParseOptions.ts +2 -2
- package/src/internal/E2ETrace.ts +3 -1
- package/src/internal/OwnedNativeProcess.ts +2 -2
- package/src/internal/SourceNativeRetirement.ts +42 -19
- package/src/internal/TtsxNodeOptions.ts +124 -0
- package/src/internal/javascriptRuntimeCapabilities.ts +6 -1
- package/src/internal/parseWindowsDirectoryCaseSensitivity.ts +5 -5
- package/src/internal/pathIdentity/createCaseSensitivityObservations.ts +242 -0
- package/src/internal/pathIdentity/createFilesystemPathIdentityContext.ts +2 -169
- package/src/internal/projectInputPathIdentity.ts +1 -0
- 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/parseTtsxCLI.ts +5 -4
- package/src/launcher/internal/prepareExecution.ts +6 -1
- package/src/launcher/internal/resolveSingleFileOutput.ts +8 -9
- package/src/launcher/internal/runTtsc.ts +127 -49
- package/src/launcher/internal/runTtsx.ts +17 -8
- package/src/launcher/internal/runtime/CommonJsRuntimeSource.ts +11 -9
- package/src/launcher/internal/runtime/RuntimeEntrySources.ts +57 -0
- package/src/launcher/internal/runtime/RuntimeProjectOwnership.ts +23 -10
- package/src/launcher/internal/runtime/advertiseTypeScriptExtensions.ts +25 -0
- package/src/launcher/internal/runtime/commonJsExportNames.ts +11 -4
- package/src/launcher/internal/runtime/installRuntimeHooks.ts +62 -16
- package/src/launcher/internal/runtime/resolveRuntimeCleanTargets.ts +17 -5
- 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 +461 -102
- package/src/launcher/internal/watch/WatchTopologyWorkerProtocol.ts +106 -0
- package/src/launcher/internal/watch/projectInputReloadEventShouldNotify.ts +14 -9
- 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 +683 -593
- package/src/plugin/internal/load/pluginResolutionFailure.ts +37 -0
- package/src/plugin/internal/load/resolveNativeSource.ts +10 -4
- package/src/plugin/internal/source/PluginBuildEnvironmentReadings.ts +8 -2
- package/src/plugin/internal/source/pluginModuleReplaceDirectories.ts +10 -1
- 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/TtscCommonOptions.ts +2 -2
- package/src/structures/internal/TtscSingleFileEmitOptions.ts +22 -11
- package/internal/graphsymbols/position_helpers_follow_ecma_line_terminators_test.go +0 -78
- package/internal/graphsymbols/provider.go +0 -650
- package/internal/lspserver/lsp_symbols.go +0 -212
|
@@ -4,11 +4,13 @@ import { createRequire } from "node:module";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
+
import { WatchInputPublication } from "../../../compiler/internal/build/WatchInputPublication";
|
|
7
8
|
import { readJsonFile } from "../../../compiler/internal/project/readJsonFile";
|
|
8
9
|
import { readProjectConfig } from "../../../compiler/internal/project/readProjectConfig";
|
|
9
10
|
import { SidecarEnvironment } from "../../../compiler/internal/sharedHost/SidecarEnvironment";
|
|
10
11
|
import { E2ETrace } from "../../../internal/E2ETrace";
|
|
11
12
|
import { OwnedSynchronousProcess } from "../../../internal/OwnedSynchronousProcess";
|
|
13
|
+
import { TtsxNodeOptions } from "../../../internal/TtsxNodeOptions";
|
|
12
14
|
import { createCanonicalTempDirectory } from "../../../internal/createCanonicalTempDirectory";
|
|
13
15
|
import { javascriptRuntimeCapabilities } from "../../../internal/javascriptRuntimeCapabilities";
|
|
14
16
|
import { resolveNodeBinary } from "../../../internal/resolveNodeBinary";
|
|
@@ -19,6 +21,7 @@ import type { ITtscPluginFactoryContext } from "../../../structures/ITtscPluginF
|
|
|
19
21
|
import type { ITtscProjectPluginConfig } from "../../../structures/ITtscProjectPluginConfig";
|
|
20
22
|
import type { ITtscLoadedNativePlugin } from "../../../structures/internal/ITtscLoadedNativePlugin";
|
|
21
23
|
import type { ITtscParsedProjectConfig } from "../../../structures/internal/ITtscParsedProjectConfig";
|
|
24
|
+
import type { TtscPluginSourceInputsHandler } from "../../../structures/internal/TtscSingleFileEmitOptions";
|
|
22
25
|
import { pluginDescriptorFailureReason } from "../pluginDescriptorFailureReason";
|
|
23
26
|
import { pluginDescriptorProcessFailure } from "../pluginDescriptorProcessFailure";
|
|
24
27
|
import { NativeSourcePackages } from "../source/NativeSourcePackages";
|
|
@@ -82,6 +85,9 @@ import { visitImportMappedCandidates } from "./visitImportMappedCandidates";
|
|
|
82
85
|
* declaration. Sequential content, metadata and physical-path observations are
|
|
83
86
|
* not an atomic snapshot or detection of every omitted read.
|
|
84
87
|
*
|
|
88
|
+
* Synchronous callers require synchronous watch-input handlers; use
|
|
89
|
+
* {@link loadProjectPlugins.async} to await a worker's baseline publication.
|
|
90
|
+
*
|
|
85
91
|
* @param options.binary - Absolute path to the ttsc native helper binary.
|
|
86
92
|
* @param options.cacheDir - Override the plugin binary cache directory.
|
|
87
93
|
* @param options.cwd - Working directory for resolving relative paths.
|
|
@@ -92,11 +98,12 @@ import { visitImportMappedCandidates } from "./visitImportMappedCandidates";
|
|
|
92
98
|
* native environment-name identity. Defaults to `process.env` for CLI
|
|
93
99
|
* callers, so ambient behavior is unchanged.
|
|
94
100
|
* @param options.file - Path to the tsconfig/jsconfig file.
|
|
95
|
-
* @param options.pluginConfigDir - Caller-declared
|
|
96
|
-
* config-file discovery
|
|
97
|
-
* @param options.projectRoot - Override the
|
|
101
|
+
* @param options.pluginConfigDir - Caller-declared consumer directory for
|
|
102
|
+
* plugin packages, factory contexts and config-file discovery.
|
|
103
|
+
* @param options.projectRoot - Override the source root, native working
|
|
104
|
+
* directory, cache anchor and returned relative Go-source base.
|
|
98
105
|
* @param options.tsconfig - Alias for `file`.
|
|
99
|
-
* @evidence contracts/common.md#principled-implementation The loader brackets
|
|
106
|
+
* @evidence contracts/common.md#principled-implementation The loader brackets discovery at the selected config or explicit pluginConfigDir and factories receive that consumer anchor, independently of the source root retained for descriptor/native process cwd, caches and relative Go sources. It validates declarations before publishing conservative source repair interests. Metadata refusal remains terminal; valid records narrow watch interests before final admission/build, while contradictory content or physical observations are omitted from proof rather than retroactively blessed.
|
|
100
107
|
* @evidence contracts/common.md#clear-and-simple-design The operation owns one ordered load generation; private helpers separate discovery, evaluation, validation, composition and proof merging, while package resolution and source building remain their own modules.
|
|
101
108
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Descriptor module caches are isolated rather than deleting application singletons. ttsx retry occurs only for explicit supported TypeScript loader incompatibility, with plugins disabled to avoid recursive self-hosting; arbitrary descriptor failures are not retried into false success.
|
|
102
109
|
* @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.
|
|
@@ -134,10 +141,7 @@ export function loadProjectPlugins(options: {
|
|
|
134
141
|
* Observe plugin build roots before building, including failed builds, with
|
|
135
142
|
* the record store that proves their states (#1728).
|
|
136
143
|
*/
|
|
137
|
-
onWatchInputs?:
|
|
138
|
-
inputs: readonly string[],
|
|
139
|
-
identities?: PluginContentIdentities.Store,
|
|
140
|
-
) => void;
|
|
144
|
+
onWatchInputs?: TtscPluginSourceInputsHandler;
|
|
141
145
|
|
|
142
146
|
/** Caller-selected anchor for plugin-owned configuration discovery. */
|
|
143
147
|
pluginConfigDir?: string;
|
|
@@ -198,615 +202,676 @@ export function loadProjectPlugins(options: {
|
|
|
198
202
|
/** Resolved project values and logical/physical configuration identity. */
|
|
199
203
|
project: ITtscParsedProjectConfig;
|
|
200
204
|
} {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
205
|
+
return WatchInputPublication.run(loadProjectPlugins.steps(options));
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Keep synchronous loading and awaited watch handoffs on one load sequence.
|
|
210
|
+
*
|
|
211
|
+
* @evidence contracts/common.md#principled-implementation Both completion modes advance one ordered discovery, admission, publication and build sequence. Awaited stepping preserves baseline-before-read handoffs before package selection and source builds, including empty selection and conservative repair roots.
|
|
212
|
+
* @evidence contracts/common.md#clear-and-simple-design The namespace adds an awaited runner beside synchronous loading and exposes one generator to build orchestration; existing helpers retain discovery, validation and compilation responsibilities.
|
|
213
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Publication suspension retains failed-build interests and source proof rather than rebuilding a baseline after compilation. Pending publication cannot establish observation; rejection enters the real load failure path without replacing admission or native builds.
|
|
214
|
+
* @evidence contracts/common.md#meaningful-documentation Entry prose distinguishes completion modes, baseline-before-read ordering and internal sequence completion/rejection duties; the primary loader documents input and result provenance.
|
|
215
|
+
* @evidence contracts/portability.md#os-neutral-implementation The shared sequence retains existing native resolution, paths, environment and argument-array handling; the namespace adds no independent boundary.
|
|
216
|
+
* @evidence contracts/performance.md#efficient-algorithms Discovery, source hashing, Go metadata, validation and builds retain their original input costs; each publication adds one suspension without repeating those phases.
|
|
217
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Validated descriptor/source records and load-local digest/reader sharing remain available across suspension; the completion wrapper retains no reusable load or in-flight cache.
|
|
218
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources One load generation stays live while its current handoff settles; evaluator cleanup and returned-generation ownership remain with the sequence, and handler rejection enters generator cleanup.
|
|
219
|
+
*/
|
|
220
|
+
export namespace loadProjectPlugins {
|
|
221
|
+
/**
|
|
222
|
+
* Load plugins after each watch owner confirms its reported input baseline. A
|
|
223
|
+
* rejected handoff fails loading before the next source read or build.
|
|
224
|
+
*/
|
|
225
|
+
export function async(
|
|
226
|
+
options: Parameters<typeof loadProjectPlugins>[0],
|
|
227
|
+
): Promise<ReturnType<typeof loadProjectPlugins>> {
|
|
228
|
+
return WatchInputPublication.runAsync(steps(options));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Produce one load, suspending at each watch-input handoff before continuing.
|
|
233
|
+
* Internal build orchestration consumes the whole sequence with its chosen
|
|
234
|
+
* completion runner; it must deliver rejection back into the sequence.
|
|
235
|
+
*/
|
|
236
|
+
export function* steps(
|
|
237
|
+
options: Parameters<typeof loadProjectPlugins>[0],
|
|
238
|
+
): WatchInputPublication.Sequence<ReturnType<typeof loadProjectPlugins>> {
|
|
239
|
+
// Snapshot the caller environment before `withPluginLoaderEnv` injects
|
|
240
|
+
// host-owned Node/ttsx locators into process.env. Under a Bun parent the
|
|
241
|
+
// direct descriptor evaluator must remain Bun unless the caller explicitly
|
|
242
|
+
// selected another runtime.
|
|
243
|
+
const effectiveEnv = SidecarEnvironment.merge(options.env ?? process.env);
|
|
244
|
+
const projectSnapshot = readProjectHostInputSnapshot({
|
|
245
|
+
cwd: options.cwd,
|
|
246
|
+
file: options.file,
|
|
247
|
+
includePluginDiscovery: options.entries === undefined,
|
|
248
|
+
pluginConfigDir: options.pluginConfigDir,
|
|
249
|
+
projectRoot: options.projectRoot,
|
|
250
|
+
tsconfig: options.tsconfig,
|
|
251
|
+
});
|
|
252
|
+
const { project } = projectSnapshot;
|
|
253
|
+
const projectHostInputs = projectSnapshot.hostInputs;
|
|
254
|
+
const projectHostInputHashes = projectSnapshot.hostInputHashes;
|
|
255
|
+
const projectHostInputRealpaths = projectSnapshot.hostInputRealpaths;
|
|
256
|
+
const entries: ProjectPluginEntries.ProjectPluginEntry[] =
|
|
257
|
+
options.entries === false
|
|
258
|
+
? []
|
|
259
|
+
: ProjectPluginEntries.resolvePluginEntries(
|
|
260
|
+
project,
|
|
261
|
+
options.entries,
|
|
262
|
+
options.pluginConfigDir,
|
|
263
|
+
).filter((entry) => entry.config.enabled !== false);
|
|
264
|
+
if (entries.length === 0) {
|
|
265
|
+
yield options.onWatchInputs?.([]);
|
|
266
|
+
return {
|
|
267
|
+
...collectHostInputSnapshot(
|
|
221
268
|
project,
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (entries.length === 0) {
|
|
225
|
-
options.onWatchInputs?.([]);
|
|
226
|
-
return {
|
|
227
|
-
...collectHostInputSnapshot(
|
|
228
|
-
project,
|
|
229
|
-
{},
|
|
230
|
-
[],
|
|
231
|
-
projectHostInputs,
|
|
232
|
-
revalidateHostInputHashes(projectHostInputHashes, projectHostInputs),
|
|
233
|
-
revalidateHostInputRealpaths(
|
|
234
|
-
projectHostInputRealpaths,
|
|
269
|
+
{},
|
|
270
|
+
[],
|
|
235
271
|
projectHostInputs,
|
|
272
|
+
revalidateHostInputHashes(projectHostInputHashes, projectHostInputs),
|
|
273
|
+
revalidateHostInputRealpaths(
|
|
274
|
+
projectHostInputRealpaths,
|
|
275
|
+
projectHostInputs,
|
|
276
|
+
),
|
|
236
277
|
),
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
}
|
|
278
|
+
descriptorReadsDeclared: true,
|
|
279
|
+
discoveryInputsComplete: project.configInputsComplete === true,
|
|
280
|
+
nativePlugins: [],
|
|
281
|
+
pluginSources: {},
|
|
282
|
+
project,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
245
285
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
tsconfig: project.path,
|
|
255
|
-
};
|
|
256
|
-
// Where isolated descriptor evaluations keep their answers across launches
|
|
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({
|
|
286
|
+
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
287
|
+
const context = {
|
|
288
|
+
binary: options.binary,
|
|
289
|
+
cwd,
|
|
290
|
+
...(options.pluginConfigDir === undefined ||
|
|
291
|
+
options.pluginConfigDir === ""
|
|
292
|
+
? {}
|
|
293
|
+
: { pluginConfigDir: path.resolve(cwd, options.pluginConfigDir) }),
|
|
265
294
|
projectRoot: project.root,
|
|
295
|
+
tsconfig: project.path,
|
|
296
|
+
};
|
|
297
|
+
// Where isolated descriptor evaluations keep their answers across launches
|
|
298
|
+
// (`PluginDescriptorEvaluationCache`).
|
|
299
|
+
// WARNING (#1721, #1722, #1723): a warm load must prove its unchanged inputs
|
|
300
|
+
// from this store, not re-read them. Every launch is a new process, so any
|
|
301
|
+
// module-level memo of this load's work dies with it; a 27 s warm typia
|
|
302
|
+
// launch whose native build took 0.28 s is what that looked like.
|
|
303
|
+
const identities =
|
|
304
|
+
options.identities ??
|
|
305
|
+
PluginContentIdentities.open({
|
|
306
|
+
projectRoot: project.root,
|
|
307
|
+
cacheDir: options.cacheDir,
|
|
308
|
+
env: effectiveEnv,
|
|
309
|
+
});
|
|
310
|
+
const descriptorCache: DescriptorCacheOptions = {
|
|
266
311
|
cacheDir: options.cacheDir,
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
const entryParent = path.join(entry.baseDir, "package.json");
|
|
284
|
-
const probedCandidates = collectModuleResolutionCandidates(
|
|
285
|
-
specifier,
|
|
286
|
-
entryParent,
|
|
287
|
-
undefined,
|
|
288
|
-
);
|
|
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(
|
|
312
|
+
identities,
|
|
313
|
+
projectRoot: project.root,
|
|
314
|
+
version: pluginBuildVersions(project.root).ttsc,
|
|
315
|
+
};
|
|
316
|
+
const loadedEntries = withPluginLoaderEnv(
|
|
317
|
+
() =>
|
|
318
|
+
entries.map((entry) => {
|
|
319
|
+
const specifier = entry.config.transform;
|
|
320
|
+
if (typeof specifier !== "string" || specifier.length === 0) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
`ttsc: plugin entry is missing a string "transform" field`,
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
const entryParent = path.join(entry.baseDir, "package.json");
|
|
326
|
+
const probedCandidates = collectModuleResolutionCandidates(
|
|
304
327
|
specifier,
|
|
305
328
|
entryParent,
|
|
329
|
+
undefined,
|
|
330
|
+
);
|
|
331
|
+
// Capture every candidate before resolution chooses the descriptor entry.
|
|
332
|
+
// A post-resolution snapshot could bless a higher-priority file created
|
|
333
|
+
// after the resolver had already selected the old entry.
|
|
334
|
+
const probedCandidateHashes = hashHostInputPaths(probedCandidates);
|
|
335
|
+
const probedCandidateRealpaths =
|
|
336
|
+
realpathHostInputPaths(probedCandidates);
|
|
337
|
+
const request = PluginPackageResolution.resolvePluginRequest(
|
|
338
|
+
specifier,
|
|
339
|
+
entry.baseDir,
|
|
340
|
+
);
|
|
341
|
+
// Keep the candidates of the search roots up to the one the entry
|
|
342
|
+
// resolved in: the lookup never read the roots after it
|
|
343
|
+
// (`moduleResolutionBaseSelects`).
|
|
344
|
+
const read = new Set(
|
|
345
|
+
collectModuleResolutionCandidates(
|
|
346
|
+
specifier,
|
|
347
|
+
entryParent,
|
|
348
|
+
request,
|
|
349
|
+
).map((candidate) => path.resolve(candidate)),
|
|
350
|
+
);
|
|
351
|
+
const entryCandidates = probedCandidates.filter((candidate) =>
|
|
352
|
+
read.has(path.resolve(candidate)),
|
|
353
|
+
);
|
|
354
|
+
const entryCandidateHashes = pickHostInputEntries(
|
|
355
|
+
probedCandidateHashes,
|
|
356
|
+
entryCandidates,
|
|
357
|
+
);
|
|
358
|
+
const entryCandidateRealpaths = pickHostInputEntries(
|
|
359
|
+
probedCandidateRealpaths,
|
|
360
|
+
entryCandidates,
|
|
361
|
+
);
|
|
362
|
+
const loaded = loadPluginEntry(
|
|
363
|
+
entry.config,
|
|
364
|
+
{
|
|
365
|
+
...context,
|
|
366
|
+
plugin: entry.config,
|
|
367
|
+
// Package factories such as typia resolve their own package from
|
|
368
|
+
// this consumer anchor. Keep the compiler source root below for
|
|
369
|
+
// native cwd, cache ownership and returned relative Go sources.
|
|
370
|
+
projectRoot: ProjectPluginEntries.resolvePluginBaseDir(
|
|
371
|
+
project,
|
|
372
|
+
options.pluginConfigDir,
|
|
373
|
+
),
|
|
374
|
+
},
|
|
306
375
|
request,
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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];
|
|
376
|
+
effectiveEnv,
|
|
377
|
+
descriptorCache,
|
|
378
|
+
);
|
|
379
|
+
const loadedHostInputHashes = mergeObservedHostInputHashes(
|
|
380
|
+
loaded.hostInputHashes,
|
|
381
|
+
hashHostInputPaths(Object.keys(loaded.hostInputHashes)),
|
|
382
|
+
);
|
|
383
|
+
const loadedHostInputRealpaths = mergeObservedHostInputRealpaths(
|
|
384
|
+
loaded.hostInputRealpaths,
|
|
385
|
+
realpathHostInputPaths(Object.keys(loaded.hostInputRealpaths)),
|
|
386
|
+
);
|
|
387
|
+
const hostInputHashes = mergeObservedHostInputHashes(
|
|
388
|
+
entryCandidateHashes,
|
|
389
|
+
loadedHostInputHashes,
|
|
390
|
+
);
|
|
391
|
+
const hostInputRealpaths = mergeObservedHostInputRealpaths(
|
|
392
|
+
entryCandidateRealpaths,
|
|
393
|
+
loadedHostInputRealpaths,
|
|
394
|
+
);
|
|
395
|
+
for (const input of loaded.hostInputs) {
|
|
396
|
+
const absolute = path.resolve(input);
|
|
397
|
+
if (
|
|
398
|
+
!Object.prototype.hasOwnProperty.call(
|
|
399
|
+
loadedHostInputHashes,
|
|
400
|
+
absolute,
|
|
401
|
+
)
|
|
402
|
+
) {
|
|
403
|
+
delete hostInputHashes[absolute];
|
|
404
|
+
}
|
|
352
405
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
);
|
|
406
|
+
return {
|
|
407
|
+
...loaded,
|
|
408
|
+
hostInputHashes,
|
|
409
|
+
hostInputRealpaths,
|
|
410
|
+
hostInputs: [...loaded.hostInputs, ...entryCandidates],
|
|
411
|
+
request,
|
|
412
|
+
};
|
|
413
|
+
}),
|
|
414
|
+
identities,
|
|
415
|
+
);
|
|
416
|
+
const plugins = composePluginSources(
|
|
417
|
+
entries,
|
|
418
|
+
loadedEntries.map((entry) => entry.plugin),
|
|
419
|
+
);
|
|
368
420
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
);
|
|
372
|
-
const candidates = plugins
|
|
373
|
-
.map((plugin, index) => {
|
|
374
|
-
const stage = PluginDescriptorAdmission.stage(plugin);
|
|
375
|
-
validatePluginSource(plugin);
|
|
376
|
-
const contributors = validatePluginContributors(plugin);
|
|
377
|
-
const source = resolvePluginSource(plugin.source, context.projectRoot);
|
|
378
|
-
const label = pluginLabel(plugin, entries[index]!.config, index);
|
|
379
|
-
requirePluginSource(source, label);
|
|
380
|
-
return { plugin, index, stage, contributors, source, label };
|
|
381
|
-
})
|
|
382
|
-
.map((candidate) => ({
|
|
383
|
-
...candidate,
|
|
384
|
-
...resolvePluginGoModule(candidate.source, candidate.label),
|
|
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
|
-
]);
|
|
413
|
-
// One fixed-effective-environment load owns manifest syntax sharing from the
|
|
414
|
-
// first watch query through metadata and builds. Do not allocate this after
|
|
415
|
-
// watch projection: that silently repeats selected-Go work (#1712).
|
|
416
|
-
const packageReaders = new Map<string, SourcePluginWorkspace.GoModReader>();
|
|
417
|
-
const watchReplacements =
|
|
418
|
-
options.onWatchInputs === undefined
|
|
419
|
-
? undefined
|
|
420
|
-
: new Map<string, readonly string[]>();
|
|
421
|
-
if (options.onWatchInputs !== undefined) {
|
|
422
|
-
// The prospective context reads the admitted module layout and anchors its
|
|
423
|
-
// tool there before kind exists. Keep both possible final-root baselines:
|
|
424
|
-
// a linked package keeps packageDir, and an executable keeps moduleRoot.
|
|
425
|
-
const interests = new Set(
|
|
426
|
-
candidates
|
|
427
|
-
.flatMap((candidate) => [
|
|
428
|
-
candidate.moduleRoot,
|
|
429
|
-
candidate.packageDir,
|
|
430
|
-
...(candidate.contributors ?? []).map((input) => input.source),
|
|
431
|
-
])
|
|
432
|
-
.filter(reportsPluginSource),
|
|
421
|
+
const { ttsc: ttscVersion, tsgo: tsgoVersion } = pluginBuildVersions(
|
|
422
|
+
context.projectRoot,
|
|
433
423
|
);
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
424
|
+
const candidates = plugins
|
|
425
|
+
.map((plugin, index) => {
|
|
426
|
+
const stage = PluginDescriptorAdmission.stage(plugin);
|
|
427
|
+
validatePluginSource(plugin);
|
|
428
|
+
const contributors = validatePluginContributors(plugin);
|
|
429
|
+
const source = resolvePluginSource(plugin.source, context.projectRoot);
|
|
430
|
+
const label = pluginLabel(plugin, entries[index]!.config, index);
|
|
431
|
+
requirePluginSource(source, label);
|
|
432
|
+
return { plugin, index, stage, contributors, source, label };
|
|
433
|
+
})
|
|
434
|
+
.map((candidate) => ({
|
|
435
|
+
...candidate,
|
|
436
|
+
...resolvePluginGoModule(candidate.source, candidate.label),
|
|
437
|
+
}));
|
|
438
|
+
// One reading of each source directory, shared by package selection and
|
|
439
|
+
// every build below and reported as the state the binaries were keyed on.
|
|
440
|
+
const sourceDigests = new Map<string, string>();
|
|
441
|
+
// And one reading of the environment each build directory is keyed on, which
|
|
442
|
+
// a plugin module root's state reports as it is.
|
|
443
|
+
const environmentDigests = new Map<string, string>();
|
|
444
|
+
// With the witness of each such reading, so a build of a directory package
|
|
445
|
+
// selection already read keys on that reading instead of probing Go again.
|
|
446
|
+
const environmentWitnesses = new Map<
|
|
447
|
+
string,
|
|
448
|
+
PluginBuildEnvironmentWitness.Record
|
|
449
|
+
>();
|
|
450
|
+
const readings = {
|
|
451
|
+
sources: sourceDigests,
|
|
452
|
+
environments: environmentDigests,
|
|
453
|
+
witnesses: environmentWitnesses,
|
|
454
|
+
};
|
|
455
|
+
// Records describing sources must never land inside one, so the store is
|
|
456
|
+
// admitted for source proofs only once every source of the load is known.
|
|
457
|
+
const sourceIdentities = PluginContentIdentities.outside(identities, [
|
|
458
|
+
...candidates.flatMap((candidate) => [
|
|
444
459
|
candidate.moduleRoot,
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
index,
|
|
471
|
-
{
|
|
472
|
-
env: effectiveEnv,
|
|
473
|
-
observation: proposals[index]!.observation,
|
|
474
|
-
},
|
|
460
|
+
candidate.packageDir,
|
|
461
|
+
...(candidate.contributors ?? []).map((input) => input.source),
|
|
462
|
+
]),
|
|
463
|
+
...SourcePluginWorkspace.findTtscOverlayDirs(),
|
|
464
|
+
]);
|
|
465
|
+
// One fixed-effective-environment load owns manifest syntax sharing from the
|
|
466
|
+
// first watch query through metadata and builds. Do not allocate this after
|
|
467
|
+
// watch projection: that silently repeats selected-Go work (#1712).
|
|
468
|
+
const packageReaders = new Map<string, SourcePluginWorkspace.GoModReader>();
|
|
469
|
+
const watchReplacements =
|
|
470
|
+
options.onWatchInputs === undefined
|
|
471
|
+
? undefined
|
|
472
|
+
: new Map<string, readonly string[]>();
|
|
473
|
+
if (options.onWatchInputs !== undefined) {
|
|
474
|
+
// The prospective context reads the admitted module layout and anchors its
|
|
475
|
+
// tool there before kind exists. Keep both possible final-root baselines:
|
|
476
|
+
// a linked package keeps packageDir, and an executable keeps moduleRoot.
|
|
477
|
+
const interests = new Set(
|
|
478
|
+
candidates
|
|
479
|
+
.flatMap((candidate) => [
|
|
480
|
+
candidate.moduleRoot,
|
|
481
|
+
candidate.packageDir,
|
|
482
|
+
...(candidate.contributors ?? []).map((input) => input.source),
|
|
483
|
+
])
|
|
484
|
+
.filter(reportsPluginSource),
|
|
475
485
|
);
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
486
|
+
// WARNING (#1728): hand the watch owner this load's store with the roots.
|
|
487
|
+
// It baselines each root before any build reads it; without the store it
|
|
488
|
+
// read every source the load proves from records a moment later.
|
|
489
|
+
// A worker owns the watch baseline now. Complete this handoff before Go
|
|
490
|
+
// metadata or source proof consumes the roots, preserving #1728 (#1758).
|
|
491
|
+
yield options.onWatchInputs([...interests].sort(), sourceIdentities);
|
|
492
|
+
const initialSize = interests.size;
|
|
493
|
+
for (const candidate of candidates) {
|
|
494
|
+
// Nested source-only proposals replace the outer root manifests. Do not
|
|
495
|
+
// activate their irrelevant module graph just to discover watch inputs.
|
|
496
|
+
if (candidate.stage === "transform" && candidate.entry !== ".")
|
|
497
|
+
continue;
|
|
498
|
+
for (const directory of pluginReplacementWatchDirectories(
|
|
499
|
+
candidate.moduleRoot,
|
|
500
|
+
effectiveEnv,
|
|
501
|
+
watchReplacements,
|
|
502
|
+
packageReaders,
|
|
503
|
+
sourceIdentities,
|
|
504
|
+
))
|
|
505
|
+
if (reportsPluginSource(directory)) interests.add(directory);
|
|
480
506
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
507
|
+
if (interests.size !== initialSize)
|
|
508
|
+
yield options.onWatchInputs([...interests].sort(), sourceIdentities);
|
|
509
|
+
}
|
|
510
|
+
const proposals = NativeSourcePackages.propose(
|
|
511
|
+
candidates.map((candidate) => ({
|
|
512
|
+
...candidate,
|
|
513
|
+
ownModule: candidate.stage !== "transform",
|
|
514
|
+
})),
|
|
515
|
+
effectiveEnv,
|
|
516
|
+
packageReaders,
|
|
517
|
+
sourceIdentities,
|
|
518
|
+
readings,
|
|
519
|
+
);
|
|
520
|
+
const records = candidates.map(
|
|
521
|
+
({ plugin, index, stage, contributors, source, packageDir }) => {
|
|
522
|
+
const { kind, moduleRoot } = resolveNativeSource(
|
|
523
|
+
source,
|
|
524
|
+
plugin,
|
|
525
|
+
entries[index]!.config,
|
|
526
|
+
index,
|
|
527
|
+
{
|
|
528
|
+
env: effectiveEnv,
|
|
529
|
+
observation: proposals[index]!.observation,
|
|
530
|
+
},
|
|
531
|
+
);
|
|
532
|
+
if (kind === "linked" && stage !== "transform") {
|
|
533
|
+
throw new Error(
|
|
534
|
+
`ttsc: plugin "${pluginLabel(plugin, entries[index]!.config, index)}" source is a linked Go package, but only transform-stage plugins can be linked into a compiler host`,
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
const linkedContributorName =
|
|
538
|
+
kind === "linked"
|
|
539
|
+
? `linked_${String(index).padStart(6, "0")}`
|
|
540
|
+
: undefined;
|
|
541
|
+
const hostInputs = validatePluginHostInputs(plugin, index);
|
|
542
|
+
const pluginHostInputHashes = validatePluginHostInputHashes(
|
|
543
|
+
plugin,
|
|
544
|
+
index,
|
|
511
545
|
hostInputs,
|
|
512
|
-
)
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
loadedEntries[index]!.hostInputs,
|
|
546
|
+
);
|
|
547
|
+
const pluginHostInputRealpaths = validatePluginHostInputRealpaths(
|
|
548
|
+
plugin,
|
|
549
|
+
index,
|
|
517
550
|
hostInputs,
|
|
518
|
-
)
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
551
|
+
);
|
|
552
|
+
return {
|
|
553
|
+
capabilities: plugin.capabilities,
|
|
554
|
+
contributors,
|
|
555
|
+
config: entries[index]!.config,
|
|
556
|
+
kind,
|
|
557
|
+
label: pluginLabel(plugin, entries[index]!.config, index),
|
|
558
|
+
linkedContributorName,
|
|
559
|
+
name: plugin.name,
|
|
560
|
+
reportsTypeScriptDiagnostics:
|
|
561
|
+
plugin.reportsTypeScriptDiagnostics === true,
|
|
562
|
+
request: loadedEntries[index]!.request,
|
|
563
|
+
hostInputHashes: mergePluginHostInputHashes(
|
|
564
|
+
loadedEntries[index]!.hostInputHashes,
|
|
565
|
+
pluginHostInputHashes,
|
|
566
|
+
loadedEntries[index]!.hostInputs,
|
|
567
|
+
hostInputs,
|
|
568
|
+
),
|
|
569
|
+
hostInputRealpaths: mergePluginHostInputHashes(
|
|
570
|
+
loadedEntries[index]!.hostInputRealpaths,
|
|
571
|
+
pluginHostInputRealpaths,
|
|
572
|
+
loadedEntries[index]!.hostInputs,
|
|
573
|
+
hostInputs,
|
|
574
|
+
),
|
|
575
|
+
hostInputs: [...loadedEntries[index]!.hostInputs, ...hostInputs],
|
|
576
|
+
moduleRoot,
|
|
577
|
+
packageDir,
|
|
578
|
+
source,
|
|
579
|
+
stage,
|
|
580
|
+
};
|
|
581
|
+
},
|
|
548
582
|
);
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
583
|
+
const executableCandidates = candidates.filter(
|
|
584
|
+
(candidate) =>
|
|
585
|
+
records[candidate.index]!.kind === "executable" &&
|
|
586
|
+
!proposals[candidate.index]!.ownModule,
|
|
587
|
+
);
|
|
588
|
+
const buildDirectories = pluginBuildDirectories(
|
|
589
|
+
records,
|
|
590
|
+
effectiveEnv,
|
|
591
|
+
watchReplacements,
|
|
592
|
+
packageReaders,
|
|
593
|
+
sourceIdentities,
|
|
594
|
+
);
|
|
595
|
+
// Admission can now narrow the provisional interests without restamping the
|
|
596
|
+
// retained package/module baselines. Final host errors still keep these roots.
|
|
597
|
+
yield options.onWatchInputs?.(buildDirectories, sourceIdentities);
|
|
598
|
+
const keyedDirectories = new Set(buildDirectories);
|
|
599
|
+
const linkedContributors = records
|
|
600
|
+
.filter((record) => record.stage === "transform")
|
|
601
|
+
.flatMap((record) =>
|
|
602
|
+
record.kind === "linked"
|
|
603
|
+
? [{ name: record.linkedContributorName!, source: record.source }]
|
|
604
|
+
: [],
|
|
605
|
+
);
|
|
606
|
+
const transformHosts = records.filter(
|
|
607
|
+
(record) => record.stage === "transform" && record.kind === "executable",
|
|
608
|
+
);
|
|
609
|
+
const hostContributors =
|
|
610
|
+
linkedContributors.length === 0 ? undefined : linkedContributors;
|
|
611
|
+
// Every host compiles the linked sources under its own module/tool context.
|
|
612
|
+
// Equivalent entries in one module share this metadata command and reader;
|
|
613
|
+
// a second executable host can select a genuinely different Go context.
|
|
614
|
+
const admittedExecutables = new Set<string>();
|
|
615
|
+
if (linkedContributors.length !== 0) {
|
|
616
|
+
const hosts =
|
|
617
|
+
transformHosts.length === 0
|
|
618
|
+
? [
|
|
619
|
+
{
|
|
620
|
+
source: path.join(ttscPackageRoot(), "cmd", "utility-host"),
|
|
621
|
+
label: "linked-plugin-host",
|
|
622
|
+
},
|
|
623
|
+
]
|
|
624
|
+
: transformHosts;
|
|
625
|
+
const contexts = new Map<
|
|
626
|
+
string,
|
|
627
|
+
{ source: string; label: string; records: typeof transformHosts }
|
|
628
|
+
>();
|
|
629
|
+
for (const host of hosts) {
|
|
630
|
+
const moduleRoot = resolvePluginGoModule(
|
|
631
|
+
host.source,
|
|
632
|
+
host.label,
|
|
633
|
+
).moduleRoot;
|
|
634
|
+
let context = contexts.get(moduleRoot);
|
|
635
|
+
if (context === undefined) {
|
|
636
|
+
context = { source: host.source, label: host.label, records: [] };
|
|
637
|
+
contexts.set(moduleRoot, context);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
for (const record of transformHosts)
|
|
641
|
+
contexts.get(record.moduleRoot)!.records.push(record);
|
|
642
|
+
for (const host of contexts.values()) {
|
|
643
|
+
const moduleHosts = host.records;
|
|
644
|
+
const hostEntries = moduleHosts.map((record) => ({
|
|
645
|
+
entry: resolvePluginGoModule(record.source, record.label).entry,
|
|
646
|
+
}));
|
|
647
|
+
const observations = NativeSourcePackages.inspect({
|
|
648
|
+
source: host.source,
|
|
649
|
+
pluginName: host.label,
|
|
650
|
+
env: effectiveEnv,
|
|
651
|
+
readers: packageReaders,
|
|
652
|
+
identities: sourceIdentities,
|
|
653
|
+
readings,
|
|
654
|
+
packages: [
|
|
655
|
+
...hostEntries,
|
|
656
|
+
...linkedContributors.map((input) => ({
|
|
657
|
+
...input,
|
|
658
|
+
entry: `./contrib/${input.name}`,
|
|
659
|
+
})),
|
|
660
|
+
],
|
|
661
|
+
});
|
|
662
|
+
moduleHosts.forEach((record, index) => {
|
|
663
|
+
NativeSourcePackages.kind(
|
|
664
|
+
observations[index]!,
|
|
665
|
+
record.label,
|
|
666
|
+
"executable",
|
|
667
|
+
);
|
|
668
|
+
admittedExecutables.add(record.source);
|
|
669
|
+
});
|
|
670
|
+
linkedContributors.forEach((input, index) => {
|
|
671
|
+
NativeSourcePackages.kind(
|
|
672
|
+
observations[hostEntries.length + index]!,
|
|
673
|
+
`${input.name} inside host ${host.label}`,
|
|
674
|
+
"linked",
|
|
675
|
+
);
|
|
676
|
+
});
|
|
581
677
|
}
|
|
582
678
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
entry: resolvePluginGoModule(record.source, record.label).entry,
|
|
589
|
-
}));
|
|
590
|
-
const observations = NativeSourcePackages.inspect({
|
|
591
|
-
source: host.source,
|
|
592
|
-
pluginName: host.label,
|
|
593
|
-
env: effectiveEnv,
|
|
594
|
-
readers: packageReaders,
|
|
595
|
-
identities: sourceIdentities,
|
|
596
|
-
readings,
|
|
597
|
-
packages: [
|
|
598
|
-
...hostEntries,
|
|
599
|
-
...linkedContributors.map((input) => ({
|
|
600
|
-
...input,
|
|
601
|
-
entry: `./contrib/${input.name}`,
|
|
602
|
-
})),
|
|
603
|
-
],
|
|
604
|
-
});
|
|
605
|
-
moduleHosts.forEach((record, index) => {
|
|
606
|
-
NativeSourcePackages.kind(
|
|
607
|
-
observations[index]!,
|
|
608
|
-
record.label,
|
|
609
|
-
"executable",
|
|
610
|
-
);
|
|
611
|
-
admittedExecutables.add(record.source);
|
|
612
|
-
});
|
|
613
|
-
linkedContributors.forEach((input, index) => {
|
|
614
|
-
NativeSourcePackages.kind(
|
|
615
|
-
observations[hostEntries.length + index]!,
|
|
616
|
-
`${input.name} inside host ${host.label}`,
|
|
617
|
-
"linked",
|
|
618
|
-
);
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
// A nested main proposal still needs its actual owning manifests. Hosts
|
|
623
|
-
// with linked contributors were admitted together above; other equivalent
|
|
624
|
-
// entries share one standalone observation, with no repeated host copy.
|
|
625
|
-
const standaloneCandidates = executableCandidates.filter(
|
|
626
|
-
(candidate) => !admittedExecutables.has(candidate.source),
|
|
627
|
-
);
|
|
628
|
-
const executablePackages = NativeSourcePackages.ownPackages(
|
|
629
|
-
standaloneCandidates,
|
|
630
|
-
effectiveEnv,
|
|
631
|
-
packageReaders,
|
|
632
|
-
sourceIdentities,
|
|
633
|
-
readings,
|
|
634
|
-
);
|
|
635
|
-
standaloneCandidates.forEach((candidate, index) => {
|
|
636
|
-
NativeSourcePackages.kind(
|
|
637
|
-
executablePackages[index]!,
|
|
638
|
-
candidate.label,
|
|
639
|
-
"executable",
|
|
679
|
+
// A nested main proposal still needs its actual owning manifests. Hosts
|
|
680
|
+
// with linked contributors were admitted together above; other equivalent
|
|
681
|
+
// entries share one standalone observation, with no repeated host copy.
|
|
682
|
+
const standaloneCandidates = executableCandidates.filter(
|
|
683
|
+
(candidate) => !admittedExecutables.has(candidate.source),
|
|
640
684
|
);
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
...(linked
|
|
648
|
-
? linkedContributors.map((input) => ({
|
|
649
|
-
entry: `./contrib/${input.name}`,
|
|
650
|
-
kind: "linked" as const,
|
|
651
|
-
}))
|
|
652
|
-
: []),
|
|
653
|
-
];
|
|
654
|
-
const builtTransformHosts = new Map<object, string>();
|
|
655
|
-
for (const record of transformHosts) {
|
|
656
|
-
builtTransformHosts.set(
|
|
657
|
-
record,
|
|
658
|
-
buildSourcePlugin({
|
|
659
|
-
baseDir: context.projectRoot,
|
|
660
|
-
cacheDir: options.cacheDir,
|
|
661
|
-
contributors: mergeContributors(record.contributors, hostContributors),
|
|
662
|
-
env: effectiveEnv,
|
|
663
|
-
goModReaders: packageReaders,
|
|
664
|
-
identities: sourceIdentities,
|
|
665
|
-
pluginName: record.label,
|
|
666
|
-
packageOwnership: packageOwnership(record.source, record.label, true),
|
|
667
|
-
source: record.source,
|
|
668
|
-
environmentDigests,
|
|
669
|
-
environmentWitnesses,
|
|
670
|
-
sourceDigests,
|
|
671
|
-
ttscVersion,
|
|
672
|
-
tsgoVersion,
|
|
673
|
-
}),
|
|
685
|
+
const executablePackages = NativeSourcePackages.ownPackages(
|
|
686
|
+
standaloneCandidates,
|
|
687
|
+
effectiveEnv,
|
|
688
|
+
packageReaders,
|
|
689
|
+
sourceIdentities,
|
|
690
|
+
readings,
|
|
674
691
|
);
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
692
|
+
standaloneCandidates.forEach((candidate, index) => {
|
|
693
|
+
NativeSourcePackages.kind(
|
|
694
|
+
executablePackages[index]!,
|
|
695
|
+
candidate.label,
|
|
696
|
+
"executable",
|
|
697
|
+
);
|
|
698
|
+
});
|
|
699
|
+
const packageOwnership = (
|
|
700
|
+
source: string,
|
|
701
|
+
label: string,
|
|
702
|
+
linked: boolean,
|
|
703
|
+
) => [
|
|
704
|
+
{
|
|
705
|
+
entry: resolvePluginGoModule(source, label).entry,
|
|
706
|
+
kind: "executable" as const,
|
|
707
|
+
},
|
|
708
|
+
...(linked
|
|
709
|
+
? linkedContributors.map((input) => ({
|
|
710
|
+
entry: `./contrib/${input.name}`,
|
|
711
|
+
kind: "linked" as const,
|
|
712
|
+
}))
|
|
713
|
+
: []),
|
|
714
|
+
];
|
|
715
|
+
const builtTransformHosts = new Map<object, string>();
|
|
716
|
+
for (const record of transformHosts) {
|
|
717
|
+
builtTransformHosts.set(
|
|
718
|
+
record,
|
|
719
|
+
buildSourcePlugin({
|
|
679
720
|
baseDir: context.projectRoot,
|
|
680
721
|
cacheDir: options.cacheDir,
|
|
681
|
-
contributors:
|
|
722
|
+
contributors: mergeContributors(
|
|
723
|
+
record.contributors,
|
|
724
|
+
hostContributors,
|
|
725
|
+
),
|
|
682
726
|
env: effectiveEnv,
|
|
683
727
|
goModReaders: packageReaders,
|
|
684
728
|
identities: sourceIdentities,
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
source:
|
|
688
|
-
packageOwnership: packageOwnership(
|
|
689
|
-
path.join(ttscPackageRoot(), "cmd", "utility-host"),
|
|
690
|
-
"linked-plugin-host",
|
|
691
|
-
true,
|
|
692
|
-
),
|
|
729
|
+
pluginName: record.label,
|
|
730
|
+
packageOwnership: packageOwnership(record.source, record.label, true),
|
|
731
|
+
source: record.source,
|
|
693
732
|
environmentDigests,
|
|
694
733
|
environmentWitnesses,
|
|
695
734
|
sourceDigests,
|
|
696
735
|
ttscVersion,
|
|
697
736
|
tsgoVersion,
|
|
698
|
-
})
|
|
699
|
-
: undefined;
|
|
700
|
-
const selectedTransformHost =
|
|
701
|
-
transformHosts.length === 0
|
|
702
|
-
? fallbackDriverHost
|
|
703
|
-
: builtTransformHosts.get(transformHosts[0]!);
|
|
704
|
-
const nativePlugins: ITtscLoadedNativePlugin[] = records.map((record) => {
|
|
705
|
-
const binary =
|
|
706
|
-
record.stage === "transform" && record.kind === "linked"
|
|
707
|
-
? selectedTransformHost
|
|
708
|
-
: record.stage === "transform"
|
|
709
|
-
? builtTransformHosts.get(record)
|
|
710
|
-
: buildSourcePlugin({
|
|
711
|
-
baseDir: context.projectRoot,
|
|
712
|
-
cacheDir: options.cacheDir,
|
|
713
|
-
contributors: record.contributors,
|
|
714
|
-
env: effectiveEnv,
|
|
715
|
-
goModReaders: packageReaders,
|
|
716
|
-
identities: sourceIdentities,
|
|
717
|
-
pluginName: record.label,
|
|
718
|
-
packageOwnership: packageOwnership(
|
|
719
|
-
record.source,
|
|
720
|
-
record.label,
|
|
721
|
-
false,
|
|
722
|
-
),
|
|
723
|
-
source: record.source,
|
|
724
|
-
environmentDigests,
|
|
725
|
-
environmentWitnesses,
|
|
726
|
-
sourceDigests,
|
|
727
|
-
ttscVersion,
|
|
728
|
-
tsgoVersion,
|
|
729
|
-
});
|
|
730
|
-
if (binary === undefined) {
|
|
731
|
-
throw new Error(
|
|
732
|
-
`ttsc: plugin "${record.label}" is a linked Go package, but no compiler host is available`,
|
|
737
|
+
}),
|
|
733
738
|
);
|
|
734
739
|
}
|
|
740
|
+
const fallbackDriverHost =
|
|
741
|
+
transformHosts.length === 0 && linkedContributors.length !== 0
|
|
742
|
+
? buildSourcePlugin({
|
|
743
|
+
baseDir: context.projectRoot,
|
|
744
|
+
cacheDir: options.cacheDir,
|
|
745
|
+
contributors: linkedContributors,
|
|
746
|
+
env: effectiveEnv,
|
|
747
|
+
goModReaders: packageReaders,
|
|
748
|
+
identities: sourceIdentities,
|
|
749
|
+
label: "linked plugin host",
|
|
750
|
+
pluginName: "linked-plugin-host",
|
|
751
|
+
source: path.join(ttscPackageRoot(), "cmd", "utility-host"),
|
|
752
|
+
packageOwnership: packageOwnership(
|
|
753
|
+
path.join(ttscPackageRoot(), "cmd", "utility-host"),
|
|
754
|
+
"linked-plugin-host",
|
|
755
|
+
true,
|
|
756
|
+
),
|
|
757
|
+
environmentDigests,
|
|
758
|
+
environmentWitnesses,
|
|
759
|
+
sourceDigests,
|
|
760
|
+
ttscVersion,
|
|
761
|
+
tsgoVersion,
|
|
762
|
+
})
|
|
763
|
+
: undefined;
|
|
764
|
+
const selectedTransformHost =
|
|
765
|
+
transformHosts.length === 0
|
|
766
|
+
? fallbackDriverHost
|
|
767
|
+
: builtTransformHosts.get(transformHosts[0]!);
|
|
768
|
+
const nativePlugins: ITtscLoadedNativePlugin[] = records.map((record) => {
|
|
769
|
+
const binary =
|
|
770
|
+
record.stage === "transform" && record.kind === "linked"
|
|
771
|
+
? selectedTransformHost
|
|
772
|
+
: record.stage === "transform"
|
|
773
|
+
? builtTransformHosts.get(record)
|
|
774
|
+
: buildSourcePlugin({
|
|
775
|
+
baseDir: context.projectRoot,
|
|
776
|
+
cacheDir: options.cacheDir,
|
|
777
|
+
contributors: record.contributors,
|
|
778
|
+
env: effectiveEnv,
|
|
779
|
+
goModReaders: packageReaders,
|
|
780
|
+
identities: sourceIdentities,
|
|
781
|
+
pluginName: record.label,
|
|
782
|
+
packageOwnership: packageOwnership(
|
|
783
|
+
record.source,
|
|
784
|
+
record.label,
|
|
785
|
+
false,
|
|
786
|
+
),
|
|
787
|
+
source: record.source,
|
|
788
|
+
environmentDigests,
|
|
789
|
+
environmentWitnesses,
|
|
790
|
+
sourceDigests,
|
|
791
|
+
ttscVersion,
|
|
792
|
+
tsgoVersion,
|
|
793
|
+
});
|
|
794
|
+
if (binary === undefined) {
|
|
795
|
+
throw new Error(
|
|
796
|
+
`ttsc: plugin "${record.label}" is a linked Go package, but no compiler host is available`,
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
return {
|
|
800
|
+
binary,
|
|
801
|
+
// This fallback is compiled from our utility-host, whose actual writer
|
|
802
|
+
// publishes provenance and supports a separate compiler argument cwd.
|
|
803
|
+
// A separately selected executable host must opt in itself; a linked
|
|
804
|
+
// library cannot certify that foreign host. An undeclared capability
|
|
805
|
+
// only withholds the optional protocol: build execution still runs such
|
|
806
|
+
// a host and observes it from outside, never rejecting it.
|
|
807
|
+
capabilities:
|
|
808
|
+
record.stage === "transform" &&
|
|
809
|
+
record.kind === "linked" &&
|
|
810
|
+
fallbackDriverHost !== undefined
|
|
811
|
+
? {
|
|
812
|
+
...record.capabilities,
|
|
813
|
+
compilerArgsCwd: true,
|
|
814
|
+
emitProvenance: true,
|
|
815
|
+
}
|
|
816
|
+
: record.capabilities,
|
|
817
|
+
config: record.config,
|
|
818
|
+
contributors: record.contributors,
|
|
819
|
+
kind: record.kind,
|
|
820
|
+
name: record.name,
|
|
821
|
+
reportsTypeScriptDiagnostics: record.reportsTypeScriptDiagnostics,
|
|
822
|
+
source: record.source,
|
|
823
|
+
stage: record.stage,
|
|
824
|
+
};
|
|
825
|
+
});
|
|
735
826
|
return {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
// library cannot certify that foreign host. An undeclared capability
|
|
741
|
-
// only withholds the optional protocol: build execution still runs such
|
|
742
|
-
// a host and observes it from outside, never rejecting it.
|
|
743
|
-
capabilities:
|
|
744
|
-
record.stage === "transform" &&
|
|
745
|
-
record.kind === "linked" &&
|
|
746
|
-
fallbackDriverHost !== undefined
|
|
747
|
-
? {
|
|
748
|
-
...record.capabilities,
|
|
749
|
-
compilerArgsCwd: true,
|
|
750
|
-
emitProvenance: true,
|
|
751
|
-
}
|
|
752
|
-
: record.capabilities,
|
|
753
|
-
config: record.config,
|
|
754
|
-
contributors: record.contributors,
|
|
755
|
-
kind: record.kind,
|
|
756
|
-
name: record.name,
|
|
757
|
-
reportsTypeScriptDiagnostics: record.reportsTypeScriptDiagnostics,
|
|
758
|
-
source: record.source,
|
|
759
|
-
stage: record.stage,
|
|
760
|
-
};
|
|
761
|
-
});
|
|
762
|
-
return {
|
|
763
|
-
...collectHostInputSnapshot(
|
|
764
|
-
project,
|
|
765
|
-
context,
|
|
766
|
-
records,
|
|
767
|
-
projectHostInputs,
|
|
768
|
-
revalidateHostInputHashes(projectHostInputHashes, projectHostInputs),
|
|
769
|
-
revalidateHostInputRealpaths(
|
|
770
|
-
projectHostInputRealpaths,
|
|
827
|
+
...collectHostInputSnapshot(
|
|
828
|
+
project,
|
|
829
|
+
context,
|
|
830
|
+
records,
|
|
771
831
|
projectHostInputs,
|
|
832
|
+
revalidateHostInputHashes(projectHostInputHashes, projectHostInputs),
|
|
833
|
+
revalidateHostInputRealpaths(
|
|
834
|
+
projectHostInputRealpaths,
|
|
835
|
+
projectHostInputs,
|
|
836
|
+
),
|
|
772
837
|
),
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
}
|
|
838
|
+
descriptorReadsDeclared: loadedEntries.every(
|
|
839
|
+
(entry) =>
|
|
840
|
+
entry.observationsComplete && declaresHostInputReads(entry.plugin),
|
|
841
|
+
),
|
|
842
|
+
discoveryInputsComplete: project.configInputsComplete === true,
|
|
843
|
+
...(identities === undefined ? {} : { identities }),
|
|
844
|
+
nativePlugins: orderNativePlugins(nativePlugins),
|
|
845
|
+
...(loadedEntries.some((entry) => !entry.observationsComplete)
|
|
846
|
+
? { observationsComplete: false as const }
|
|
847
|
+
: {}),
|
|
848
|
+
// The directories the watch inputs named before the builds, as the builds
|
|
849
|
+
// read them. Package selection shares these readings and also reads a
|
|
850
|
+
// linked plugin's module root, which no build keys on, so only the build
|
|
851
|
+
// directories are reported.
|
|
852
|
+
pluginSources: Object.fromEntries(
|
|
853
|
+
[...sourceDigests]
|
|
854
|
+
.filter(([directory]) => keyedDirectories.has(directory))
|
|
855
|
+
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
|
|
856
|
+
.map(([directory, sourceDigest]) => [
|
|
857
|
+
directory,
|
|
858
|
+
pluginSourceState(directory, {
|
|
859
|
+
env: effectiveEnv,
|
|
860
|
+
sourceDigest,
|
|
861
|
+
environment:
|
|
862
|
+
environmentDigests.get(directory) ??
|
|
863
|
+
pluginBuildEnvironment(
|
|
864
|
+
directory,
|
|
865
|
+
effectiveEnv,
|
|
866
|
+
undefined,
|
|
867
|
+
sourceIdentities,
|
|
868
|
+
),
|
|
869
|
+
}),
|
|
870
|
+
]),
|
|
871
|
+
),
|
|
872
|
+
project,
|
|
873
|
+
};
|
|
874
|
+
}
|
|
810
875
|
}
|
|
811
876
|
|
|
812
877
|
type ProjectHostInputSnapshot = {
|
|
@@ -945,12 +1010,18 @@ function readProjectHostInputSnapshot(options: {
|
|
|
945
1010
|
cwd?: string;
|
|
946
1011
|
file?: string;
|
|
947
1012
|
includePluginDiscovery: boolean;
|
|
1013
|
+
pluginConfigDir?: string;
|
|
948
1014
|
projectRoot?: string;
|
|
949
1015
|
tsconfig?: string;
|
|
950
1016
|
}): ProjectHostInputSnapshot {
|
|
951
|
-
const { includePluginDiscovery, ...projectOptions } =
|
|
1017
|
+
const { includePluginDiscovery, pluginConfigDir, ...projectOptions } =
|
|
1018
|
+
options;
|
|
952
1019
|
let project = readProjectConfig(projectOptions);
|
|
953
|
-
let hostInputs = collectProjectHostInputs(
|
|
1020
|
+
let hostInputs = collectProjectHostInputs(
|
|
1021
|
+
project,
|
|
1022
|
+
includePluginDiscovery,
|
|
1023
|
+
pluginConfigDir,
|
|
1024
|
+
);
|
|
954
1025
|
const observedInputs = new Set(hostInputs);
|
|
955
1026
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
956
1027
|
const before = hashHostInputPaths(hostInputs);
|
|
@@ -960,6 +1031,7 @@ function readProjectHostInputSnapshot(options: {
|
|
|
960
1031
|
const candidateInputs = collectProjectHostInputs(
|
|
961
1032
|
candidateProject,
|
|
962
1033
|
includePluginDiscovery,
|
|
1034
|
+
pluginConfigDir,
|
|
963
1035
|
);
|
|
964
1036
|
for (const input of candidateInputs) observedInputs.add(input);
|
|
965
1037
|
const after = hashHostInputPaths(candidateInputs);
|
|
@@ -1381,7 +1453,7 @@ function loadPluginDescriptor(
|
|
|
1381
1453
|
request,
|
|
1382
1454
|
context,
|
|
1383
1455
|
effectiveEnv,
|
|
1384
|
-
descriptorCache
|
|
1456
|
+
descriptorCache,
|
|
1385
1457
|
);
|
|
1386
1458
|
if (loaded === undefined) {
|
|
1387
1459
|
throw error;
|
|
@@ -1398,6 +1470,9 @@ interface DescriptorCacheOptions {
|
|
|
1398
1470
|
/** Record store that proves the evaluating runtimes from metadata (#1723). */
|
|
1399
1471
|
identities: PluginContentIdentities.Store | undefined;
|
|
1400
1472
|
|
|
1473
|
+
/** Source-project cache anchor, independent of descriptor consumer context. */
|
|
1474
|
+
projectRoot: string;
|
|
1475
|
+
|
|
1401
1476
|
/** This ttsc build's version. */
|
|
1402
1477
|
version: string;
|
|
1403
1478
|
}
|
|
@@ -1438,15 +1513,19 @@ class CommonJsDescriptorLoadError extends Error {
|
|
|
1438
1513
|
function loadCommonJsDescriptor(
|
|
1439
1514
|
request: string,
|
|
1440
1515
|
context: ITtscPluginFactoryContext,
|
|
1441
|
-
|
|
1516
|
+
loadEnv: NodeJS.ProcessEnv,
|
|
1442
1517
|
descriptorCache: DescriptorCacheOptions,
|
|
1443
1518
|
): IsolatedPluginDescriptor {
|
|
1519
|
+
// The evaluator is ttsc's own helper: inside a ttsx run it gets the user's
|
|
1520
|
+
// NODE_OPTIONS, not ttsx's preloads, which would refuse the descriptor cache
|
|
1521
|
+
// and run in every evaluation (#1740). The runtime probe below does the same.
|
|
1522
|
+
const effectiveEnv = TtsxNodeOptions.forHelpers(loadEnv);
|
|
1444
1523
|
const runtime = pluginDescriptorRuntimeBinary(effectiveEnv);
|
|
1445
1524
|
const ttsx = effectiveEnv.TTSC_TTSX_BINARY ?? process.env.TTSC_TTSX_BINARY;
|
|
1446
1525
|
const runtimeCapabilities = javascriptRuntimeCapabilities(
|
|
1447
1526
|
runtime,
|
|
1448
1527
|
effectiveEnv,
|
|
1449
|
-
|
|
1528
|
+
descriptorCache.projectRoot,
|
|
1450
1529
|
descriptorCache.identities,
|
|
1451
1530
|
);
|
|
1452
1531
|
const node =
|
|
@@ -1456,7 +1535,7 @@ function loadCommonJsDescriptor(
|
|
|
1456
1535
|
? runtimeCapabilities.executable
|
|
1457
1536
|
: resolveNodeBinary(
|
|
1458
1537
|
effectiveEnv,
|
|
1459
|
-
|
|
1538
|
+
descriptorCache.projectRoot,
|
|
1460
1539
|
descriptorCache.identities,
|
|
1461
1540
|
);
|
|
1462
1541
|
const cacheAuthority = {
|
|
@@ -1464,6 +1543,8 @@ function loadCommonJsDescriptor(
|
|
|
1464
1543
|
cacheDir: descriptorCache.cacheDir,
|
|
1465
1544
|
identities: descriptorCache.identities,
|
|
1466
1545
|
context,
|
|
1546
|
+
// Factory context anchors the consumer; the evaluator runs at the source root.
|
|
1547
|
+
cwd: descriptorCache.projectRoot,
|
|
1467
1548
|
// Everything the child receives besides the per-evaluation output paths.
|
|
1468
1549
|
env: {
|
|
1469
1550
|
...effectiveEnv,
|
|
@@ -1471,7 +1552,7 @@ function loadCommonJsDescriptor(
|
|
|
1471
1552
|
...descriptorRecordRoot(descriptorCache.identities),
|
|
1472
1553
|
TTSC_TTSX_BINARY: ttsx,
|
|
1473
1554
|
},
|
|
1474
|
-
projectRoot:
|
|
1555
|
+
projectRoot: descriptorCache.projectRoot,
|
|
1475
1556
|
request,
|
|
1476
1557
|
runtime,
|
|
1477
1558
|
version: descriptorCache.version,
|
|
@@ -1552,7 +1633,7 @@ function loadCommonJsDescriptor(
|
|
|
1552
1633
|
shim,
|
|
1553
1634
|
],
|
|
1554
1635
|
{
|
|
1555
|
-
cwd:
|
|
1636
|
+
cwd: descriptorCache.projectRoot,
|
|
1556
1637
|
env: {
|
|
1557
1638
|
...effectiveEnv,
|
|
1558
1639
|
// The direct evaluator may be Bun, but ttsx and native config
|
|
@@ -1943,12 +2024,16 @@ function loadDescriptorViaTtsx(
|
|
|
1943
2024
|
request: string,
|
|
1944
2025
|
context: ITtscPluginFactoryContext,
|
|
1945
2026
|
effectiveEnv: NodeJS.ProcessEnv,
|
|
1946
|
-
|
|
2027
|
+
descriptorCache: DescriptorCacheOptions,
|
|
1947
2028
|
): IsolatedPluginDescriptor | undefined {
|
|
1948
2029
|
// Binary discovery prefers the instance environment, then the ambient
|
|
1949
2030
|
// process.env (where `withPluginLoaderEnv` injects ttsc's own node/ttsx paths
|
|
1950
2031
|
// just before this runs), then the running interpreter.
|
|
1951
|
-
const node = resolveNodeBinary(
|
|
2032
|
+
const node = resolveNodeBinary(
|
|
2033
|
+
effectiveEnv,
|
|
2034
|
+
descriptorCache.projectRoot,
|
|
2035
|
+
descriptorCache.identities,
|
|
2036
|
+
);
|
|
1952
2037
|
const ttsx = effectiveEnv.TTSC_TTSX_BINARY ?? process.env.TTSC_TTSX_BINARY;
|
|
1953
2038
|
if (node === undefined || ttsx === undefined || ttsx.length === 0) {
|
|
1954
2039
|
return undefined;
|
|
@@ -1975,11 +2060,11 @@ function loadDescriptorViaTtsx(
|
|
|
1975
2060
|
const trace = E2ETrace.begin(
|
|
1976
2061
|
node,
|
|
1977
2062
|
[ttsx, "--no-plugins", shim],
|
|
1978
|
-
{ cwd:
|
|
2063
|
+
{ cwd: descriptorCache.projectRoot },
|
|
1979
2064
|
"plugin-descriptor",
|
|
1980
2065
|
);
|
|
1981
2066
|
const result = spawnOwnedDescriptor(node, [ttsx, "--no-plugins", shim], {
|
|
1982
|
-
cwd:
|
|
2067
|
+
cwd: descriptorCache.projectRoot,
|
|
1983
2068
|
encoding: "utf8",
|
|
1984
2069
|
env: {
|
|
1985
2070
|
...effectiveEnv,
|
|
@@ -1987,7 +2072,7 @@ function loadDescriptorViaTtsx(
|
|
|
1987
2072
|
// may recurse into further descriptor loads) finds them even when the
|
|
1988
2073
|
// instance-env snapshot predates `withPluginLoaderEnv`.
|
|
1989
2074
|
TTSC_NODE_BINARY: node,
|
|
1990
|
-
...descriptorRecordRoot(identities),
|
|
2075
|
+
...descriptorRecordRoot(descriptorCache.identities),
|
|
1991
2076
|
TTSC_TTSX_BINARY: ttsx,
|
|
1992
2077
|
TTSC_PLUGIN_CONTEXT: JSON.stringify({
|
|
1993
2078
|
binary: context.binary,
|
|
@@ -2349,6 +2434,7 @@ function pluginBuildDirectories(
|
|
|
2349
2434
|
env: NodeJS.ProcessEnv,
|
|
2350
2435
|
replacements?: Map<string, readonly string[]>,
|
|
2351
2436
|
readers?: Map<string, SourcePluginWorkspace.GoModReader>,
|
|
2437
|
+
identities?: PluginContentIdentities.Store,
|
|
2352
2438
|
): string[] {
|
|
2353
2439
|
const directories = new Set<string>();
|
|
2354
2440
|
for (const record of records) {
|
|
@@ -2363,6 +2449,7 @@ function pluginBuildDirectories(
|
|
|
2363
2449
|
env,
|
|
2364
2450
|
replacements,
|
|
2365
2451
|
readers,
|
|
2452
|
+
identities,
|
|
2366
2453
|
))
|
|
2367
2454
|
directories.add(directory);
|
|
2368
2455
|
}
|
|
@@ -2382,17 +2469,20 @@ function pluginReplacementWatchDirectories(
|
|
|
2382
2469
|
env: NodeJS.ProcessEnv,
|
|
2383
2470
|
observed?: Map<string, readonly string[]>,
|
|
2384
2471
|
readers?: Map<string, SourcePluginWorkspace.GoModReader>,
|
|
2472
|
+
identities?: PluginContentIdentities.Store,
|
|
2385
2473
|
): readonly string[] {
|
|
2386
2474
|
const previous = observed?.get(moduleRoot);
|
|
2387
2475
|
if (previous !== undefined) return previous;
|
|
2388
2476
|
let directories: readonly string[];
|
|
2389
2477
|
try {
|
|
2478
|
+
// The load's store goes with the reader this registers first (#1739).
|
|
2390
2479
|
directories = pluginModuleReplaceDirectories(
|
|
2391
2480
|
moduleRoot,
|
|
2392
2481
|
env,
|
|
2393
2482
|
undefined,
|
|
2394
2483
|
undefined,
|
|
2395
2484
|
readers,
|
|
2485
|
+
identities,
|
|
2396
2486
|
).map((replacement) => replacement.directory);
|
|
2397
2487
|
} catch {
|
|
2398
2488
|
// An unreadable manifest/tool is not valid metadata. The already observed
|