@hydranium/core 1.0.0-next.35 → 1.0.0-next.351

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 (779) hide show
  1. package/README.md +78 -82
  2. package/lib/browser/host-heads-in-worker.d.ts +77 -0
  3. package/lib/browser/host-heads-in-worker.d.ts.map +1 -0
  4. package/lib/browser/host-heads-in-worker.js +169 -0
  5. package/lib/browser/host-heads-in-worker.js.map +1 -0
  6. package/lib/browser/index.d.ts +12 -0
  7. package/lib/browser/index.d.ts.map +1 -0
  8. package/lib/browser/index.js +17 -0
  9. package/lib/browser/index.js.map +1 -0
  10. package/lib/browser/indexeddb-file-system-store.d.ts +82 -0
  11. package/lib/browser/indexeddb-file-system-store.d.ts.map +1 -0
  12. package/lib/browser/indexeddb-file-system-store.js +181 -0
  13. package/lib/browser/indexeddb-file-system-store.js.map +1 -0
  14. package/lib/browser/start-language-server-in-worker.d.ts +32 -0
  15. package/lib/browser/start-language-server-in-worker.d.ts.map +1 -0
  16. package/lib/browser/start-language-server-in-worker.js +40 -0
  17. package/lib/browser/start-language-server-in-worker.js.map +1 -0
  18. package/lib/documents/ast-document-manager.d.ts +266 -124
  19. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  20. package/lib/documents/ast-document-manager.js +293 -132
  21. package/lib/documents/ast-document-manager.js.map +1 -1
  22. package/lib/documents/client-ids.d.ts +5 -19
  23. package/lib/documents/client-ids.d.ts.map +1 -1
  24. package/lib/documents/client-ids.js +5 -19
  25. package/lib/documents/client-ids.js.map +1 -1
  26. package/lib/documents/client-session-errors.d.ts +15 -0
  27. package/lib/documents/client-session-errors.d.ts.map +1 -0
  28. package/lib/documents/client-session-errors.js +15 -0
  29. package/lib/documents/client-session-errors.js.map +1 -0
  30. package/lib/documents/client-session-registry.d.ts +146 -0
  31. package/lib/documents/client-session-registry.d.ts.map +1 -0
  32. package/lib/documents/client-session-registry.js +207 -0
  33. package/lib/documents/client-session-registry.js.map +1 -0
  34. package/lib/documents/dirty-state-tracker.d.ts +101 -0
  35. package/lib/documents/dirty-state-tracker.d.ts.map +1 -0
  36. package/lib/documents/dirty-state-tracker.js +85 -0
  37. package/lib/documents/dirty-state-tracker.js.map +1 -0
  38. package/lib/documents/document-release-handler.d.ts +204 -0
  39. package/lib/documents/document-release-handler.d.ts.map +1 -0
  40. package/lib/documents/document-release-handler.js +317 -0
  41. package/lib/documents/document-release-handler.js.map +1 -0
  42. package/lib/documents/document-release-scheduler.d.ts +67 -0
  43. package/lib/documents/document-release-scheduler.d.ts.map +1 -0
  44. package/lib/documents/document-release-scheduler.js +80 -0
  45. package/lib/documents/document-release-scheduler.js.map +1 -0
  46. package/lib/documents/file-system-task-queue.d.ts +52 -0
  47. package/lib/documents/file-system-task-queue.d.ts.map +1 -0
  48. package/lib/documents/file-system-task-queue.js +37 -0
  49. package/lib/documents/file-system-task-queue.js.map +1 -0
  50. package/lib/documents/hydranium-text-documents.d.ts +445 -282
  51. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  52. package/lib/documents/hydranium-text-documents.js +903 -483
  53. package/lib/documents/hydranium-text-documents.js.map +1 -1
  54. package/lib/documents/index.d.ts +10 -2
  55. package/lib/documents/index.d.ts.map +1 -1
  56. package/lib/documents/index.js +10 -2
  57. package/lib/documents/index.js.map +1 -1
  58. package/lib/documents/language-client-shadow.d.ts +234 -0
  59. package/lib/documents/language-client-shadow.d.ts.map +1 -0
  60. package/lib/documents/language-client-shadow.js +306 -0
  61. package/lib/documents/language-client-shadow.js.map +1 -0
  62. package/lib/documents/model-ledger.d.ts +47 -0
  63. package/lib/documents/model-ledger.d.ts.map +1 -0
  64. package/lib/documents/model-ledger.js +30 -0
  65. package/lib/documents/model-ledger.js.map +1 -0
  66. package/lib/documents/text-ledger.d.ts +64 -0
  67. package/lib/documents/text-ledger.d.ts.map +1 -0
  68. package/lib/documents/text-ledger.js +63 -0
  69. package/lib/documents/text-ledger.js.map +1 -0
  70. package/lib/documents/version-sync-service.d.ts +138 -0
  71. package/lib/documents/version-sync-service.d.ts.map +1 -0
  72. package/lib/documents/version-sync-service.js +173 -0
  73. package/lib/documents/version-sync-service.js.map +1 -0
  74. package/lib/index.d.ts +4 -0
  75. package/lib/index.d.ts.map +1 -1
  76. package/lib/index.js +7 -0
  77. package/lib/index.js.map +1 -1
  78. package/lib/langium/ast-extension/ast-extension-service.d.ts +42 -31
  79. package/lib/langium/ast-extension/ast-extension-service.d.ts.map +1 -1
  80. package/lib/langium/ast-extension/ast-extension-service.js +45 -19
  81. package/lib/langium/ast-extension/ast-extension-service.js.map +1 -1
  82. package/lib/langium/ast-extension/ast-node-builder.d.ts +12 -7
  83. package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
  84. package/lib/langium/ast-extension/ast-node-builder.js +25 -9
  85. package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
  86. package/lib/langium/bootstrap.d.ts +49 -36
  87. package/lib/langium/bootstrap.d.ts.map +1 -1
  88. package/lib/langium/bootstrap.js +83 -44
  89. package/lib/langium/bootstrap.js.map +1 -1
  90. package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts +9 -9
  91. package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts.map +1 -1
  92. package/lib/langium/build-phase-pass/build-phase-pass-service.js +25 -16
  93. package/lib/langium/build-phase-pass/build-phase-pass-service.js.map +1 -1
  94. package/lib/langium/build-phase-pass/build-phase-pass.d.ts +20 -8
  95. package/lib/langium/build-phase-pass/build-phase-pass.d.ts.map +1 -1
  96. package/lib/langium/build-phase-pass/build-phase-pass.js +20 -0
  97. package/lib/langium/build-phase-pass/build-phase-pass.js.map +1 -1
  98. package/lib/langium/composite-ast-reflection.d.ts +46 -0
  99. package/lib/langium/composite-ast-reflection.d.ts.map +1 -0
  100. package/lib/langium/composite-ast-reflection.js +97 -0
  101. package/lib/langium/composite-ast-reflection.js.map +1 -0
  102. package/lib/langium/config/configuration-provider.d.ts +81 -0
  103. package/lib/langium/config/configuration-provider.d.ts.map +1 -0
  104. package/lib/langium/config/configuration-provider.js +112 -0
  105. package/lib/langium/config/configuration-provider.js.map +1 -0
  106. package/lib/langium/config/index.d.ts +1 -0
  107. package/lib/langium/config/index.d.ts.map +1 -1
  108. package/lib/langium/config/index.js +1 -0
  109. package/lib/langium/config/index.js.map +1 -1
  110. package/lib/langium/config/settings.js.map +1 -1
  111. package/lib/langium/diagnostics/console-tee.d.ts +27 -0
  112. package/lib/langium/diagnostics/console-tee.d.ts.map +1 -0
  113. package/lib/langium/diagnostics/console-tee.js +142 -0
  114. package/lib/langium/diagnostics/console-tee.js.map +1 -0
  115. package/lib/langium/diagnostics/format-log-arg.d.ts +18 -0
  116. package/lib/langium/diagnostics/format-log-arg.d.ts.map +1 -0
  117. package/lib/langium/diagnostics/format-log-arg.js +36 -0
  118. package/lib/langium/diagnostics/format-log-arg.js.map +1 -0
  119. package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts +9 -20
  120. package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts.map +1 -1
  121. package/lib/langium/diagnostics/hydranium-langium-profiler.js +15 -24
  122. package/lib/langium/diagnostics/hydranium-langium-profiler.js.map +1 -1
  123. package/lib/langium/diagnostics/log-preamble.js +1 -1
  124. package/lib/langium/diagnostics/log-preamble.js.map +1 -1
  125. package/lib/langium/diagnostics/logger.d.ts +25 -6
  126. package/lib/langium/diagnostics/logger.d.ts.map +1 -1
  127. package/lib/langium/diagnostics/logger.js +49 -17
  128. package/lib/langium/diagnostics/logger.js.map +1 -1
  129. package/lib/langium/diagnostics/lsp-logger.d.ts +25 -0
  130. package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
  131. package/lib/langium/diagnostics/lsp-logger.js +81 -45
  132. package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
  133. package/lib/langium/diagnostics/server-tracer.d.ts.map +1 -1
  134. package/lib/langium/diagnostics/server-tracer.js.map +1 -1
  135. package/lib/langium/document-builder/build-pipeline-integration.d.ts +21 -1
  136. package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
  137. package/lib/langium/document-builder/build-pipeline-integration.js +28 -30
  138. package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
  139. package/lib/langium/document-builder/build-session.d.ts +6 -5
  140. package/lib/langium/document-builder/build-session.d.ts.map +1 -1
  141. package/lib/langium/document-builder/build-session.js +5 -5
  142. package/lib/langium/document-builder/build-session.js.map +1 -1
  143. package/lib/langium/document-builder/document-builder.d.ts +310 -41
  144. package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
  145. package/lib/langium/document-builder/document-builder.js +490 -79
  146. package/lib/langium/document-builder/document-builder.js.map +1 -1
  147. package/lib/langium/documentation/comment-provider.d.ts.map +1 -1
  148. package/lib/langium/documentation/comment-provider.js.map +1 -1
  149. package/lib/langium/integration-services.d.ts +40 -24
  150. package/lib/langium/integration-services.d.ts.map +1 -1
  151. package/lib/langium/integration-services.js +7 -4
  152. package/lib/langium/integration-services.js.map +1 -1
  153. package/lib/langium/integrity/integrity-rule.d.ts +17 -8
  154. package/lib/langium/integrity/integrity-rule.d.ts.map +1 -1
  155. package/lib/langium/integrity/integrity-rule.js.map +1 -1
  156. package/lib/langium/integrity/integrity-service.d.ts +95 -27
  157. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  158. package/lib/langium/integrity/integrity-service.js +303 -63
  159. package/lib/langium/integrity/integrity-service.js.map +1 -1
  160. package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
  161. package/lib/langium/keys/name-based-key-provider.js.map +1 -1
  162. package/lib/langium/keys/positional-key-provider.d.ts.map +1 -1
  163. package/lib/langium/keys/positional-key-provider.js.map +1 -1
  164. package/lib/langium/labeling/label-provider.d.ts.map +1 -1
  165. package/lib/langium/labeling/label-provider.js.map +1 -1
  166. package/lib/langium/language-module.d.ts +30 -5
  167. package/lib/langium/language-module.d.ts.map +1 -1
  168. package/lib/langium/language-module.js +18 -4
  169. package/lib/langium/language-module.js.map +1 -1
  170. package/lib/langium/model-service/client-session.d.ts +383 -0
  171. package/lib/langium/model-service/client-session.d.ts.map +1 -0
  172. package/lib/langium/model-service/client-session.js +455 -0
  173. package/lib/langium/model-service/client-session.js.map +1 -0
  174. package/lib/langium/model-service/index.d.ts +2 -0
  175. package/lib/langium/model-service/index.d.ts.map +1 -1
  176. package/lib/langium/model-service/index.js +2 -0
  177. package/lib/langium/model-service/index.js.map +1 -1
  178. package/lib/langium/model-service/model-events.d.ts +66 -0
  179. package/lib/langium/model-service/model-events.d.ts.map +1 -0
  180. package/lib/langium/model-service/model-events.js +10 -0
  181. package/lib/langium/model-service/model-events.js.map +1 -0
  182. package/lib/langium/model-service/model-service.d.ts +456 -300
  183. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  184. package/lib/langium/model-service/model-service.js +571 -466
  185. package/lib/langium/model-service/model-service.js.map +1 -1
  186. package/lib/langium/module.d.ts +141 -40
  187. package/lib/langium/module.d.ts.map +1 -1
  188. package/lib/langium/module.js +52 -40
  189. package/lib/langium/module.js.map +1 -1
  190. package/lib/langium/naming/name-provider.d.ts +32 -7
  191. package/lib/langium/naming/name-provider.d.ts.map +1 -1
  192. package/lib/langium/naming/name-provider.js +10 -4
  193. package/lib/langium/naming/name-provider.js.map +1 -1
  194. package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
  195. package/lib/langium/project/abstract-project-manager.d.ts.map +1 -1
  196. package/lib/langium/project/abstract-project-manager.js +13 -6
  197. package/lib/langium/project/abstract-project-manager.js.map +1 -1
  198. package/lib/langium/project/project-change-event.d.ts +2 -2
  199. package/lib/langium/project/single-project-manager.d.ts.map +1 -1
  200. package/lib/langium/project/single-project-manager.js.map +1 -1
  201. package/lib/langium/residency/cst-residency-service.d.ts +38 -14
  202. package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
  203. package/lib/langium/residency/cst-residency-service.js +24 -58
  204. package/lib/langium/residency/cst-residency-service.js.map +1 -1
  205. package/lib/langium/scope/ast-node-description-provider.d.ts.map +1 -1
  206. package/lib/langium/scope/ast-node-description-provider.js.map +1 -1
  207. package/lib/langium/scope/fallback-scope.d.ts +27 -0
  208. package/lib/langium/scope/fallback-scope.d.ts.map +1 -0
  209. package/lib/langium/scope/fallback-scope.js +35 -0
  210. package/lib/langium/scope/fallback-scope.js.map +1 -0
  211. package/lib/langium/scope/hydranium-scope-computation.d.ts +21 -18
  212. package/lib/langium/scope/hydranium-scope-computation.d.ts.map +1 -1
  213. package/lib/langium/scope/hydranium-scope-computation.js +38 -39
  214. package/lib/langium/scope/hydranium-scope-computation.js.map +1 -1
  215. package/lib/langium/scope/hydranium-scope-provider.d.ts +115 -32
  216. package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
  217. package/lib/langium/scope/hydranium-scope-provider.js +201 -39
  218. package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
  219. package/lib/langium/scope/index.d.ts +1 -0
  220. package/lib/langium/scope/index.d.ts.map +1 -1
  221. package/lib/langium/scope/index.js +1 -0
  222. package/lib/langium/scope/index.js.map +1 -1
  223. package/lib/langium/scope/reference-builder.d.ts.map +1 -1
  224. package/lib/langium/scope/reference-builder.js.map +1 -1
  225. package/lib/langium/scope/reference-candidate-provider.d.ts +6 -5
  226. package/lib/langium/scope/reference-candidate-provider.d.ts.map +1 -1
  227. package/lib/langium/scope/reference-candidate-provider.js +3 -2
  228. package/lib/langium/scope/reference-candidate-provider.js.map +1 -1
  229. package/lib/langium/scope/scope-extension-service.d.ts +69 -37
  230. package/lib/langium/scope/scope-extension-service.d.ts.map +1 -1
  231. package/lib/langium/scope/scope-extension-service.js +102 -29
  232. package/lib/langium/scope/scope-extension-service.js.map +1 -1
  233. package/lib/langium/scope/scoped-ast-node-description.d.ts +1 -3
  234. package/lib/langium/scope/scoped-ast-node-description.d.ts.map +1 -1
  235. package/lib/langium/scope/scoped-ast-node-description.js +1 -3
  236. package/lib/langium/scope/scoped-ast-node-description.js.map +1 -1
  237. package/lib/langium/serialization/abstract-serializer.d.ts +38 -27
  238. package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
  239. package/lib/langium/serialization/abstract-serializer.js +54 -30
  240. package/lib/langium/serialization/abstract-serializer.js.map +1 -1
  241. package/lib/langium/serialization/json-serializer.d.ts +8 -1
  242. package/lib/langium/serialization/json-serializer.d.ts.map +1 -1
  243. package/lib/langium/serialization/json-serializer.js +13 -3
  244. package/lib/langium/serialization/json-serializer.js.map +1 -1
  245. package/lib/langium/serialization/serializer.d.ts +1 -1
  246. package/lib/langium/serialization/yaml-serializer.d.ts +12 -0
  247. package/lib/langium/serialization/yaml-serializer.d.ts.map +1 -1
  248. package/lib/langium/serialization/yaml-serializer.js +24 -4
  249. package/lib/langium/serialization/yaml-serializer.js.map +1 -1
  250. package/lib/langium/service-registry.d.ts +29 -1
  251. package/lib/langium/service-registry.d.ts.map +1 -1
  252. package/lib/langium/service-registry.js +37 -0
  253. package/lib/langium/service-registry.js.map +1 -1
  254. package/lib/langium/shared-services.d.ts +13 -7
  255. package/lib/langium/shared-services.d.ts.map +1 -1
  256. package/lib/langium/shared-services.js.map +1 -1
  257. package/lib/langium/single-langium-copy.d.ts +22 -0
  258. package/lib/langium/single-langium-copy.d.ts.map +1 -0
  259. package/lib/langium/single-langium-copy.js +36 -0
  260. package/lib/langium/single-langium-copy.js.map +1 -0
  261. package/lib/langium/transfer/transfer-encoder.d.ts +86 -37
  262. package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
  263. package/lib/langium/transfer/transfer-encoder.js +36 -25
  264. package/lib/langium/transfer/transfer-encoder.js.map +1 -1
  265. package/lib/langium/trivia/comment-preserver.d.ts +543 -0
  266. package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
  267. package/lib/langium/trivia/comment-preserver.js +1164 -0
  268. package/lib/langium/trivia/comment-preserver.js.map +1 -0
  269. package/lib/langium/trivia/document-ending-preserver.d.ts +51 -0
  270. package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
  271. package/lib/langium/trivia/document-ending-preserver.js +62 -0
  272. package/lib/langium/trivia/document-ending-preserver.js.map +1 -0
  273. package/lib/langium/trivia/index.d.ts +14 -0
  274. package/lib/langium/trivia/index.d.ts.map +1 -0
  275. package/lib/langium/trivia/index.js +14 -0
  276. package/lib/langium/trivia/index.js.map +1 -0
  277. package/lib/langium/trivia/trivia-contribution.d.ts +37 -0
  278. package/lib/langium/trivia/trivia-contribution.d.ts.map +1 -0
  279. package/lib/langium/trivia/trivia-contribution.js +10 -0
  280. package/lib/langium/trivia/trivia-contribution.js.map +1 -0
  281. package/lib/langium/trivia/trivia-preserver.d.ts +52 -0
  282. package/lib/langium/trivia/trivia-preserver.d.ts.map +1 -0
  283. package/lib/langium/trivia/trivia-preserver.js +10 -0
  284. package/lib/langium/trivia/trivia-preserver.js.map +1 -0
  285. package/lib/langium/trivia/trivia-service.d.ts +70 -0
  286. package/lib/langium/trivia/trivia-service.d.ts.map +1 -0
  287. package/lib/langium/trivia/trivia-service.js +56 -0
  288. package/lib/langium/trivia/trivia-service.js.map +1 -0
  289. package/lib/langium/update-rewrite/normalize-empty-strings.d.ts.map +1 -1
  290. package/lib/langium/update-rewrite/update-rewrite-service.d.ts +1 -1
  291. package/lib/langium/update-rewrite/update-rewrite-service.d.ts.map +1 -1
  292. package/lib/langium/update-rewrite/update-rewrite-service.js.map +1 -1
  293. package/lib/langium/update-rewrite/update-rewrite.d.ts +1 -1
  294. package/lib/langium/validation/document-validator.d.ts +168 -23
  295. package/lib/langium/validation/document-validator.d.ts.map +1 -1
  296. package/lib/langium/validation/document-validator.js +264 -26
  297. package/lib/langium/validation/document-validator.js.map +1 -1
  298. package/lib/langium/validation/validation-contribution-collector.d.ts +9 -1
  299. package/lib/langium/validation/validation-contribution-collector.d.ts.map +1 -1
  300. package/lib/langium/validation/validation-contribution-collector.js +1 -1
  301. package/lib/langium/validation/validation-contribution-collector.js.map +1 -1
  302. package/lib/langium/workspace/document-uri-policy.d.ts +24 -15
  303. package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
  304. package/lib/langium/workspace/document-uri-policy.js +22 -13
  305. package/lib/langium/workspace/document-uri-policy.js.map +1 -1
  306. package/lib/langium/workspace/file-not-found.d.ts +23 -0
  307. package/lib/langium/workspace/file-not-found.d.ts.map +1 -0
  308. package/lib/langium/workspace/file-not-found.js +31 -0
  309. package/lib/langium/workspace/file-not-found.js.map +1 -0
  310. package/lib/langium/workspace/file-system-provider.d.ts +167 -8
  311. package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
  312. package/lib/langium/workspace/file-system-provider.js +115 -13
  313. package/lib/langium/workspace/file-system-provider.js.map +1 -1
  314. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +31 -1
  315. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
  316. package/lib/langium/workspace/hydranium-langium-document-factory.js +54 -0
  317. package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
  318. package/lib/langium/workspace/hydranium-workspace-lock.d.ts +43 -1
  319. package/lib/langium/workspace/hydranium-workspace-lock.d.ts.map +1 -1
  320. package/lib/langium/workspace/hydranium-workspace-lock.js +58 -1
  321. package/lib/langium/workspace/hydranium-workspace-lock.js.map +1 -1
  322. package/lib/langium/workspace/hydranium-workspace-manager.d.ts +103 -21
  323. package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
  324. package/lib/langium/workspace/hydranium-workspace-manager.js +184 -31
  325. package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
  326. package/lib/langium/workspace/in-memory-file-system-provider.d.ts +26 -9
  327. package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
  328. package/lib/langium/workspace/in-memory-file-system-provider.js +45 -22
  329. package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
  330. package/lib/langium/workspace/index-manager.d.ts.map +1 -1
  331. package/lib/langium/workspace/index-manager.js.map +1 -1
  332. package/lib/langium/workspace/index.d.ts +1 -0
  333. package/lib/langium/workspace/index.d.ts.map +1 -1
  334. package/lib/langium/workspace/index.js +1 -0
  335. package/lib/langium/workspace/index.js.map +1 -1
  336. package/lib/langium/workspace/initialize-workspace.d.ts +40 -3
  337. package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
  338. package/lib/langium/workspace/initialize-workspace.js +68 -3
  339. package/lib/langium/workspace/initialize-workspace.js.map +1 -1
  340. package/lib/langium/workspace/langium-documents.d.ts +7 -0
  341. package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
  342. package/lib/langium/workspace/langium-documents.js +18 -1
  343. package/lib/langium/workspace/langium-documents.js.map +1 -1
  344. package/lib/langium/workspace/persistent-file-system-provider.d.ts +16 -10
  345. package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
  346. package/lib/langium/workspace/persistent-file-system-provider.js +25 -13
  347. package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
  348. package/lib/langium/workspace/self-save-registry.d.ts +84 -0
  349. package/lib/langium/workspace/self-save-registry.d.ts.map +1 -0
  350. package/lib/{documents → langium/workspace}/self-save-registry.js +33 -22
  351. package/lib/langium/workspace/self-save-registry.js.map +1 -0
  352. package/lib/langium/workspace/virtual-document.d.ts +55 -21
  353. package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
  354. package/lib/langium/workspace/virtual-document.js +87 -24
  355. package/lib/langium/workspace/virtual-document.js.map +1 -1
  356. package/lib/langium/workspace/write-lock-scope.d.ts +22 -10
  357. package/lib/langium/workspace/write-lock-scope.d.ts.map +1 -1
  358. package/lib/langium/workspace/write-lock-scope.js +15 -5
  359. package/lib/langium/workspace/write-lock-scope.js.map +1 -1
  360. package/lib/launcher/integrated-server.d.ts +3 -1
  361. package/lib/launcher/integrated-server.d.ts.map +1 -1
  362. package/lib/locale/server-locale.d.ts +19 -5
  363. package/lib/locale/server-locale.d.ts.map +1 -1
  364. package/lib/locale/server-locale.js +1 -1
  365. package/lib/locale/server-locale.js.map +1 -1
  366. package/lib/lsp/completion/hydranium-completion-provider.d.ts +44 -2
  367. package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
  368. package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
  369. package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
  370. package/lib/lsp/connection-features.d.ts +23 -0
  371. package/lib/lsp/connection-features.d.ts.map +1 -0
  372. package/lib/lsp/connection-features.js +60 -0
  373. package/lib/lsp/connection-features.js.map +1 -0
  374. package/lib/lsp/diagnostics-connection.d.ts +27 -0
  375. package/lib/lsp/diagnostics-connection.d.ts.map +1 -0
  376. package/lib/lsp/diagnostics-connection.js +53 -0
  377. package/lib/lsp/diagnostics-connection.js.map +1 -0
  378. package/lib/lsp/edit-requests-guard.d.ts +31 -0
  379. package/lib/lsp/edit-requests-guard.d.ts.map +1 -0
  380. package/lib/lsp/edit-requests-guard.js +125 -0
  381. package/lib/lsp/edit-requests-guard.js.map +1 -0
  382. package/lib/lsp/hydranium-document-update-handler.d.ts +126 -82
  383. package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
  384. package/lib/lsp/hydranium-document-update-handler.js +235 -102
  385. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  386. package/lib/lsp/index.d.ts +6 -2
  387. package/lib/lsp/index.d.ts.map +1 -1
  388. package/lib/lsp/index.js +6 -2
  389. package/lib/lsp/index.js.map +1 -1
  390. package/lib/lsp/lsp-latency.d.ts +39 -0
  391. package/lib/lsp/lsp-latency.d.ts.map +1 -0
  392. package/lib/lsp/lsp-latency.js +58 -0
  393. package/lib/lsp/lsp-latency.js.map +1 -0
  394. package/lib/lsp/save-text-document.d.ts +31 -0
  395. package/lib/lsp/save-text-document.d.ts.map +1 -0
  396. package/lib/lsp/save-text-document.js +52 -0
  397. package/lib/lsp/save-text-document.js.map +1 -0
  398. package/lib/lsp/semantic-token-provider.d.ts +58 -2
  399. package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
  400. package/lib/lsp/semantic-token-provider.js +98 -9
  401. package/lib/lsp/semantic-token-provider.js.map +1 -1
  402. package/lib/lsp/shared-module.d.ts +4 -8
  403. package/lib/lsp/shared-module.d.ts.map +1 -1
  404. package/lib/lsp/shared-module.js.map +1 -1
  405. package/lib/lsp/start-language-server.d.ts +12 -7
  406. package/lib/lsp/start-language-server.d.ts.map +1 -1
  407. package/lib/lsp/start-language-server.js +21 -7
  408. package/lib/lsp/start-language-server.js.map +1 -1
  409. package/lib/messages/carriers.d.ts +4 -6
  410. package/lib/messages/carriers.d.ts.map +1 -1
  411. package/lib/messages/carriers.js +4 -6
  412. package/lib/messages/carriers.js.map +1 -1
  413. package/lib/messages/index.d.ts +2 -2
  414. package/lib/messages/index.d.ts.map +1 -1
  415. package/lib/messages/index.js +2 -2
  416. package/lib/messages/index.js.map +1 -1
  417. package/lib/messages/renderer.d.ts +32 -7
  418. package/lib/messages/renderer.d.ts.map +1 -1
  419. package/lib/messages/renderer.js +7 -1
  420. package/lib/messages/renderer.js.map +1 -1
  421. package/lib/node/event-loop-monitor.d.ts.map +1 -1
  422. package/lib/node/event-loop-monitor.js +2 -1
  423. package/lib/node/event-loop-monitor.js.map +1 -1
  424. package/lib/node/heap-ceiling.d.ts +61 -0
  425. package/lib/node/heap-ceiling.d.ts.map +1 -0
  426. package/lib/node/heap-ceiling.js +72 -0
  427. package/lib/node/heap-ceiling.js.map +1 -0
  428. package/lib/node/index.d.ts +1 -1
  429. package/lib/node/index.d.ts.map +1 -1
  430. package/lib/node/index.js +5 -1
  431. package/lib/node/index.js.map +1 -1
  432. package/lib/node/latency-from-env.d.ts +1 -1
  433. package/lib/node/latency-from-env.js +1 -1
  434. package/lib/node/lint-grammar.js.map +1 -1
  435. package/lib/node/log-file-sink.d.ts +3 -2
  436. package/lib/node/log-file-sink.d.ts.map +1 -1
  437. package/lib/node/log-file-sink.js +6 -2
  438. package/lib/node/log-file-sink.js.map +1 -1
  439. package/lib/node/log-preamble-node.d.ts +5 -3
  440. package/lib/node/log-preamble-node.d.ts.map +1 -1
  441. package/lib/node/log-preamble-node.js +13 -10
  442. package/lib/node/log-preamble-node.js.map +1 -1
  443. package/lib/node/measure-memory.d.ts.map +1 -1
  444. package/lib/node/measure-memory.js +5 -4
  445. package/lib/node/measure-memory.js.map +1 -1
  446. package/lib/node/memory-monitor.d.ts +2 -2
  447. package/lib/node/memory-monitor.d.ts.map +1 -1
  448. package/lib/node/memory-monitor.js +9 -10
  449. package/lib/node/memory-monitor.js.map +1 -1
  450. package/lib/node/node-file-system-provider.d.ts +67 -9
  451. package/lib/node/node-file-system-provider.d.ts.map +1 -1
  452. package/lib/node/node-file-system-provider.js +198 -53
  453. package/lib/node/node-file-system-provider.js.map +1 -1
  454. package/lib/node/profile-capture.d.ts +12 -4
  455. package/lib/node/profile-capture.d.ts.map +1 -1
  456. package/lib/node/profile-capture.js +8 -6
  457. package/lib/node/profile-capture.js.map +1 -1
  458. package/lib/node/profile-digest.js.map +1 -1
  459. package/lib/node/profiling-run.d.ts +13 -3
  460. package/lib/node/profiling-run.d.ts.map +1 -1
  461. package/lib/node/profiling-run.js +17 -8
  462. package/lib/node/profiling-run.js.map +1 -1
  463. package/lib/node/rename-over-open-readers.d.ts +61 -0
  464. package/lib/node/rename-over-open-readers.d.ts.map +1 -0
  465. package/lib/node/rename-over-open-readers.js +80 -0
  466. package/lib/node/rename-over-open-readers.js.map +1 -0
  467. package/lib/node/server-diagnostics.js +1 -1
  468. package/lib/node/server-diagnostics.js.map +1 -1
  469. package/lib/node/server-state-snapshot.js +4 -4
  470. package/lib/node/server-state-snapshot.js.map +1 -1
  471. package/lib/node/socket-launcher.d.ts +43 -7
  472. package/lib/node/socket-launcher.d.ts.map +1 -1
  473. package/lib/node/socket-launcher.js +42 -7
  474. package/lib/node/socket-launcher.js.map +1 -1
  475. package/lib/node/startup-cpu-profile.d.ts +29 -0
  476. package/lib/node/startup-cpu-profile.d.ts.map +1 -0
  477. package/lib/node/startup-cpu-profile.js +91 -0
  478. package/lib/node/startup-cpu-profile.js.map +1 -0
  479. package/lib/node/stdio-launcher.d.ts +13 -13
  480. package/lib/node/stdio-launcher.d.ts.map +1 -1
  481. package/lib/node/stdio-launcher.js +21 -11
  482. package/lib/node/stdio-launcher.js.map +1 -1
  483. package/lib/node/validate-workspace.d.ts +1 -1
  484. package/lib/node/validate-workspace.d.ts.map +1 -1
  485. package/lib/node/validate-workspace.js +5 -1
  486. package/lib/node/validate-workspace.js.map +1 -1
  487. package/lib/testing/document-uri-policy-conformance.js +1 -1
  488. package/lib/testing/document-uri-policy-conformance.js.map +1 -1
  489. package/lib/testing/fake-description.js.map +1 -1
  490. package/lib/testing/fake-document.d.ts +2 -1
  491. package/lib/testing/fake-document.d.ts.map +1 -1
  492. package/lib/testing/fake-document.js.map +1 -1
  493. package/lib/testing/index.d.ts +1 -1
  494. package/lib/testing/index.d.ts.map +1 -1
  495. package/lib/testing/index.js +2 -1
  496. package/lib/testing/index.js.map +1 -1
  497. package/lib/testing/langium-test-helpers.d.ts.map +1 -1
  498. package/lib/testing/langium-test-helpers.js +1 -0
  499. package/lib/testing/langium-test-helpers.js.map +1 -1
  500. package/lib/testing/make-noop-language-services.js.map +1 -1
  501. package/lib/testing/make-noop-shared-services.d.ts +4 -4
  502. package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
  503. package/lib/testing/make-noop-shared-services.js +4 -4
  504. package/lib/testing/make-noop-shared-services.js.map +1 -1
  505. package/lib/testing/make-test-services.d.ts +51 -20
  506. package/lib/testing/make-test-services.d.ts.map +1 -1
  507. package/lib/testing/make-test-services.js +29 -13
  508. package/lib/testing/make-test-services.js.map +1 -1
  509. package/lib/testing/make-test-tracer.d.ts +12 -0
  510. package/lib/testing/make-test-tracer.d.ts.map +1 -1
  511. package/lib/testing/make-test-tracer.js +13 -0
  512. package/lib/testing/make-test-tracer.js.map +1 -1
  513. package/lib/testing/node/applied-edit-capture.d.ts +29 -0
  514. package/lib/testing/node/applied-edit-capture.d.ts.map +1 -0
  515. package/lib/testing/node/applied-edit-capture.js +117 -0
  516. package/lib/testing/node/applied-edit-capture.js.map +1 -0
  517. package/lib/testing/node/golden-corpus.js.map +1 -1
  518. package/lib/testing/node/index.d.ts +1 -0
  519. package/lib/testing/node/index.d.ts.map +1 -1
  520. package/lib/testing/node/index.js +1 -0
  521. package/lib/testing/node/index.js.map +1 -1
  522. package/lib/testing/node/lsp-harness.d.ts.map +1 -1
  523. package/lib/testing/node/lsp-harness.js +2 -0
  524. package/lib/testing/node/lsp-harness.js.map +1 -1
  525. package/lib/testing/node/lsp-server-connection.d.ts +21 -6
  526. package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
  527. package/lib/testing/node/lsp-server-connection.js +49 -106
  528. package/lib/testing/node/lsp-server-connection.js.map +1 -1
  529. package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
  530. package/lib/testing/node/scratch-workspace.js +10 -5
  531. package/lib/testing/node/scratch-workspace.js.map +1 -1
  532. package/lib/testing/node/spawned-server.d.ts +30 -1
  533. package/lib/testing/node/spawned-server.d.ts.map +1 -1
  534. package/lib/testing/node/spawned-server.js +39 -2
  535. package/lib/testing/node/spawned-server.js.map +1 -1
  536. package/lib/testing/node/unhandled-rejections.d.ts +20 -0
  537. package/lib/testing/node/unhandled-rejections.d.ts.map +1 -0
  538. package/lib/testing/node/unhandled-rejections.js +32 -0
  539. package/lib/testing/node/unhandled-rejections.js.map +1 -0
  540. package/lib/testing/playwright/browser-capture-bridge.js.map +1 -1
  541. package/lib/testing/playwright/e2e-profiling.js.map +1 -1
  542. package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
  543. package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
  544. package/lib/testing/playwright/flaky-network-proxy.js +164 -0
  545. package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
  546. package/lib/testing/playwright/index.d.ts +1 -0
  547. package/lib/testing/playwright/index.d.ts.map +1 -1
  548. package/lib/testing/playwright/index.js +1 -0
  549. package/lib/testing/playwright/index.js.map +1 -1
  550. package/lib/testing/playwright/server-log-capture.d.ts +46 -16
  551. package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
  552. package/lib/testing/playwright/server-log-capture.js +111 -40
  553. package/lib/testing/playwright/server-log-capture.js.map +1 -1
  554. package/lib/testing/playwright/server-log-fixture.d.ts +16 -0
  555. package/lib/testing/playwright/server-log-fixture.d.ts.map +1 -1
  556. package/lib/testing/playwright/server-log-fixture.js +25 -6
  557. package/lib/testing/playwright/server-log-fixture.js.map +1 -1
  558. package/lib/testing/playwright/server-log-region.d.ts +15 -0
  559. package/lib/testing/playwright/server-log-region.d.ts.map +1 -0
  560. package/lib/testing/playwright/server-log-region.js +30 -0
  561. package/lib/testing/playwright/server-log-region.js.map +1 -0
  562. package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
  563. package/lib/testing/playwright/server-log-rename-reporter.js +4 -3
  564. package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
  565. package/lib/testing/run-update-pipeline.d.ts +8 -5
  566. package/lib/testing/run-update-pipeline.d.ts.map +1 -1
  567. package/lib/testing/run-update-pipeline.js.map +1 -1
  568. package/lib/testing/stub-ast-document-manager.d.ts +11 -52
  569. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  570. package/lib/testing/stub-ast-document-manager.js +31 -62
  571. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  572. package/lib/testing/stub-document-builder.d.ts +33 -11
  573. package/lib/testing/stub-document-builder.d.ts.map +1 -1
  574. package/lib/testing/stub-document-builder.js +103 -5
  575. package/lib/testing/stub-document-builder.js.map +1 -1
  576. package/lib/testing/stub-hydranium-text-documents.d.ts +33 -10
  577. package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
  578. package/lib/testing/stub-hydranium-text-documents.js +132 -16
  579. package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
  580. package/lib/testing/stub-index-manager.js.map +1 -1
  581. package/lib/testing/stub-langium-documents.d.ts +3 -2
  582. package/lib/testing/stub-langium-documents.d.ts.map +1 -1
  583. package/lib/testing/stub-langium-documents.js.map +1 -1
  584. package/lib/testing/stub-model-service.d.ts +9 -8
  585. package/lib/testing/stub-model-service.d.ts.map +1 -1
  586. package/lib/testing/stub-model-service.js +6 -6
  587. package/lib/testing/stub-model-service.js.map +1 -1
  588. package/lib/testing/stub-project-manager.js.map +1 -1
  589. package/lib/testing/stub-self-save-registry.d.ts +1 -1
  590. package/lib/testing/stub-self-save-registry.d.ts.map +1 -1
  591. package/lib/testing/stub-service-registry.d.ts +1 -1
  592. package/lib/testing/stub-service-registry.js.map +1 -1
  593. package/lib/testing/stub-writable-file-system.d.ts +1 -1
  594. package/lib/testing/stub-writable-file-system.d.ts.map +1 -1
  595. package/lib/testing/stub-writable-file-system.js +2 -1
  596. package/lib/testing/stub-writable-file-system.js.map +1 -1
  597. package/lib/util/connection-liveness.d.ts +22 -6
  598. package/lib/util/connection-liveness.d.ts.map +1 -1
  599. package/lib/util/connection-liveness.js +74 -15
  600. package/lib/util/connection-liveness.js.map +1 -1
  601. package/lib/util/environment.d.ts +7 -0
  602. package/lib/util/environment.d.ts.map +1 -1
  603. package/lib/util/environment.js +15 -1
  604. package/lib/util/environment.js.map +1 -1
  605. package/lib/util/registry.d.ts.map +1 -1
  606. package/package.json +41 -60
  607. package/src/browser/host-heads-in-worker.ts +218 -0
  608. package/src/browser/index.ts +17 -0
  609. package/src/browser/indexeddb-file-system-store.ts +192 -0
  610. package/src/browser/start-language-server-in-worker.ts +56 -0
  611. package/src/documents/ast-document-manager.ts +479 -233
  612. package/src/documents/client-ids.ts +5 -22
  613. package/src/documents/client-session-errors.ts +24 -0
  614. package/src/documents/client-session-registry.ts +262 -0
  615. package/src/documents/dirty-state-tracker.ts +167 -0
  616. package/src/documents/document-release-handler.ts +404 -0
  617. package/src/documents/document-release-scheduler.ts +121 -0
  618. package/src/documents/file-system-task-queue.ts +74 -0
  619. package/src/documents/hydranium-text-documents.ts +1029 -595
  620. package/src/documents/index.ts +10 -2
  621. package/src/documents/language-client-shadow.ts +501 -0
  622. package/src/documents/model-ledger.ts +66 -0
  623. package/src/documents/text-ledger.ts +112 -0
  624. package/src/documents/version-sync-service.ts +275 -0
  625. package/src/index.ts +7 -0
  626. package/src/langium/ast-extension/ast-extension-service.ts +77 -41
  627. package/src/langium/ast-extension/ast-node-builder.ts +35 -13
  628. package/src/langium/bootstrap.ts +87 -51
  629. package/src/langium/build-phase-pass/build-phase-pass-service.ts +29 -19
  630. package/src/langium/build-phase-pass/build-phase-pass.ts +37 -8
  631. package/src/langium/composite-ast-reflection.ts +112 -0
  632. package/src/langium/config/configuration-provider.ts +119 -0
  633. package/src/langium/config/index.ts +1 -0
  634. package/src/langium/diagnostics/console-tee.ts +151 -0
  635. package/src/langium/diagnostics/format-log-arg.ts +36 -0
  636. package/src/langium/diagnostics/hydranium-langium-profiler.ts +15 -39
  637. package/src/langium/diagnostics/log-preamble.ts +1 -1
  638. package/src/langium/diagnostics/logger.ts +51 -17
  639. package/src/langium/diagnostics/lsp-logger.ts +83 -44
  640. package/src/langium/document-builder/build-pipeline-integration.ts +46 -32
  641. package/src/langium/document-builder/build-session.ts +4 -3
  642. package/src/langium/document-builder/document-builder.ts +615 -79
  643. package/src/langium/integration-services.ts +59 -28
  644. package/src/langium/integrity/integrity-rule.ts +17 -8
  645. package/src/langium/integrity/integrity-service.ts +332 -69
  646. package/src/langium/language-module.ts +49 -8
  647. package/src/langium/model-service/client-session.ts +726 -0
  648. package/src/langium/model-service/index.ts +2 -0
  649. package/src/langium/model-service/model-events.ts +80 -0
  650. package/src/langium/model-service/model-service.ts +878 -494
  651. package/src/langium/module.ts +195 -72
  652. package/src/langium/naming/name-provider.ts +34 -8
  653. package/src/langium/project/abstract-project-manager.ts +13 -5
  654. package/src/langium/project/project-change-event.ts +2 -2
  655. package/src/langium/residency/cst-residency-service.ts +54 -19
  656. package/src/langium/scope/fallback-scope.ts +38 -0
  657. package/src/langium/scope/hydranium-scope-computation.ts +45 -44
  658. package/src/langium/scope/hydranium-scope-provider.ts +228 -41
  659. package/src/langium/scope/index.ts +1 -0
  660. package/src/langium/scope/reference-candidate-provider.ts +6 -5
  661. package/src/langium/scope/scope-extension-service.ts +148 -56
  662. package/src/langium/scope/scoped-ast-node-description.ts +1 -3
  663. package/src/langium/serialization/abstract-serializer.ts +57 -41
  664. package/src/langium/serialization/json-serializer.ts +14 -3
  665. package/src/langium/serialization/serializer.ts +1 -1
  666. package/src/langium/serialization/yaml-serializer.ts +26 -4
  667. package/src/langium/service-registry.ts +41 -2
  668. package/src/langium/shared-services.ts +16 -7
  669. package/src/langium/single-langium-copy.ts +42 -0
  670. package/src/langium/transfer/transfer-encoder.ts +104 -47
  671. package/src/langium/trivia/comment-preserver.ts +1409 -0
  672. package/src/langium/trivia/document-ending-preserver.ts +71 -0
  673. package/src/langium/trivia/index.ts +14 -0
  674. package/src/langium/trivia/trivia-contribution.ts +39 -0
  675. package/src/langium/trivia/trivia-preserver.ts +56 -0
  676. package/src/langium/trivia/trivia-service.ts +99 -0
  677. package/src/langium/update-rewrite/update-rewrite-service.ts +1 -1
  678. package/src/langium/update-rewrite/update-rewrite.ts +1 -1
  679. package/src/langium/validation/document-validator.ts +312 -31
  680. package/src/langium/validation/validation-contribution-collector.ts +10 -1
  681. package/src/langium/workspace/document-uri-policy.ts +32 -18
  682. package/src/langium/workspace/file-not-found.ts +35 -0
  683. package/src/langium/workspace/file-system-provider.ts +258 -16
  684. package/src/langium/workspace/hydranium-langium-document-factory.ts +83 -0
  685. package/src/langium/workspace/hydranium-workspace-lock.ts +86 -2
  686. package/src/langium/workspace/hydranium-workspace-manager.ts +212 -35
  687. package/src/langium/workspace/in-memory-file-system-provider.ts +54 -23
  688. package/src/langium/workspace/index.ts +1 -0
  689. package/src/langium/workspace/initialize-workspace.ts +96 -4
  690. package/src/langium/workspace/langium-documents.ts +19 -1
  691. package/src/langium/workspace/persistent-file-system-provider.ts +27 -15
  692. package/src/langium/workspace/self-save-registry.ts +118 -0
  693. package/src/langium/workspace/virtual-document.ts +106 -25
  694. package/src/langium/workspace/write-lock-scope.ts +27 -12
  695. package/src/launcher/integrated-server.ts +3 -1
  696. package/src/locale/server-locale.ts +20 -5
  697. package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
  698. package/src/lsp/connection-features.ts +67 -0
  699. package/src/lsp/diagnostics-connection.ts +56 -0
  700. package/src/lsp/edit-requests-guard.ts +152 -0
  701. package/src/lsp/hydranium-document-update-handler.ts +285 -111
  702. package/src/lsp/index.ts +6 -2
  703. package/src/lsp/lsp-latency.ts +62 -0
  704. package/src/lsp/save-text-document.ts +63 -0
  705. package/src/lsp/semantic-token-provider.ts +146 -8
  706. package/src/lsp/shared-module.ts +4 -8
  707. package/src/lsp/start-language-server.ts +21 -7
  708. package/src/messages/carriers.ts +4 -6
  709. package/src/messages/index.ts +11 -2
  710. package/src/messages/renderer.ts +34 -6
  711. package/src/node/event-loop-monitor.ts +2 -1
  712. package/src/node/heap-ceiling.ts +108 -0
  713. package/src/node/index.ts +5 -1
  714. package/src/node/latency-from-env.ts +1 -1
  715. package/src/node/log-file-sink.ts +6 -2
  716. package/src/node/log-preamble-node.ts +20 -10
  717. package/src/node/measure-memory.ts +5 -4
  718. package/src/node/memory-monitor.ts +10 -10
  719. package/src/node/node-file-system-provider.ts +214 -57
  720. package/src/node/profile-capture.ts +16 -15
  721. package/src/node/profiling-run.ts +30 -8
  722. package/src/node/rename-over-open-readers.ts +94 -0
  723. package/src/node/server-diagnostics.ts +1 -1
  724. package/src/node/server-state-snapshot.ts +5 -5
  725. package/src/node/socket-launcher.ts +78 -14
  726. package/src/node/startup-cpu-profile.ts +94 -0
  727. package/src/node/stdio-launcher.ts +29 -19
  728. package/src/node/validate-workspace.ts +8 -2
  729. package/src/testing/document-uri-policy-conformance.ts +1 -1
  730. package/src/testing/fake-document.ts +2 -1
  731. package/src/testing/index.ts +2 -1
  732. package/src/testing/langium-test-helpers.ts +1 -0
  733. package/src/testing/make-noop-shared-services.ts +6 -6
  734. package/src/testing/make-test-services.ts +93 -41
  735. package/src/testing/make-test-tracer.ts +26 -0
  736. package/src/testing/node/applied-edit-capture.ts +141 -0
  737. package/src/testing/node/index.ts +1 -0
  738. package/src/testing/node/lsp-harness.ts +2 -0
  739. package/src/testing/node/lsp-server-connection.ts +83 -119
  740. package/src/testing/node/scratch-workspace.ts +10 -5
  741. package/src/testing/node/spawned-server.ts +57 -3
  742. package/src/testing/node/unhandled-rejections.ts +31 -0
  743. package/src/testing/parse-semantic-root.ts +1 -1
  744. package/src/testing/playwright/flaky-network-proxy.ts +240 -0
  745. package/src/testing/playwright/index.ts +1 -0
  746. package/src/testing/playwright/server-log-capture.ts +137 -47
  747. package/src/testing/playwright/server-log-fixture.ts +46 -6
  748. package/src/testing/playwright/server-log-region.ts +32 -0
  749. package/src/testing/playwright/server-log-rename-reporter.ts +4 -3
  750. package/src/testing/run-update-pipeline.ts +8 -5
  751. package/src/testing/stub-ast-document-manager.ts +47 -128
  752. package/src/testing/stub-document-builder.ts +138 -18
  753. package/src/testing/stub-hydranium-text-documents.ts +184 -27
  754. package/src/testing/stub-langium-documents.ts +3 -2
  755. package/src/testing/stub-model-service.ts +11 -10
  756. package/src/testing/stub-self-save-registry.ts +1 -1
  757. package/src/testing/stub-service-registry.ts +1 -1
  758. package/src/testing/stub-writable-file-system.ts +3 -2
  759. package/src/util/connection-liveness.ts +80 -15
  760. package/src/util/environment.ts +24 -2
  761. package/lib/documents/language-client-text-shadow.d.ts +0 -101
  762. package/lib/documents/language-client-text-shadow.d.ts.map +0 -1
  763. package/lib/documents/language-client-text-shadow.js +0 -156
  764. package/lib/documents/language-client-text-shadow.js.map +0 -1
  765. package/lib/documents/self-save-registry.d.ts +0 -55
  766. package/lib/documents/self-save-registry.d.ts.map +0 -1
  767. package/lib/documents/self-save-registry.js.map +0 -1
  768. package/lib/lsp/instrument-connection.d.ts +0 -36
  769. package/lib/lsp/instrument-connection.d.ts.map +0 -1
  770. package/lib/lsp/instrument-connection.js +0 -62
  771. package/lib/lsp/instrument-connection.js.map +0 -1
  772. package/lib/node/process-memory.d.ts +0 -66
  773. package/lib/node/process-memory.d.ts.map +0 -1
  774. package/lib/node/process-memory.js +0 -252
  775. package/lib/node/process-memory.js.map +0 -1
  776. package/src/documents/language-client-text-shadow.ts +0 -175
  777. package/src/documents/self-save-registry.ts +0 -81
  778. package/src/lsp/instrument-connection.ts +0 -66
  779. package/src/node/process-memory.ts +0 -299
@@ -8,81 +8,30 @@
8
8
  ********************************************************************************/
9
9
 
10
10
  import {
11
+ type CanonicalUri,
11
12
  type CloseModelArgs,
12
13
  type Tracer,
13
14
  type TransferSavedEvent,
14
15
  type TransferUpdatedEvent,
15
- type OpenModelArgs
16
+ type OpenModelArgs,
17
+ asModelVersion,
18
+ type ModelVersion,
19
+ type TextVersion,
20
+ UNRECORDED_VERSION,
21
+ describeErrorWithStack
16
22
  } from '@hydranium/protocol';
17
- import {
18
- type AstNode,
19
- type DocumentBuilder,
20
- DocumentState,
21
- type FileSystemProvider,
22
- type LangiumDocument,
23
- type LangiumDocuments,
24
- UriUtils
25
- } from '@hydranium/langium';
23
+ import { type AstNode, DocumentState, type LangiumDocument, type LangiumDocuments, URI, UriUtils } from '@hydranium/langium';
26
24
  import { type LogNameOptions } from '../langium/diagnostics/logger.js';
27
-
28
- /**
29
- * File-system provider extension that supports writes. Langium's standard
30
- * {@link FileSystemProvider} is read-only; the manager needs to persist saves,
31
- * so consumers wire in a provider that implements this superset.
32
- *
33
- * Implementations may optionally hold a reference to a
34
- * {@link SelfSaveRegistry} so they can record their own write mtimes and
35
- * help downstream file-watchers suppress echo events for those writes.
36
- * The framework's `DefaultFileSystemProvider` takes the registry as
37
- * a constructor parameter; alternative implementations can either follow
38
- * the same pattern or leave the field unset.
39
- */
40
- export interface WritableFileSystemProvider extends FileSystemProvider {
41
- writeFile(uri: URI, content: string): Promise<void>;
42
- /**
43
- * Last-modified time (ms) of the file at `uri`, or `undefined` if it can't
44
- * be determined (missing file, or a provider with no disk — in-memory /
45
- * browser). Optional: the only consumer is self-save echo suppression
46
- * (`didChangeWatchedFiles`), which simply lets a change through when the
47
- * mtime is unavailable. Distinct from Langium's `stat` (whose
48
- * `FileSystemNode` carries no mtime). Keeping disk access on the provider
49
- * seam is what lets the LSP update handler avoid a direct `node:fs` import.
50
- */
51
- mtimeMs?(uri: URI): Promise<number | undefined>;
52
- /**
53
- * Resolve `uri` to its real on-disk identity (symlinks collapsed, `..`/`.`
54
- * walked, case-folded on case-insensitive filesystems), or `undefined` *iff
55
- * the filesystem knows the path is absent*. The single source of the
56
- * "nothing loadable here" signal `RealpathDocumentUriPolicy` turns into
57
- * the synthetic-placeholder branch of `getOrCreateDocument`.
58
- *
59
- * Contract for implementers:
60
- * - A `file:`-backed provider returns the resolved URI when the file exists,
61
- * and `undefined` when it cannot resolve the path (missing / unreadable).
62
- * - A non-`file:` URI (or any URI the provider cannot stat) passes through
63
- * **unchanged** — it is treated as present, never reported absent.
64
- * - A provider with no disk to check (in-memory / browser / empty) simply
65
- * omits this method; `RealpathDocumentUriPolicy` then degrades to the
66
- * syntactic `DefaultDocumentUriPolicy` behaviour automatically.
67
- *
68
- * Synchronous (a `realpath` is a kernel-cached syscall) and optional — the
69
- * only consumers are the document-identity policy's `canonicalUri`/`loadUri`.
70
- * Keeping the syscall on the provider seam is what lets the policy stay
71
- * browser-neutral (no `node:fs` import).
72
- */
73
- realpath?(uri: URI): URI | undefined;
74
- /** Registry the provider records its own writes against. Optional — providers without watcher integration may omit. */
75
- readonly selfSaveRegistry?: SelfSaveRegistry;
76
- }
25
+ import { type AstDiagnostic } from '../langium/validation/document-validator.js';
26
+ import { type WritableFileSystemProvider } from '../langium/workspace/file-system-provider.js';
27
+ import { ReentrantWriteLockError, isInsideWriteLock } from '../langium/workspace/write-lock-scope.js';
77
28
  import { Disposable } from 'vscode-languageserver';
78
29
  import { TextDocumentIdentifier, type TextDocumentItem } from 'vscode-languageserver-protocol';
79
30
  import { type TextDocument } from 'vscode-languageserver-textdocument';
80
- import { URI } from '@hydranium/langium';
81
31
  import { type ServerSharedServices } from '../langium/module.js';
82
- import { labelPhaseListener } from '../langium/document-builder/index.js';
32
+ import { type HydraniumDocumentBuilder } from '../langium/document-builder/index.js';
83
33
  import { UNKNOWN_CLIENT_ID } from './client-ids.js';
84
34
  import { type HydraniumTextDocuments } from './hydranium-text-documents.js';
85
- import { type SelfSaveRegistry } from './self-save-registry.js';
86
35
  import { type DocumentUriPolicy } from '../langium/workspace/document-uri-policy.js';
87
36
 
88
37
  export interface UpdateInfo {
@@ -91,80 +40,187 @@ export interface UpdateInfo {
91
40
  }
92
41
 
93
42
  /**
94
- * Server-internal document envelope at the AST layer. Emitted by
95
- * {@link AstDocumentManager.onUpdate} / {@link AstDocumentManager.onSave}
96
- * for in-process subscribers (`ModelService`, integrity service, etc.).
43
+ * Server-internal document envelope at the AST layer, which `ModelService`
44
+ * reads and events hand to in-process callers.
97
45
  *
98
- * Carries an AST-typed root (`TAst extends AstNode`) — distinct from
99
- * `TransferDocument<TTransfer extends TransferElement, …>` in
100
- * `@hydranium/protocol`, which carries the wire-transfer shape (no
101
- * `$container` cycles, references as strings). The two are structural
102
- * twins; the type-system distinction is the generic constraint, and the
103
- * conversion seam between them is the framework `TransferEncoder`.
46
+ * `root` is the live AST the build holds, not an encoded copy like
47
+ * `TransferDocument.model`, so mutating it changes the model every reader sees.
104
48
  */
105
- export interface AstDocument<TAst extends AstNode, TDiagnostic> {
49
+ export interface AstDocument<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> {
106
50
  root: TAst;
107
- diagnostics: TDiagnostic[];
51
+ /** Absent until the document is validated, and on any `ModelService` read below `Validated`; `[]` means validated and clean. */
52
+ diagnostics?: TDiagnostic[];
108
53
  uri: string;
109
54
  /**
110
- * Text-document version this snapshot was taken at — read from
111
- * `LangiumDocument.textDocument.version`. Symmetric with
112
- * `TransferDocument.version` on the wire side: in-process callers
113
- * that hold an `AstDocument` and mutate it pass this value back as
114
- * `TransferUpdateArgs.baseVersion` / `TransferSaveArgs.baseVersion` to opt
115
- * into the conflict gate.
55
+ * The version of the text `root` was parsed from (`ModelLedger.versionOf`).
56
+ * A caller that mutates the document sends it back as the `baseVersion` of
57
+ * its session's write, and the conflict gate arms on it.
116
58
  */
117
- version: number;
59
+ version: ModelVersion;
118
60
  }
119
61
 
62
+ /**
63
+ * What a session's write resolves to: the document, and in `written` the
64
+ * version its text took. A `version` past it means the document was built
65
+ * from a later text, which holds another client's edit too.
66
+ */
67
+ export type WrittenAstDocument<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> = AstDocument<TAst, TDiagnostic> & {
68
+ written: { version: TextVersion };
69
+ };
70
+
71
+ /**
72
+ * What a session's save resolves to: the written document, and in
73
+ * `persisted` the version of the text it wrote to the file. That can differ
74
+ * from `version` either way, since writes land between the build and the
75
+ * take.
76
+ */
77
+ export type SavedAstDocument<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> = WrittenAstDocument<
78
+ TAst,
79
+ TDiagnostic
80
+ > & {
81
+ persisted: { version: TextVersion };
82
+ };
83
+
120
84
  export namespace AstDocument {
121
85
  /**
122
- * Construct an {@link AstDocument} envelope. `diagnostics` defaults
123
- * to `[]` so test fixtures and the in-process pre-validated paths
124
- * don't need to repeat the empty array at every call site. Mirrors
125
- * `TransferDocument.create` on the wire side.
86
+ * Construct an {@link AstDocument} envelope, its version marked as coming
87
+ * from a read. `diagnostics` absent means not validated.
126
88
  */
127
- export function create<TAst extends AstNode, TDiagnostic = unknown>(
89
+ export function create<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic>(
128
90
  uri: string,
129
91
  version: number,
130
92
  root: TAst,
131
- diagnostics: TDiagnostic[] = []
93
+ diagnostics?: TDiagnostic[]
132
94
  ): AstDocument<TAst, TDiagnostic> {
133
- return { uri, version, root, diagnostics };
95
+ return { uri, version: asModelVersion(version), root, ...(diagnostics === undefined ? {} : { diagnostics }) };
134
96
  }
97
+ }
98
+
99
+ /** The update event a document's build delivers, typed over the generic event wrapper. */
100
+ export type AstDocumentUpdatedEvent<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> = TransferUpdatedEvent<
101
+ AstDocument<TAst, TDiagnostic>
102
+ >;
103
+
104
+ /** The event a save delivers, typed over the generic event wrapper. */
105
+ export type AstDocumentSavedEvent<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> = TransferSavedEvent<
106
+ AstDocument<TAst, TDiagnostic>
107
+ >;
108
+
109
+ /**
110
+ * Why an update event fired and whose write it echoes, as
111
+ * {@link AstDocumentManager.attributeUpdate} answers for a document. The
112
+ * fields mean what they mean on `TransferUpdatedEvent`.
113
+ */
114
+ export interface UpdateAttribution {
115
+ reason: 'changed' | 'rebuilt';
116
+ sourceClientId: string;
117
+ causedBy: string;
118
+ }
135
119
 
120
+ /** Construction options for {@link AstDocumentManager}. */
121
+ export interface AstDocumentManagerOptions extends LogNameOptions {
136
122
  /**
137
- * Project a {@link LangiumDocument} into its {@link AstDocument}
138
- * envelope — the single place that reads `root` / `diagnostics` /
139
- * `version` / `uri` off a built document. Both the event path
140
- * ({@link AstDocumentManager.onUpdate} / `onSave`) and the read path
141
- * (`ModelService`'s snapshot accessors) go through here so the
142
- * field mapping lives once.
143
- *
144
- * The emitted `uri` is always the document's own `textDocument.uri` — the
145
- * canonical document-identity form (see {@link DocumentUriPolicy}). Events
146
- * carry that identity, not the subscriber's (possibly non-canonical) URI:
147
- * a subscriber already knows the URI it subscribed with, so the useful
148
- * thing to surface is the canonical one every other layer keys by.
123
+ * Skip a queued save of a URI when a newer save of it is queued behind. The
124
+ * newer save took its text later, so disk ends the same with fewer writes.
125
+ * A skipped save announces nothing and takes the newer save's outcome: it
126
+ * resolves when that one lands and rejects with its error when it fails,
127
+ * since disk then holds neither text. Defaults to `false`: every save
128
+ * writes. The framework binds the manager without options, so turning this
129
+ * on means rebinding `AstDocumentManager` with them.
149
130
  */
150
- export function from<TAst extends AstNode, TDiagnostic = unknown>(document: LangiumDocument): AstDocument<TAst, TDiagnostic> {
151
- return create<TAst, TDiagnostic>(
152
- document.textDocument.uri,
153
- document.textDocument.version,
154
- document.parseResult.value as TAst,
155
- (document.diagnostics ?? []) as unknown as TDiagnostic[]
156
- );
157
- }
131
+ readonly coalesceSaves?: boolean;
158
132
  }
159
133
 
160
- /** Update event delivered by {@link AstDocumentManager.onUpdate} — typed alias over the generic event wrapper. */
161
- export type AstDocumentUpdatedEvent<TAst extends AstNode, TDiagnostic> = TransferUpdatedEvent<AstDocument<TAst, TDiagnostic>>;
134
+ /**
135
+ * The document slot the model server and the integrity service talk to:
136
+ * open/close/update/save and the attribution of update events, with the LSP
137
+ * plumbing hidden. Events are `ModelService`'s, which builds them from here.
138
+ *
139
+ * Generic over `<TAst extends AstNode, TDiagnostic>` so each consumer projects
140
+ * its own AST root type and diagnostic shape into the emitted
141
+ * {@link AstDocument} envelopes. A diagnostic shape narrower than
142
+ * `AstDiagnostic` is asserted unchecked; see {@link toAstDocument}.
143
+ *
144
+ * **URI contract.** Every URI-accepting member takes a URI in *any* spelling
145
+ * (canonical, symlinked, `..`/case-divergent) and canonicalizes internally
146
+ * through the {@link DocumentUriPolicy}, so a caller never has to canonicalize
147
+ * first and an implementation may not require it.
148
+ */
149
+ export interface AstDocumentManager<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> {
150
+ open(args: OpenModelArgs): Promise<Disposable>;
151
+ close(args: CloseModelArgs): Promise<void>;
152
+ isOpen(uri: string): boolean;
153
+
154
+ /** Apply `text` as `clientId`'s edit. Resolves to the resulting text-document version. */
155
+ update(uri: string, text: string, clientId: string): Promise<TextVersion>;
156
+ /**
157
+ * Write the document's current text to disk through `FileSystemTaskQueue`.
158
+ * The text is taken when this is called, so saves of one file land in the
159
+ * order they were called.
160
+ *
161
+ * Resolves to the version of the text on disk once it lands: the version
162
+ * taken, or under `coalesceSaves` the version of the newer save that wrote
163
+ * in its place. A caller reporting what it persisted takes it from here,
164
+ * since a version read beside the call names text a coalesced save never
165
+ * wrote.
166
+ */
167
+ save(uri: string, clientId: string): Promise<TextVersion>;
168
+ /**
169
+ * Remove the document's file through `FileSystemTaskQueue`, then the
170
+ * document, in a build that closes every open of it but the editor's.
171
+ * Resolves once that build has run, also when it fails after removing the
172
+ * document; rejects, having changed nothing, when the file cannot be
173
+ * removed.
174
+ *
175
+ * From the call until it settles, {@link isDeleting} answers `true`, which
176
+ * refuses every session's write of the document: one landing before the
177
+ * build would be lost with it, or, as a save, write the file back. Marked
178
+ * before the first await, so checks a caller runs in the same step as the
179
+ * call hold up to the removal. A second delete of the document while one is
180
+ * under way is refused, and so is a delete from inside a holder of the write
181
+ * lock, with `ReentrantWriteLockError`, since its builds take that lock.
182
+ *
183
+ * A change requested before the build starts merges over the deletion, and
184
+ * the document lives on with every open but `clientId`'s, which is closed.
185
+ */
186
+ delete(uri: string, clientId: string): Promise<void>;
187
+ /** Whether a {@link delete} of `uri` is under way. */
188
+ isDeleting(uri: string): boolean;
189
+ /**
190
+ * The client a deletion event for `uri` names: the one whose {@link delete}
191
+ * of it is under way, or the unknown-client id for a file removed outside
192
+ * any, as a file watcher reports one.
193
+ */
194
+ attributeDeletion(uri: string): string;
162
195
 
163
- /** Save event delivered by {@link AstDocumentManager.onSave} — typed alias over the generic event wrapper. */
164
- export type AstDocumentSavedEvent<TAst extends AstNode, TDiagnostic> = TransferSavedEvent<AstDocument<TAst, TDiagnostic>>;
196
+ getDocument(uri: string): LangiumDocument | undefined;
165
197
 
166
- /** Construction options for {@link AstDocumentManager}. */
167
- export type AstDocumentManagerOptions = LogNameOptions;
198
+ /**
199
+ * `document` as the envelope every event and snapshot read hands out, its
200
+ * `version` the one `ModelLedger` recorded for its root.
201
+ *
202
+ * The `uri` is the document's own canonical one, not a subscriber's
203
+ * spelling, so it matches the key every other layer uses. The diagnostics
204
+ * are asserted to be `TDiagnostic` unchecked: a lexer error or another
205
+ * validator's diagnostic satisfies the declared type and not a narrower one.
206
+ */
207
+ toAstDocument(document: LangiumDocument): AstDocument<TAst, TDiagnostic>;
208
+
209
+ /** Client id that authored the document's current version, or `undefined` for a framework-internal build. */
210
+ getAuthor(document: LangiumDocument): string | undefined;
211
+
212
+ /**
213
+ * The reason, source and cause of an update event for `document` emitted
214
+ * now, from a phase listener of the build that carries it. `ModelService`
215
+ * takes its update events' attribution from here, once per document and
216
+ * phase, so every subscriber names the same client for one build. For a
217
+ * document a client opened, while rebuilds validate, the answer changes
218
+ * once its `Validated` listeners have all run: a later event at that
219
+ * version is `'rebuilt'`. `TransferDocumentUpdateReason` names the cases
220
+ * that fall back to the last update.
221
+ */
222
+ attributeUpdate(document: LangiumDocument): UpdateAttribution;
223
+ }
168
224
 
169
225
  /**
170
226
  * Higher-level facade over {@link HydraniumTextDocuments} that speaks the
@@ -174,8 +230,9 @@ export type AstDocumentManagerOptions = LogNameOptions;
174
230
  *
175
231
  * Generic over `<TAst extends AstNode, TDiagnostic>` so each consumer
176
232
  * projects its own AST root type and diagnostic shape into the emitted
177
- * `AstDocument` envelopes. `TDiagnostic` defaults to `unknown`; consumers
178
- * that care about the diagnostic shape name a concrete one.
233
+ * `AstDocument` envelopes. `TDiagnostic` defaults to `AstDiagnostic`; a
234
+ * narrower one is asserted unchecked, as
235
+ * {@link AstDocumentManager.toAstDocument} says.
179
236
  *
180
237
  * **URI contract.** Every URI-accepting method takes a URI in *any* spelling
181
238
  * (canonical, symlinked, `..`/case-divergent) and canonicalizes internally
@@ -186,13 +243,57 @@ export type AstDocumentManagerOptions = LogNameOptions;
186
243
  * resolution (the egress `applyEditToLanguageClient`) stay on
187
244
  * {@link HydraniumTextDocuments}, their owner.
188
245
  */
189
- export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = unknown> {
246
+ export class DefaultAstDocumentManager<
247
+ TAst extends AstNode,
248
+ TDiagnostic extends AstDiagnostic = AstDiagnostic
249
+ > implements AstDocumentManager<TAst, TDiagnostic> {
250
+ /** The last `DocumentBuilder.update`'s URIs; the reason for a document the store does not track. */
190
251
  protected lastUpdate?: UpdateInfo;
252
+ /**
253
+ * Canonical URIs a client has opened since the file was last deleted,
254
+ * whose versions the store keeps. One no client has opened keeps Langium's
255
+ * version `0` through every change of its content, so its version says
256
+ * nothing. Kept past the last close, since the store continues the version
257
+ * sequence on the next open; a delivery can land after that close.
258
+ */
259
+ protected readonly trackedUris = new Set<CanonicalUri>();
260
+ /**
261
+ * Per tracked URI, the version whose `Validated` listeners last all ran,
262
+ * which is the version an update event was delivered for. Dropped on
263
+ * deletion, so a file created again with the same text is changed again.
264
+ */
265
+ protected readonly deliveredVersions = new Map<CanonicalUri, number>();
266
+ /**
267
+ * Whose writes the build under way carries, set when it starts: the author
268
+ * of every open document's undelivered version, and the unknown-client id
269
+ * for a change no write explains, such as a deletion no session's delete
270
+ * made, a document no client has open, or a write that changed nothing.
271
+ * An undelivered version is one whose build has not validated it yet, so a
272
+ * write whose build was cancelled stays a cause of the build that takes
273
+ * over.
274
+ *
275
+ * Errs toward more than one cause, and so toward the unknown client, which
276
+ * a reader treats as foreign: an answer it repeats, never one it misses.
277
+ * A change no write explains counts for its own build only, so a build
278
+ * that takes over from a cancelled one loses it. One field for every build:
279
+ * a build started outside the workspace lock, such as a re-queue of an
280
+ * orphaned document, reads the causes of whichever build started last.
281
+ * An open document no build delivers, one a `shouldValidate` override
282
+ * skips, stays undelivered, so it is a cause of every build while open.
283
+ */
284
+ protected readonly buildCauses = new Set<string>();
285
+
286
+ /** Per canonical URI, the client whose {@link delete} of it is under way. */
287
+ protected readonly deletions = new Map<CanonicalUri, string>();
288
+
289
+ /** Per canonical URI, the newest save queued for it, which {@link coalesceSaves} lets older queued saves defer to. */
290
+ protected readonly newestSaves = new Map<CanonicalUri, Promise<TextVersion>>();
291
+ protected readonly coalesceSaves: boolean;
191
292
 
192
293
  protected readonly textDocuments: HydraniumTextDocuments<TextDocument>;
193
294
  protected readonly fileSystemProvider: WritableFileSystemProvider;
194
295
  protected readonly langiumDocs: LangiumDocuments;
195
- protected readonly documentBuilder: DocumentBuilder;
296
+ protected readonly documentBuilder: HydraniumDocumentBuilder;
196
297
  protected readonly uriPolicy: DocumentUriPolicy;
197
298
  protected readonly tracer: Tracer;
198
299
 
@@ -206,32 +307,42 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
206
307
  this.documentBuilder = services.workspace.DocumentBuilder;
207
308
  this.uriPolicy = services.workspace.DocumentUriPolicy;
208
309
  this.tracer = services.Tracer.for(options.logName ?? 'AstDocumentManager').trace('instantiated');
209
- this.textDocuments.onDidOpen(event =>
210
- this.open({ clientId: event.clientId, uri: event.document.uri, languageId: event.document.languageId })
211
- );
310
+ this.coalesceSaves = options.coalesceSaves ?? false;
311
+ this.textDocuments.onDidOpen(event => {
312
+ this.trackedUris.add(this.uriPolicy.canonicalUri(event.document.uri));
313
+ return this.open({ clientId: event.clientId, uri: event.document.uri, languageId: event.document.languageId });
314
+ });
212
315
  this.textDocuments.onDidClose(event => this.close({ clientId: event.clientId, uri: event.document.uri }));
213
316
  this.documentBuilder.onUpdate((changed, deleted) => {
214
317
  this.lastUpdate = { changed, deleted };
215
- });
216
- // Content transitions for CLOSED documents bypass the text store: the
217
- // last-close revert and watched-file changes rebuild from disk into a
218
- // factory-fresh text document carrying the factory's own version. At the
219
- // Parsed transition (the earliest phase with text, and one only re-read
220
- // documents pass through — cascade relinks re-enter later), reconcile the
221
- // store's persisted version sequence with the rebuilt content and
222
- // re-stamp the document so every downstream envelope (revert broadcast,
223
- // snapshot reads) carries the continued sequence. An empty-changes
224
- // update only re-stamps the version. Previously-untracked URIs exit on a
225
- // map lookup, so workspace-wide builds don't hash untouched documents.
226
- this.documentBuilder.onDocumentPhase(
227
- DocumentState.Parsed,
228
- labelPhaseListener(document => {
229
- const sequenceVersion = this.textDocuments.reconcileExternalContent(document.textDocument.uri, document.textDocument.getText());
230
- if (sequenceVersion !== undefined && document.textDocument.version !== sequenceVersion) {
231
- this.textDocuments.update(document.textDocument, [], sequenceVersion);
318
+ this.buildCauses.clear();
319
+ for (const textDocument of this.textDocuments.all()) {
320
+ if (!this.isDelivered(textDocument.uri, textDocument.version)) {
321
+ this.buildCauses.add(this.textDocuments.getAuthor(textDocument.uri, textDocument.version) ?? UNKNOWN_CLIENT_ID);
232
322
  }
233
- }, 'AstDocumentManager.reconcileExternalContent')
234
- );
323
+ }
324
+ const unexplained = changed.some(uri => {
325
+ const textDocument = this.textDocuments.get(uri.toString());
326
+ return textDocument === undefined || this.isDelivered(textDocument.uri, textDocument.version);
327
+ });
328
+ if (unexplained) {
329
+ this.buildCauses.add(UNKNOWN_CLIENT_ID);
330
+ }
331
+ deleted.forEach(uri => this.buildCauses.add(this.attributeDeletion(uri.toString())));
332
+ // The only place a deletion is observable: `DocumentBuilder.update`
333
+ // removes a deleted document before it builds anything, so no phase
334
+ // listener ever sees it.
335
+ for (const uri of deleted) {
336
+ const key = this.uriPolicy.canonicalUri(uri.toString());
337
+ this.trackedUris.delete(key);
338
+ this.deliveredVersions.delete(key);
339
+ this.textDocuments.notifyDocumentDeleted(uri.toString());
340
+ }
341
+ });
342
+ // Once every listener ran, not in a listener of its own: listeners after
343
+ // it could still be skipped by a cancel, and the next build would then
344
+ // report as rebuilt a version they never delivered.
345
+ this.documentBuilder.onDocumentPhaseDelivered(DocumentState.Validated, (document, version) => this.markDelivered(document, version));
235
346
  }
236
347
 
237
348
  /**
@@ -263,86 +374,87 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
263
374
  }
264
375
 
265
376
  /**
266
- * Subscribe to the save event of the document at `uri`. The callback fires only when the
267
- * URI of the saved document matches `uri` (compared by canonical form).
377
+ * The client that authored `document`'s current version, or `undefined` when
378
+ * no client wrote it: a document no client has open. A rebuild that keeps
379
+ * the version keeps its author, so this does not say who caused a build;
380
+ * {@link attributeUpdate} does.
381
+ * Honest about absence so a routing consumer tests `undefined` directly
382
+ * rather than against a sentinel; the presentation default
383
+ * ({@link UNKNOWN_CLIENT_ID}) is applied where an event needs a value.
268
384
  */
269
- onSave(uri: string, listener: (event: TransferSavedEvent<AstDocument<TAst, TDiagnostic>>) => void | Promise<void>): Disposable {
270
- const target = this.uriPolicy.canonicalUri(uri);
271
- return this.textDocuments.onDidSave(async event => {
272
- if (this.uriPolicy.canonicalUri(event.document.uri) !== target) {
273
- return undefined;
274
- }
275
- // Look the document up by its canonical URI: the adopter's
276
- // `LangiumDocuments` keys by the canonical form, while the saved
277
- // event carries the (possibly symlinked) client-facing URI.
278
- const documentURI = UriUtils.toUri(target);
279
- if (documentURI !== undefined && this.langiumDocs.hasDocument(documentURI)) {
280
- const document = await this.langiumDocs.getOrCreateDocument(documentURI);
281
- return listener({
282
- document: this.toAstDocument(document),
283
- sourceClientId: event.clientId
284
- });
285
- }
286
- return undefined;
287
- });
385
+ getAuthor(document: LangiumDocument): string | undefined {
386
+ return this.textDocuments.getAuthor(document.textDocument.uri, document.textDocument.version);
288
387
  }
289
388
 
290
- /** Fires when `clientId` detaches from the document at `uri` (matched by canonical form). */
291
- onClientClosed(uri: string, clientId: string, listener: () => void): Disposable {
292
- const target = this.uriPolicy.canonicalUri(uri);
293
- return this.textDocuments.onDidClose(event => {
294
- if (event.clientId === clientId && this.uriPolicy.canonicalUri(event.document.uri) === target) {
295
- listener();
296
- }
297
- });
389
+ /**
390
+ * `'changed'` for the first delivery of the document's version, crediting
391
+ * its author; `'rebuilt'` for a later one, crediting nobody, since it echoes
392
+ * no write, and naming the build's single cause if it has one.
393
+ *
394
+ * A document the rule does not apply to (see {@link isTracked}) falls back
395
+ * to the last update: it is `'changed'` when its URI was passed to
396
+ * `DocumentBuilder.update`. An open document that a validating build skips,
397
+ * through a `shouldValidate` override, is never delivered, so each of its
398
+ * events is its author's change.
399
+ */
400
+ attributeUpdate(document: LangiumDocument): UpdateAttribution {
401
+ const key = this.uriPolicy.canonicalUri(document.uri.toString());
402
+ const changed = this.isTracked(key)
403
+ ? this.deliveredVersions.get(key) !== document.textDocument.version
404
+ : this.lastUpdate?.changed.some(uri => UriUtils.equals(uri, document.uri)) === true;
405
+ if (changed) {
406
+ // Presentation boundary: the event field is a concrete `string`, so an
407
+ // unauthored document surfaces the readable default rather than
408
+ // `undefined` to subscribers and logs.
409
+ const author = this.getAuthor(document) ?? UNKNOWN_CLIENT_ID;
410
+ return { reason: 'changed', sourceClientId: author, causedBy: author };
411
+ }
412
+ const [cause] = this.buildCauses;
413
+ return { reason: 'rebuilt', sourceClientId: UNKNOWN_CLIENT_ID, causedBy: this.buildCauses.size === 1 ? cause : UNKNOWN_CLIENT_ID };
298
414
  }
299
415
 
300
- /** Fires when the document at `uri` reaches `Validated` after each rebuild. */
301
- onUpdate(uri: string, listener: (event: TransferUpdatedEvent<AstDocument<TAst, TDiagnostic>>) => void): Disposable {
302
- const target = this.uriPolicy.canonicalUri(uri);
303
- const emitUpdate = (document: LangiumDocument): void => {
304
- if (this.uriPolicy.canonicalUri(document.uri) !== target) {
305
- return;
306
- }
307
- // Presentation boundary: the event field is a concrete `string`, so an
308
- // unauthored (framework-rebuilt) document surfaces the readable default
309
- // rather than `undefined` to subscribers and logs.
310
- const sourceClientId = this.getAuthor(document) ?? UNKNOWN_CLIENT_ID;
311
- const event: TransferUpdatedEvent<AstDocument<TAst, TDiagnostic>> = {
312
- document: this.toAstDocument(document),
313
- sourceClientId,
314
- reason: this.lastUpdate?.changed.find(changed => UriUtils.equals(changed, document.uri))
315
- ? 'changed'
316
- : this.lastUpdate?.deleted.find(deleted => UriUtils.equals(deleted, document.uri))
317
- ? 'deleted'
318
- : 'rebuilt'
319
- };
320
- this.tracer.with(uri).trace(`emitUpdate start: source=${sourceClientId}, reason=${event.reason}`);
321
- listener(event);
322
- this.tracer.with(uri).trace('emitUpdate listener returned');
323
- };
324
- return this.documentBuilder.onDocumentPhase(DocumentState.Validated, labelPhaseListener(emitUpdate, 'AstDocumentManager.onUpdate'));
416
+ /**
417
+ * Whether the version rule applies to `uri`: the store keeps its version,
418
+ * and rebuilds validate. With `updateBuildOptions.validation` off no version
419
+ * is ever delivered, and the rule would report every event of an open
420
+ * document as its author's change.
421
+ */
422
+ protected isTracked(uri: CanonicalUri): boolean {
423
+ return this.keepsVersion(uri) && Boolean(this.documentBuilder.updateBuildOptions.validation);
325
424
  }
326
425
 
327
426
  /**
328
- * The client that authored `document`'s current version, or `undefined` when
329
- * no client wrote it — a framework-internal rebuild (workspace startup, a
330
- * cascade relink, a `didClose`-reload) or a genuine author gap. Honest about
331
- * absence so routing consumers (`ModelService.isNonLanguageClientEdit`)
332
- * test `undefined` directly rather than against a sentinel; the presentation
333
- * default ({@link UNKNOWN_CLIENT_ID}) is applied at the boundary that needs a
334
- * concrete value (the `onUpdate` event's `sourceClientId`, the data-server's
335
- * `resolveSourceClientId`).
427
+ * Whether the store keeps `uri`'s version: a client opened it since its
428
+ * file was last deleted, or has it open still, as an editor keeps a
429
+ * deleted file's buffer.
336
430
  */
337
- getAuthor(document: LangiumDocument<AstNode>): string | undefined {
338
- return this.textDocuments.getAuthor(document.textDocument.uri, document.textDocument.version);
431
+ protected keepsVersion(uri: CanonicalUri): boolean {
432
+ return this.trackedUris.has(uri) || this.textDocuments.isOpen(uri);
433
+ }
434
+
435
+ /**
436
+ * Record that `version` of `document` was delivered, when the store tracks
437
+ * it. The version the listeners saw, not the document's current one: a
438
+ * write during them has moved that on, and marking it would report the
439
+ * write's own build as rebuilt.
440
+ */
441
+ protected markDelivered(document: LangiumDocument, version: number): void {
442
+ const key = this.uriPolicy.canonicalUri(document.uri.toString());
443
+ if (this.keepsVersion(key)) {
444
+ this.deliveredVersions.set(key, version);
445
+ }
446
+ }
447
+
448
+ /** Whether `version` of `uri` was delivered. */
449
+ protected isDelivered(uri: string, version: number): boolean {
450
+ return this.deliveredVersions.get(this.uriPolicy.canonicalUri(uri)) === version;
339
451
  }
340
452
 
341
453
  async open(args: OpenModelArgs): Promise<Disposable> {
342
454
  // `open()` is the RPC-level "ensure this document is loaded" call. It is issued
343
- // by a view attaching, but also internally by `update()` / `save()` and by every
344
- // additional client attaching to the same URI, including the several sub-editors
345
- // a composite view opens. When the document is already loaded there is nothing to
455
+ // by a session opening the document, including by every additional client
456
+ // attaching to the same URI and the several sub-editors a composite view
457
+ // opens. When the document is already loaded there is nothing to
346
458
  // do here but hand back the close-disposable — callers that want the current
347
459
  // state read it from this method's surrounding RPC response, not from a re-build.
348
460
  //
@@ -355,10 +467,36 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
355
467
  // transiently breaks cross-document linking mid-rebuild (a dependent briefly
356
468
  // seeing an `extends`/`type` reference unresolved). And because the constructor
357
469
  // wires `onDidOpen -> this.open`, it would fire a second, identical rebuild on
358
- // every first open. So an already-open `open()` is a no-op.
470
+ // every first open.
471
+ //
472
+ // So an already-open `open()` records the attaching client's open and nothing
473
+ // else. The open is per `(uri, clientId)` and the store releases the document
474
+ // only once none is left, so skipping it lets the first client's close tear down a document
475
+ // another client is still reading. A document waiting out the release grace
476
+ // is still loaded: a client lost from it within its own grace attaches and
477
+ // keeps its text, and for any other client the attach releases it, so the
478
+ // open reads the file.
479
+ if (this.isOpen(args.uri)) {
480
+ this.textDocuments.attachClient(args.uri, args.clientId);
481
+ }
359
482
  if (!this.isOpen(args.uri)) {
360
483
  const textDocument = await this.createDocumentFromTextOrFileSystem(args.uri, args.languageId, args.version, args.text);
484
+ const creates = !this.isOpen(args.uri);
361
485
  this.textDocuments.notifyDidOpenTextDocument({ textDocument }, args.clientId);
486
+ if (creates && args.text !== undefined) {
487
+ // Text the caller supplies was not read from the file, so no file
488
+ // is assumed: the document is dirty until its first save, whatever
489
+ // the file holds.
490
+ this.textDocuments.markCreated(args.uri);
491
+ }
492
+ const built = this.getDocument(args.uri);
493
+ if (creates && built) {
494
+ // Without an LSP head nothing else builds the opened text. Nothing
495
+ // waits on the build either, so its failure ends here.
496
+ this.services.workspace.VersionSyncService.syncTo(built.uri, this.textDocuments.version(args.uri))?.catch((error: unknown) =>
497
+ this.tracer.with(args.uri).error(`The build of the opened text failed. ${describeErrorWithStack(error)}`)
498
+ );
499
+ }
362
500
  }
363
501
  return Disposable.create(() => this.close(args));
364
502
  }
@@ -378,7 +516,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
378
516
  * correlate the change against subsequent build events can. Throws if the
379
517
  * document isn't open.
380
518
  */
381
- async update(uri: string, text: string, clientId: string): Promise<number> {
519
+ async update(uri: string, text: string, clientId: string): Promise<TextVersion> {
382
520
  if (!this.isOpen(uri)) {
383
521
  throw new Error(`Document ${uri} hasn't been opened for updating yet`);
384
522
  }
@@ -393,31 +531,128 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
393
531
  * callers don't need to pass it — the manager owns content and version
394
532
  * sequencing.
395
533
  *
534
+ * The text is taken synchronously, before the save waits in the file's task
535
+ * queue; the compare and the write run in the queue. Taken later, a save
536
+ * that waits behind another writes whatever the store holds when its turn
537
+ * comes, edits made after the call included, and announces that text under
538
+ * its own client id.
539
+ *
540
+ * **The write is skipped when the file already holds that text; the
541
+ * notification is not.** A save announces that the content is on disk, which
542
+ * is true either way — so a subscriber clearing a dirty marker or reacting to
543
+ * a persist behaves the same, while an mtime is not moved for byte-identical
544
+ * content that a downstream mtime-keyed build would then read as new work.
545
+ *
396
546
  * Throws if no document is open for `uri`.
397
547
  */
398
- async save(uri: string, clientId: string): Promise<void> {
399
- const document = this.textDocuments.get(uri);
548
+ async save(uri: string, clientId: string): Promise<TextVersion> {
549
+ // Canonical throughout: the write and the read that gates it must address
550
+ // the same file the store was keyed by, or a divergent spelling compares
551
+ // one file and writes another.
552
+ const canonical = this.uriPolicy.canonicalUri(uri);
553
+ const document = this.textDocuments.get(canonical);
400
554
  if (!document) {
401
555
  throw new Error(`Document ${uri} hasn't been opened for saving yet`);
402
556
  }
403
557
  const text = document.getText();
404
- await this.tracer.with(uri).time(
405
- `Write file (${text.length} bytes, from ${clientId})`,
406
- // Async write so a slow disk does not block the event loop for the duration of the fs call.
407
- () => this.fileSystemProvider.writeFile(UriUtils.toUri(uri), text),
408
- 'debug'
409
- );
558
+ const version = document.version;
559
+ let supersededBy: Promise<TextVersion> | undefined;
560
+ const saved: Promise<TextVersion> = this.services.workspace.FileSystemTaskQueue.enqueue(canonical, async () => {
561
+ const newest = this.newestSaves.get(canonical);
562
+ if (this.coalesceSaves && newest !== saved) {
563
+ supersededBy = newest;
564
+ return;
565
+ }
566
+ await this.writeSave(canonical, text, clientId);
567
+ })
568
+ .then(() => supersededBy ?? version)
569
+ .finally(() => {
570
+ if (this.newestSaves.get(canonical) === saved) {
571
+ this.newestSaves.delete(canonical);
572
+ }
573
+ });
574
+ this.newestSaves.set(canonical, saved);
575
+ return saved;
576
+ }
577
+
578
+ async delete(uri: string, clientId: string): Promise<void> {
579
+ const canonical = this.uriPolicy.canonicalUri(uri);
580
+ const target = UriUtils.toUri(canonical);
581
+ // The builds below wait for a holder of the write lock, which would be
582
+ // waiting for this delete.
583
+ if (isInsideWriteLock()) {
584
+ throw new ReentrantWriteLockError(canonical);
585
+ }
586
+ // The mark holds one client: a second delete would share it, and the
587
+ // first to settle would clear it under the other.
588
+ if (this.deletions.has(canonical)) {
589
+ throw new Error(`Cannot delete ${uri}: a delete of it is under way`);
590
+ }
591
+ this.deletions.set(canonical, clientId);
592
+ try {
593
+ // A document no build has reached yet is not registered, and the
594
+ // deletion build would remove nothing and leave every open of it.
595
+ if (!this.langiumDocs.getDocument(target)) {
596
+ await this.documentBuilder.scheduleUpdate([target], []);
597
+ }
598
+ await this.services.workspace.FileSystemTaskQueue.enqueue(canonical, () => this.fileSystemProvider.deleteFile(target));
599
+ // Langium removes the document before the build's first await, so a
600
+ // failure is the dependents' build, and reaches no one else.
601
+ await this.documentBuilder
602
+ .scheduleUpdate([], [target])
603
+ .catch((error: unknown) =>
604
+ this.tracer.with(canonical).error(`The build after a deletion failed. ${describeErrorWithStack(error)}`)
605
+ );
606
+ // A change requested before that build started merges over the
607
+ // deletion, and the document lives on; the deleting client takes it as
608
+ // gone, so its open ends here.
609
+ if (this.textDocuments.isOpenInClient(canonical, clientId)) {
610
+ await this.close({ uri: canonical, clientId });
611
+ }
612
+ } finally {
613
+ this.deletions.delete(canonical);
614
+ }
615
+ }
616
+
617
+ isDeleting(uri: string): boolean {
618
+ return this.deletions.has(this.uriPolicy.canonicalUri(uri));
619
+ }
620
+
621
+ attributeDeletion(uri: string): string {
622
+ return this.deletions.get(this.uriPolicy.canonicalUri(uri)) ?? UNKNOWN_CLIENT_ID;
623
+ }
624
+
625
+ /** Write `text` to `uri` unless the file already holds it, then announce the save. Runs inside the file's task queue. */
626
+ protected async writeSave(uri: CanonicalUri, text: string, clientId: string): Promise<void> {
627
+ if (!(await this.matchesDisk(uri, text))) {
628
+ await this.tracer.with(uri).time(
629
+ `Write file (${text.length} bytes, from ${clientId})`,
630
+ // Async write so a slow disk does not block the event loop for the duration of the fs call.
631
+ () => this.fileSystemProvider.writeFile(UriUtils.toUri(uri), text),
632
+ 'debug'
633
+ );
634
+ }
410
635
  this.textDocuments.notifyDidSaveTextDocument({ textDocument: TextDocumentIdentifier.create(uri), text }, clientId);
411
636
  }
412
637
 
413
- isOpen(uri: string): boolean {
414
- return !!this.textDocuments.get(uri);
638
+ /**
639
+ * Whether the file at `uri` already holds `text`.
640
+ *
641
+ * Compared by CONTENT rather than against a remembered version, so a write
642
+ * from outside this server is still corrected: a version this manager already
643
+ * saved says nothing about what is on disk now. `false` when the file cannot
644
+ * be read at all, which is the answer that writes — a document whose file does
645
+ * not exist yet is exactly the one a first save has to create.
646
+ */
647
+ protected async matchesDisk(uri: string, text: string): Promise<boolean> {
648
+ return this.fileSystemProvider
649
+ .readFile(UriUtils.toUri(uri))
650
+ .then(onDisk => onDisk === text)
651
+ .catch(() => false);
415
652
  }
416
653
 
417
- /** True if the URI was in the directly-changed set of the most recent build (not just affected). */
418
- isDirectChange(uri: string): boolean {
419
- const canonical = this.uriPolicy.canonicalUri(uri);
420
- return this.lastUpdate?.changed.some(changed => this.uriPolicy.canonicalUri(changed) === canonical) ?? false;
654
+ isOpen(uri: string): boolean {
655
+ return !!this.textDocuments.get(uri);
421
656
  }
422
657
 
423
658
  /**
@@ -437,19 +672,30 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
437
672
  version = 0,
438
673
  text?: string
439
674
  ): Promise<TextDocumentItem> {
440
- return { uri, languageId, version, text: text ?? (await this.readFile(uri)) };
441
- }
442
-
443
- async readFile(uri: string): Promise<string> {
444
- return this.fileSystemProvider.readFile(UriUtils.toUri(uri));
675
+ // Read in the file's task queue: a read beside a queued save of the file
676
+ // returns the text from before it, and the document then opens on that.
677
+ return {
678
+ uri,
679
+ languageId,
680
+ version,
681
+ text:
682
+ text ??
683
+ (await this.services.workspace.FileSystemTaskQueue.enqueue(uri, () => this.fileSystemProvider.readFile(UriUtils.toUri(uri))))
684
+ };
445
685
  }
446
686
 
447
687
  /**
448
- * Hook for subclasses that want to re-shape the emitted document (e.g. inject
449
- * a custom-typed `diagnostics` field). The default delegates to
450
- * {@link AstDocument.from}, the shared LangiumDocument→envelope projection.
688
+ * Events and the model service's snapshot reads both come through here, so
689
+ * an override that re-shapes the document re-shapes both.
451
690
  */
452
- protected toAstDocument(document: LangiumDocument): AstDocument<TAst, TDiagnostic> {
453
- return AstDocument.from<TAst, TDiagnostic>(document);
691
+ toAstDocument(document: LangiumDocument): AstDocument<TAst, TDiagnostic> {
692
+ const uri = document.textDocument.uri;
693
+ const root = document.parseResult.value as TAst;
694
+ const ledger = this.services.workspace.ModelLedger;
695
+ const version = ledger.versionOf(root);
696
+ if (version === UNRECORDED_VERSION && !ledger.isPlaceholder(root)) {
697
+ this.tracer.with(uri).warn('No model version recorded for the root: it was built outside the document factory');
698
+ }
699
+ return AstDocument.create<TAst, TDiagnostic>(uri, version, root, document.diagnostics as TDiagnostic[] | undefined);
454
700
  }
455
701
  }