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
|
@@ -12,9 +12,11 @@ const CompilerProjectSelection_1 = require("../../../compiler/internal/project/C
|
|
|
12
12
|
const readJsoncFile_1 = require("../../../compiler/internal/project/readJsoncFile");
|
|
13
13
|
const readProjectConfig_1 = require("../../../compiler/internal/project/readProjectConfig");
|
|
14
14
|
const resolveTsgo_1 = require("../../../compiler/internal/resolveTsgo");
|
|
15
|
+
const SidecarEnvironment_1 = require("../../../compiler/internal/sharedHost/SidecarEnvironment");
|
|
15
16
|
const spawnNative_1 = require("../../../compiler/internal/spawnNative");
|
|
16
17
|
const normalizeCompilerEnumValue_1 = require("../../../flags/normalizeCompilerEnumValue");
|
|
17
18
|
const readCompilerOptionValues_1 = require("../../../flags/readCompilerOptionValues");
|
|
19
|
+
const createCaseSensitivityObservations_1 = require("../../../internal/pathIdentity/createCaseSensitivityObservations");
|
|
18
20
|
const createProjectInputPathIdentityContext_1 = require("../../../internal/pathIdentity/createProjectInputPathIdentityContext");
|
|
19
21
|
const isProjectInputPathIdentityWithin_1 = require("../../../internal/pathIdentity/isProjectInputPathIdentityWithin");
|
|
20
22
|
const resolveProjectInputPath_1 = require("../../../internal/pathIdentity/resolveProjectInputPath");
|
|
@@ -44,26 +46,26 @@ const watchDirectory_1 = require("./watchDirectory");
|
|
|
44
46
|
* output for source and declaration membership. An explicit reader supplies the
|
|
45
47
|
* same absolute-path membership and failure contract for each resolved project.
|
|
46
48
|
* Configuration files, project-reference roots, output inference and native
|
|
47
|
-
* filesystem identity remain this topology's responsibility.
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
49
|
+
* filesystem identity remain this topology's responsibility. Response frames
|
|
50
|
+
* are observed once per project refresh at its compiler cwd; that option view
|
|
51
|
+
* serves all project-output queries while the original argv reaches compiler
|
|
52
|
+
* membership. A second observation rejects response changes across membership
|
|
53
|
+
* resolution. Response files join the config reload set; these observations do
|
|
54
|
+
* not pin files or detect a change restored in between.
|
|
53
55
|
*
|
|
54
56
|
* `TTSC_WATCH_DEBUG_INPUTS` reports the named event, observed population deltas
|
|
55
57
|
* and reload decision. These diagnostics reuse the decision's existing inputs;
|
|
56
58
|
* they perform no extra filesystem observations.
|
|
57
59
|
*
|
|
58
60
|
* @evidence contracts/common.md#principled-implementation The compiler-input operation's membership, published rule inputs and actual content fingerprints qualify notifications; its native default obtains the real compiler list. Post-registration reconciliation compares baselines to recover observed handoff changes, not an atomic guarantee against every transient mutation. Explicit operations preserve native defaults without replacing global filesystem or compiler methods. Project-input attribution: Observed member deltas establish attribution; stale selected names cannot override them, while directory names retain supported population causality and unrelated multiple members remain unnamed.
|
|
59
|
-
* @evidence contracts/common.md#clear-and-simple-design Compiler, plugin and project-input watch populations keep their own baselines and callbacks under one topology owner; small classifiers separate membership, selection and handle replacement.
|
|
61
|
+
* @evidence contracts/common.md#clear-and-simple-design Compiler, plugin and project-input watch populations keep their own baselines and callbacks under one topology owner; small classifiers separate membership, selection and handle replacement. Five distinct operations own directory subscriptions, file subscriptions, immediate reload-directory reads, compiler membership and each decision's case-policy observations; existing callers need no new argument. Project-input attribution: One private reconciliation separates member deltas from immediate resolution-directory digests before choosing a supported event name or an observed single member.
|
|
60
62
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts Supported native backends and explicit gap/replacement ownership replace foreign watcher patching; failed observation is reported rather than represented as complete coverage. The constructor manufactures no observations and bypasses no input or content proof; supplied operations retain the existing callback and result contracts. Project-input attribution: Native event names do not manufacture a delta; the current and previous physical membership identify already observed names without filename or fixture exceptions.
|
|
61
63
|
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain membership authority, plugin fingerprinting, publication races, physical registration and public lifecycle operations following the documentation skill. Parameters identify each supplied operation and native default beside the constructor. Project-input attribution: Native paragraphs explain stale attention, directory causality, accompanying resolution digests and unselected immediate entries.
|
|
62
64
|
* @evidence contracts/portability.md#os-neutral-implementation Native paths use Node APIs and registration uses realpath; compiler/plugin maps preserve lexical aliases and fold only measured insensitive ASCII components. Project inputs use physical identities, while unknown/native Unicode relations remain conservative event candidates rather than identity proof. Registration paths and read options are passed unchanged; compiler-input readers supply absolute membership paths without replacing the topology's native identity policy. Project-input attribution: The supplied filesystem identity transaction establishes selected names and ancestry without an OS-wide case assumption or lexical alias guess.
|
|
63
65
|
*
|
|
64
|
-
* @evidence contracts/performance.md#efficient-algorithms Identity-keyed maps separate membership, baselines and handle registries; reconciliation delegates project/config discovery, native compiler listing, filesystem traversal/hashing and backend callbacks, with costs described by its members. Construction retains operation references and empty indexes without a filesystem observation or build. Attribution indexed visits additionally pay path/key text, ancestor and native identity work; shared ancestor keys avoid repeating the same walk within a transaction.
|
|
65
|
-
* @evidence contracts/performance.md#reuse-equivalent-work Current membership, content baselines and live registrations belong to one topology; reconciliation owners decide their reuse against fresh premises. Supplied operation identities are retained without
|
|
66
|
-
* @evidence contracts/performance.md#bound-retention-and-release-resources Current and pending maps and live subscriptions remain topology-owned without a population cap; reconciliation attempts obsolete handle retirement. Constructor acquires no handle; directory arrays and attribution deltas are call-local. close invokes supplied close methods but does not await backend closure, and a thrown close can interrupt later map cleanup; retained snapshots remain until the facade is released.
|
|
66
|
+
* @evidence contracts/performance.md#efficient-algorithms Identity-keyed maps separate membership, baselines and handle registries; reconciliation delegates project/config discovery, native compiler listing, filesystem traversal/hashing and backend callbacks, with costs described by its members. A directory-triggered refresh additionally visits R active reload files even on failure and compares their metadata/owner snapshots, reading bytes only when those snapshots changed. Changed-owner and notification arrays and a reported-key set require O(R) references; moved owners share one existing watcher synchronization and post-registration reconciliation, whose selected-file traversal remains part of the operation. No additional compiler listing is requested. Construction retains operation references and empty indexes without a filesystem observation or build. Attribution indexed visits additionally pay path/key text, ancestor and native identity work; shared ancestor keys avoid repeating the same walk within a transaction.
|
|
67
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Current membership, content baselines and live registrations belong to one topology; reconciliation owners decide their reuse against fresh premises. Supplied operation identities are retained without assuming changed inputs remain equivalent. Each project's last compiler listing is kept with its arguments and answers only a plugin-input change, which cannot move Program membership; every other refresh lists again. Notifications delivered in one poll iteration are decided together in the check phase, so one change lists and rescans once. Project-input attribution: This classifier borrows one scan's deltas and identity transaction without retaining cross-event answers.
|
|
68
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Current and pending maps and live subscriptions remain topology-owned without a population cap; compiler listings are replaced by each resolution and hold only its projects; reconciliation attempts obsolete handle retirement. Constructor acquires no handle; directory arrays and attribution deltas are call-local. close invokes supplied close methods but does not await backend closure, and a thrown close can interrupt later map cleanup; retained snapshots remain until the facade is released.
|
|
67
69
|
*/
|
|
68
70
|
class WatchTopology {
|
|
69
71
|
options;
|
|
@@ -72,6 +74,7 @@ class WatchTopology {
|
|
|
72
74
|
openFileWatch;
|
|
73
75
|
readDirectory;
|
|
74
76
|
getCompilerInputs;
|
|
77
|
+
observeCaseSensitivity;
|
|
75
78
|
analysisOnly = false;
|
|
76
79
|
closed = false;
|
|
77
80
|
compilerPostRegistrationMembershipRefresh = false;
|
|
@@ -102,15 +105,36 @@ class WatchTopology {
|
|
|
102
105
|
/** The plugin inputs whose directories the last sync already watched. */
|
|
103
106
|
watchedExtraInputs = new Set();
|
|
104
107
|
compilerFileSnapshots = new Map();
|
|
108
|
+
/**
|
|
109
|
+
* The last compiler listing of each project the topology resolved, by its
|
|
110
|
+
* config path, with the arguments it was asked under (`listingQuestion`). A
|
|
111
|
+
* change of plugin inputs reuses it (samchon/ttsc#1741).
|
|
112
|
+
*/
|
|
113
|
+
compilerListings = new Map();
|
|
114
|
+
/**
|
|
115
|
+
* Notifications the current poll iteration delivered, decided together in the
|
|
116
|
+
* check phase (`deferNotification`).
|
|
117
|
+
*/
|
|
118
|
+
pendingNotifications = new Map();
|
|
119
|
+
notificationsScheduled = false;
|
|
105
120
|
files = new Map();
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
121
|
+
/**
|
|
122
|
+
* The current decision's directory case-policy observations, which every
|
|
123
|
+
* identity context the decision creates shares (samchon/ttsc#1742).
|
|
124
|
+
*/
|
|
125
|
+
caseObservations;
|
|
126
|
+
lexicalIdentities;
|
|
109
127
|
fileWatchers = new Map();
|
|
110
128
|
observedDirectories = new Map();
|
|
111
129
|
outputFiles = new Map();
|
|
112
130
|
outputs = new Map();
|
|
113
131
|
projectInputFingerprints = new Map();
|
|
132
|
+
/**
|
|
133
|
+
* The metadata and physical owner each matched project-input file had when
|
|
134
|
+
* its fingerprint was taken, by match key; a named notification re-reads only
|
|
135
|
+
* the files whose metadata moved (samchon/ttsc#1748).
|
|
136
|
+
*/
|
|
137
|
+
projectInputFileSnapshots = new Map();
|
|
114
138
|
projectInputMatches = new Map();
|
|
115
139
|
projectInputs = {
|
|
116
140
|
files: [],
|
|
@@ -150,14 +174,18 @@ class WatchTopology {
|
|
|
150
174
|
* membership; the default invokes the native compiler. Readers throw
|
|
151
175
|
* listing failures and retain ownership of their returned array, which this
|
|
152
176
|
* topology does not mutate.
|
|
177
|
+
* @param observeCaseSensitivity Create one decision's directory case-policy
|
|
178
|
+
* observations; the default asks the native filesystem.
|
|
153
179
|
*/
|
|
154
|
-
constructor(options, callbacks, openDirectoryWatch = watchDirectory_1.watchDirectory, openFileWatch = node_fs_1.default.watch, readDirectory = node_fs_1.default.readdirSync, getCompilerInputs = listCompilerInputs) {
|
|
180
|
+
constructor(options, callbacks, openDirectoryWatch = watchDirectory_1.watchDirectory, openFileWatch = node_fs_1.default.watch, readDirectory = node_fs_1.default.readdirSync, getCompilerInputs = listCompilerInputs, observeCaseSensitivity = createCaseSensitivityObservations_1.createCaseSensitivityObservations) {
|
|
155
181
|
this.options = options;
|
|
156
182
|
this.callbacks = callbacks;
|
|
157
183
|
this.openDirectoryWatch = openDirectoryWatch;
|
|
158
184
|
this.openFileWatch = openFileWatch;
|
|
159
185
|
this.readDirectory = readDirectory;
|
|
160
186
|
this.getCompilerInputs = getCompilerInputs;
|
|
187
|
+
this.observeCaseSensitivity = observeCaseSensitivity;
|
|
188
|
+
this.beginLexicalTransaction();
|
|
161
189
|
}
|
|
162
190
|
/**
|
|
163
191
|
* Re-resolve compiler inputs and notify when the resolved topology changes,
|
|
@@ -177,16 +205,61 @@ class WatchTopology {
|
|
|
177
205
|
refresh(notify) {
|
|
178
206
|
this.refreshCompilerInputs(notify, false);
|
|
179
207
|
}
|
|
180
|
-
|
|
208
|
+
/**
|
|
209
|
+
* Wait until delivered notifications and registration reconciliation finish.
|
|
210
|
+
*
|
|
211
|
+
* A completed build does not imply a quiet topology: its final refresh can
|
|
212
|
+
* queue another decision and another build (#1756). Yield through the check
|
|
213
|
+
* phase before inspecting every scheduled owner so a decision queued by
|
|
214
|
+
* another decision remains part of this barrier. Later filesystem changes
|
|
215
|
+
* belong to a later barrier; this does not freeze the filesystem.
|
|
216
|
+
*
|
|
217
|
+
* @evidence contracts/common.md#principled-implementation A check-phase observation follows delivered events, and every notification, recovery and registration queue must be empty before completion.
|
|
218
|
+
* @evidence contracts/common.md#clear-and-simple-design The topology owns the barrier because it alone owns all five scheduled queues.
|
|
219
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Queue state establishes completion without a quiet-time estimate or an invented filesystem snapshot.
|
|
220
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose distinguishes delivered work from later mutations and explains the post-build queued-decision race.
|
|
221
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation The barrier observes owned JavaScript queues without a separate native operation.
|
|
222
|
+
* @evidence contracts/performance.md#efficient-algorithms Each check turn inspects five flags and two map sizes; notification processing retains its owning traversal and native-operation costs.
|
|
223
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Each call observes current work rather than reusing an earlier completion.
|
|
224
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources One immediate callback and promise remain live per waiting call; continuous new work can prevent completion and no deadline is imposed.
|
|
225
|
+
*/
|
|
226
|
+
async whenIdle() {
|
|
227
|
+
do {
|
|
228
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
229
|
+
} while (!this.closed &&
|
|
230
|
+
(this.notificationsScheduled ||
|
|
231
|
+
this.pluginNotificationsScheduled ||
|
|
232
|
+
this.compilerPostRegistrationReconciliationScheduled ||
|
|
233
|
+
this.projectInputRecoveryScheduled ||
|
|
234
|
+
this.projectInputPostRegistrationReconciliationScheduled ||
|
|
235
|
+
this.pendingNotifications.size !== 0 ||
|
|
236
|
+
this.pendingPluginNotifications.size !== 0));
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* @param reuseListings Answer each project's membership with its last listing
|
|
240
|
+
* under the same arguments instead of asking the compiler again. Only a
|
|
241
|
+
* refresh whose cause cannot move Program membership passes it.
|
|
242
|
+
*/
|
|
243
|
+
refreshCompilerInputs(notify, skipUnobservedProjectInputWatchRoots, reuseListings = false) {
|
|
181
244
|
this.beginLexicalTransaction();
|
|
182
|
-
const
|
|
245
|
+
const listings = new Map();
|
|
246
|
+
const next = resolveWatchTopology(this.options, this.extraInputs, this.lexicalIdentities, (project, options) => {
|
|
247
|
+
const question = listingQuestion(project, options);
|
|
248
|
+
const last = this.compilerListings.get(project.path);
|
|
249
|
+
const inputs = reuseListings && last?.question === question
|
|
250
|
+
? last.inputs
|
|
251
|
+
: this.getCompilerInputs(project, options);
|
|
252
|
+
listings.set(project.path, { inputs, question });
|
|
253
|
+
return inputs;
|
|
254
|
+
});
|
|
255
|
+
this.compilerListings = listings;
|
|
183
256
|
const compilerProgramMembershipChange = next.analysisOnly &&
|
|
184
257
|
WatchPaths_1.WatchPaths.mapsEqual(this.reloadFiles, next.reloadFiles) &&
|
|
185
258
|
WatchPaths_1.WatchPaths.mapsEqual(this.outputFiles, next.outputFiles) &&
|
|
186
259
|
WatchPaths_1.WatchPaths.mapsEqual(this.outputs, next.outputs)
|
|
187
260
|
? compilerMembershipChange(this.files, next.files)
|
|
188
261
|
: [];
|
|
189
|
-
const projectInputProgramOverlap = projectInputCompilerMembershipChange(this.projectInputs, compilerProgramMembershipChange);
|
|
262
|
+
const projectInputProgramOverlap = projectInputCompilerMembershipChange(this.projectInputs, compilerProgramMembershipChange, this.projectInputIdentities());
|
|
190
263
|
const projectInputProgramChange = compilerProgramMembershipChange.length !== 0 &&
|
|
191
264
|
projectInputProgramOverlap.length ===
|
|
192
265
|
compilerProgramMembershipChange.length
|
|
@@ -260,7 +333,7 @@ class WatchTopology {
|
|
|
260
333
|
*/
|
|
261
334
|
acknowledgeProjectInputCompilerMembership(changed) {
|
|
262
335
|
const matches = this.collectProjectInputMatches();
|
|
263
|
-
const fingerprints = fingerprintProjectInputMatches(matches, this.readDirectory);
|
|
336
|
+
const { fingerprints, snapshots } = fingerprintProjectInputMatches(matches, this.readDirectory);
|
|
264
337
|
const changedInputs = projectInputChangedPaths({
|
|
265
338
|
next: matches,
|
|
266
339
|
nextFingerprints: fingerprints,
|
|
@@ -268,7 +341,7 @@ class WatchTopology {
|
|
|
268
341
|
previousFingerprints: this.projectInputFingerprints,
|
|
269
342
|
});
|
|
270
343
|
const population = this.projectInputPopulation();
|
|
271
|
-
const causedBy = projectInputCompilerMembershipProjectChanges(changed, population.globs);
|
|
344
|
+
const causedBy = projectInputCompilerMembershipProjectChanges(changed, population.globs, this.projectInputIdentities());
|
|
272
345
|
const reloadInput = {
|
|
273
346
|
causedBy,
|
|
274
347
|
changed: causedBy.length === 1 ? causedBy[0] : undefined,
|
|
@@ -277,7 +350,7 @@ class WatchTopology {
|
|
|
277
350
|
reloadDirectories: population.reloadDirectories,
|
|
278
351
|
reloadFiles: population.reloadFiles ?? [],
|
|
279
352
|
};
|
|
280
|
-
const reload = (0, projectInputReloadEventShouldNotify_1.projectInputReloadEventShouldNotify)(reloadInput);
|
|
353
|
+
const reload = (0, projectInputReloadEventShouldNotify_1.projectInputReloadEventShouldNotify)(reloadInput, this.projectInputIdentities());
|
|
281
354
|
reportProjectInputDecision({
|
|
282
355
|
source: "compiler-membership",
|
|
283
356
|
...reloadInput,
|
|
@@ -289,6 +362,7 @@ class WatchTopology {
|
|
|
289
362
|
// instead of disappearing behind the warm compiler-membership handoff.
|
|
290
363
|
this.projectInputMatches = matches;
|
|
291
364
|
this.projectInputFingerprints = fingerprints;
|
|
365
|
+
this.projectInputFileSnapshots = snapshots;
|
|
292
366
|
return reload;
|
|
293
367
|
}
|
|
294
368
|
/**
|
|
@@ -313,8 +387,8 @@ class WatchTopology {
|
|
|
313
387
|
* @evidence contracts/common.md#prohibited-implementation-shortcuts The actual plugin source digest applies its owning source-selection and pruning policy; named plugins or fixture output do not replace observed input state.
|
|
314
388
|
* @evidence contracts/common.md#meaningful-documentation Native prose explains baseline timing and why existing inputs are not restamped following the documentation skill.
|
|
315
389
|
* @evidence contracts/portability.md#os-neutral-implementation Native path resolution and canonical backend registration govern source trees; lexical keys preserve declarations and unknown names, folding ASCII only under measured insensitive parents rather than an OS-derived rule.
|
|
316
|
-
* @evidence contracts/performance.md#efficient-algorithms Input/path keys deduplicate with text and native case/ancestor work; only newly admitted inputs compute initial source digests, each proven from the selected files' metadata when the load's records hold and read from the selected pruned corpus otherwise;
|
|
317
|
-
* @evidence contracts/performance.md#reuse-equivalent-work Unchanged ordered input sets return immediately; existing inputs reuse their recorded digest until actual notification processing establishes changed consumed state; a new input's digest is the one the load recorded while its metadata holds.
|
|
390
|
+
* @evidence contracts/performance.md#efficient-algorithms Input/path keys deduplicate with text and native case/ancestor work; only newly admitted inputs compute initial source digests, each proven from the selected files' metadata when the load's records hold and read from the selected pruned corpus otherwise; the following reconciliation pays project configuration, directory traversal and watcher work but answers membership from each project's last compiler listing; fixed publication count does not bound delegated bytes or backend work.
|
|
391
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Unchanged ordered input sets return immediately; a changed set reuses each project's last compiler listing under the same arguments, since plugin inputs cannot move Program membership; existing inputs reuse their recorded digest until actual notification processing establishes changed consumed state; a new input's digest is the one the load recorded while its metadata holds.
|
|
318
392
|
* @evidence contracts/performance.md#bound-retention-and-release-resources Publications replace input/digest populations and case-observation caches without a population cap; synchronization attempts obsolete watcher closure. Native/supplied closure has its own lifetime and can throw; owner close does not prove every backend has stopped or every retained snapshot byte was released.
|
|
319
393
|
*/
|
|
320
394
|
setExtraInputs(inputs, identities) {
|
|
@@ -337,7 +411,12 @@ class WatchTopology {
|
|
|
337
411
|
pluginInputState(input, this.pluginInputIdentities));
|
|
338
412
|
}
|
|
339
413
|
this.pluginInputStates = states;
|
|
340
|
-
|
|
414
|
+
// Plugin inputs join the watched files and directories, never Program
|
|
415
|
+
// membership, so the compiler's last answer stands. A load reports up to
|
|
416
|
+
// three different sets, and asking again for each spawned tsgo three times
|
|
417
|
+
// per load (samchon/ttsc#1741). A membership change meanwhile reaches the
|
|
418
|
+
// refresh its own notification starts, which lists again.
|
|
419
|
+
this.refreshCompilerInputs(false, false, true);
|
|
341
420
|
}
|
|
342
421
|
/**
|
|
343
422
|
* Reconcile project-rule dependencies, retaining absent files and empty glob
|
|
@@ -353,7 +432,8 @@ class WatchTopology {
|
|
|
353
432
|
* @evidence contracts/performance.md#bound-retention-and-release-resources Publication prunes retired declaration-owner choices and replaces uncapped match/fingerprint populations. Watcher retirement invokes close without awaiting backend completion, and supplied errors can interrupt cleanup. Weak output-overlap keys do not retain old identity transactions; the current declaration snapshot can borrow caller arrays until replaced or the facade is released.
|
|
354
433
|
*/
|
|
355
434
|
setProjectInputs(inputs) {
|
|
356
|
-
|
|
435
|
+
this.beginLexicalTransaction();
|
|
436
|
+
const next = normalizeProjectInputSnapshot(inputs, this.projectInputIdentities());
|
|
357
437
|
// The declared spellings are recorded even when the normalized snapshot did
|
|
358
438
|
// not move, because a republication can carry a new alias for identities
|
|
359
439
|
// that already matched, and anchoring the spelling that was retired would
|
|
@@ -362,7 +442,7 @@ class WatchTopology {
|
|
|
362
442
|
inputs.declared === undefined
|
|
363
443
|
? inputs
|
|
364
444
|
: { ...inputs.declared, root: inputs.root };
|
|
365
|
-
if (projectInputSnapshotsEqual(this.projectInputs, next)) {
|
|
445
|
+
if (projectInputSnapshotsEqual(this.projectInputs, next, this.projectInputIdentities())) {
|
|
366
446
|
this.syncProjectInputWatchers();
|
|
367
447
|
return;
|
|
368
448
|
}
|
|
@@ -374,7 +454,9 @@ class WatchTopology {
|
|
|
374
454
|
{ ...(inputs.declared ?? inputs), root: inputs.root },
|
|
375
455
|
]);
|
|
376
456
|
this.projectInputMatches = this.collectProjectInputMatches();
|
|
377
|
-
|
|
457
|
+
const baseline = fingerprintProjectInputMatches(this.projectInputMatches, this.readDirectory);
|
|
458
|
+
this.projectInputFingerprints = baseline.fingerprints;
|
|
459
|
+
this.projectInputFileSnapshots = baseline.snapshots;
|
|
378
460
|
this.syncProjectInputWatchers();
|
|
379
461
|
}
|
|
380
462
|
/**
|
|
@@ -406,10 +488,24 @@ class WatchTopology {
|
|
|
406
488
|
}
|
|
407
489
|
/** Start fresh native case observations for one synchronous watch decision. */
|
|
408
490
|
beginLexicalTransaction() {
|
|
491
|
+
this.caseObservations = this.observeCaseSensitivity();
|
|
409
492
|
this.lexicalIdentities = (0, createProjectInputPathIdentityContext_1.createProjectInputPathIdentityContext)({
|
|
493
|
+
caseSensitive: this.caseObservations,
|
|
410
494
|
throwOnRealpathError: false,
|
|
411
495
|
});
|
|
412
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* A strict project-input identity context for the current decision. Its
|
|
499
|
+
* physical paths are resolved afresh, and its case answers are the
|
|
500
|
+
* decision's: one decision builds such contexts per declaration and per
|
|
501
|
+
* candidate, and each asked every directory again, which on Windows is an
|
|
502
|
+
* `fsutil` process per question (samchon/ttsc#1742).
|
|
503
|
+
*/
|
|
504
|
+
projectInputIdentities() {
|
|
505
|
+
return (0, createProjectInputPathIdentityContext_1.createProjectInputPathIdentityContext)({
|
|
506
|
+
caseSensitive: this.caseObservations,
|
|
507
|
+
});
|
|
508
|
+
}
|
|
413
509
|
/** Keep lexical alias ownership while sharing this decision's case probes. */
|
|
414
510
|
pathKey(location) {
|
|
415
511
|
return WatchPaths_1.WatchPaths.pathKey(location, this.lexicalIdentities);
|
|
@@ -487,32 +583,93 @@ class WatchTopology {
|
|
|
487
583
|
}
|
|
488
584
|
}
|
|
489
585
|
}
|
|
490
|
-
(0, syncWatchers_1.syncWatchers)(this.directoryWatchers, desired, (location) => this.openDirectoryWatch(watcherRegistrationPath(location), process.platform === "win32", (event, filename, gap) => {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
changed,
|
|
500
|
-
event,
|
|
501
|
-
exists: node_fs_1.default.existsSync,
|
|
502
|
-
location,
|
|
503
|
-
identities: this.lexicalIdentities,
|
|
504
|
-
platform: process.platform,
|
|
505
|
-
trackedFiles: this.files,
|
|
506
|
-
});
|
|
507
|
-
this.rearmFileWatchers(plan.rearm);
|
|
508
|
-
for (const file of this.compilerChangesToReport(plan.changes, changed, gap === true)) {
|
|
509
|
-
this.reportCompilerFileChange(file);
|
|
510
|
-
}
|
|
511
|
-
if (plan.refresh)
|
|
512
|
-
this.refreshFromDirectory(location, changed);
|
|
513
|
-
}), (location, error) => this.callbacks.onError(location, error), () => this.closed === false);
|
|
586
|
+
(0, syncWatchers_1.syncWatchers)(this.directoryWatchers, desired, (location) => this.openDirectoryWatch(watcherRegistrationPath(location), process.platform === "win32", (event, filename, gap) => this.deferNotification({
|
|
587
|
+
gap: gap === true,
|
|
588
|
+
lane: "compiler",
|
|
589
|
+
location,
|
|
590
|
+
changed: filename === null
|
|
591
|
+
? undefined
|
|
592
|
+
: node_path_1.default.resolve(location, filename),
|
|
593
|
+
rename: event === "rename",
|
|
594
|
+
})), (location, error) => this.callbacks.onError(location, error), () => this.closed === false);
|
|
514
595
|
return [...this.directoryWatchers].some(([key, watcher]) => previous.get(key) !== watcher);
|
|
515
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* Decide a notification in the event loop's check phase, together with every
|
|
599
|
+
* other notification the same poll iteration delivered (samchon/ttsc#1741).
|
|
600
|
+
*
|
|
601
|
+
* One filesystem change usually arrives as several notifications, rename and
|
|
602
|
+
* change or create and modify, and each listed the compiler inputs or
|
|
603
|
+
* rescanned the project inputs again. Identical notifications of one lane,
|
|
604
|
+
* location and path merge, keeping a rename or a gap any of them carried, and
|
|
605
|
+
* the batch refreshes compiler membership once after deciding them all. The
|
|
606
|
+
* refresh therefore starts after every notification it absorbs, and one
|
|
607
|
+
* delivered later schedules another batch.
|
|
608
|
+
*/
|
|
609
|
+
deferNotification(notification) {
|
|
610
|
+
if (this.closed)
|
|
611
|
+
return;
|
|
612
|
+
const key = [
|
|
613
|
+
notification.lane,
|
|
614
|
+
notification.location,
|
|
615
|
+
notification.changed ?? "",
|
|
616
|
+
].join("\0");
|
|
617
|
+
const pending = this.pendingNotifications.get(key);
|
|
618
|
+
if (pending !== undefined) {
|
|
619
|
+
pending.rename ||= notification.rename;
|
|
620
|
+
pending.gap ||= notification.gap;
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
this.pendingNotifications.set(key, { ...notification });
|
|
624
|
+
if (this.notificationsScheduled)
|
|
625
|
+
return;
|
|
626
|
+
this.notificationsScheduled = true;
|
|
627
|
+
setImmediate(() => this.decideNotifications());
|
|
628
|
+
}
|
|
629
|
+
decideNotifications() {
|
|
630
|
+
this.notificationsScheduled = false;
|
|
631
|
+
const pending = [...this.pendingNotifications.values()];
|
|
632
|
+
this.pendingNotifications.clear();
|
|
633
|
+
if (this.closed)
|
|
634
|
+
return;
|
|
635
|
+
const refreshes = [];
|
|
636
|
+
for (const notification of pending) {
|
|
637
|
+
if (notification.lane === "project-input") {
|
|
638
|
+
this.refreshProjectInputs(notification.location, notification.changed);
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
this.decideCompilerDirectoryNotification(notification, refreshes);
|
|
642
|
+
}
|
|
643
|
+
if (refreshes.length === 0 || this.closed)
|
|
644
|
+
return;
|
|
645
|
+
this.beginLexicalTransaction();
|
|
646
|
+
this.refreshFromDirectories(refreshes);
|
|
647
|
+
}
|
|
648
|
+
/** Decide one merged directory notification of the compiler lane. */
|
|
649
|
+
decideCompilerDirectoryNotification(notification, refreshes) {
|
|
650
|
+
this.beginLexicalTransaction();
|
|
651
|
+
const { changed, location } = notification;
|
|
652
|
+
const pluginInput = changed ?? location;
|
|
653
|
+
if (this.isPluginInput(pluginInput)) {
|
|
654
|
+
this.notePluginNotification(pluginInput);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
const plan = (0, planCompilerDirectoryWatchEvent_1.planCompilerDirectoryWatchEvent)({
|
|
658
|
+
changed,
|
|
659
|
+
event: notification.rename ? "rename" : "change",
|
|
660
|
+
exists: node_fs_1.default.existsSync,
|
|
661
|
+
location,
|
|
662
|
+
identities: this.lexicalIdentities,
|
|
663
|
+
platform: process.platform,
|
|
664
|
+
trackedFiles: this.files,
|
|
665
|
+
});
|
|
666
|
+
this.rearmFileWatchers(plan.rearm);
|
|
667
|
+
for (const file of this.compilerChangesToReport(plan.changes, changed, notification.gap)) {
|
|
668
|
+
this.reportCompilerFileChange(file);
|
|
669
|
+
}
|
|
670
|
+
if (plan.refresh)
|
|
671
|
+
refreshes.push({ changed, location });
|
|
672
|
+
}
|
|
516
673
|
/**
|
|
517
674
|
* Reconcile tracked compiler files after a newly registered watcher returns.
|
|
518
675
|
*
|
|
@@ -607,6 +764,7 @@ class WatchTopology {
|
|
|
607
764
|
if (node_fs_1.default.existsSync(location)) {
|
|
608
765
|
if (this.projectInputMatches.size !== 0) {
|
|
609
766
|
const key = (0, createProjectInputPathIdentityContext_1.createProjectInputPathIdentityContext)({
|
|
767
|
+
caseSensitive: this.caseObservations,
|
|
610
768
|
throwOnRealpathError: false,
|
|
611
769
|
}).resolve(location).key;
|
|
612
770
|
if (this.projectInputMatches.has(key) &&
|
|
@@ -701,7 +859,7 @@ class WatchTopology {
|
|
|
701
859
|
return;
|
|
702
860
|
const previous = new Map(this.projectInputWatchers);
|
|
703
861
|
const previousLinks = new Map(this.projectInputLinkWatchers);
|
|
704
|
-
const identities =
|
|
862
|
+
const identities = this.projectInputIdentities();
|
|
705
863
|
const desired = new Map();
|
|
706
864
|
const required = new Map();
|
|
707
865
|
for (const file of this.projectInputDeclarations("file")) {
|
|
@@ -737,10 +895,15 @@ class WatchTopology {
|
|
|
737
895
|
active.set(identity.key, identity.path);
|
|
738
896
|
}
|
|
739
897
|
this.projectInputRequiredWatchRoots = required;
|
|
740
|
-
(0, syncWatchers_1.syncWatchers)(this.projectInputWatchers, active, (location) => this.openDirectoryWatch(watcherRegistrationPath(location), true, (_event, filename) => {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
898
|
+
(0, syncWatchers_1.syncWatchers)(this.projectInputWatchers, active, (location) => this.openDirectoryWatch(watcherRegistrationPath(location), true, (_event, filename) => this.deferNotification({
|
|
899
|
+
gap: false,
|
|
900
|
+
lane: "project-input",
|
|
901
|
+
location,
|
|
902
|
+
changed: filename === null
|
|
903
|
+
? undefined
|
|
904
|
+
: node_path_1.default.resolve(location, filename),
|
|
905
|
+
rename: false,
|
|
906
|
+
})), (location, error) => {
|
|
744
907
|
const key = identities.resolve(location).key;
|
|
745
908
|
const firstFailure = !this.projectInputRejectedWatchRoots.has(key);
|
|
746
909
|
this.projectInputRejectedWatchRoots.add(key);
|
|
@@ -796,10 +959,15 @@ class WatchTopology {
|
|
|
796
959
|
desired.set(identities.resolve(parent).key, parent);
|
|
797
960
|
}
|
|
798
961
|
}
|
|
799
|
-
(0, syncWatchers_1.syncWatchers)(this.projectInputLinkWatchers, desired, (location) => this.openDirectoryWatch(watcherRegistrationPath(location), false, (_event, filename) => {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
962
|
+
(0, syncWatchers_1.syncWatchers)(this.projectInputLinkWatchers, desired, (location) => this.openDirectoryWatch(watcherRegistrationPath(location), false, (_event, filename) => this.deferNotification({
|
|
963
|
+
gap: false,
|
|
964
|
+
lane: "project-input",
|
|
965
|
+
location,
|
|
966
|
+
changed: filename === null
|
|
967
|
+
? undefined
|
|
968
|
+
: node_path_1.default.resolve(location, filename),
|
|
969
|
+
rename: false,
|
|
970
|
+
})), (location, error) => this.callbacks.onError(location, error), () => this.closed === false);
|
|
803
971
|
}
|
|
804
972
|
/** Drop the watcher that just reported a directory replacement. */
|
|
805
973
|
retireProjectInputWatcher(location, identities) {
|
|
@@ -857,6 +1025,7 @@ class WatchTopology {
|
|
|
857
1025
|
return;
|
|
858
1026
|
this.projectInputRecoveryScheduled = true;
|
|
859
1027
|
queueMicrotask(() => {
|
|
1028
|
+
this.beginLexicalTransaction();
|
|
860
1029
|
try {
|
|
861
1030
|
let previousRejectionCount = -1;
|
|
862
1031
|
while (this.closed === false &&
|
|
@@ -895,6 +1064,7 @@ class WatchTopology {
|
|
|
895
1064
|
this.projectInputPostRegistrationReconciliationScheduled = false;
|
|
896
1065
|
if (this.closed)
|
|
897
1066
|
return;
|
|
1067
|
+
this.beginLexicalTransaction();
|
|
898
1068
|
this.refreshPublishedProjectInputIdentities();
|
|
899
1069
|
this.refreshProjectInputs(this.projectInputs.root, undefined, true);
|
|
900
1070
|
});
|
|
@@ -908,8 +1078,9 @@ class WatchTopology {
|
|
|
908
1078
|
* that must observe later target changes.
|
|
909
1079
|
*/
|
|
910
1080
|
refreshPublishedProjectInputIdentities() {
|
|
911
|
-
const
|
|
912
|
-
|
|
1081
|
+
const identities = this.projectInputIdentities();
|
|
1082
|
+
const next = normalizeProjectInputSnapshot(this.declaredProjectInputs, identities);
|
|
1083
|
+
if (projectInputSnapshotsEqual(this.projectInputs, next, identities))
|
|
913
1084
|
return;
|
|
914
1085
|
this.projectInputs = next;
|
|
915
1086
|
this.pruneProjectInputWatchRoots([next, this.declaredProjectInputs]);
|
|
@@ -997,7 +1168,7 @@ class WatchTopology {
|
|
|
997
1168
|
const retained = this.projectInputWatchRoots.get(key);
|
|
998
1169
|
if (retained !== undefined && WatchPaths_1.WatchPaths.isDirectory(retained))
|
|
999
1170
|
return retained;
|
|
1000
|
-
const resolved = ProjectInputWatchRules_1.ProjectInputWatchRules.projectInputRecursiveWatchRoot(target, this.projectInputs.root);
|
|
1171
|
+
const resolved = ProjectInputWatchRules_1.ProjectInputWatchRules.projectInputRecursiveWatchRoot(target, this.projectInputs.root, this.projectInputIdentities());
|
|
1001
1172
|
if (resolved !== undefined)
|
|
1002
1173
|
this.projectInputWatchRoots.set(key, resolved);
|
|
1003
1174
|
return resolved;
|
|
@@ -1006,7 +1177,7 @@ class WatchTopology {
|
|
|
1006
1177
|
this.beginLexicalTransaction();
|
|
1007
1178
|
try {
|
|
1008
1179
|
const previous = this.projectInputMatches;
|
|
1009
|
-
const identities =
|
|
1180
|
+
const identities = this.projectInputIdentities();
|
|
1010
1181
|
// One population for the whole decision. Every question below is asked of
|
|
1011
1182
|
// the same declarations, and rebuilding it per question would both cost
|
|
1012
1183
|
// more and let two answers disagree about what was declared.
|
|
@@ -1033,12 +1204,25 @@ class WatchTopology {
|
|
|
1033
1204
|
}
|
|
1034
1205
|
const next = this.collectProjectInputMatches();
|
|
1035
1206
|
const membershipChanged = WatchPaths_1.WatchPaths.mapsEqual(previous, next) === false;
|
|
1036
|
-
|
|
1207
|
+
// A named notification reads the named path's bytes and any file whose
|
|
1208
|
+
// metadata or owner moved; one that names nothing reads every file
|
|
1209
|
+
// (samchon/ttsc#1748).
|
|
1210
|
+
const scanned = changed === undefined ||
|
|
1037
1211
|
membershipChanged ||
|
|
1038
1212
|
directlyMatched ||
|
|
1039
1213
|
topologyMatched
|
|
1040
|
-
? fingerprintProjectInputMatches(next, this.readDirectory
|
|
1041
|
-
|
|
1214
|
+
? fingerprintProjectInputMatches(next, this.readDirectory, changed === undefined
|
|
1215
|
+
? undefined
|
|
1216
|
+
: {
|
|
1217
|
+
fingerprints: this.projectInputFingerprints,
|
|
1218
|
+
named: identities.resolve(changed).key,
|
|
1219
|
+
snapshots: this.projectInputFileSnapshots,
|
|
1220
|
+
})
|
|
1221
|
+
: {
|
|
1222
|
+
fingerprints: this.projectInputFingerprints,
|
|
1223
|
+
snapshots: this.projectInputFileSnapshots,
|
|
1224
|
+
};
|
|
1225
|
+
const nextFingerprints = scanned.fingerprints;
|
|
1042
1226
|
const contentChanged = WatchPaths_1.WatchPaths.mapsEqual(this.projectInputFingerprints, nextFingerprints) === false;
|
|
1043
1227
|
const changedInputs = projectInputChangedPaths({
|
|
1044
1228
|
next,
|
|
@@ -1065,7 +1249,7 @@ class WatchTopology {
|
|
|
1065
1249
|
reloadDirectories: population.reloadDirectories ?? [],
|
|
1066
1250
|
reloadFiles: population.reloadFiles ?? [],
|
|
1067
1251
|
};
|
|
1068
|
-
const reload = (0, projectInputReloadEventShouldNotify_1.projectInputReloadEventShouldNotify)(reloadInput);
|
|
1252
|
+
const reload = (0, projectInputReloadEventShouldNotify_1.projectInputReloadEventShouldNotify)(reloadInput, identities);
|
|
1069
1253
|
const invalidate = (0, projectInputMembershipInvalidatesProgram_1.projectInputMembershipInvalidatesProgram)({
|
|
1070
1254
|
changed: reconciledChange,
|
|
1071
1255
|
changedInputs,
|
|
@@ -1075,6 +1259,7 @@ class WatchTopology {
|
|
|
1075
1259
|
});
|
|
1076
1260
|
this.projectInputMatches = next;
|
|
1077
1261
|
this.projectInputFingerprints = nextFingerprints;
|
|
1262
|
+
this.projectInputFileSnapshots = scanned.snapshots;
|
|
1078
1263
|
this.syncProjectInputWatchers(skipUnobservedProjectInputWatchRoots);
|
|
1079
1264
|
// A JSON/TS/JS project-input member can simultaneously enter or leave
|
|
1080
1265
|
// the compiler Program. Reconcile the compiler watch snapshot before
|
|
@@ -1126,7 +1311,7 @@ class WatchTopology {
|
|
|
1126
1311
|
}
|
|
1127
1312
|
}
|
|
1128
1313
|
collectProjectInputMatches() {
|
|
1129
|
-
const identities =
|
|
1314
|
+
const identities = this.projectInputIdentities();
|
|
1130
1315
|
const matches = new Map();
|
|
1131
1316
|
// Both spellings are scanned, and each is resolved here rather than when
|
|
1132
1317
|
// the snapshot arrived. A declaration reached through a symlink otherwise
|
|
@@ -1207,20 +1392,81 @@ class WatchTopology {
|
|
|
1207
1392
|
return matches;
|
|
1208
1393
|
}
|
|
1209
1394
|
refreshFromDirectory(location, changed) {
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1395
|
+
this.refreshFromDirectories([{ changed, location }]);
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Refresh compiler membership once for every directory a decision asked
|
|
1399
|
+
* about. A failed refresh still reports, once each, the reload inputs every
|
|
1400
|
+
* requested change names.
|
|
1401
|
+
*
|
|
1402
|
+
* A replacement can be delivered under only its vanished temporary name,
|
|
1403
|
+
* including when its malformed bytes prevent refresh. Reconcile active
|
|
1404
|
+
* reload-file snapshots on either outcome, deduplicate failed-refresh
|
|
1405
|
+
* recovery against actual reported movement, and preserve the original
|
|
1406
|
+
* refresh error after recovery. Batch moved owners through the existing rearm
|
|
1407
|
+
* operation before notifying, because a POSIX per-file handle still owns the
|
|
1408
|
+
* old inode. Unchanged snapshots stay quiet unless the existing
|
|
1409
|
+
* failed-refresh selector explicitly names or cannot find the reload input.
|
|
1410
|
+
*/
|
|
1411
|
+
refreshFromDirectories(refreshes) {
|
|
1412
|
+
for (const { changed } of refreshes) {
|
|
1413
|
+
if (changed !== undefined &&
|
|
1414
|
+
WatchPaths_1.WatchPaths.isDirectory(changed) &&
|
|
1415
|
+
this.isCompilerOutputDirectory(changed) === false &&
|
|
1416
|
+
this.isProjectInputDirectory(changed) === false) {
|
|
1417
|
+
this.observedDirectories.set(this.pathKey(changed), changed);
|
|
1418
|
+
}
|
|
1215
1419
|
}
|
|
1420
|
+
let refreshFailure;
|
|
1216
1421
|
try {
|
|
1217
1422
|
this.refresh(true);
|
|
1218
1423
|
}
|
|
1219
1424
|
catch (error) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1425
|
+
refreshFailure = { error };
|
|
1426
|
+
}
|
|
1427
|
+
try {
|
|
1428
|
+
if (this.closed)
|
|
1429
|
+
return;
|
|
1430
|
+
const changed = [];
|
|
1431
|
+
const rearm = [];
|
|
1432
|
+
const reported = new Set();
|
|
1433
|
+
for (const reload of this.reloadFiles.values()) {
|
|
1434
|
+
if (this.closed)
|
|
1435
|
+
return;
|
|
1436
|
+
const movement = this.compilerFileMovement(reload);
|
|
1437
|
+
if (movement.owner)
|
|
1438
|
+
rearm.push(reload);
|
|
1439
|
+
if (this.compilerMovementReports(reload, movement))
|
|
1440
|
+
changed.push(reload);
|
|
1222
1441
|
}
|
|
1223
|
-
|
|
1442
|
+
if (rearm.length !== 0)
|
|
1443
|
+
this.rearmFileWatchers(rearm, true);
|
|
1444
|
+
for (const reload of changed) {
|
|
1445
|
+
if (this.closed)
|
|
1446
|
+
return;
|
|
1447
|
+
reported.add(this.pathKey(reload));
|
|
1448
|
+
this.reportCompilerFileChange(reload);
|
|
1449
|
+
}
|
|
1450
|
+
if (refreshFailure !== undefined) {
|
|
1451
|
+
for (const { changed } of refreshes) {
|
|
1452
|
+
for (const reload of (0, reloadInputsForFailedTopologyRefresh_1.reloadInputsForFailedTopologyRefresh)(this.reloadFiles.values(), changed, this.lexicalIdentities)) {
|
|
1453
|
+
if (this.closed)
|
|
1454
|
+
return;
|
|
1455
|
+
const key = this.pathKey(reload);
|
|
1456
|
+
if (reported.has(key))
|
|
1457
|
+
continue;
|
|
1458
|
+
reported.add(key);
|
|
1459
|
+
this.callbacks.onInputChange({ kind: "config", path: reload });
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
catch (error) {
|
|
1465
|
+
this.callbacks.onError(refreshes[0].location, error);
|
|
1466
|
+
}
|
|
1467
|
+
finally {
|
|
1468
|
+
if (refreshFailure !== undefined)
|
|
1469
|
+
this.callbacks.onError(refreshes[0].location, refreshFailure.error);
|
|
1224
1470
|
}
|
|
1225
1471
|
}
|
|
1226
1472
|
isCompilerOutputDirectory(location) {
|
|
@@ -1265,7 +1511,7 @@ class WatchTopology {
|
|
|
1265
1511
|
}
|
|
1266
1512
|
isProjectInputDirectory(location) {
|
|
1267
1513
|
const resolved = node_path_1.default.resolve(location);
|
|
1268
|
-
const identities =
|
|
1514
|
+
const identities = this.projectInputIdentities();
|
|
1269
1515
|
return (this.projectInputs.files.some((file) => identities.isWithin(resolved, file) ||
|
|
1270
1516
|
identities.isWithin(node_path_1.default.dirname(file), resolved)) ||
|
|
1271
1517
|
(this.projectInputs.reloadFiles ?? []).some((file) => identities.isWithin(resolved, file) ||
|
|
@@ -1378,6 +1624,23 @@ class WatchTopology {
|
|
|
1378
1624
|
}
|
|
1379
1625
|
}
|
|
1380
1626
|
exports.WatchTopology = WatchTopology;
|
|
1627
|
+
/**
|
|
1628
|
+
* Everything a compiler listing of `project` is asked with: the project, and
|
|
1629
|
+
* each option `listCompilerInputs` passes to the compiler. Two refreshes with
|
|
1630
|
+
* the same question ask the compiler the same thing; only the disk can answer
|
|
1631
|
+
* them differently.
|
|
1632
|
+
*/
|
|
1633
|
+
function listingQuestion(project, options) {
|
|
1634
|
+
return JSON.stringify([
|
|
1635
|
+
project.path,
|
|
1636
|
+
project.root,
|
|
1637
|
+
options.binary ?? null,
|
|
1638
|
+
options.compilerArgsCwd ?? null,
|
|
1639
|
+
options.env ?? null,
|
|
1640
|
+
options.passthrough ?? null,
|
|
1641
|
+
options.pinCompilerProject ?? null,
|
|
1642
|
+
]);
|
|
1643
|
+
}
|
|
1381
1644
|
function resolveWatchTopology(options, extraInputs, identities, getCompilerInputs) {
|
|
1382
1645
|
const selection = CompilerProjectSelection_1.CompilerProjectSelection.read(options);
|
|
1383
1646
|
if (selection.inspectionError !== undefined)
|
|
@@ -1506,10 +1769,11 @@ function readProjectReferences(tsconfig) {
|
|
|
1506
1769
|
return references;
|
|
1507
1770
|
}
|
|
1508
1771
|
function listCompilerInputs(project, options) {
|
|
1772
|
+
const env = SidecarEnvironment_1.SidecarEnvironment.merge(process.env, options.env);
|
|
1509
1773
|
const tsgo = (0, resolveTsgo_1.resolveTsgo)({
|
|
1510
1774
|
binary: options.binary,
|
|
1511
1775
|
cwd: project.root,
|
|
1512
|
-
env
|
|
1776
|
+
env,
|
|
1513
1777
|
});
|
|
1514
1778
|
const result = (0, spawnNative_1.spawnNative)(tsgo.binary, [
|
|
1515
1779
|
"-p",
|
|
@@ -1521,7 +1785,7 @@ function listCompilerInputs(project, options) {
|
|
|
1521
1785
|
...(options.pinCompilerProject === true ? ["-p", project.path] : []),
|
|
1522
1786
|
], {
|
|
1523
1787
|
cwd: options.compilerArgsCwd ?? project.root,
|
|
1524
|
-
env
|
|
1788
|
+
env,
|
|
1525
1789
|
encoding: "utf8",
|
|
1526
1790
|
});
|
|
1527
1791
|
if (result.error) {
|
|
@@ -1811,8 +2075,7 @@ function uniqueExistingPaths(paths, identities) {
|
|
|
1811
2075
|
}
|
|
1812
2076
|
return [...unique.values()];
|
|
1813
2077
|
}
|
|
1814
|
-
function normalizeProjectInputSnapshot(snapshot) {
|
|
1815
|
-
const identities = (0, createProjectInputPathIdentityContext_1.createProjectInputPathIdentityContext)();
|
|
2078
|
+
function normalizeProjectInputSnapshot(snapshot, identities) {
|
|
1816
2079
|
const files = new Map();
|
|
1817
2080
|
const globs = new Map();
|
|
1818
2081
|
const reloadDirectories = new Map();
|
|
@@ -1841,8 +2104,7 @@ function normalizeProjectInputSnapshot(snapshot) {
|
|
|
1841
2104
|
root: identities.resolve(snapshot.root).path,
|
|
1842
2105
|
};
|
|
1843
2106
|
}
|
|
1844
|
-
function projectInputSnapshotsEqual(left, right) {
|
|
1845
|
-
const identities = (0, createProjectInputPathIdentityContext_1.createProjectInputPathIdentityContext)();
|
|
2107
|
+
function projectInputSnapshotsEqual(left, right, identities) {
|
|
1846
2108
|
return (
|
|
1847
2109
|
// Every sibling comparison in this class decides on identity, and this one
|
|
1848
2110
|
// is only safe today because both operands come from the same normalizer.
|
|
@@ -1885,7 +2147,7 @@ function isSymbolicLink(location) {
|
|
|
1885
2147
|
return false;
|
|
1886
2148
|
}
|
|
1887
2149
|
}
|
|
1888
|
-
function matchesProjectInput(snapshot, location, identities
|
|
2150
|
+
function matchesProjectInput(snapshot, location, identities) {
|
|
1889
2151
|
const key = identities.resolve(location).key;
|
|
1890
2152
|
return (snapshot.files.some((file) => identities.resolve(file).key === key) ||
|
|
1891
2153
|
(snapshot.reloadFiles ?? []).some((file) => identities.resolve(file).key === key) ||
|
|
@@ -1971,8 +2233,7 @@ function compilerMembershipChange(previous, next) {
|
|
|
1971
2233
|
}
|
|
1972
2234
|
return [...changed.values()].sort();
|
|
1973
2235
|
}
|
|
1974
|
-
function projectInputCompilerMembershipChange(snapshot, changed) {
|
|
1975
|
-
const identities = (0, createProjectInputPathIdentityContext_1.createProjectInputPathIdentityContext)();
|
|
2236
|
+
function projectInputCompilerMembershipChange(snapshot, changed, identities) {
|
|
1976
2237
|
return changed.filter((location) => matchesProjectInput(snapshot, location, identities) &&
|
|
1977
2238
|
ProjectInputWatchRules_1.ProjectInputWatchRules.projectInputPathMayAffectProgram(location));
|
|
1978
2239
|
}
|
|
@@ -1985,8 +2246,7 @@ function projectInputCompilerMembershipChange(snapshot, changed) {
|
|
|
1985
2246
|
* immediate-entry delta instead of turning ordinary project data into a cold
|
|
1986
2247
|
* selection reload. The deepest matching glob owns the most specific delivery.
|
|
1987
2248
|
*/
|
|
1988
|
-
function projectInputCompilerMembershipProjectChanges(locations, globs) {
|
|
1989
|
-
const identities = (0, createProjectInputPathIdentityContext_1.createProjectInputPathIdentityContext)();
|
|
2249
|
+
function projectInputCompilerMembershipProjectChanges(locations, globs, identities) {
|
|
1990
2250
|
const roots = globs.map((glob) => identities.resolve((0, literalGlobRoot_1.literalGlobRoot)(glob)));
|
|
1991
2251
|
const changes = new Map();
|
|
1992
2252
|
for (const location of locations) {
|
|
@@ -2003,14 +2263,39 @@ function projectInputCompilerMembershipProjectChanges(locations, globs) {
|
|
|
2003
2263
|
}
|
|
2004
2264
|
return [...changes.values()].sort();
|
|
2005
2265
|
}
|
|
2006
|
-
|
|
2266
|
+
/**
|
|
2267
|
+
* Fingerprint every matched project input: a directory by its entries, a file
|
|
2268
|
+
* by its bytes.
|
|
2269
|
+
*
|
|
2270
|
+
* Without `previous`, every file is read. With it, a file keeps its previous
|
|
2271
|
+
* digest while its metadata and physical owner hold, unless it is the `named`
|
|
2272
|
+
* path, whose bytes are always read: a notification that names a file is the
|
|
2273
|
+
* one whose same-size rewrite within a timestamp tick metadata cannot show.
|
|
2274
|
+
*/
|
|
2275
|
+
function fingerprintProjectInputMatches(matches, readDirectory, previous) {
|
|
2007
2276
|
const fingerprints = new Map();
|
|
2277
|
+
const snapshots = new Map();
|
|
2008
2278
|
for (const [key, location] of matches) {
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2279
|
+
if (WatchPaths_1.WatchPaths.isDirectory(location)) {
|
|
2280
|
+
fingerprints.set(key, fingerprintProjectInputDirectory(location, readDirectory));
|
|
2281
|
+
continue;
|
|
2282
|
+
}
|
|
2283
|
+
const metadata = compilerFileSnapshot(location, "");
|
|
2284
|
+
const before = previous?.snapshots.get(key);
|
|
2285
|
+
const kept = previous?.fingerprints.get(key);
|
|
2286
|
+
const fingerprint = previous !== undefined &&
|
|
2287
|
+
key !== previous.named &&
|
|
2288
|
+
before !== undefined &&
|
|
2289
|
+
kept !== undefined &&
|
|
2290
|
+
metadata.content !== "" &&
|
|
2291
|
+
before.content === metadata.content &&
|
|
2292
|
+
before.owner === metadata.owner
|
|
2293
|
+
? kept
|
|
2294
|
+
: fingerprintProjectInputFile(location);
|
|
2295
|
+
fingerprints.set(key, fingerprint);
|
|
2296
|
+
snapshots.set(key, { ...metadata, fingerprint });
|
|
2297
|
+
}
|
|
2298
|
+
return { fingerprints, snapshots };
|
|
2014
2299
|
}
|
|
2015
2300
|
function fingerprintProjectInputFile(location) {
|
|
2016
2301
|
try {
|
|
@@ -2052,7 +2337,7 @@ function fingerprintProjectInputDirectory(location, readDirectory) {
|
|
|
2052
2337
|
return "";
|
|
2053
2338
|
}
|
|
2054
2339
|
}
|
|
2055
|
-
function matchesProjectInputGlob(pattern, location, identities
|
|
2340
|
+
function matchesProjectInputGlob(pattern, location, identities) {
|
|
2056
2341
|
const root = identities.resolve((0, literalGlobRoot_1.literalGlobRoot)(pattern));
|
|
2057
2342
|
const candidate = identities.resolve(location);
|
|
2058
2343
|
if (!(0, isProjectInputPathIdentityWithin_1.isProjectInputPathIdentityWithin)(root.key, candidate.key))
|