@ttsc/unplugin 0.31.5 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/core/bridge/TtscProjectRecord.d.cts +8 -0
- package/lib/core/bridge/TtscProjectRecord.d.mts +8 -0
- package/lib/core/bridge/TtscProjectRecord.d.ts +8 -0
- package/lib/core/bridge/readProjectRecordFile.js +5 -1
- package/lib/core/bridge/readProjectRecordFile.js.map +1 -1
- package/lib/core/bridge/readProjectRecordFile.mjs +5 -1
- package/lib/core/bridge/readProjectRecordFile.mjs.map +1 -1
- package/lib/core/observer/WatchScope.d.cts +3 -3
- package/lib/core/observer/WatchScope.d.mts +3 -3
- package/lib/core/observer/WatchScope.d.ts +3 -3
- package/lib/core/observer/createInputObserver.d.cts +7 -8
- package/lib/core/observer/createInputObserver.d.mts +7 -8
- package/lib/core/observer/createInputObserver.d.ts +7 -8
- package/lib/core/observer/createInputObserver.js +7 -8
- package/lib/core/observer/createInputObserver.js.map +1 -1
- package/lib/core/observer/createInputObserver.mjs +7 -8
- package/lib/core/observer/createInputObserver.mjs.map +1 -1
- package/lib/core/options/ResolvedTtscUnpluginOptions.d.cts +2 -0
- package/lib/core/options/ResolvedTtscUnpluginOptions.d.mts +2 -0
- package/lib/core/options/ResolvedTtscUnpluginOptions.d.ts +2 -0
- package/lib/core/options/TtscUnpluginOptions.d.cts +12 -2
- package/lib/core/options/TtscUnpluginOptions.d.mts +12 -2
- package/lib/core/options/TtscUnpluginOptions.d.ts +12 -2
- package/lib/core/options/resolveOptions.d.cts +4 -3
- package/lib/core/options/resolveOptions.d.mts +4 -3
- package/lib/core/options/resolveOptions.d.ts +4 -3
- package/lib/core/options/resolveOptions.js +5 -3
- package/lib/core/options/resolveOptions.js.map +1 -1
- package/lib/core/options/resolveOptions.mjs +5 -3
- package/lib/core/options/resolveOptions.mjs.map +1 -1
- package/lib/core/transform/TtscPrecompilation.d.cts +52 -0
- package/lib/core/transform/TtscPrecompilation.d.mts +52 -0
- package/lib/core/transform/TtscPrecompilation.d.ts +52 -0
- package/lib/core/transform/TtscPrecompilation.js +101 -0
- package/lib/core/transform/TtscPrecompilation.js.map +1 -0
- package/lib/core/transform/TtscPrecompilation.mjs +101 -0
- package/lib/core/transform/TtscPrecompilation.mjs.map +1 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.d.cts +2 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.d.mts +2 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.d.ts +2 -0
- package/lib/core/transform/cache/selectCachedGenerationAction.js +1 -1
- package/lib/core/transform/cache/selectCachedGenerationAction.js.map +1 -1
- package/lib/core/transform/cache/selectCachedGenerationAction.mjs +1 -1
- package/lib/core/transform/cache/selectCachedGenerationAction.mjs.map +1 -1
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.js +2 -0
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.js.map +1 -1
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.mjs +2 -0
- package/lib/core/transform/cache/withdrawTtscTransformGenerations.mjs.map +1 -1
- package/lib/core/transform/envelope/generationCaseSensitivity.d.cts +32 -0
- package/lib/core/transform/envelope/generationCaseSensitivity.d.mts +32 -0
- package/lib/core/transform/envelope/generationCaseSensitivity.d.ts +32 -0
- package/lib/core/transform/envelope/generationCaseSensitivity.js +39 -0
- package/lib/core/transform/envelope/generationCaseSensitivity.js.map +1 -0
- package/lib/core/transform/envelope/generationCaseSensitivity.mjs +37 -0
- package/lib/core/transform/envelope/generationCaseSensitivity.mjs.map +1 -0
- package/lib/core/transform/envelope/selectExternalInputPaths.js +2 -1
- package/lib/core/transform/envelope/selectExternalInputPaths.js.map +1 -1
- package/lib/core/transform/envelope/selectExternalInputPaths.mjs +2 -1
- package/lib/core/transform/envelope/selectExternalInputPaths.mjs.map +1 -1
- package/lib/core/transform/envelope/selectNotifiableAbsentInputs.js +2 -1
- package/lib/core/transform/envelope/selectNotifiableAbsentInputs.js.map +1 -1
- package/lib/core/transform/envelope/selectNotifiableAbsentInputs.mjs +2 -1
- package/lib/core/transform/envelope/selectNotifiableAbsentInputs.mjs.map +1 -1
- package/lib/core/transform/filesystem/createHostPathIdentityContext.d.cts +9 -1
- package/lib/core/transform/filesystem/createHostPathIdentityContext.d.mts +9 -1
- package/lib/core/transform/filesystem/createHostPathIdentityContext.d.ts +9 -1
- package/lib/core/transform/filesystem/createHostPathIdentityContext.js +10 -2
- package/lib/core/transform/filesystem/createHostPathIdentityContext.js.map +1 -1
- package/lib/core/transform/filesystem/createHostPathIdentityContext.mjs +10 -2
- package/lib/core/transform/filesystem/createHostPathIdentityContext.mjs.map +1 -1
- package/lib/core/transform/generation/captureTransformGeneration.d.cts +2 -0
- package/lib/core/transform/generation/captureTransformGeneration.d.mts +2 -0
- package/lib/core/transform/generation/captureTransformGeneration.d.ts +2 -0
- package/lib/core/transform/generation/captureTransformGeneration.js +17 -4
- package/lib/core/transform/generation/captureTransformGeneration.js.map +1 -1
- package/lib/core/transform/generation/captureTransformGeneration.mjs +17 -4
- package/lib/core/transform/generation/captureTransformGeneration.mjs.map +1 -1
- package/lib/core/transform/generation/selectPersistentHostInputs.js +2 -1
- package/lib/core/transform/generation/selectPersistentHostInputs.js.map +1 -1
- package/lib/core/transform/generation/selectPersistentHostInputs.mjs +2 -1
- package/lib/core/transform/generation/selectPersistentHostInputs.mjs.map +1 -1
- package/lib/core/transform/generation/transformProject.d.cts +2 -0
- package/lib/core/transform/generation/transformProject.d.mts +2 -0
- package/lib/core/transform/generation/transformProject.d.ts +2 -0
- package/lib/core/transform/generation/transformProject.js.map +1 -1
- package/lib/core/transform/generation/transformProject.mjs.map +1 -1
- package/lib/core/transform/inputs/nativeInputPredicateState.js.map +1 -1
- package/lib/core/transform/inputs/nativeInputPredicateState.mjs.map +1 -1
- package/lib/core/transform/tracker/createHostInputMutationTracker.d.cts +7 -1
- package/lib/core/transform/tracker/createHostInputMutationTracker.d.mts +7 -1
- package/lib/core/transform/tracker/createHostInputMutationTracker.d.ts +7 -1
- package/lib/core/transform/tracker/createHostInputMutationTracker.js +8 -2
- package/lib/core/transform/tracker/createHostInputMutationTracker.js.map +1 -1
- package/lib/core/transform/tracker/createHostInputMutationTracker.mjs +8 -2
- package/lib/core/transform/tracker/createHostInputMutationTracker.mjs.map +1 -1
- package/lib/core/transform/tracker/createProjectMutationTracker.d.cts +6 -4
- package/lib/core/transform/tracker/createProjectMutationTracker.d.mts +6 -4
- package/lib/core/transform/tracker/createProjectMutationTracker.d.ts +6 -4
- package/lib/core/transform/tracker/createProjectMutationTracker.js +29 -6
- package/lib/core/transform/tracker/createProjectMutationTracker.js.map +1 -1
- package/lib/core/transform/tracker/createProjectMutationTracker.mjs +29 -6
- package/lib/core/transform/tracker/createProjectMutationTracker.mjs.map +1 -1
- package/lib/core/transform/transformTtsc.d.cts +8 -24
- package/lib/core/transform/transformTtsc.d.mts +8 -24
- package/lib/core/transform/transformTtsc.d.ts +8 -24
- package/lib/core/transform/transformTtsc.js +56 -32
- package/lib/core/transform/transformTtsc.js.map +1 -1
- package/lib/core/transform/transformTtsc.mjs +56 -32
- package/lib/core/transform/transformTtsc.mjs.map +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.d.cts +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.d.mts +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.d.ts +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.js +12 -4
- package/lib/core/transform/validation/captureUniversalHostInputValidation.js.map +1 -1
- package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs +12 -4
- package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs.map +1 -1
- package/lib/core/transform/validation/matchesCachedSource.d.cts +9 -2
- package/lib/core/transform/validation/matchesCachedSource.d.mts +9 -2
- package/lib/core/transform/validation/matchesCachedSource.d.ts +9 -2
- package/lib/core/transform/validation/matchesCachedSource.js +11 -3
- package/lib/core/transform/validation/matchesCachedSource.js.map +1 -1
- package/lib/core/transform/validation/matchesCachedSource.mjs +11 -3
- package/lib/core/transform/validation/matchesCachedSource.mjs.map +1 -1
- package/lib/core/transform/watch/TtscTransformHooks.d.cts +9 -0
- package/lib/core/transform/watch/TtscTransformHooks.d.mts +9 -0
- package/lib/core/transform/watch/TtscTransformHooks.d.ts +9 -0
- package/lib/core/transform/watch/TtscWatchInputBaseline.d.cts +2 -1
- package/lib/core/transform/watch/TtscWatchInputBaseline.d.mts +2 -1
- package/lib/core/transform/watch/TtscWatchInputBaseline.d.ts +2 -1
- package/lib/core/transform/watch/isWatchInputKeyBaseline.js.map +1 -1
- package/lib/core/transform/watch/isWatchInputKeyBaseline.mjs.map +1 -1
- package/lib/core/transform/watch/notifyProjectRecord.d.cts +3 -4
- package/lib/core/transform/watch/notifyProjectRecord.d.mts +3 -4
- package/lib/core/transform/watch/notifyProjectRecord.d.ts +3 -4
- package/lib/core/transform/watch/notifyProjectRecord.js +5 -4
- package/lib/core/transform/watch/notifyProjectRecord.js.map +1 -1
- package/lib/core/transform/watch/notifyProjectRecord.mjs +5 -4
- package/lib/core/transform/watch/notifyProjectRecord.mjs.map +1 -1
- package/lib/core/transform/watch/recordedDependencyWitnesses.d.cts +30 -0
- package/lib/core/transform/watch/recordedDependencyWitnesses.d.mts +30 -0
- package/lib/core/transform/watch/recordedDependencyWitnesses.d.ts +30 -0
- package/lib/core/transform/watch/recordedDependencyWitnesses.js +51 -0
- package/lib/core/transform/watch/recordedDependencyWitnesses.js.map +1 -0
- package/lib/core/transform/watch/recordedDependencyWitnesses.mjs +49 -0
- package/lib/core/transform/watch/recordedDependencyWitnesses.mjs.map +1 -0
- package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.d.cts +1 -2
- package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.d.mts +1 -2
- package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.d.ts +1 -2
- package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.js +1 -2
- package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.js.map +1 -1
- package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.mjs +1 -2
- package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.mjs.map +1 -1
- package/lib/core/tsconfig/TsconfigReadTransaction.d.cts +11 -8
- package/lib/core/tsconfig/TsconfigReadTransaction.d.mts +11 -8
- package/lib/core/tsconfig/TsconfigReadTransaction.d.ts +11 -8
- package/lib/core/tsconfig/TsconfigReadTransaction.js +11 -8
- package/lib/core/tsconfig/TsconfigReadTransaction.js.map +1 -1
- package/lib/core/tsconfig/TsconfigReadTransaction.mjs +11 -8
- package/lib/core/tsconfig/TsconfigReadTransaction.mjs.map +1 -1
- package/lib/core/tsconfig/findDeclaredCompilerOption.d.cts +3 -2
- package/lib/core/tsconfig/findDeclaredCompilerOption.d.mts +3 -2
- package/lib/core/tsconfig/findDeclaredCompilerOption.d.ts +3 -2
- package/lib/core/tsconfig/findDeclaredCompilerOption.js +3 -2
- package/lib/core/tsconfig/findDeclaredCompilerOption.js.map +1 -1
- package/lib/core/tsconfig/findDeclaredCompilerOption.mjs +3 -2
- package/lib/core/tsconfig/findDeclaredCompilerOption.mjs.map +1 -1
- package/lib/core/tsconfig/findDeclaredFileSpecs.d.cts +3 -2
- package/lib/core/tsconfig/findDeclaredFileSpecs.d.mts +3 -2
- package/lib/core/tsconfig/findDeclaredFileSpecs.d.ts +3 -2
- package/lib/core/tsconfig/findDeclaredFileSpecs.js +3 -2
- package/lib/core/tsconfig/findDeclaredFileSpecs.js.map +1 -1
- package/lib/core/tsconfig/findDeclaredFileSpecs.mjs +3 -2
- package/lib/core/tsconfig/findDeclaredFileSpecs.mjs.map +1 -1
- package/lib/core/tsconfig/findDeclaredPaths.d.cts +3 -3
- package/lib/core/tsconfig/findDeclaredPaths.d.mts +3 -3
- package/lib/core/tsconfig/findDeclaredPaths.d.ts +3 -3
- package/lib/core/tsconfig/findDeclaredPaths.js +2 -2
- package/lib/core/tsconfig/findDeclaredPaths.mjs +2 -2
- package/lib/core/tsconfig/findDeclaredValue.d.cts +2 -1
- package/lib/core/tsconfig/findDeclaredValue.d.mts +2 -1
- package/lib/core/tsconfig/findDeclaredValue.d.ts +2 -1
- package/lib/core/tsconfig/findDeclaredValue.js +2 -1
- package/lib/core/tsconfig/findDeclaredValue.js.map +1 -1
- package/lib/core/tsconfig/findDeclaredValue.mjs +2 -1
- package/lib/core/tsconfig/findDeclaredValue.mjs.map +1 -1
- package/lib/core/tsconfig/readEffectiveTsconfigTemplateCompilerOptions.js +1 -1
- package/lib/core/tsconfig/readEffectiveTsconfigTemplateCompilerOptions.mjs +1 -1
- package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.d.cts +2 -2
- package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.d.mts +2 -2
- package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.d.ts +2 -2
- package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.js +2 -2
- package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.mjs +2 -2
- package/lib/core/tsconfig/readProjectMembershipPolicy.d.cts +3 -3
- package/lib/core/tsconfig/readProjectMembershipPolicy.d.mts +3 -3
- package/lib/core/tsconfig/readProjectMembershipPolicy.d.ts +3 -3
- package/lib/core/tsconfig/readProjectMembershipPolicy.js +4 -4
- package/lib/core/tsconfig/readProjectMembershipPolicy.mjs +4 -4
- package/lib/core/unplugin.js +14 -0
- package/lib/core/unplugin.js.map +1 -1
- package/lib/core/unplugin.mjs +14 -0
- package/lib/core/unplugin.mjs.map +1 -1
- package/lib/core/vite/installViteDependencyScanPlugins.d.cts +46 -0
- package/lib/core/vite/installViteDependencyScanPlugins.d.mts +46 -0
- package/lib/core/vite/installViteDependencyScanPlugins.d.ts +46 -0
- package/lib/core/vite/installViteDependencyScanPlugins.js +186 -0
- package/lib/core/vite/installViteDependencyScanPlugins.js.map +1 -0
- package/lib/core/vite/installViteDependencyScanPlugins.mjs +184 -0
- package/lib/core/vite/installViteDependencyScanPlugins.mjs.map +1 -0
- package/package.json +5 -4
- package/src/core/bridge/TtscProjectRecord.ts +9 -0
- package/src/core/bridge/readProjectRecordFile.ts +5 -1
- package/src/core/observer/WatchScope.ts +3 -3
- package/src/core/observer/createInputObserver.ts +7 -8
- package/src/core/options/ResolvedTtscUnpluginOptions.ts +3 -0
- package/src/core/options/TtscUnpluginOptions.ts +13 -2
- package/src/core/options/resolveOptions.ts +6 -3
- package/src/core/transform/TtscPrecompilation.ts +103 -0
- package/src/core/transform/cache/selectCachedGenerationAction.ts +3 -0
- package/src/core/transform/cache/withdrawTtscTransformGenerations.ts +2 -0
- package/src/core/transform/envelope/generationCaseSensitivity.ts +46 -0
- package/src/core/transform/envelope/selectExternalInputPaths.ts +5 -1
- package/src/core/transform/envelope/selectNotifiableAbsentInputs.ts +5 -1
- package/src/core/transform/filesystem/createHostPathIdentityContext.ts +9 -1
- package/src/core/transform/generation/captureTransformGeneration.ts +22 -2
- package/src/core/transform/generation/selectPersistentHostInputs.ts +5 -1
- package/src/core/transform/generation/transformProject.ts +3 -0
- package/src/core/transform/inputs/nativeInputPredicateState.ts +1 -3
- package/src/core/transform/tracker/createHostInputMutationTracker.ts +10 -1
- package/src/core/transform/tracker/createProjectMutationTracker.ts +34 -6
- package/src/core/transform/transformTtsc.ts +86 -37
- package/src/core/transform/validation/captureUniversalHostInputValidation.ts +12 -4
- package/src/core/transform/validation/matchesCachedSource.ts +9 -2
- package/src/core/transform/watch/TtscTransformHooks.ts +10 -0
- package/src/core/transform/watch/TtscWatchInputBaseline.ts +2 -1
- package/src/core/transform/watch/isWatchInputKeyBaseline.ts +4 -2
- package/src/core/transform/watch/notifyProjectRecord.ts +5 -4
- package/src/core/transform/watch/recordedDependencyWitnesses.ts +50 -0
- package/src/core/transform/watch/watchInputEvidenceMatchesBaseline.ts +1 -2
- package/src/core/tsconfig/TsconfigReadTransaction.ts +11 -8
- package/src/core/tsconfig/findDeclaredCompilerOption.ts +3 -2
- package/src/core/tsconfig/findDeclaredFileSpecs.ts +3 -2
- package/src/core/tsconfig/findDeclaredPaths.ts +3 -3
- package/src/core/tsconfig/findDeclaredValue.ts +2 -1
- package/src/core/tsconfig/readEffectiveTsconfigTemplateCompilerOptions.ts +1 -1
- package/src/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.ts +2 -2
- package/src/core/tsconfig/readProjectMembershipPolicy.ts +4 -4
- package/src/core/unplugin.ts +32 -0
- package/src/core/vite/installViteDependencyScanPlugins.ts +219 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { isTransformTarget } from "../isTransformTarget";
|
|
4
|
+
import type { ResolvedTtscUnpluginOptions } from "../options/ResolvedTtscUnpluginOptions";
|
|
5
|
+
import type { TtscTransformCache } from "./cache/TtscTransformCache";
|
|
6
|
+
import { transformCacheEpoch } from "./cache/transformCacheEpoch";
|
|
7
|
+
import { transformFilesystem } from "./cache/transformFilesystem";
|
|
8
|
+
import { pluginsAreDisabled } from "./utils/pluginsAreDisabled";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Schedule explicitly selected source entries before the host reaches their
|
|
12
|
+
* imports. Compilation and proof stay with the ordinary transform core.
|
|
13
|
+
*
|
|
14
|
+
* A host often discovers its next workspace project only after the preceding
|
|
15
|
+
* project's transform finishes (#1764). Starting known entries together avoids
|
|
16
|
+
* that dependency on host traversal order. Walking unrelated projects would
|
|
17
|
+
* execute plugins the user never selected, so this owner uses only the supplied
|
|
18
|
+
* entries. Preparation leaves module delivery and host registration to the
|
|
19
|
+
* actual request.
|
|
20
|
+
*
|
|
21
|
+
* @evidence contracts/common.md#principled-implementation Explicit entries authorize scheduling; the supplied core capture retains project selection, configuration identity and all generation proofs. The context contains the current working directory, options, aliases and delivery epoch, not new cache authority.
|
|
22
|
+
* @evidence contracts/common.md#clear-and-simple-design One scheduler owns per-cache startup deduplication and reset; the transform core owns compiled generations and their disposal.
|
|
23
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts No directory-wide discovery, plugin substitution or skipped proof is introduced; preparation never impersonates a host module delivery.
|
|
24
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains host traversal order, explicit effectful selection and separation from delivery; members state context lifetime and failure ownership.
|
|
25
|
+
* @evidence contracts/portability.md#os-neutral-implementation Entries resolve through native path semantics from the current cwd and read through the cache's filesystem boundary; source eligibility uses the adapter's existing shared predicate.
|
|
26
|
+
* @evidence contracts/performance.md#efficient-algorithms Each new context serializes cwd, options and aliases, then resolves and deduplicates E entries and reads their source bytes once. Capture starts without waiting for other entries; native capture and proof retain their own costs. Repeated requests serialize the context but do not reread the entries.
|
|
27
|
+
* @evidence contracts/performance.md#reuse-equivalent-work One latest context per cache and epoch starts each entry once; ordinary project keys deduplicate entries in the same project. Context equality controls scheduling only, and retained results still need normal admission.
|
|
28
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources A WeakMap retains one context string per live cache. Startup rejection handlers consume each detached promise; running captures and native resources remain cache-owned and withdrawal disposes their fulfilled generations. No cancellation deadline or entry-count cap is added.
|
|
29
|
+
*/
|
|
30
|
+
export namespace TtscPrecompilation {
|
|
31
|
+
const contexts = new WeakMap<TtscTransformCache, string>();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Start every eligible explicit entry without waiting for its siblings.
|
|
35
|
+
* Failed speculative preparation is reported when its module is requested, so
|
|
36
|
+
* an unrelated delivered project's load can proceed.
|
|
37
|
+
*
|
|
38
|
+
* @evidence contracts/common.md#principled-implementation The context is installed before captures start, so recursive and concurrent deliveries cannot restart the same batch; only supported source entries reach normal core capture.
|
|
39
|
+
* @evidence contracts/common.md#clear-and-simple-design One synchronous loop separates startup ownership from asynchronous capture settlement.
|
|
40
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Failed entry reads are not fabricated as empty source, and rejected captures do not become successful output. Actual delivery remains the error boundary.
|
|
41
|
+
* @evidence contracts/common.md#meaningful-documentation Prose states parallel startup and deferred error reporting; callback and context ownership remain explicit.
|
|
42
|
+
* @evidence contracts/portability.md#os-neutral-implementation Native absolute entry paths are passed as exact paths to capture and source reads use the same cache-owned filesystem as generation validation.
|
|
43
|
+
* @evidence contracts/performance.md#efficient-algorithms Context serialization precedes one E-entry deduplicating loop and actual source-byte reads; captures overlap their asynchronous work rather than being awaited sequentially.
|
|
44
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Identical latest cwd, options, aliases and epoch skip scheduling; project Promise identity and normal input proof decide compile reuse, independently of this scheduling record.
|
|
45
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Context state follows its weak cache key. Every started capture receives a rejection handler immediately; its own core/cache owners release native resources, including withdrawal during capture.
|
|
46
|
+
*/
|
|
47
|
+
export function start(
|
|
48
|
+
cache: TtscTransformCache,
|
|
49
|
+
options: ResolvedTtscUnpluginOptions,
|
|
50
|
+
aliasPaths: Record<string, string[]> | undefined,
|
|
51
|
+
capture: (file: string, source: string) => Promise<unknown>,
|
|
52
|
+
): void {
|
|
53
|
+
if (
|
|
54
|
+
options.precompile?.length === 0 ||
|
|
55
|
+
options.precompile === undefined ||
|
|
56
|
+
pluginsAreDisabled(options.plugins)
|
|
57
|
+
)
|
|
58
|
+
return;
|
|
59
|
+
// Entry, project and projectRoot paths all use cwd. The same relative
|
|
60
|
+
// options under another directory select different work, even if the
|
|
61
|
+
// host retains its cache; capture coordinates must belong to this call.
|
|
62
|
+
const cwd = process.cwd();
|
|
63
|
+
const context = JSON.stringify([
|
|
64
|
+
cwd,
|
|
65
|
+
options,
|
|
66
|
+
aliasPaths,
|
|
67
|
+
transformCacheEpoch(cache),
|
|
68
|
+
]);
|
|
69
|
+
if (contexts.get(cache) === context) return;
|
|
70
|
+
contexts.set(cache, context);
|
|
71
|
+
const entries = new Set<string>();
|
|
72
|
+
const filesystem = transformFilesystem(cache);
|
|
73
|
+
for (const entry of options.precompile) {
|
|
74
|
+
if (!isTransformTarget(entry)) continue;
|
|
75
|
+
const file = path.resolve(cwd, entry);
|
|
76
|
+
if (entries.has(file)) continue;
|
|
77
|
+
entries.add(file);
|
|
78
|
+
try {
|
|
79
|
+
const source = filesystem.readFile(file).toString("utf8");
|
|
80
|
+
void capture(file, source).catch(() => undefined);
|
|
81
|
+
} catch {
|
|
82
|
+
// A missing entry must not poison another project's load. Its actual
|
|
83
|
+
// host delivery still owns the native read error and recovery.
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* End startup ownership when the cache withdraws its generations.
|
|
90
|
+
*
|
|
91
|
+
* @evidence contracts/common.md#principled-implementation Withdrawal removes scheduling state with generation ownership so a later lifecycle can prepare the same entries again.
|
|
92
|
+
* @evidence contracts/common.md#clear-and-simple-design One weak-key deletion shares the cache's existing reset boundary.
|
|
93
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Clearing scheduling permission does not admit or cancel any compiled result.
|
|
94
|
+
* @evidence contracts/common.md#meaningful-documentation The headline identifies the same generation withdrawal boundary used by callers.
|
|
95
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation WeakMap deletion performs no native operation.
|
|
96
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms One identity deletion chooses no traversal or processing strategy.
|
|
97
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This operation withdraws the previous scheduling record rather than reusing work.
|
|
98
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Deletion releases the single scheduling record; native resources remain owned by generation withdrawal.
|
|
99
|
+
*/
|
|
100
|
+
export function clear(cache: TtscTransformCache): void {
|
|
101
|
+
contexts.delete(cache);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -43,6 +43,8 @@ export function selectCachedGenerationAction(props: {
|
|
|
43
43
|
generation: Promise<TtscCachedProjectTransform>;
|
|
44
44
|
key: string;
|
|
45
45
|
source: string;
|
|
46
|
+
/** False only for speculative source reads before an actual module delivery. */
|
|
47
|
+
reportDivergence?: boolean;
|
|
46
48
|
proof?: TtscGenerationProof.Transaction;
|
|
47
49
|
}): "serve" | "retry" | "capture" {
|
|
48
50
|
if (
|
|
@@ -57,6 +59,7 @@ export function selectCachedGenerationAction(props: {
|
|
|
57
59
|
props.source,
|
|
58
60
|
props.epoch,
|
|
59
61
|
props.proof,
|
|
62
|
+
props.reportDivergence,
|
|
60
63
|
)
|
|
61
64
|
) {
|
|
62
65
|
return "serve";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TtscPrecompilation } from "../TtscPrecompilation";
|
|
1
2
|
import type { TtscTransformCache } from "./TtscTransformCache";
|
|
2
3
|
import { disposeCachedTransform } from "./disposeCachedTransform";
|
|
3
4
|
|
|
@@ -35,6 +36,7 @@ export function withdrawTtscTransformGenerations(
|
|
|
35
36
|
cache: TtscTransformCache,
|
|
36
37
|
): void {
|
|
37
38
|
const generations = [...cache.values()];
|
|
39
|
+
TtscPrecompilation.clear(cache);
|
|
38
40
|
cache.clear();
|
|
39
41
|
for (const generation of generations) {
|
|
40
42
|
void generation.then(disposeCachedTransform, () => undefined);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ITtscCompilerTransformation } from "ttsc";
|
|
2
|
+
|
|
3
|
+
import { resultFilesystem } from "../cache/resultFilesystem";
|
|
4
|
+
import type { TtscTransformFilesystemOperations } from "../filesystem/TtscTransformFilesystemOperations";
|
|
5
|
+
import { envelopeDerivation } from "./envelopeDerivation";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The directory case answers of one generation's identity context
|
|
9
|
+
* (`envelopeDerivation`), for another identity context built while that
|
|
10
|
+
* generation is captured over the same filesystem view.
|
|
11
|
+
*
|
|
12
|
+
* Capturing a generation builds several identity contexts: the input selections
|
|
13
|
+
* and the trackers' baselines. Each asked every directory's case policy again,
|
|
14
|
+
* which on Windows costs an `fsutil` process for a directory whose names cannot
|
|
15
|
+
* settle it (samchon/ttsc#1742). They now ask the generation's own context,
|
|
16
|
+
* which memoizes each directory once for the generation. A view other than the
|
|
17
|
+
* one registered for the result observes for itself, and a tracker's re-check
|
|
18
|
+
* after an event still builds a context of its own.
|
|
19
|
+
*
|
|
20
|
+
* @evidence contracts/common.md#principled-implementation Sharing is admitted only for the filesystem view registered for the result, the view the generation context observes; any other view keeps its own observations.
|
|
21
|
+
* @evidence contracts/common.md#clear-and-simple-design One selector returns the generation's case operation, or the view's own for another view, and callers pass it to the existing context factory.
|
|
22
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts No answer is cached beyond the generation context that observed it, and a tracker's event re-check is not routed through it.
|
|
23
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain the repeated probes, the view condition and the re-check exception.
|
|
24
|
+
* @evidence contracts/portability.md#os-neutral-implementation The generation context observes case policy through the registered view's own probes; no platform assumption is introduced.
|
|
25
|
+
* @evidence contracts/performance.md#efficient-algorithms One registry lookup and one derivation lookup; the returned operation delegates to the generation context's memo.
|
|
26
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Every context capturing one generation shares the generation's answer for each directory.
|
|
27
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The answers belong to the generation context, which the generation already owns; this selector retains nothing.
|
|
28
|
+
*/
|
|
29
|
+
export function generationCaseSensitivity(props: {
|
|
30
|
+
/** The view the caller's context observes through. */
|
|
31
|
+
filesystem: TtscTransformFilesystemOperations;
|
|
32
|
+
|
|
33
|
+
/** Native project directory of the generation. */
|
|
34
|
+
projectRoot: string;
|
|
35
|
+
|
|
36
|
+
/** The generation's compiler result. */
|
|
37
|
+
result: ITtscCompilerTransformation;
|
|
38
|
+
}): TtscTransformFilesystemOperations["caseSensitive"] {
|
|
39
|
+
if (resultFilesystem(props.result) !== props.filesystem)
|
|
40
|
+
return props.filesystem.caseSensitive;
|
|
41
|
+
const context = envelopeDerivation({
|
|
42
|
+
projectRoot: props.projectRoot,
|
|
43
|
+
result: props.result,
|
|
44
|
+
}).identityContext;
|
|
45
|
+
return (directory) => context.caseSensitive(directory);
|
|
46
|
+
}
|
|
@@ -10,6 +10,7 @@ import { isProjectWalkPath } from "../project/isProjectWalkPath";
|
|
|
10
10
|
import { isTransformScratchInput } from "../tsconfig/isTransformScratchInput";
|
|
11
11
|
import { envelopeDerivation } from "./envelopeDerivation";
|
|
12
12
|
import { envelopeGraphIndexes } from "./envelopeGraphIndexes";
|
|
13
|
+
import { generationCaseSensitivity } from "./generationCaseSensitivity";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Derive the absolute out-of-walk input set of a whole project transform: the
|
|
@@ -63,7 +64,10 @@ export function selectExternalInputPaths(props: {
|
|
|
63
64
|
}
|
|
64
65
|
const members: string[] = [];
|
|
65
66
|
const filesystem = props.filesystem ?? DEFAULT_FILESYSTEM_OPERATIONS;
|
|
66
|
-
const identities = createHostPathIdentityContext(
|
|
67
|
+
const identities = createHostPathIdentityContext(
|
|
68
|
+
filesystem,
|
|
69
|
+
generationCaseSensitivity({ ...props, filesystem }),
|
|
70
|
+
);
|
|
67
71
|
const resolutionCandidates = new Set<string>();
|
|
68
72
|
const graph = props.result.graph;
|
|
69
73
|
const graphState = envelopeDerivation({
|
|
@@ -8,6 +8,7 @@ import { relativeToProject } from "../filesystem/relativeToProject";
|
|
|
8
8
|
import { isTransformScratchInput } from "../tsconfig/isTransformScratchInput";
|
|
9
9
|
import { envelopeDerivation } from "./envelopeDerivation";
|
|
10
10
|
import { envelopeGraphIndexes } from "./envelopeGraphIndexes";
|
|
11
|
+
import { generationCaseSensitivity } from "./generationCaseSensitivity";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* The generation's resolution candidates recorded as not files, so its
|
|
@@ -72,7 +73,10 @@ export function selectNotifiableAbsentInputs(props: {
|
|
|
72
73
|
if (graph === undefined) {
|
|
73
74
|
return empty;
|
|
74
75
|
}
|
|
75
|
-
const identities = createHostPathIdentityContext(
|
|
76
|
+
const identities = createHostPathIdentityContext(
|
|
77
|
+
props.filesystem,
|
|
78
|
+
generationCaseSensitivity(props),
|
|
79
|
+
);
|
|
76
80
|
const graphState = envelopeDerivation({
|
|
77
81
|
projectRoot: props.projectRoot,
|
|
78
82
|
result: props.result,
|
|
@@ -29,6 +29,8 @@ import type { TtscTransformFilesystemOperations } from "./TtscTransformFilesyste
|
|
|
29
29
|
* The returned context memoizes path, realpath and case observations for
|
|
30
30
|
* repeated questions within one filesystem transaction. Callers must create
|
|
31
31
|
* a new context when later filesystem changes can invalidate those observations.
|
|
32
|
+
* A caller capturing one generation can hand in that generation's case answers,
|
|
33
|
+
* so its contexts do not each ask the filesystem again (samchon/ttsc#1742).
|
|
32
34
|
* @evidence contracts/performance.md#bound-retention-and-release-resources
|
|
33
35
|
* Ownership of the context and its maps transfers to the caller. Retained
|
|
34
36
|
* entries grow with queried paths and ancestors and have no internal eviction;
|
|
@@ -36,9 +38,15 @@ import type { TtscTransformFilesystemOperations } from "./TtscTransformFilesyste
|
|
|
36
38
|
*/
|
|
37
39
|
export function createHostPathIdentityContext(
|
|
38
40
|
filesystem: TtscTransformFilesystemOperations = DEFAULT_FILESYSTEM_OPERATIONS,
|
|
41
|
+
/**
|
|
42
|
+
* Case answers this context shares with the others of its unit of work,
|
|
43
|
+
* observed through the same `filesystem`; omitted, the context asks for
|
|
44
|
+
* itself.
|
|
45
|
+
*/
|
|
46
|
+
caseSensitive: TtscTransformFilesystemOperations["caseSensitive"] = filesystem.caseSensitive,
|
|
39
47
|
): FilesystemPathIdentityContext {
|
|
40
48
|
return createFilesystemPathIdentityContext({
|
|
41
|
-
caseSensitive
|
|
49
|
+
caseSensitive,
|
|
42
50
|
lstat: filesystem.lstat,
|
|
43
51
|
platform: filesystem.platform,
|
|
44
52
|
readdir: (directory) =>
|
|
@@ -12,6 +12,7 @@ import { TRANSFORM_RESULT_MEMBERSHIP } from "../cache/TRANSFORM_RESULT_MEMBERSHI
|
|
|
12
12
|
import type { TtscCachedProjectTransform } from "../cache/TtscCachedProjectTransform";
|
|
13
13
|
import { refreshFilesystemClockReference } from "../clock/refreshFilesystemClockReference";
|
|
14
14
|
import { reportDivergentDelivery } from "../diagnostics/reportDivergentDelivery";
|
|
15
|
+
import { generationCaseSensitivity } from "../envelope/generationCaseSensitivity";
|
|
15
16
|
import { selectDeclaredProjectInputKeys } from "../envelope/selectDeclaredProjectInputKeys";
|
|
16
17
|
import { selectExternalInputPaths } from "../envelope/selectExternalInputPaths";
|
|
17
18
|
import { selectNotifiableAbsentInputs } from "../envelope/selectNotifiableAbsentInputs";
|
|
@@ -126,6 +127,9 @@ export async function captureTransformGeneration(props: {
|
|
|
126
127
|
/** Host-delivered text compared with the compiler's on-disk source baseline. */
|
|
127
128
|
currentSource: string;
|
|
128
129
|
|
|
130
|
+
/** False for preparation, whose source read is not a host module delivery. */
|
|
131
|
+
reportDivergence?: boolean;
|
|
132
|
+
|
|
129
133
|
/** Optional delivery epoch to which this captured observation belongs. */
|
|
130
134
|
deliveryEpoch?: number;
|
|
131
135
|
|
|
@@ -457,6 +461,13 @@ export async function captureTransformGeneration(props: {
|
|
|
457
461
|
clockReferenceDirectory ?? scratchDirectory,
|
|
458
462
|
props.filesystem,
|
|
459
463
|
);
|
|
464
|
+
// Every context capturing this generation below shares the generation's
|
|
465
|
+
// directory case answers, rather than each asking again (samchon/ttsc#1742).
|
|
466
|
+
const generationCase = generationCaseSensitivity({
|
|
467
|
+
filesystem: props.filesystem,
|
|
468
|
+
projectRoot,
|
|
469
|
+
result,
|
|
470
|
+
});
|
|
460
471
|
const persistentHostInputs = selectPersistentHostInputs({
|
|
461
472
|
filesystem: props.filesystem,
|
|
462
473
|
projectRoot,
|
|
@@ -518,6 +529,7 @@ export async function captureTransformGeneration(props: {
|
|
|
518
529
|
projectRoot,
|
|
519
530
|
result,
|
|
520
531
|
}),
|
|
532
|
+
generationCase,
|
|
521
533
|
)
|
|
522
534
|
: undefined;
|
|
523
535
|
compileTrace?.("bridge-tracker-lifecycle", {
|
|
@@ -566,6 +578,7 @@ export async function captureTransformGeneration(props: {
|
|
|
566
578
|
.filter((input) => !absentCandidates.has(input))
|
|
567
579
|
.map((input) => [path.resolve(input), "presence" as const]),
|
|
568
580
|
),
|
|
581
|
+
generationCase,
|
|
569
582
|
)
|
|
570
583
|
: undefined;
|
|
571
584
|
compileTrace?.("bridge-tracker-lifecycle", {
|
|
@@ -628,7 +641,7 @@ export async function captureTransformGeneration(props: {
|
|
|
628
641
|
// this generation. A delivered text that differs, because a plugin ordered
|
|
629
642
|
// before ttsc rewrote the module or the file changed after the host read
|
|
630
643
|
// it, must not replace them: every sibling delivery compares the disk and
|
|
631
|
-
// would recompile the project (samchon/ttsc#1394).
|
|
644
|
+
// would recompile the project (samchon/ttsc#1394). An actual delivery is reported once
|
|
632
645
|
// instead, and the file's own compile is served.
|
|
633
646
|
const currentFileKey = toProjectKey(
|
|
634
647
|
projectRoot,
|
|
@@ -681,7 +694,14 @@ export async function captureTransformGeneration(props: {
|
|
|
681
694
|
props.currentFile,
|
|
682
695
|
diskHash ?? deliveredHash,
|
|
683
696
|
);
|
|
684
|
-
|
|
697
|
+
// Preparation reads native source only to seed the ordinary capture. A
|
|
698
|
+
// later edit is handled by generation proof, not a warning about a host
|
|
699
|
+
// rewrite: no host delivered that speculative module (#1764).
|
|
700
|
+
if (
|
|
701
|
+
props.reportDivergence !== false &&
|
|
702
|
+
diskHash !== undefined &&
|
|
703
|
+
diskHash !== deliveredHash
|
|
704
|
+
) {
|
|
685
705
|
reportDivergentDelivery(cached, props.currentFile);
|
|
686
706
|
}
|
|
687
707
|
// An adopted compile was certified by its publisher, and is matched below
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ITtscCompilerTransformation } from "ttsc";
|
|
2
2
|
|
|
3
|
+
import { generationCaseSensitivity } from "../envelope/generationCaseSensitivity";
|
|
3
4
|
import { selectListedFiles } from "../envelope/selectListedFiles";
|
|
4
5
|
import type { TtscTransformFilesystemOperations } from "../filesystem/TtscTransformFilesystemOperations";
|
|
5
6
|
import { createHostPathIdentityContext } from "../filesystem/createHostPathIdentityContext";
|
|
@@ -43,7 +44,10 @@ export function selectPersistentHostInputs(props: {
|
|
|
43
44
|
props.temporaryTsconfig === undefined
|
|
44
45
|
)
|
|
45
46
|
return inputs;
|
|
46
|
-
const identities = createHostPathIdentityContext(
|
|
47
|
+
const identities = createHostPathIdentityContext(
|
|
48
|
+
props.filesystem,
|
|
49
|
+
generationCaseSensitivity(props),
|
|
50
|
+
);
|
|
47
51
|
const temporary =
|
|
48
52
|
props.temporaryTsconfig === undefined
|
|
49
53
|
? undefined
|
|
@@ -97,6 +97,9 @@ export async function transformProject(props: {
|
|
|
97
97
|
/** Delivered module text compared against the compiler's disk observation. */
|
|
98
98
|
currentSource: string;
|
|
99
99
|
|
|
100
|
+
/** False for preparation, whose source read is not a host module delivery. */
|
|
101
|
+
reportDivergence?: boolean;
|
|
102
|
+
|
|
100
103
|
/**
|
|
101
104
|
* Delivery pass this compile was started for; see
|
|
102
105
|
* {@link TtscCachedProjectTransform.deliveryEpoch}.
|
|
@@ -69,9 +69,7 @@ export function nativeInputPredicateState(
|
|
|
69
69
|
} else if (kind === "optional-file") {
|
|
70
70
|
try {
|
|
71
71
|
digest = filesystem.stat(file).isFile()
|
|
72
|
-
? hash(
|
|
73
|
-
Buffer.concat([Buffer.from("file\0"), readBytes()]),
|
|
74
|
-
)
|
|
72
|
+
? hash(Buffer.concat([Buffer.from("file\0"), readBytes()]))
|
|
75
73
|
: hash("missing\0");
|
|
76
74
|
} catch (error) {
|
|
77
75
|
if (!missing(error)) return undefined;
|
|
@@ -114,12 +114,21 @@ export async function createHostInputMutationTracker(
|
|
|
114
114
|
* filesystem.
|
|
115
115
|
*/
|
|
116
116
|
scopes?: ReadonlyMap<string, TtscTrackedInputScope>,
|
|
117
|
+
/**
|
|
118
|
+
* The case answers of the generation this tracker watches, for its baseline
|
|
119
|
+
* (`generationCaseSensitivity`); omitted, the baseline observes for itself.
|
|
120
|
+
* An event's re-check always observes afresh.
|
|
121
|
+
*/
|
|
122
|
+
caseSensitive?: TtscTransformFilesystemOperations["caseSensitive"],
|
|
117
123
|
): Promise<TtscProjectMutationTracker> {
|
|
118
124
|
const paths =
|
|
119
125
|
(filesystem.platform ?? process.platform) === "win32"
|
|
120
126
|
? path.win32
|
|
121
127
|
: path.posix;
|
|
122
|
-
const identities = createHostPathIdentityContext(
|
|
128
|
+
const identities = createHostPathIdentityContext(
|
|
129
|
+
filesystem,
|
|
130
|
+
caseSensitive ?? filesystem.caseSensitive,
|
|
131
|
+
);
|
|
123
132
|
// The project root in both of its spellings: an input the compiler reported
|
|
124
133
|
// physically is the project's as much as one spelled as the project was
|
|
125
134
|
// named, and the root's observer is opened once, under the name.
|
|
@@ -38,10 +38,12 @@ import { watchLocationIdentity } from "./watchLocationIdentity";
|
|
|
38
38
|
* directory excluded in both lexical and native spellings. Unknown, missing and
|
|
39
39
|
* linked ancestry remains conservative. Membership rejection withdraws
|
|
40
40
|
* notification authority except below such a proven excluded directory, so a
|
|
41
|
-
* recursive backend's writes to a cache or output tree cost no proof
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* recursive backend's writes to a cache or output tree cost no proof, nor does
|
|
42
|
+
* an edit to an existing unlinked file whose every name the program cannot
|
|
43
|
+
* admit (samchon/ttsc#1737). Named events also compare current native identity
|
|
44
|
+
* and case policy with the retained identity transaction. Retargeting withdraws
|
|
45
|
+
* notification authority without changing the meaning of earlier recorded event
|
|
46
|
+
* spellings.
|
|
45
47
|
*
|
|
46
48
|
* @evidence contracts/common.md#principled-implementation
|
|
47
49
|
* The project walk and membership policy own structural relevance; content
|
|
@@ -193,6 +195,26 @@ export async function createProjectMutationTracker(
|
|
|
193
195
|
}
|
|
194
196
|
return excluded;
|
|
195
197
|
};
|
|
198
|
+
// Whether an event names an existing file no spelling can make a program
|
|
199
|
+
// member: a regular file with no second hard link, whose own and physical
|
|
200
|
+
// names are both names the program cannot admit. A directory alias can move
|
|
201
|
+
// a file into the program but cannot rename it, and a removed name, a link
|
|
202
|
+
// or a directory stays conservative.
|
|
203
|
+
const existingNonProgramFile = (changed: string): boolean => {
|
|
204
|
+
try {
|
|
205
|
+
const stats = filesystem.lstat(changed);
|
|
206
|
+
if (!stats.isFile() || stats.nlink > 1n) return false;
|
|
207
|
+
return (
|
|
208
|
+
!isPossibleProgramFileName(paths.basename(changed), policy) &&
|
|
209
|
+
!isPossibleProgramFileName(
|
|
210
|
+
paths.basename(filesystem.realpath(changed)),
|
|
211
|
+
policy,
|
|
212
|
+
)
|
|
213
|
+
);
|
|
214
|
+
} catch {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
196
218
|
const reportsMembership = (location: string, filename: string): boolean => {
|
|
197
219
|
const changed = paths.join(location, filename);
|
|
198
220
|
const current = createHostPathIdentityContext(filesystem);
|
|
@@ -221,8 +243,14 @@ export async function createProjectMutationTracker(
|
|
|
221
243
|
// except below a directory the walk provably excludes. A recursive backend
|
|
222
244
|
// (macOS, Windows) hears every write under the root, a cache or an output
|
|
223
245
|
// directory among them, and withdrawing authority for each sent every later
|
|
224
|
-
// delivery to the whole-snapshot proof.
|
|
225
|
-
|
|
246
|
+
// delivery to the whole-snapshot proof. An existing file whose every name
|
|
247
|
+
// the program cannot admit is no member either, a stylesheet or an asset
|
|
248
|
+
// edited in a source directory among them, on every backend.
|
|
249
|
+
if (
|
|
250
|
+
!membership &&
|
|
251
|
+
!excludedFromWalk(changed, true) &&
|
|
252
|
+
!existingNonProgramFile(changed)
|
|
253
|
+
)
|
|
226
254
|
tracker.unverified = true;
|
|
227
255
|
return membership;
|
|
228
256
|
};
|