@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.
Files changed (248) hide show
  1. package/lib/core/bridge/TtscProjectRecord.d.cts +8 -0
  2. package/lib/core/bridge/TtscProjectRecord.d.mts +8 -0
  3. package/lib/core/bridge/TtscProjectRecord.d.ts +8 -0
  4. package/lib/core/bridge/readProjectRecordFile.js +5 -1
  5. package/lib/core/bridge/readProjectRecordFile.js.map +1 -1
  6. package/lib/core/bridge/readProjectRecordFile.mjs +5 -1
  7. package/lib/core/bridge/readProjectRecordFile.mjs.map +1 -1
  8. package/lib/core/observer/WatchScope.d.cts +3 -3
  9. package/lib/core/observer/WatchScope.d.mts +3 -3
  10. package/lib/core/observer/WatchScope.d.ts +3 -3
  11. package/lib/core/observer/createInputObserver.d.cts +7 -8
  12. package/lib/core/observer/createInputObserver.d.mts +7 -8
  13. package/lib/core/observer/createInputObserver.d.ts +7 -8
  14. package/lib/core/observer/createInputObserver.js +7 -8
  15. package/lib/core/observer/createInputObserver.js.map +1 -1
  16. package/lib/core/observer/createInputObserver.mjs +7 -8
  17. package/lib/core/observer/createInputObserver.mjs.map +1 -1
  18. package/lib/core/options/ResolvedTtscUnpluginOptions.d.cts +2 -0
  19. package/lib/core/options/ResolvedTtscUnpluginOptions.d.mts +2 -0
  20. package/lib/core/options/ResolvedTtscUnpluginOptions.d.ts +2 -0
  21. package/lib/core/options/TtscUnpluginOptions.d.cts +12 -2
  22. package/lib/core/options/TtscUnpluginOptions.d.mts +12 -2
  23. package/lib/core/options/TtscUnpluginOptions.d.ts +12 -2
  24. package/lib/core/options/resolveOptions.d.cts +4 -3
  25. package/lib/core/options/resolveOptions.d.mts +4 -3
  26. package/lib/core/options/resolveOptions.d.ts +4 -3
  27. package/lib/core/options/resolveOptions.js +5 -3
  28. package/lib/core/options/resolveOptions.js.map +1 -1
  29. package/lib/core/options/resolveOptions.mjs +5 -3
  30. package/lib/core/options/resolveOptions.mjs.map +1 -1
  31. package/lib/core/transform/TtscPrecompilation.d.cts +52 -0
  32. package/lib/core/transform/TtscPrecompilation.d.mts +52 -0
  33. package/lib/core/transform/TtscPrecompilation.d.ts +52 -0
  34. package/lib/core/transform/TtscPrecompilation.js +101 -0
  35. package/lib/core/transform/TtscPrecompilation.js.map +1 -0
  36. package/lib/core/transform/TtscPrecompilation.mjs +101 -0
  37. package/lib/core/transform/TtscPrecompilation.mjs.map +1 -0
  38. package/lib/core/transform/cache/selectCachedGenerationAction.d.cts +2 -0
  39. package/lib/core/transform/cache/selectCachedGenerationAction.d.mts +2 -0
  40. package/lib/core/transform/cache/selectCachedGenerationAction.d.ts +2 -0
  41. package/lib/core/transform/cache/selectCachedGenerationAction.js +1 -1
  42. package/lib/core/transform/cache/selectCachedGenerationAction.js.map +1 -1
  43. package/lib/core/transform/cache/selectCachedGenerationAction.mjs +1 -1
  44. package/lib/core/transform/cache/selectCachedGenerationAction.mjs.map +1 -1
  45. package/lib/core/transform/cache/withdrawTtscTransformGenerations.js +2 -0
  46. package/lib/core/transform/cache/withdrawTtscTransformGenerations.js.map +1 -1
  47. package/lib/core/transform/cache/withdrawTtscTransformGenerations.mjs +2 -0
  48. package/lib/core/transform/cache/withdrawTtscTransformGenerations.mjs.map +1 -1
  49. package/lib/core/transform/envelope/generationCaseSensitivity.d.cts +32 -0
  50. package/lib/core/transform/envelope/generationCaseSensitivity.d.mts +32 -0
  51. package/lib/core/transform/envelope/generationCaseSensitivity.d.ts +32 -0
  52. package/lib/core/transform/envelope/generationCaseSensitivity.js +39 -0
  53. package/lib/core/transform/envelope/generationCaseSensitivity.js.map +1 -0
  54. package/lib/core/transform/envelope/generationCaseSensitivity.mjs +37 -0
  55. package/lib/core/transform/envelope/generationCaseSensitivity.mjs.map +1 -0
  56. package/lib/core/transform/envelope/selectExternalInputPaths.js +2 -1
  57. package/lib/core/transform/envelope/selectExternalInputPaths.js.map +1 -1
  58. package/lib/core/transform/envelope/selectExternalInputPaths.mjs +2 -1
  59. package/lib/core/transform/envelope/selectExternalInputPaths.mjs.map +1 -1
  60. package/lib/core/transform/envelope/selectNotifiableAbsentInputs.js +2 -1
  61. package/lib/core/transform/envelope/selectNotifiableAbsentInputs.js.map +1 -1
  62. package/lib/core/transform/envelope/selectNotifiableAbsentInputs.mjs +2 -1
  63. package/lib/core/transform/envelope/selectNotifiableAbsentInputs.mjs.map +1 -1
  64. package/lib/core/transform/filesystem/createHostPathIdentityContext.d.cts +9 -1
  65. package/lib/core/transform/filesystem/createHostPathIdentityContext.d.mts +9 -1
  66. package/lib/core/transform/filesystem/createHostPathIdentityContext.d.ts +9 -1
  67. package/lib/core/transform/filesystem/createHostPathIdentityContext.js +10 -2
  68. package/lib/core/transform/filesystem/createHostPathIdentityContext.js.map +1 -1
  69. package/lib/core/transform/filesystem/createHostPathIdentityContext.mjs +10 -2
  70. package/lib/core/transform/filesystem/createHostPathIdentityContext.mjs.map +1 -1
  71. package/lib/core/transform/generation/captureTransformGeneration.d.cts +2 -0
  72. package/lib/core/transform/generation/captureTransformGeneration.d.mts +2 -0
  73. package/lib/core/transform/generation/captureTransformGeneration.d.ts +2 -0
  74. package/lib/core/transform/generation/captureTransformGeneration.js +17 -4
  75. package/lib/core/transform/generation/captureTransformGeneration.js.map +1 -1
  76. package/lib/core/transform/generation/captureTransformGeneration.mjs +17 -4
  77. package/lib/core/transform/generation/captureTransformGeneration.mjs.map +1 -1
  78. package/lib/core/transform/generation/selectPersistentHostInputs.js +2 -1
  79. package/lib/core/transform/generation/selectPersistentHostInputs.js.map +1 -1
  80. package/lib/core/transform/generation/selectPersistentHostInputs.mjs +2 -1
  81. package/lib/core/transform/generation/selectPersistentHostInputs.mjs.map +1 -1
  82. package/lib/core/transform/generation/transformProject.d.cts +2 -0
  83. package/lib/core/transform/generation/transformProject.d.mts +2 -0
  84. package/lib/core/transform/generation/transformProject.d.ts +2 -0
  85. package/lib/core/transform/generation/transformProject.js.map +1 -1
  86. package/lib/core/transform/generation/transformProject.mjs.map +1 -1
  87. package/lib/core/transform/inputs/nativeInputPredicateState.js.map +1 -1
  88. package/lib/core/transform/inputs/nativeInputPredicateState.mjs.map +1 -1
  89. package/lib/core/transform/tracker/createHostInputMutationTracker.d.cts +7 -1
  90. package/lib/core/transform/tracker/createHostInputMutationTracker.d.mts +7 -1
  91. package/lib/core/transform/tracker/createHostInputMutationTracker.d.ts +7 -1
  92. package/lib/core/transform/tracker/createHostInputMutationTracker.js +8 -2
  93. package/lib/core/transform/tracker/createHostInputMutationTracker.js.map +1 -1
  94. package/lib/core/transform/tracker/createHostInputMutationTracker.mjs +8 -2
  95. package/lib/core/transform/tracker/createHostInputMutationTracker.mjs.map +1 -1
  96. package/lib/core/transform/tracker/createProjectMutationTracker.d.cts +6 -4
  97. package/lib/core/transform/tracker/createProjectMutationTracker.d.mts +6 -4
  98. package/lib/core/transform/tracker/createProjectMutationTracker.d.ts +6 -4
  99. package/lib/core/transform/tracker/createProjectMutationTracker.js +29 -6
  100. package/lib/core/transform/tracker/createProjectMutationTracker.js.map +1 -1
  101. package/lib/core/transform/tracker/createProjectMutationTracker.mjs +29 -6
  102. package/lib/core/transform/tracker/createProjectMutationTracker.mjs.map +1 -1
  103. package/lib/core/transform/transformTtsc.d.cts +8 -24
  104. package/lib/core/transform/transformTtsc.d.mts +8 -24
  105. package/lib/core/transform/transformTtsc.d.ts +8 -24
  106. package/lib/core/transform/transformTtsc.js +56 -32
  107. package/lib/core/transform/transformTtsc.js.map +1 -1
  108. package/lib/core/transform/transformTtsc.mjs +56 -32
  109. package/lib/core/transform/transformTtsc.mjs.map +1 -1
  110. package/lib/core/transform/validation/captureUniversalHostInputValidation.d.cts +1 -1
  111. package/lib/core/transform/validation/captureUniversalHostInputValidation.d.mts +1 -1
  112. package/lib/core/transform/validation/captureUniversalHostInputValidation.d.ts +1 -1
  113. package/lib/core/transform/validation/captureUniversalHostInputValidation.js +12 -4
  114. package/lib/core/transform/validation/captureUniversalHostInputValidation.js.map +1 -1
  115. package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs +12 -4
  116. package/lib/core/transform/validation/captureUniversalHostInputValidation.mjs.map +1 -1
  117. package/lib/core/transform/validation/matchesCachedSource.d.cts +9 -2
  118. package/lib/core/transform/validation/matchesCachedSource.d.mts +9 -2
  119. package/lib/core/transform/validation/matchesCachedSource.d.ts +9 -2
  120. package/lib/core/transform/validation/matchesCachedSource.js +11 -3
  121. package/lib/core/transform/validation/matchesCachedSource.js.map +1 -1
  122. package/lib/core/transform/validation/matchesCachedSource.mjs +11 -3
  123. package/lib/core/transform/validation/matchesCachedSource.mjs.map +1 -1
  124. package/lib/core/transform/watch/TtscTransformHooks.d.cts +9 -0
  125. package/lib/core/transform/watch/TtscTransformHooks.d.mts +9 -0
  126. package/lib/core/transform/watch/TtscTransformHooks.d.ts +9 -0
  127. package/lib/core/transform/watch/TtscWatchInputBaseline.d.cts +2 -1
  128. package/lib/core/transform/watch/TtscWatchInputBaseline.d.mts +2 -1
  129. package/lib/core/transform/watch/TtscWatchInputBaseline.d.ts +2 -1
  130. package/lib/core/transform/watch/isWatchInputKeyBaseline.js.map +1 -1
  131. package/lib/core/transform/watch/isWatchInputKeyBaseline.mjs.map +1 -1
  132. package/lib/core/transform/watch/notifyProjectRecord.d.cts +3 -4
  133. package/lib/core/transform/watch/notifyProjectRecord.d.mts +3 -4
  134. package/lib/core/transform/watch/notifyProjectRecord.d.ts +3 -4
  135. package/lib/core/transform/watch/notifyProjectRecord.js +5 -4
  136. package/lib/core/transform/watch/notifyProjectRecord.js.map +1 -1
  137. package/lib/core/transform/watch/notifyProjectRecord.mjs +5 -4
  138. package/lib/core/transform/watch/notifyProjectRecord.mjs.map +1 -1
  139. package/lib/core/transform/watch/recordedDependencyWitnesses.d.cts +30 -0
  140. package/lib/core/transform/watch/recordedDependencyWitnesses.d.mts +30 -0
  141. package/lib/core/transform/watch/recordedDependencyWitnesses.d.ts +30 -0
  142. package/lib/core/transform/watch/recordedDependencyWitnesses.js +51 -0
  143. package/lib/core/transform/watch/recordedDependencyWitnesses.js.map +1 -0
  144. package/lib/core/transform/watch/recordedDependencyWitnesses.mjs +49 -0
  145. package/lib/core/transform/watch/recordedDependencyWitnesses.mjs.map +1 -0
  146. package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.d.cts +1 -2
  147. package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.d.mts +1 -2
  148. package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.d.ts +1 -2
  149. package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.js +1 -2
  150. package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.js.map +1 -1
  151. package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.mjs +1 -2
  152. package/lib/core/transform/watch/watchInputEvidenceMatchesBaseline.mjs.map +1 -1
  153. package/lib/core/tsconfig/TsconfigReadTransaction.d.cts +11 -8
  154. package/lib/core/tsconfig/TsconfigReadTransaction.d.mts +11 -8
  155. package/lib/core/tsconfig/TsconfigReadTransaction.d.ts +11 -8
  156. package/lib/core/tsconfig/TsconfigReadTransaction.js +11 -8
  157. package/lib/core/tsconfig/TsconfigReadTransaction.js.map +1 -1
  158. package/lib/core/tsconfig/TsconfigReadTransaction.mjs +11 -8
  159. package/lib/core/tsconfig/TsconfigReadTransaction.mjs.map +1 -1
  160. package/lib/core/tsconfig/findDeclaredCompilerOption.d.cts +3 -2
  161. package/lib/core/tsconfig/findDeclaredCompilerOption.d.mts +3 -2
  162. package/lib/core/tsconfig/findDeclaredCompilerOption.d.ts +3 -2
  163. package/lib/core/tsconfig/findDeclaredCompilerOption.js +3 -2
  164. package/lib/core/tsconfig/findDeclaredCompilerOption.js.map +1 -1
  165. package/lib/core/tsconfig/findDeclaredCompilerOption.mjs +3 -2
  166. package/lib/core/tsconfig/findDeclaredCompilerOption.mjs.map +1 -1
  167. package/lib/core/tsconfig/findDeclaredFileSpecs.d.cts +3 -2
  168. package/lib/core/tsconfig/findDeclaredFileSpecs.d.mts +3 -2
  169. package/lib/core/tsconfig/findDeclaredFileSpecs.d.ts +3 -2
  170. package/lib/core/tsconfig/findDeclaredFileSpecs.js +3 -2
  171. package/lib/core/tsconfig/findDeclaredFileSpecs.js.map +1 -1
  172. package/lib/core/tsconfig/findDeclaredFileSpecs.mjs +3 -2
  173. package/lib/core/tsconfig/findDeclaredFileSpecs.mjs.map +1 -1
  174. package/lib/core/tsconfig/findDeclaredPaths.d.cts +3 -3
  175. package/lib/core/tsconfig/findDeclaredPaths.d.mts +3 -3
  176. package/lib/core/tsconfig/findDeclaredPaths.d.ts +3 -3
  177. package/lib/core/tsconfig/findDeclaredPaths.js +2 -2
  178. package/lib/core/tsconfig/findDeclaredPaths.mjs +2 -2
  179. package/lib/core/tsconfig/findDeclaredValue.d.cts +2 -1
  180. package/lib/core/tsconfig/findDeclaredValue.d.mts +2 -1
  181. package/lib/core/tsconfig/findDeclaredValue.d.ts +2 -1
  182. package/lib/core/tsconfig/findDeclaredValue.js +2 -1
  183. package/lib/core/tsconfig/findDeclaredValue.js.map +1 -1
  184. package/lib/core/tsconfig/findDeclaredValue.mjs +2 -1
  185. package/lib/core/tsconfig/findDeclaredValue.mjs.map +1 -1
  186. package/lib/core/tsconfig/readEffectiveTsconfigTemplateCompilerOptions.js +1 -1
  187. package/lib/core/tsconfig/readEffectiveTsconfigTemplateCompilerOptions.mjs +1 -1
  188. package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.d.cts +2 -2
  189. package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.d.mts +2 -2
  190. package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.d.ts +2 -2
  191. package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.js +2 -2
  192. package/lib/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.mjs +2 -2
  193. package/lib/core/tsconfig/readProjectMembershipPolicy.d.cts +3 -3
  194. package/lib/core/tsconfig/readProjectMembershipPolicy.d.mts +3 -3
  195. package/lib/core/tsconfig/readProjectMembershipPolicy.d.ts +3 -3
  196. package/lib/core/tsconfig/readProjectMembershipPolicy.js +4 -4
  197. package/lib/core/tsconfig/readProjectMembershipPolicy.mjs +4 -4
  198. package/lib/core/unplugin.js +14 -0
  199. package/lib/core/unplugin.js.map +1 -1
  200. package/lib/core/unplugin.mjs +14 -0
  201. package/lib/core/unplugin.mjs.map +1 -1
  202. package/lib/core/vite/installViteDependencyScanPlugins.d.cts +46 -0
  203. package/lib/core/vite/installViteDependencyScanPlugins.d.mts +46 -0
  204. package/lib/core/vite/installViteDependencyScanPlugins.d.ts +46 -0
  205. package/lib/core/vite/installViteDependencyScanPlugins.js +186 -0
  206. package/lib/core/vite/installViteDependencyScanPlugins.js.map +1 -0
  207. package/lib/core/vite/installViteDependencyScanPlugins.mjs +184 -0
  208. package/lib/core/vite/installViteDependencyScanPlugins.mjs.map +1 -0
  209. package/package.json +5 -4
  210. package/src/core/bridge/TtscProjectRecord.ts +9 -0
  211. package/src/core/bridge/readProjectRecordFile.ts +5 -1
  212. package/src/core/observer/WatchScope.ts +3 -3
  213. package/src/core/observer/createInputObserver.ts +7 -8
  214. package/src/core/options/ResolvedTtscUnpluginOptions.ts +3 -0
  215. package/src/core/options/TtscUnpluginOptions.ts +13 -2
  216. package/src/core/options/resolveOptions.ts +6 -3
  217. package/src/core/transform/TtscPrecompilation.ts +103 -0
  218. package/src/core/transform/cache/selectCachedGenerationAction.ts +3 -0
  219. package/src/core/transform/cache/withdrawTtscTransformGenerations.ts +2 -0
  220. package/src/core/transform/envelope/generationCaseSensitivity.ts +46 -0
  221. package/src/core/transform/envelope/selectExternalInputPaths.ts +5 -1
  222. package/src/core/transform/envelope/selectNotifiableAbsentInputs.ts +5 -1
  223. package/src/core/transform/filesystem/createHostPathIdentityContext.ts +9 -1
  224. package/src/core/transform/generation/captureTransformGeneration.ts +22 -2
  225. package/src/core/transform/generation/selectPersistentHostInputs.ts +5 -1
  226. package/src/core/transform/generation/transformProject.ts +3 -0
  227. package/src/core/transform/inputs/nativeInputPredicateState.ts +1 -3
  228. package/src/core/transform/tracker/createHostInputMutationTracker.ts +10 -1
  229. package/src/core/transform/tracker/createProjectMutationTracker.ts +34 -6
  230. package/src/core/transform/transformTtsc.ts +86 -37
  231. package/src/core/transform/validation/captureUniversalHostInputValidation.ts +12 -4
  232. package/src/core/transform/validation/matchesCachedSource.ts +9 -2
  233. package/src/core/transform/watch/TtscTransformHooks.ts +10 -0
  234. package/src/core/transform/watch/TtscWatchInputBaseline.ts +2 -1
  235. package/src/core/transform/watch/isWatchInputKeyBaseline.ts +4 -2
  236. package/src/core/transform/watch/notifyProjectRecord.ts +5 -4
  237. package/src/core/transform/watch/recordedDependencyWitnesses.ts +50 -0
  238. package/src/core/transform/watch/watchInputEvidenceMatchesBaseline.ts +1 -2
  239. package/src/core/tsconfig/TsconfigReadTransaction.ts +11 -8
  240. package/src/core/tsconfig/findDeclaredCompilerOption.ts +3 -2
  241. package/src/core/tsconfig/findDeclaredFileSpecs.ts +3 -2
  242. package/src/core/tsconfig/findDeclaredPaths.ts +3 -3
  243. package/src/core/tsconfig/findDeclaredValue.ts +2 -1
  244. package/src/core/tsconfig/readEffectiveTsconfigTemplateCompilerOptions.ts +1 -1
  245. package/src/core/tsconfig/readEffectiveTsconfigTemplateFileSpecs.ts +2 -2
  246. package/src/core/tsconfig/readProjectMembershipPolicy.ts +4 -4
  247. package/src/core/unplugin.ts +32 -0
  248. package/src/core/vite/installViteDependencyScanPlugins.ts +219 -0
@@ -1,6 +1,7 @@
1
1
  import path from "node:path";
2
2
 
3
3
  import type { ResolvedTtscUnpluginOptions } from "../options/ResolvedTtscUnpluginOptions";
4
+ import { TtscPrecompilation } from "./TtscPrecompilation";
4
5
  import type { TtscTransformResult } from "./TtscTransformResult";
5
6
  import { createAliasPaths } from "./alias/createAliasPaths";
6
7
  import { TERMINAL_TRANSFORM_GENERATIONS } from "./cache/TERMINAL_TRANSFORM_GENERATIONS";
@@ -33,6 +34,7 @@ import type { TtscTransformHooks } from "./watch/TtscTransformHooks";
33
34
  import type { TtscWatchSelection } from "./watch/TtscWatchSelection";
34
35
  import { notifyRejectedGenerationInputs } from "./watch/notifyRejectedGenerationInputs";
35
36
  import { prepareProjectRecordDirectories } from "./watch/prepareProjectRecordDirectories";
37
+ import { recordedDependencyWitnesses } from "./watch/recordedDependencyWitnesses";
36
38
 
37
39
  /**
38
40
  * Apply the ttsc plugin transform to a single source file.
@@ -67,38 +69,40 @@ import { prepareProjectRecordDirectories } from "./watch/prepareProjectRecordDir
67
69
  * @param hooks - Optional adapter callbacks; see {@link TtscTransformHooks}.
68
70
  * Dependency notifications fire on cache hits too; watch registrations are
69
71
  * per build, not per compilation.
70
- * @evidence contracts/common.md#principled-implementation Project selection and generation-qualified cache admission preserve compiler disk authority; fresh-only success additionally needs an explicit nonwatching lifecycle, coherent project declaration and actual host-cache withdrawal, because incomplete observation cannot support watch invalidation.
71
- * @evidence contracts/common.md#clear-and-simple-design One delivery coordinator composes project selection, cache admission, compilation, output selection and host notifications; dedicated owners handle proof and lifetime internals.
72
- * @evidence contracts/common.md#prohibited-implementation-shortcuts Wrapper modules cannot poison source baselines; incomplete local results can share only explicitly nonwatching first deliveries in their exact pass. Unknown/watching lifecycles or unsupported withdrawal reject and evict them rather than invent persistent records or dependency closure.
73
- * @evidence contracts/common.md#meaningful-documentation Native paragraphs and argument tags explain project scope, no-transform outcomes, cache epochs and per-build notification responsibilities with links to maintained reference context.
74
- * @evidence contracts/performance.md#efficient-algorithms
75
- * Selection/key construction pays ancestor/config/alias/option/path text work.
76
- * Each iteration may prepare toolchain state, settle native notifications and
77
- * replay source/project/external/universal proofs before selecting output.
78
- * In-flight/valid completed reuse avoids compilation, not those checks or
79
- * output/map/notification/record work. Capture misses pay whole native compile
80
- * and input populations. The common proof owner skips redundant environment
81
- * preparation for proven first deliveries and shares synchronous native proof
82
- * queries; persistent/repeated delivery establishes fresh authority. Concurrent supersession can repeat the outer loop
83
- * without a delivery-level retry/time bound here.
84
- * @evidence contracts/performance.md#reuse-equivalent-work Cache identity covers config/options/plugins/aliases; current generations, pass-qualified terminal verdicts and in-flight Promises are shared only while their source and dependency proof remains valid.
85
- * @evidence contracts/performance.md#bound-retention-and-release-resources
86
- * Optional cache state retains current generation Promises/results and
87
- * per-key dependency/case facts without a byte/key cap here. Native tasks
88
- * belong to compiler/capture owners; uncached captures retain no notification
89
- * or persistent clock probe. Fresh-only delivery releases capture resources,
90
- * retaining only an explicitly admitted local pass result; rejected or failed
91
- * incomplete handoff detaches its generation. Eviction/disposal attempt independent resource release
92
- * and native failures need not close every handle or remove every probe.
93
- * @evidence contracts/portability.md#os-neutral-implementation Native module paths and project coordinates use supported path/filesystem abstractions, while actual case policy and watcher capability come from generation proof rather than OS-name assumptions.
72
+ * @evidence contracts/common.md#principled-implementation Project selection and generation-qualified admission preserve compiler disk authority; preparation shares selection, keys, capture and input proofs with delivery, while host effects and first-delivery permission remain exclusive to actual delivery. Fresh-only success still requires an explicit nonwatching lifecycle, coherent project declaration and supported host-cache withdrawal because incomplete observation cannot establish watch invalidation.
73
+ * @evidence contracts/common.md#clear-and-simple-design One coordinator mode shares project selection, admission, compilation and output selection between preparation and delivery; dedicated owners retain proof and lifetime internals, and delivery alone performs host notification.
74
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Wrapper modules cannot poison source baselines. Preparation skips handoff rather than postcompile proof, and superseded preparation stops without reviving withdrawn generations. Incomplete local results share only explicitly nonwatching first deliveries in their exact pass; unknown/watching lifecycles or unsupported withdrawal reject and evict without invented persistent records or dependency closure.
75
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs and argument tags explain project scope, no-transform outcomes, cache epochs and per-build notifications; coordinator prose identifies delivery-only effects and postpreparation admission, with maintained invalidation reference context.
76
+ * @evidence contracts/performance.md#efficient-algorithms Selection and keys pay ancestor/config/alias/option/path-text work. Each iteration may prepare toolchains, settle notifications and replay source/project/external/universal proofs; reuse avoids compilation rather than those checks or output/map/notification/record work. Misses pay native compilation and input populations. Proven first deliveries skip redundant environment preparation and share synchronous proof queries; repeated delivery establishes fresh authority. Startup schedules explicit entries concurrently and skips delivery output/map/registration work. Supersession can repeat the outer loop without a retry or time bound.
77
+ * @evidence contracts/performance.md#reuse-equivalent-work Config/options/plugins/aliases key the ordinary project Promise shared by preparation, simultaneous loads and sibling entries; completed generations, pass-qualified terminal verdicts and in-flight work remain reusable only under current source and dependency proof.
78
+ * @evidence contracts/performance.md#bound-retention-and-release-resources Optional cache state retains generation Promises/results and per-key dependency/case facts without a byte/key cap. Native tasks belong to compiler/capture owners; uncached captures retain no notification or persistent clock probe. Fresh-only delivery releases capture resources while retaining an admitted local pass result; failed or rejected incomplete handoff detaches its generation. Superseded preparation preserves the new owner, and withdrawal schedules disposal of its pending fulfilled result. Eviction/disposal attempt independent release; native failure need not close every handle or remove every probe.
79
+ * @evidence contracts/portability.md#os-neutral-implementation Preparation and delivery use the same native project selection, path identity and cache-owned filesystem boundaries, with exact startup entry paths. Generation proof supplies case and watcher policy rather than OS-name assumptions.
94
80
  */
95
- export async function transformTtsc(
81
+ export function transformTtsc(
96
82
  id: string,
97
83
  source: string,
98
84
  options: ResolvedTtscUnpluginOptions,
99
85
  aliases?: unknown,
100
86
  cache?: TtscTransformCache,
101
87
  hooks?: TtscTransformHooks,
88
+ ): Promise<TtscTransformResult | undefined> {
89
+ return runTransformTtsc(id, source, options, aliases, cache, hooks, false);
90
+ }
91
+
92
+ /**
93
+ * Coordinate capture and actual delivery through the same project cache.
94
+ * Preparation stops before handoff: it cannot mark a module served, publish a
95
+ * host record, acknowledge volatility or emit module diagnostics. A prepared
96
+ * generation must still pass ordinary admission when the host requests it.
97
+ */
98
+ async function runTransformTtsc(
99
+ id: string,
100
+ source: string,
101
+ options: ResolvedTtscUnpluginOptions,
102
+ aliases: unknown,
103
+ cache: TtscTransformCache | undefined,
104
+ hooks: TtscTransformHooks | undefined,
105
+ preparing: boolean,
102
106
  ): Promise<TtscTransformResult | undefined> {
103
107
  const filesystem = transformFilesystem(cache);
104
108
  const exact = hooks?.exactPath === true;
@@ -125,7 +129,10 @@ export async function transformTtsc(
125
129
  // Writing the delivered record must not create a new member of that proof.
126
130
  prepareProjectRecordDirectories(hooks?.project);
127
131
 
128
- const selection = resolveProjectSelection(file, options.project, filesystem);
132
+ const selection =
133
+ hooks?.projectSelection === undefined
134
+ ? resolveProjectSelection(file, options.project, filesystem)
135
+ : { tsconfig: path.resolve(hooks.projectSelection), consulted: [] };
129
136
  const tsconfig = selection.tsconfig;
130
137
  const selectedProjectRoot = path.resolve(
131
138
  options.projectRoot ?? path.dirname(tsconfig),
@@ -142,6 +149,19 @@ export async function transformTtsc(
142
149
  tsconfig,
143
150
  };
144
151
  const aliasPaths = createAliasPaths(aliases);
152
+ if (!preparing && cache !== undefined) {
153
+ TtscPrecompilation.start(cache, options, aliasPaths, (entry, text) =>
154
+ runTransformTtsc(
155
+ entry,
156
+ text,
157
+ options,
158
+ aliases,
159
+ cache,
160
+ { ...hooks, exactPath: true, projectSelection: undefined },
161
+ true,
162
+ ),
163
+ );
164
+ }
145
165
  const key = createTransformCacheKey({
146
166
  aliasPaths,
147
167
  compilerOptions: options.compilerOptions,
@@ -168,7 +188,10 @@ export async function transformTtsc(
168
188
  undefined,
169
189
  terminal.validation.cached.projectRoot,
170
190
  );
171
- if (cache?.get(key) !== transformed) continue;
191
+ if (cache?.get(key) !== transformed) {
192
+ if (preparing) return undefined;
193
+ continue;
194
+ }
172
195
  }
173
196
  // A terminal verdict is an answer about one observed environment, not an
174
197
  // invitation for every later module to repeat the whole compile.
@@ -179,7 +202,13 @@ export async function transformTtsc(
179
202
  filesystem,
180
203
  })
181
204
  ) {
182
- notifyRejectedGenerationInputs(hooks, terminal, file, watchSelection);
205
+ if (!preparing)
206
+ notifyRejectedGenerationInputs(
207
+ hooks,
208
+ terminal,
209
+ file,
210
+ watchSelection,
211
+ );
183
212
  throw terminal;
184
213
  }
185
214
  evictGeneration(cache, key, transformed);
@@ -192,12 +221,13 @@ export async function transformTtsc(
192
221
  if (transformed !== undefined) {
193
222
  const cached = await awaitOrEvict(cache, key, transformed).catch(
194
223
  (rejection: unknown) => {
195
- notifyRejectedGenerationInputs(
196
- hooks,
197
- rejection,
198
- file,
199
- watchSelection,
200
- );
224
+ if (!preparing)
225
+ notifyRejectedGenerationInputs(
226
+ hooks,
227
+ rejection,
228
+ file,
229
+ watchSelection,
230
+ );
201
231
  throw rejection;
202
232
  },
203
233
  );
@@ -205,6 +235,7 @@ export async function transformTtsc(
205
235
  // While this caller awaited the old Promise, another caller may have
206
236
  // invalidated it and installed a newer authoritative generation.
207
237
  if (cache?.get(key) !== transformed) {
238
+ if (preparing) return undefined;
208
239
  continue;
209
240
  }
210
241
  // A generation captured while native notifications were trusted keeps
@@ -217,11 +248,15 @@ export async function transformTtsc(
217
248
  if (epoch === undefined) {
218
249
  await settleProjectMutationEvents(cached);
219
250
  if (cache?.get(key) !== transformed) {
251
+ if (preparing) return undefined;
220
252
  continue;
221
253
  }
222
254
  }
223
255
  await TtscGenerationProof.prepare(cached, file, epoch);
224
- if (cache?.get(key) !== transformed) continue;
256
+ if (cache?.get(key) !== transformed) {
257
+ if (preparing) return undefined;
258
+ continue;
259
+ }
225
260
  // No await between this observation and synchronous admission.
226
261
  const proof = TtscGenerationProof.create(cached, file, epoch);
227
262
  const action = selectCachedGenerationAction({
@@ -233,11 +268,13 @@ export async function transformTtsc(
233
268
  generation: transformed,
234
269
  key,
235
270
  source,
271
+ reportDivergence: !preparing,
236
272
  });
237
273
  if (action === "retry") {
238
274
  continue;
239
275
  }
240
276
  if (action === "serve") {
277
+ if (preparing) return undefined;
241
278
  return deliverCachedTransform({
242
279
  cache,
243
280
  cached,
@@ -260,6 +297,7 @@ export async function transformTtsc(
260
297
  projectRoot: selectedProjectRoot,
261
298
  currentFile: file,
262
299
  currentSource: source,
300
+ reportDivergence: !preparing,
263
301
  // Stamp the pass this compile was started for, not the one it happens
264
302
  // to finish in: a boundary crossed mid-compile leaves the generation
265
303
  // belonging to the earlier pass, so the next pass re-proves it.
@@ -282,21 +320,31 @@ export async function transformTtsc(
282
320
  cache === undefined
283
321
  ? undefined
284
322
  : TRANSFORM_CACHE_CASE_POLICIES.get(cache)?.get(key),
323
+ // A cache without a list of its own takes the names the project's
324
+ // record carries from an earlier process (samchon/ttsc#1743).
285
325
  witnessedDependencies:
286
326
  cache === undefined
287
327
  ? undefined
288
- : TRANSFORM_CACHE_DEPENDENCY_WITNESSES.get(cache)?.get(key),
328
+ : (TRANSFORM_CACHE_DEPENDENCY_WITNESSES.get(cache)?.get(key) ??
329
+ recordedDependencyWitnesses(hooks?.project, tsconfig)),
289
330
  });
290
331
  cache?.set(key, transformed);
291
332
  }
292
333
  const generation = transformed;
293
334
  const cached = await awaitOrEvict(cache, key, generation).catch(
294
335
  (rejection: unknown) => {
295
- notifyRejectedGenerationInputs(hooks, rejection, file, watchSelection);
336
+ if (!preparing)
337
+ notifyRejectedGenerationInputs(
338
+ hooks,
339
+ rejection,
340
+ file,
341
+ watchSelection,
342
+ );
296
343
  throw rejection;
297
344
  },
298
345
  );
299
346
  if (cache !== undefined && cache.get(key) !== generation) {
347
+ if (preparing) return undefined;
300
348
  continue;
301
349
  }
302
350
  if (cache !== undefined) {
@@ -316,6 +364,7 @@ export async function transformTtsc(
316
364
  policies.set(key, reported);
317
365
  }
318
366
  }
367
+ if (preparing) return undefined;
319
368
  return deliverCachedTransform({
320
369
  cache,
321
370
  cached,
@@ -42,7 +42,7 @@ import { matchesRecordedInput } from "./matchesRecordedInput";
42
42
  * @evidence contracts/common.md#meaningful-documentation Native prose explains failed admission and successful generation attachment; inline comments justify readable-state, blocker and tree distinctions.
43
43
  * @evidence contracts/portability.md#os-neutral-implementation The generation's filesystem view qualifies metadata and exact native absence. Grouped candidates retain original spelling because directory case policy alone does not define Unicode or short-name equivalence; their joined path follows that view's platform dialect. Physical targets and aliases remain distinct from content identity, and native plugin environment authority is not established by arbitrary filesystem injection.
44
44
  * @evidence contracts/performance.md#bound-retention-and-release-resources The generation retains manifest entries, lexical coverage, raw missing candidates and tree environments proportional to admitted inputs and their path/state text, without a total byte cap or native handle here. Failed attempt records are call-local and diagnostic witness counts are bounded by their owner; replacing or releasing the generation ends manifest ownership.
45
- * @evidence contracts/performance.md#efficient-algorithms Input selection materializes the union of producer lists/proof keys and scans U universal inputs and T plugin source trees. Comparisons include content bytes, physical identity/ancestor/case queries, paired metadata and exact candidate stat; source proof includes tree population/bytes and environment validation. These delegated costs and temporary input/manifest populations are not constant-time map insertion work.
45
+ * @evidence contracts/performance.md#efficient-algorithms Input selection materializes the union of producer lists/proof keys and scans U universal inputs and T plugin source trees. Async-owned environments share one synchronous batch, qualifying common SDK paths once across plugin directories. Comparisons include content bytes, physical identity/ancestor/case queries, paired metadata and exact candidate stat; source proof includes tree population/bytes and environment validation. These delegated costs and temporary input/manifest populations are not constant-time map insertion work.
46
46
  * @evidence contracts/performance.md#reuse-equivalent-work This shared generation manifest records exactly qualified lexical spellings, separable signatures and tree environments for later validators; changed proof requires new admission.
47
47
  */
48
48
  export function captureUniversalHostInputValidation(
@@ -295,13 +295,21 @@ export function captureUniversalHostInputValidation(
295
295
  // A plugin binary keyed on a source other than the disk's now, whether it
296
296
  // was built here or adopted from another worker, is output for a state
297
297
  // already gone (samchon/ttsc#1487).
298
- for (const [directory, digest] of selectPluginSourceInputs(cached.result)) {
298
+ const sources = selectPluginSourceInputs(cached.result);
299
+ const prepared = usesPreparedPluginBuildEnvironments(cached.result);
300
+ // Plugin directories commonly share the thousands-file Go SDK. Qualify it
301
+ // once for this synchronous proof, not once per directory (#1764). The map
302
+ // must stay inside this call: an await or later delivery needs fresh native
303
+ // authority, even when source watchers heard no change (#1712, #1516).
304
+ const environments = prepared
305
+ ? PluginBuildEnvironmentReadings.cachedAll(sources.keys())
306
+ : undefined;
307
+ for (const [directory, digest] of sources) {
299
308
  // The environment is recorded as read before the proof, so it is never a
300
309
  // reading the proof did not see; one that moved meanwhile only makes the
301
310
  // next delivery prove the tree again.
302
- const prepared = usesPreparedPluginBuildEnvironments(cached.result);
303
311
  const environment = prepared
304
- ? PluginBuildEnvironmentReadings.cached(directory)
312
+ ? environments!.get(directory)
305
313
  : processPluginBuildEnvironment(directory, false, cached.projectRoot);
306
314
  if (
307
315
  environment === undefined ||
@@ -37,7 +37,9 @@ import { notificationsProveProgramUnchanged } from "./notificationsProveProgramU
37
37
  * rejects this generation for the delivery; its caller chooses replacement or
38
38
  * capture. Delivered text that differs while the disk still holds the bytes the
39
39
  * generation compiled is not one: it is reported and served, since the compile
40
- * read the disk (samchon/ttsc#1394).
40
+ * read the disk (samchon/ttsc#1394). Preparation performs the same comparison
41
+ * without reporting a host rewrite, because its native source read is not a
42
+ * delivered module.
41
43
  *
42
44
  * Its place in the adapter's invalidation model, and the units beside it, are
43
45
  * mapped in the maintainer page
@@ -73,6 +75,11 @@ export function matchesCachedSource(
73
75
  /** Current host pass, or undefined for persistent input validation. */
74
76
  epoch: number | undefined,
75
77
  proof?: TtscGenerationProof.Transaction,
78
+ /**
79
+ * Preparation compares the same native bytes without reporting a host
80
+ * rewrite.
81
+ */
82
+ reportDivergence = true,
76
83
  ): boolean {
77
84
  if (!nativeInputPredicatesHold(cached, proof)) return false;
78
85
  const pass = TtscGenerationProof.sharesPass(cached, file, epoch);
@@ -133,7 +140,7 @@ export function matchesCachedSource(
133
140
  ) {
134
141
  return false;
135
142
  }
136
- reportDivergentDelivery(cached, file);
143
+ if (reportDivergence) reportDivergentDelivery(cached, file);
137
144
  }
138
145
  if (pass) return true;
139
146
  if (epoch !== undefined && cached.projectSnapshotComplete === true) {
@@ -30,6 +30,16 @@ import type { TtscWatchInputEvidence } from "./TtscWatchInputEvidence";
30
30
  * state at runtime.
31
31
  */
32
32
  export interface TtscTransformHooks {
33
+ /**
34
+ * Native config already selected by the host for this delivered module.
35
+ *
36
+ * A host that freezes routing and its discovery inputs in one transaction
37
+ * supplies that config here and retains those inputs in its watch channel.
38
+ * Startup entries select their own projects from the user's
39
+ * `options.project`, independently of another module's discovered route.
40
+ */
41
+ projectSelection?: string;
42
+
33
43
  /**
34
44
  * Invoked once per absolute watch-input path derived for the transformed file
35
45
  * `F`: the plugin-reported `dependencies[F]` list unioned with the host-owned
@@ -23,7 +23,8 @@ import type { TtscWatchInputFileBaseline } from "./TtscWatchInputFileBaseline";
23
23
  export interface TtscWatchInputBaseline extends TtscWatchInputFileBaseline {
24
24
  /**
25
25
  * Current version-one native codec facts, captured only for requested kinds.
26
- * These observations do not certify a producer's identityStable flag or scope.
26
+ * These observations do not certify a producer's identityStable flag or
27
+ * scope.
27
28
  */
28
29
  nativePredicates?: Partial<
29
30
  Record<
@@ -115,9 +115,11 @@ function isNativePredicateBaselines(value: unknown): boolean {
115
115
  stableStringify(Object.keys(state).sort()) !==
116
116
  stableStringify(["digest", "realpath"]) ||
117
117
  !isContentHash(state.digest) ||
118
- !(state.realpath === null ||
118
+ !(
119
+ state.realpath === null ||
119
120
  (typeof state.realpath === "string" &&
120
- isAbsoluteFilesystemPath(state.realpath)))
121
+ isAbsoluteFilesystemPath(state.realpath))
122
+ )
121
123
  ) {
122
124
  return false;
123
125
  }
@@ -73,10 +73,9 @@ const HANDED = new WeakMap<
73
73
  * loses acceptance and enters persistence again without rereading generation
74
74
  * inputs. Hosts and bridge readers own current byte proof, including concurrent
75
75
  * changes and unreadable/torn bytes; availability here cannot exclude removal
76
- * after the check. A host that keeps no
77
- * snapshot of the file, Rollup's cache, is handed the digest of the bytes
78
- * written for the generation to compare against instead
79
- * (`TtscProjectRegistration.digest`).
76
+ * after the check. A host that keeps no snapshot of the file, Rollup's cache,
77
+ * is handed the digest of the bytes written for the generation to compare
78
+ * against instead (`TtscProjectRegistration.digest`).
80
79
  *
81
80
  * A record lives below the host's tool directory, or, when that cannot be
82
81
  * written, below the fallback the host accepts (`fallbackToolDirectory`,
@@ -226,7 +225,9 @@ function recordOf(
226
225
  cached: TtscCachedProjectTransform,
227
226
  inputs: readonly TtscWatchInput[],
228
227
  ): TtscProjectRecord {
228
+ const dependencies = cached.externalDependencyInputs ?? [];
229
229
  const record: TtscProjectRecord = {
230
+ ...(dependencies.length === 0 ? {} : { dependencies }),
230
231
  inputs: {},
231
232
  membership:
232
233
  cached.projectDirectories === undefined
@@ -0,0 +1,50 @@
1
+ import { projectRecordFile } from "../../bridge/projectRecordFile";
2
+ import { readProjectRecordFile } from "../../bridge/readProjectRecordFile";
3
+ import type { TtscTransformHooks } from "./TtscTransformHooks";
4
+
5
+ /**
6
+ * The dependency-only paths the project record of `tsconfig` carries
7
+ * (`TtscProjectRecord.dependencies`), for a transform cache that has no witness
8
+ * list of its own yet.
9
+ *
10
+ * A compile learns a plugin-reported dependency path only from its own
11
+ * envelope, and one it had no witness for compiles again
12
+ * (`onlyLearnedCompileFacts`). A transform cache keeps the paths in memory
13
+ * (`TRANSFORM_CACHE_DEPENDENCY_WITNESSES`), so every new cache, a dev-server
14
+ * start or a build process, compiled such a project twice (samchon/ttsc#1743).
15
+ * The record the previous process wrote names them. They only say what to read:
16
+ * the capture still witnesses each path afresh, a path the compile no longer
17
+ * reports costs one read, and one the record does not name is retried as
18
+ * before.
19
+ *
20
+ * @param project The host's record directories, when it keeps records.
21
+ * @param tsconfig The project's tsconfig, as the adapter names it.
22
+ * @returns The record's paths, or `undefined` when no readable record names
23
+ * any.
24
+ * @evidence contracts/common.md#principled-implementation The record is the host's persisted project state, written from a completed generation; its paths are hints that the capture re-witnesses, never certified state.
25
+ * @evidence contracts/common.md#clear-and-simple-design One reader selects the first readable record of the host's directories, in the order the writer tries them.
26
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts No witness or digest is taken from the record; an unreadable or absent record supplies nothing.
27
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs explain the doubled first compile, the hint semantics and the absent cases.
28
+ * @evidence contracts/portability.md#os-neutral-implementation Record paths come from the host's own directories through `projectRecordFile`.
29
+ * @evidence contracts/performance.md#efficient-algorithms At most two record reads and JSON parses, only when a cache has no witness list for the key.
30
+ * @evidence contracts/performance.md#reuse-equivalent-work A new process reuses the dependency names the last generation's record holds instead of compiling once to learn them.
31
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The returned list belongs to the caller; nothing is retained here.
32
+ */
33
+ export function recordedDependencyWitnesses(
34
+ project: TtscTransformHooks["project"],
35
+ tsconfig: string,
36
+ ): readonly string[] | undefined {
37
+ if (project === undefined) return undefined;
38
+ for (const directory of [
39
+ project.toolDirectory,
40
+ ...(project.fallbackToolDirectory === undefined
41
+ ? []
42
+ : [project.fallbackToolDirectory]),
43
+ ]) {
44
+ const record = readProjectRecordFile(
45
+ projectRecordFile(directory, tsconfig),
46
+ );
47
+ if (record !== undefined) return record.dependencies;
48
+ }
49
+ return undefined;
50
+ }
@@ -10,8 +10,7 @@ import { isWatchInputKeyBaseline } from "./isWatchInputKeyBaseline";
10
10
  *
11
11
  * A codec matches only the facts the baseline actually captured. Native,
12
12
  * listing and plugin-tree observations require their optional payloads;
13
- * membership is a
14
- * separate project walk and cannot match one path's baseline.
13
+ * membership is a separate project walk and cannot match one path's baseline.
15
14
  *
16
15
  * @evidence contracts/common.md#principled-implementation Identity and every recorded codec fact must agree with a validated baseline; native predicates additionally require a supported version, stable producer identity, matching raw digest and physical target. Narrow discovery facts and absent optional native/listing/tree payloads cannot establish broader observations.
17
16
  * @evidence contracts/common.md#clear-and-simple-design Codec branches reuse the strict baseline guard and native realpath comparator, with one private refinement exposing the broader carrier.
@@ -7,14 +7,16 @@ import { resolveExtendsConfig } from "./resolveExtendsConfig";
7
7
  import { resolveRealPath } from "./resolveRealPath";
8
8
 
9
9
  /**
10
- * Share config observations and contextual selections within one synchronous read.
10
+ * Share config observations and contextual selections within one synchronous
11
+ * read.
11
12
  *
12
13
  * Lexical paths own parsing and relative extends resolution. Physical paths
13
14
  * only guard ancestry cycles. A completed selection can be borrowed when the
14
15
  * current ancestors intersect its encountered physical identities exactly as
15
16
  * they did originally; otherwise a different cycle cut requires evaluation.
16
17
  * Ordered source observations travel with a completed selection, including
17
- * unresolved file candidates, so reuse preserves the caller's invalidation inputs.
18
+ * unresolved file candidates, so reuse preserves the caller's invalidation
19
+ * inputs.
18
20
  *
19
21
  * Create a new transaction for each independent freshness observation. This
20
22
  * owner neither validates reuse across reads nor supplies compiler diagnostics.
@@ -94,12 +96,13 @@ export class TsconfigReadTransaction {
94
96
  /**
95
97
  * Select one declaration, preserving its lexical directory and observations.
96
98
  *
97
- * An undefined own selection inherits. Null masks inheritance without supplying
98
- * a value, as an invalid own file list does; a parent ignores that empty result.
99
- * First queries search later bases first; last queries visit all bases forward.
100
- * The caller's physical ancestor set is copied once and never mutated.
101
- * Selectors must preserve the parsed inputs and give the same declaration for
102
- * the same source; query reuse does not repeat their incidental effects.
99
+ * An undefined own selection inherits. Null masks inheritance without
100
+ * supplying a value, as an invalid own file list does; a parent ignores that
101
+ * empty result. First queries search later bases first; last queries visit
102
+ * all bases forward. The caller's physical ancestor set is copied once and
103
+ * never mutated. Selectors must preserve the parsed inputs and give the same
104
+ * declaration for the same source; query reuse does not repeat their
105
+ * incidental effects.
103
106
  *
104
107
  * @evidence contracts/common.md#principled-implementation A completed answer is reusable only when its encountered physical identities have the same intersection with current ancestry. That preserves every observed cycle decision, including cuts; own declarations and first/last traversal retain lexical origins and key-specific precedence.
105
108
  * @evidence contracts/common.md#clear-and-simple-design A query-local visitor owns selection and contextual completed answers; transaction nodes separately share lexical source, identity and edge observations across keys.
@@ -6,8 +6,9 @@ import { findDeclaredValue } from "./findDeclaredValue";
6
6
  *
7
7
  * Own key presence is significant even for null or undefined values; the caller
8
8
  * decides whether the selected option value is usable. An optional
9
- * decoded-source map or graph transaction belongs to one caller read; independent
10
- * option searches retain their selectors and physical ancestry contexts.
9
+ * decoded-source map or graph transaction belongs to one caller read;
10
+ * independent option searches retain their selectors and physical ancestry
11
+ * contexts.
11
12
  *
12
13
  * @evidence contracts/common.md#principled-implementation
13
14
  * A wrapper preserves key presence through the generic selector, so the own
@@ -13,8 +13,9 @@ import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
13
13
  * anchored at the named declaring config, including independent link aliases.
14
14
  *
15
15
  * @returns The list and its directory, undefined when no array is selected, or
16
- * null when the root config cannot be read as an object. A supplied transaction
17
- * belongs to this freshness observation; later reads require a fresh owner.
16
+ * null when the root config cannot be read as an object. A supplied
17
+ * transaction belongs to this freshness observation; later reads require a
18
+ * fresh owner.
18
19
  * @evidence contracts/common.md#principled-implementation
19
20
  * Own invalid values stop inheritance at that node. Forward inherited
20
21
  * traversal keeps the last array and ignores empty selections, preserving
@@ -1,5 +1,5 @@
1
- import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
2
1
  import type { IDeclaredPaths } from "./IDeclaredPaths";
2
+ import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
3
3
  import { findDeclaredValue } from "./findDeclaredValue";
4
4
 
5
5
  /**
@@ -7,8 +7,8 @@ import { findDeclaredValue } from "./findDeclaredValue";
7
7
  * rooted at `tsconfig`. The own config wins over its bases; within an `extends`
8
8
  * array, later entries win over earlier ones. `seen` breaks circular chains;
9
9
  * the compiler reports the actual config error. Optional decoded sources or
10
- * graph observations share only within the caller's current read; physical cycle
11
- * guards remain branch-local.
10
+ * graph observations share only within the caller's current read; physical
11
+ * cycle guards remain branch-local.
12
12
  *
13
13
  * @evidence contracts/common.md#principled-implementation
14
14
  * The selector accepts a non-array paths record and the shared value reader
@@ -7,7 +7,8 @@ import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
7
7
  * remain anchored at the named config; physical identity only cuts branch
8
8
  * cycles. Independent aliases can therefore resolve different relative bases.
9
9
  * Missing or malformed configs remain best-effort absence; the compiler owns
10
- * configuration diagnostics. Unresolved file candidates remain observed inputs.
10
+ * configuration diagnostics. Unresolved file candidates remain observed
11
+ * inputs.
11
12
  *
12
13
  * A supplied transaction shares source, identity and edge observations across
13
14
  * keys. A decoded-source map remains supported for callers that own that map;
@@ -1,8 +1,8 @@
1
1
  import path from "node:path";
2
2
 
3
- import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
4
3
  import { CONFIG_DIR_TEMPLATE_LIST_OPTIONS } from "./CONFIG_DIR_TEMPLATE_LIST_OPTIONS";
5
4
  import { CONFIG_DIR_TEMPLATE_SCALAR_OPTIONS } from "./CONFIG_DIR_TEMPLATE_SCALAR_OPTIONS";
5
+ import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
6
6
  import { absolutizePathsTarget } from "./absolutizePathsTarget";
7
7
  import { findDeclaredCompilerOption } from "./findDeclaredCompilerOption";
8
8
  import { findDeclaredPaths } from "./findDeclaredPaths";
@@ -15,8 +15,8 @@ const CONFIG_DIR_TEMPLATE_FILE_SPECS = ["exclude", "files", "include"] as const;
15
15
  * Lists use the compiler's last-inherited-array rule: a later base declaring
16
16
  * null cannot erase an earlier array. Invalid elements are preserved so this
17
17
  * overlay does not hide the compiler's configuration diagnostics. The three
18
- * list searches share graph observations only within this call; a later call reads
19
- * current bytes in a fresh transaction.
18
+ * list searches share graph observations only within this call; a later call
19
+ * reads current bytes in a fresh transaction.
20
20
  *
21
21
  * @param configDir The directory `${configDir}` stands for, as
22
22
  * `readEffectiveTsconfigTemplateCompilerOptions` takes it.
@@ -2,9 +2,9 @@ import path from "node:path";
2
2
 
3
3
  import { TYPESCRIPT_TRANSFORM_EXTENSIONS } from "../source/TYPESCRIPT_TRANSFORM_EXTENSIONS";
4
4
  import type { ITtscProjectMembershipPolicy } from "./ITtscProjectMembershipPolicy";
5
- import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
6
5
  import { JAVASCRIPT_INPUT_EXTENSIONS } from "./JAVASCRIPT_INPUT_EXTENSIONS";
7
6
  import { OUTPUT_DIRECTORY_OPTIONS } from "./OUTPUT_DIRECTORY_OPTIONS";
7
+ import { TsconfigReadTransaction } from "./TsconfigReadTransaction";
8
8
  import { absolutizePathsTarget } from "./absolutizePathsTarget";
9
9
  import { findDeclaredFileSpecs } from "./findDeclaredFileSpecs";
10
10
  import { findDeclaredValue } from "./findDeclaredValue";
@@ -40,9 +40,9 @@ const DEFAULT_INCLUDE_SPEC = "**/*";
40
40
  * refuses to guess in the direction that loses correctness.
41
41
  *
42
42
  * Source, identity and extends observations share this transaction. Completed
43
- * selections, including absence, require matching physical ancestry intersections.
44
- * Later calls start fresh, so unchanged metadata cannot conceal changed source
45
- * text or resolution.
43
+ * selections, including absence, require matching physical ancestry
44
+ * intersections. Later calls start fresh, so unchanged metadata cannot conceal
45
+ * changed source text or resolution.
46
46
  *
47
47
  * @evidence contracts/common.md#principled-implementation
48
48
  * Config-derived root specs, allowed extensions and exclusion provenance
@@ -42,6 +42,7 @@ import type { TtscProjectRegistration } from "./transform/watch/TtscProjectRegis
42
42
  import { createViteBuildLifecycle } from "./vite/createViteBuildLifecycle";
43
43
  import { createViteServeInputWatch } from "./vite/createViteServeInputWatch";
44
44
  import { createViteServeWatchHooks } from "./vite/createViteServeWatchHooks";
45
+ import { installViteDependencyScanPlugins } from "./vite/installViteDependencyScanPlugins";
45
46
  import { TTSC_SOURCE_MAP_STASH } from "./webpack/TTSC_SOURCE_MAP_STASH";
46
47
  import { registerTtscSourceMapLoader } from "./webpack/registerTtscSourceMapLoader";
47
48
  import { reportCompiledProjectRecords } from "./webpack/reportCompiledProjectRecords";
@@ -253,6 +254,37 @@ const unpluginFactory: UnpluginFactory<
253
254
  transformCache,
254
255
  hostDeclaresPolling(process.env, viteLifecycle.usePolling),
255
256
  );
257
+ installViteDependencyScanPlugins(
258
+ config,
259
+ isTransformTarget,
260
+ (source, file) => {
261
+ const startedAt = viteLifecycle.watching
262
+ ? serveInputs.begin()
263
+ : undefined;
264
+ return transformTtsc(
265
+ file,
266
+ source,
267
+ options,
268
+ aliases,
269
+ transformCache,
270
+ {
271
+ exactPath: true,
272
+ watching: viteLifecycle.watching,
273
+ ...createViteServeWatchHooks(
274
+ "serve",
275
+ viteLifecycle.watching,
276
+ serveInputs,
277
+ file,
278
+ startedAt,
279
+ ),
280
+ },
281
+ );
282
+ },
283
+ (this?.meta as { rolldownVersion?: string } | undefined)
284
+ ?.rolldownVersion === undefined
285
+ ? "esbuild"
286
+ : "rolldown",
287
+ );
256
288
  },
257
289
  // Compiler dependencies belong to the filesystem watch graph. Vite's
258
290
  // transform-context addWatchFile also inserts runtime imports, so none