@hydranium/core 1.0.0-next.11 → 1.0.0-next.112

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 (424) hide show
  1. package/lib/documents/ast-document-manager.d.ts +75 -16
  2. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  3. package/lib/documents/ast-document-manager.js +57 -19
  4. package/lib/documents/ast-document-manager.js.map +1 -1
  5. package/lib/documents/client-ids.d.ts +5 -19
  6. package/lib/documents/client-ids.d.ts.map +1 -1
  7. package/lib/documents/client-ids.js +5 -19
  8. package/lib/documents/client-ids.js.map +1 -1
  9. package/lib/documents/hydranium-text-documents.d.ts +132 -42
  10. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  11. package/lib/documents/hydranium-text-documents.js +199 -57
  12. package/lib/documents/hydranium-text-documents.js.map +1 -1
  13. package/lib/documents/language-client-text-shadow.d.ts +41 -9
  14. package/lib/documents/language-client-text-shadow.d.ts.map +1 -1
  15. package/lib/documents/language-client-text-shadow.js +56 -11
  16. package/lib/documents/language-client-text-shadow.js.map +1 -1
  17. package/lib/documents/self-save-registry.d.ts +37 -6
  18. package/lib/documents/self-save-registry.d.ts.map +1 -1
  19. package/lib/documents/self-save-registry.js +28 -15
  20. package/lib/documents/self-save-registry.js.map +1 -1
  21. package/lib/index.d.ts +3 -0
  22. package/lib/index.d.ts.map +1 -1
  23. package/lib/index.js +6 -0
  24. package/lib/index.js.map +1 -1
  25. package/lib/langium/ast-extension/ast-node-builder.d.ts +32 -9
  26. package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
  27. package/lib/langium/ast-extension/ast-node-builder.js +60 -22
  28. package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
  29. package/lib/langium/bootstrap.d.ts.map +1 -1
  30. package/lib/langium/bootstrap.js +16 -9
  31. package/lib/langium/bootstrap.js.map +1 -1
  32. package/lib/langium/config/configuration-provider.d.ts +81 -0
  33. package/lib/langium/config/configuration-provider.d.ts.map +1 -0
  34. package/lib/langium/config/configuration-provider.js +112 -0
  35. package/lib/langium/config/configuration-provider.js.map +1 -0
  36. package/lib/langium/config/index.d.ts +1 -0
  37. package/lib/langium/config/index.d.ts.map +1 -1
  38. package/lib/langium/config/index.js +1 -0
  39. package/lib/langium/config/index.js.map +1 -1
  40. package/lib/langium/diagnostics/lsp-logger.d.ts +17 -0
  41. package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
  42. package/lib/langium/diagnostics/lsp-logger.js +40 -6
  43. package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
  44. package/lib/langium/document-builder/build-pipeline-integration.d.ts +21 -1
  45. package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
  46. package/lib/langium/document-builder/build-pipeline-integration.js +32 -5
  47. package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
  48. package/lib/langium/document-builder/build-session.d.ts +93 -0
  49. package/lib/langium/document-builder/build-session.d.ts.map +1 -0
  50. package/lib/langium/document-builder/build-session.js +72 -0
  51. package/lib/langium/document-builder/build-session.js.map +1 -0
  52. package/lib/langium/document-builder/document-builder.d.ts +150 -7
  53. package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
  54. package/lib/langium/document-builder/document-builder.js +298 -11
  55. package/lib/langium/document-builder/document-builder.js.map +1 -1
  56. package/lib/langium/document-builder/index.d.ts +1 -0
  57. package/lib/langium/document-builder/index.d.ts.map +1 -1
  58. package/lib/langium/document-builder/index.js +1 -0
  59. package/lib/langium/document-builder/index.js.map +1 -1
  60. package/lib/langium/integration-services.d.ts +45 -1
  61. package/lib/langium/integration-services.d.ts.map +1 -1
  62. package/lib/langium/integration-services.js +10 -5
  63. package/lib/langium/integration-services.js.map +1 -1
  64. package/lib/langium/integrity/integrity-service.d.ts +16 -0
  65. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  66. package/lib/langium/integrity/integrity-service.js +110 -2
  67. package/lib/langium/integrity/integrity-service.js.map +1 -1
  68. package/lib/langium/keys/containment.d.ts +64 -0
  69. package/lib/langium/keys/containment.d.ts.map +1 -0
  70. package/lib/langium/keys/containment.js +53 -0
  71. package/lib/langium/keys/containment.js.map +1 -0
  72. package/lib/langium/keys/index.d.ts +1 -0
  73. package/lib/langium/keys/index.d.ts.map +1 -1
  74. package/lib/langium/keys/index.js +1 -0
  75. package/lib/langium/keys/index.js.map +1 -1
  76. package/lib/langium/keys/name-based-key-provider.d.ts +4 -0
  77. package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
  78. package/lib/langium/keys/name-based-key-provider.js +4 -0
  79. package/lib/langium/keys/name-based-key-provider.js.map +1 -1
  80. package/lib/langium/language-module.d.ts +25 -0
  81. package/lib/langium/language-module.d.ts.map +1 -1
  82. package/lib/langium/language-module.js +14 -0
  83. package/lib/langium/language-module.js.map +1 -1
  84. package/lib/langium/model-service/model-service.d.ts +161 -10
  85. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  86. package/lib/langium/model-service/model-service.js +176 -97
  87. package/lib/langium/model-service/model-service.js.map +1 -1
  88. package/lib/langium/module.d.ts +84 -15
  89. package/lib/langium/module.d.ts.map +1 -1
  90. package/lib/langium/module.js +26 -12
  91. package/lib/langium/module.js.map +1 -1
  92. package/lib/langium/naming/name-provider.d.ts +25 -4
  93. package/lib/langium/naming/name-provider.d.ts.map +1 -1
  94. package/lib/langium/naming/name-provider.js +2 -1
  95. package/lib/langium/naming/name-provider.js.map +1 -1
  96. package/lib/langium/naming/name-separator-validation.d.ts +23 -0
  97. package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
  98. package/lib/langium/naming/name-separator-validation.js +30 -1
  99. package/lib/langium/naming/name-separator-validation.js.map +1 -1
  100. package/lib/langium/residency/cst-residency-service.d.ts +31 -11
  101. package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
  102. package/lib/langium/residency/cst-residency-service.js +13 -56
  103. package/lib/langium/residency/cst-residency-service.js.map +1 -1
  104. package/lib/langium/scope/hydranium-scope-provider.d.ts +48 -13
  105. package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
  106. package/lib/langium/scope/hydranium-scope-provider.js +56 -20
  107. package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
  108. package/lib/langium/serialization/abstract-serializer.d.ts +11 -20
  109. package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
  110. package/lib/langium/serialization/abstract-serializer.js +12 -21
  111. package/lib/langium/serialization/abstract-serializer.js.map +1 -1
  112. package/lib/langium/service-registry.d.ts +15 -1
  113. package/lib/langium/service-registry.d.ts.map +1 -1
  114. package/lib/langium/service-registry.js +16 -0
  115. package/lib/langium/service-registry.js.map +1 -1
  116. package/lib/langium/shared-services.d.ts +15 -2
  117. package/lib/langium/shared-services.d.ts.map +1 -1
  118. package/lib/langium/shared-services.js.map +1 -1
  119. package/lib/langium/transfer/transfer-encoder.d.ts +60 -17
  120. package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
  121. package/lib/langium/transfer/transfer-encoder.js +38 -16
  122. package/lib/langium/transfer/transfer-encoder.js.map +1 -1
  123. package/lib/langium/trivia/comment-preserver.d.ts +423 -0
  124. package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
  125. package/lib/langium/trivia/comment-preserver.js +906 -0
  126. package/lib/langium/trivia/comment-preserver.js.map +1 -0
  127. package/lib/langium/trivia/document-ending-preserver.d.ts +43 -0
  128. package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
  129. package/lib/langium/trivia/document-ending-preserver.js +48 -0
  130. package/lib/langium/trivia/document-ending-preserver.js.map +1 -0
  131. package/lib/langium/trivia/index.d.ts +14 -0
  132. package/lib/langium/trivia/index.d.ts.map +1 -0
  133. package/lib/langium/trivia/index.js +14 -0
  134. package/lib/langium/trivia/index.js.map +1 -0
  135. package/lib/langium/trivia/trivia-contribution.d.ts +37 -0
  136. package/lib/langium/trivia/trivia-contribution.d.ts.map +1 -0
  137. package/lib/langium/trivia/trivia-contribution.js +10 -0
  138. package/lib/langium/trivia/trivia-contribution.js.map +1 -0
  139. package/lib/langium/trivia/trivia-preserver.d.ts +50 -0
  140. package/lib/langium/trivia/trivia-preserver.d.ts.map +1 -0
  141. package/lib/langium/trivia/trivia-preserver.js +10 -0
  142. package/lib/langium/trivia/trivia-preserver.js.map +1 -0
  143. package/lib/langium/trivia/trivia-service.d.ts +70 -0
  144. package/lib/langium/trivia/trivia-service.d.ts.map +1 -0
  145. package/lib/langium/trivia/trivia-service.js +56 -0
  146. package/lib/langium/trivia/trivia-service.js.map +1 -0
  147. package/lib/langium/validation/document-validator.d.ts +294 -10
  148. package/lib/langium/validation/document-validator.d.ts.map +1 -1
  149. package/lib/langium/validation/document-validator.js +448 -5
  150. package/lib/langium/validation/document-validator.js.map +1 -1
  151. package/lib/langium/workspace/document-uri-policy.d.ts +3 -4
  152. package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
  153. package/lib/langium/workspace/document-uri-policy.js +3 -4
  154. package/lib/langium/workspace/document-uri-policy.js.map +1 -1
  155. package/lib/langium/workspace/file-system-provider.d.ts +9 -1
  156. package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
  157. package/lib/langium/workspace/file-system-provider.js +40 -7
  158. package/lib/langium/workspace/file-system-provider.js.map +1 -1
  159. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +25 -0
  160. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
  161. package/lib/langium/workspace/hydranium-langium-document-factory.js +25 -0
  162. package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
  163. package/lib/langium/workspace/hydranium-workspace-manager.d.ts +21 -1
  164. package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
  165. package/lib/langium/workspace/hydranium-workspace-manager.js +28 -0
  166. package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
  167. package/lib/langium/workspace/in-memory-file-system-provider.d.ts +23 -0
  168. package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
  169. package/lib/langium/workspace/in-memory-file-system-provider.js +47 -9
  170. package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
  171. package/lib/langium/workspace/initialize-workspace.d.ts +23 -2
  172. package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
  173. package/lib/langium/workspace/initialize-workspace.js +13 -5
  174. package/lib/langium/workspace/initialize-workspace.js.map +1 -1
  175. package/lib/langium/workspace/langium-documents.d.ts +79 -17
  176. package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
  177. package/lib/langium/workspace/langium-documents.js +83 -28
  178. package/lib/langium/workspace/langium-documents.js.map +1 -1
  179. package/lib/langium/workspace/virtual-document.d.ts +18 -3
  180. package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
  181. package/lib/langium/workspace/virtual-document.js +19 -2
  182. package/lib/langium/workspace/virtual-document.js.map +1 -1
  183. package/lib/locale/index.d.ts +10 -0
  184. package/lib/locale/index.d.ts.map +1 -0
  185. package/lib/locale/index.js +10 -0
  186. package/lib/locale/index.js.map +1 -0
  187. package/lib/locale/server-locale.d.ts +73 -0
  188. package/lib/locale/server-locale.d.ts.map +1 -0
  189. package/lib/locale/server-locale.js +61 -0
  190. package/lib/locale/server-locale.js.map +1 -0
  191. package/lib/lsp/completion/hydranium-completion-provider.d.ts +44 -2
  192. package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
  193. package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
  194. package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
  195. package/lib/lsp/connection-features.d.ts +23 -0
  196. package/lib/lsp/connection-features.d.ts.map +1 -0
  197. package/lib/lsp/connection-features.js +60 -0
  198. package/lib/lsp/connection-features.js.map +1 -0
  199. package/lib/lsp/diagnostics-connection.d.ts +27 -0
  200. package/lib/lsp/diagnostics-connection.d.ts.map +1 -0
  201. package/lib/lsp/diagnostics-connection.js +53 -0
  202. package/lib/lsp/diagnostics-connection.js.map +1 -0
  203. package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
  204. package/lib/lsp/hydranium-document-update-handler.js +10 -1
  205. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  206. package/lib/lsp/index.d.ts +3 -1
  207. package/lib/lsp/index.d.ts.map +1 -1
  208. package/lib/lsp/index.js +3 -1
  209. package/lib/lsp/index.js.map +1 -1
  210. package/lib/lsp/lsp-latency.d.ts +39 -0
  211. package/lib/lsp/lsp-latency.d.ts.map +1 -0
  212. package/lib/lsp/lsp-latency.js +58 -0
  213. package/lib/lsp/lsp-latency.js.map +1 -0
  214. package/lib/lsp/semantic-token-provider.d.ts +34 -1
  215. package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
  216. package/lib/lsp/semantic-token-provider.js +55 -8
  217. package/lib/lsp/semantic-token-provider.js.map +1 -1
  218. package/lib/lsp/start-language-server.d.ts +5 -3
  219. package/lib/lsp/start-language-server.d.ts.map +1 -1
  220. package/lib/lsp/start-language-server.js +10 -3
  221. package/lib/lsp/start-language-server.js.map +1 -1
  222. package/lib/messages/carriers.d.ts +54 -0
  223. package/lib/messages/carriers.d.ts.map +1 -0
  224. package/lib/messages/carriers.js +62 -0
  225. package/lib/messages/carriers.js.map +1 -0
  226. package/lib/messages/index.d.ts +25 -0
  227. package/lib/messages/index.d.ts.map +1 -0
  228. package/lib/messages/index.js +25 -0
  229. package/lib/messages/index.js.map +1 -0
  230. package/lib/messages/renderer.d.ts +136 -0
  231. package/lib/messages/renderer.d.ts.map +1 -0
  232. package/lib/messages/renderer.js +159 -0
  233. package/lib/messages/renderer.js.map +1 -0
  234. package/lib/node/heap-ceiling.d.ts +61 -0
  235. package/lib/node/heap-ceiling.d.ts.map +1 -0
  236. package/lib/node/heap-ceiling.js +72 -0
  237. package/lib/node/heap-ceiling.js.map +1 -0
  238. package/lib/node/index.d.ts +1 -0
  239. package/lib/node/index.d.ts.map +1 -1
  240. package/lib/node/index.js +1 -0
  241. package/lib/node/index.js.map +1 -1
  242. package/lib/node/latency-from-env.d.ts +1 -1
  243. package/lib/node/latency-from-env.js +1 -1
  244. package/lib/node/measure-memory.d.ts.map +1 -1
  245. package/lib/node/measure-memory.js +1 -0
  246. package/lib/node/measure-memory.js.map +1 -1
  247. package/lib/node/node-file-system-provider.d.ts +35 -1
  248. package/lib/node/node-file-system-provider.d.ts.map +1 -1
  249. package/lib/node/node-file-system-provider.js +140 -45
  250. package/lib/node/node-file-system-provider.js.map +1 -1
  251. package/lib/node/profile-capture.d.ts +8 -2
  252. package/lib/node/profile-capture.d.ts.map +1 -1
  253. package/lib/node/profile-capture.js.map +1 -1
  254. package/lib/node/profiling-run.d.ts +2 -2
  255. package/lib/node/profiling-run.js +1 -1
  256. package/lib/node/profiling-run.js.map +1 -1
  257. package/lib/node/rename-over-open-readers.d.ts +52 -0
  258. package/lib/node/rename-over-open-readers.d.ts.map +1 -0
  259. package/lib/node/rename-over-open-readers.js +66 -0
  260. package/lib/node/rename-over-open-readers.js.map +1 -0
  261. package/lib/node/socket-launcher.d.ts +15 -0
  262. package/lib/node/socket-launcher.d.ts.map +1 -1
  263. package/lib/node/socket-launcher.js +3 -2
  264. package/lib/node/socket-launcher.js.map +1 -1
  265. package/lib/testing/fake-document.d.ts +16 -4
  266. package/lib/testing/fake-document.d.ts.map +1 -1
  267. package/lib/testing/fake-document.js +18 -3
  268. package/lib/testing/fake-document.js.map +1 -1
  269. package/lib/testing/make-noop-shared-services.d.ts +14 -0
  270. package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
  271. package/lib/testing/make-noop-shared-services.js +28 -2
  272. package/lib/testing/make-noop-shared-services.js.map +1 -1
  273. package/lib/testing/make-test-services.d.ts +45 -9
  274. package/lib/testing/make-test-services.d.ts.map +1 -1
  275. package/lib/testing/make-test-services.js +19 -3
  276. package/lib/testing/make-test-services.js.map +1 -1
  277. package/lib/testing/node/index.d.ts +1 -0
  278. package/lib/testing/node/index.d.ts.map +1 -1
  279. package/lib/testing/node/index.js +1 -0
  280. package/lib/testing/node/index.js.map +1 -1
  281. package/lib/testing/node/lsp-harness.d.ts.map +1 -1
  282. package/lib/testing/node/lsp-harness.js +2 -0
  283. package/lib/testing/node/lsp-harness.js.map +1 -1
  284. package/lib/testing/node/lsp-server-connection.d.ts +10 -2
  285. package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
  286. package/lib/testing/node/lsp-server-connection.js +42 -9
  287. package/lib/testing/node/lsp-server-connection.js.map +1 -1
  288. package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
  289. package/lib/testing/node/scratch-workspace.js +9 -4
  290. package/lib/testing/node/scratch-workspace.js.map +1 -1
  291. package/lib/testing/node/spawned-server.d.ts +14 -0
  292. package/lib/testing/node/spawned-server.d.ts.map +1 -1
  293. package/lib/testing/node/spawned-server.js +33 -1
  294. package/lib/testing/node/spawned-server.js.map +1 -1
  295. package/lib/testing/node/unhandled-rejections.d.ts +20 -0
  296. package/lib/testing/node/unhandled-rejections.d.ts.map +1 -0
  297. package/lib/testing/node/unhandled-rejections.js +32 -0
  298. package/lib/testing/node/unhandled-rejections.js.map +1 -0
  299. package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
  300. package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
  301. package/lib/testing/playwright/flaky-network-proxy.js +164 -0
  302. package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
  303. package/lib/testing/playwright/index.d.ts +1 -0
  304. package/lib/testing/playwright/index.d.ts.map +1 -1
  305. package/lib/testing/playwright/index.js +1 -0
  306. package/lib/testing/playwright/index.js.map +1 -1
  307. package/lib/testing/playwright/server-log-capture.d.ts +14 -4
  308. package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
  309. package/lib/testing/playwright/server-log-capture.js +21 -4
  310. package/lib/testing/playwright/server-log-capture.js.map +1 -1
  311. package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
  312. package/lib/testing/playwright/server-log-rename-reporter.js +10 -1
  313. package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
  314. package/lib/testing/stub-ast-document-manager.d.ts +5 -5
  315. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  316. package/lib/testing/stub-ast-document-manager.js +4 -6
  317. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  318. package/lib/testing/stub-document-builder.d.ts +8 -0
  319. package/lib/testing/stub-document-builder.d.ts.map +1 -1
  320. package/lib/testing/stub-document-builder.js +22 -3
  321. package/lib/testing/stub-document-builder.js.map +1 -1
  322. package/lib/testing/stub-langium-documents.d.ts +3 -2
  323. package/lib/testing/stub-langium-documents.d.ts.map +1 -1
  324. package/lib/testing/stub-langium-documents.js.map +1 -1
  325. package/lib/testing/stub-model-service.d.ts +5 -4
  326. package/lib/testing/stub-model-service.d.ts.map +1 -1
  327. package/lib/testing/stub-model-service.js +2 -2
  328. package/lib/testing/stub-model-service.js.map +1 -1
  329. package/lib/util/connection-liveness.d.ts +7 -6
  330. package/lib/util/connection-liveness.d.ts.map +1 -1
  331. package/lib/util/connection-liveness.js +35 -14
  332. package/lib/util/connection-liveness.js.map +1 -1
  333. package/package.json +17 -8
  334. package/src/documents/ast-document-manager.ts +129 -36
  335. package/src/documents/client-ids.ts +5 -22
  336. package/src/documents/hydranium-text-documents.ts +256 -81
  337. package/src/documents/language-client-text-shadow.ts +59 -11
  338. package/src/documents/self-save-registry.ts +52 -13
  339. package/src/index.ts +6 -0
  340. package/src/langium/ast-extension/ast-node-builder.ts +66 -22
  341. package/src/langium/bootstrap.ts +16 -9
  342. package/src/langium/config/configuration-provider.ts +119 -0
  343. package/src/langium/config/index.ts +1 -0
  344. package/src/langium/diagnostics/lsp-logger.ts +41 -6
  345. package/src/langium/document-builder/build-pipeline-integration.ts +50 -5
  346. package/src/langium/document-builder/build-session.ts +87 -0
  347. package/src/langium/document-builder/document-builder.ts +339 -11
  348. package/src/langium/document-builder/index.ts +1 -0
  349. package/src/langium/integration-services.ts +67 -6
  350. package/src/langium/integrity/integrity-service.ts +116 -2
  351. package/src/langium/keys/containment.ts +87 -0
  352. package/src/langium/keys/index.ts +1 -0
  353. package/src/langium/keys/name-based-key-provider.ts +4 -0
  354. package/src/langium/language-module.ts +38 -0
  355. package/src/langium/model-service/model-service.ts +266 -34
  356. package/src/langium/module.ts +106 -21
  357. package/src/langium/naming/name-provider.ts +27 -5
  358. package/src/langium/naming/name-separator-validation.ts +34 -5
  359. package/src/langium/residency/cst-residency-service.ts +36 -14
  360. package/src/langium/scope/hydranium-scope-provider.ts +60 -22
  361. package/src/langium/serialization/abstract-serializer.ts +13 -32
  362. package/src/langium/service-registry.ts +19 -2
  363. package/src/langium/shared-services.ts +19 -2
  364. package/src/langium/transfer/transfer-encoder.ts +85 -24
  365. package/src/langium/trivia/comment-preserver.ts +1100 -0
  366. package/src/langium/trivia/document-ending-preserver.ts +55 -0
  367. package/src/langium/trivia/index.ts +14 -0
  368. package/src/langium/trivia/trivia-contribution.ts +39 -0
  369. package/src/langium/trivia/trivia-preserver.ts +54 -0
  370. package/src/langium/trivia/trivia-service.ts +99 -0
  371. package/src/langium/validation/document-validator.ts +537 -11
  372. package/src/langium/workspace/document-uri-policy.ts +3 -4
  373. package/src/langium/workspace/file-system-provider.ts +48 -8
  374. package/src/langium/workspace/hydranium-langium-document-factory.ts +34 -0
  375. package/src/langium/workspace/hydranium-workspace-manager.ts +30 -1
  376. package/src/langium/workspace/in-memory-file-system-provider.ts +53 -10
  377. package/src/langium/workspace/initialize-workspace.ts +35 -5
  378. package/src/langium/workspace/langium-documents.ts +106 -33
  379. package/src/langium/workspace/virtual-document.ts +21 -3
  380. package/src/locale/index.ts +10 -0
  381. package/src/locale/server-locale.ts +86 -0
  382. package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
  383. package/src/lsp/connection-features.ts +67 -0
  384. package/src/lsp/diagnostics-connection.ts +56 -0
  385. package/src/lsp/hydranium-document-update-handler.ts +10 -1
  386. package/src/lsp/index.ts +3 -1
  387. package/src/lsp/lsp-latency.ts +62 -0
  388. package/src/lsp/semantic-token-provider.ts +74 -7
  389. package/src/lsp/start-language-server.ts +10 -3
  390. package/src/messages/carriers.ts +78 -0
  391. package/src/messages/index.ts +36 -0
  392. package/src/messages/renderer.ts +206 -0
  393. package/src/node/heap-ceiling.ts +108 -0
  394. package/src/node/index.ts +1 -0
  395. package/src/node/latency-from-env.ts +1 -1
  396. package/src/node/measure-memory.ts +1 -0
  397. package/src/node/node-file-system-provider.ts +154 -47
  398. package/src/node/profile-capture.ts +8 -2
  399. package/src/node/profiling-run.ts +3 -3
  400. package/src/node/rename-over-open-readers.ts +78 -0
  401. package/src/node/socket-launcher.ts +18 -2
  402. package/src/testing/fake-document.ts +24 -5
  403. package/src/testing/make-noop-shared-services.ts +50 -2
  404. package/src/testing/make-test-services.ts +74 -18
  405. package/src/testing/node/index.ts +1 -0
  406. package/src/testing/node/lsp-harness.ts +2 -0
  407. package/src/testing/node/lsp-server-connection.ts +60 -10
  408. package/src/testing/node/scratch-workspace.ts +9 -4
  409. package/src/testing/node/spawned-server.ts +35 -1
  410. package/src/testing/node/unhandled-rejections.ts +31 -0
  411. package/src/testing/playwright/flaky-network-proxy.ts +240 -0
  412. package/src/testing/playwright/index.ts +1 -0
  413. package/src/testing/playwright/server-log-capture.ts +24 -5
  414. package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
  415. package/src/testing/stub-ast-document-manager.ts +10 -14
  416. package/src/testing/stub-document-builder.ts +32 -3
  417. package/src/testing/stub-langium-documents.ts +3 -2
  418. package/src/testing/stub-model-service.ts +7 -6
  419. package/src/util/connection-liveness.ts +37 -14
  420. package/lib/lsp/instrument-connection.d.ts +0 -36
  421. package/lib/lsp/instrument-connection.d.ts.map +0 -1
  422. package/lib/lsp/instrument-connection.js +0 -62
  423. package/lib/lsp/instrument-connection.js.map +0 -1
  424. package/src/lsp/instrument-connection.ts +0 -66
@@ -7,38 +7,59 @@
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
9
  /**
10
- * Phrases `vscode-jsonrpc` uses when a call loses its connection. Matched on the
11
- * message because the condition surfaces in two different shapes:
10
+ * Phrases that mean a call lost its connection. Matched on the message because
11
+ * the condition surfaces in shapes that share no discriminator:
12
12
  *
13
13
  * - a **throw** from `throwIfClosedOrDisposed` (`Connection is disposed.` /
14
14
  * `Connection is closed.`), a `ConnectionError` raised synchronously by
15
15
  * `sendRequest` / `sendNotification` and by `RemoteConsole.send`;
16
16
  * - a **rejection** of an already-issued request (`Pending response rejected
17
17
  * since connection got disposed`), a `ResponseError` produced when the
18
- * pending-response map is drained on teardown.
18
+ * pending-response map is drained on teardown;
19
+ * - a **write into a destroyed transport** (`Cannot call write after a stream
20
+ * was destroyed`), Node's own error for a message the writer queued before
21
+ * the connection was disposed and flushed after its stream was destroyed.
22
+ * A notification rejects with Node's error itself, which
23
+ * {@link isDestroyedStreamError} catches by its code; a request rejects with
24
+ * a `ResponseError` that copies only the message, so the phrase is needed
25
+ * too.
19
26
  *
20
- * Both are typed, but they are different error classes carrying codes from
21
- * different enums, so no single code check covers both. Kept
22
- * lowercase-normalised and anchored on `connection` so an unrelated "disposed"
23
- * message cannot match.
27
+ * The typed errors come from different classes carrying codes from different
28
+ * enums, so no single code check covers them. Kept lowercase-normalised and
29
+ * anchored on `connection` or `stream` so an unrelated "disposed" message
30
+ * cannot match.
24
31
  */
25
- const CONNECTION_GONE_PATTERNS = [/connection is disposed/, /connection is closed/, /connection got disposed/, /connection got closed/];
32
+ const CONNECTION_GONE_PATTERNS = [
33
+ /connection is disposed/,
34
+ /connection is closed/,
35
+ /connection got disposed/,
36
+ /connection got closed/,
37
+ /after a stream was destroyed/
38
+ ];
39
+ const DESTROYED_STREAM_CODE = 'ERR_STREAM_DESTROYED';
40
+ function isDestroyedStreamError(err) {
41
+ return err instanceof Error && 'code' in err && err.code === DESTROYED_STREAM_CODE;
42
+ }
26
43
  /**
27
44
  * Whether `err` means "the peer is gone", as opposed to a genuine failure of
28
45
  * the operation.
29
46
  *
30
- * The distinction is a **log-severity** one, and it matters because the two are
31
- * indistinguishable at the call site otherwise. Pushing an edit to a language
32
- * client that has already disconnected is a no-op, not a fault — it happens on
33
- * every ordinary shutdown, and reporting it at `error` turns routine teardown
34
- * into something that looks like it needs investigation. A real `applyEdit`
35
- * failure (the client refused, the request malformed) still deserves `error`.
47
+ * The two are indistinguishable at the call site otherwise, and callers act on
48
+ * the answer: a gone peer is logged at `debug` or dropped, a genuine failure is
49
+ * logged at `error` or re-raised as an unhandled rejection. Pushing an edit to
50
+ * a language client that has already disconnected is a no-op, not a fault — it
51
+ * happens on every ordinary shutdown — so a `false` here turns routine teardown
52
+ * into errors that look like they need investigation. A `true` for a real
53
+ * `applyEdit` failure (the client refused, the request malformed) hides it.
36
54
  *
37
55
  * Callers that only need to *survive* a dead connection rather than classify it
38
56
  * should just catch — see `LspLogger.emit`, whose fallback path does exactly
39
57
  * that, since a logger has nowhere to report a logging failure anyway.
40
58
  */
41
59
  export function isConnectionGoneError(err) {
60
+ if (isDestroyedStreamError(err)) {
61
+ return true;
62
+ }
42
63
  const message = err instanceof Error ? err.message : String(err);
43
64
  const normalized = message.toLowerCase();
44
65
  return CONNECTION_GONE_PATTERNS.some(pattern => pattern.test(normalized));
@@ -1 +1 @@
1
- {"version":3,"file":"connection-liveness.js","sourceRoot":"","sources":["../../src/util/connection-liveness.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,wBAAwB,GAAG,CAAC,wBAAwB,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,uBAAuB,CAAC,CAAC;AAExI;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAY;IAC/C,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACzC,OAAO,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7E,CAAC"}
1
+ {"version":3,"file":"connection-liveness.js","sourceRoot":"","sources":["../../src/util/connection-liveness.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,wBAAwB,GAAG;IAC9B,wBAAwB;IACxB,sBAAsB;IACtB,yBAAyB;IACzB,uBAAuB;IACvB,8BAA8B;CAChC,CAAC;AAEF,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAErD,SAAS,sBAAsB,CAAC,GAAY;IACzC,OAAO,GAAG,YAAY,KAAK,IAAI,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,qBAAqB,CAAC;AACtF,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAY;IAC/C,IAAI,sBAAsB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACf,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACzC,OAAO,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAC7E,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/core",
3
- "version": "1.0.0-next.11",
3
+ "version": "1.0.0-next.112",
4
4
  "description": "Foundational runtime of the hydranium framework: AST coordination layer (services, integrity, AST extension, serialization, multi-client documents) plus the LSP textual head at the /lsp subpath. Consumed by protocol-head packages (@hydranium/data-server, @hydranium/glsp-server).",
5
5
  "keywords": [
6
6
  "hydranium",
@@ -72,6 +72,14 @@
72
72
  "./lib/testing/playwright": {
73
73
  "types": "./lib/testing/playwright/index.d.ts",
74
74
  "default": "./lib/testing/playwright/index.js"
75
+ },
76
+ "./messages": {
77
+ "types": "./lib/messages/index.d.ts",
78
+ "default": "./lib/messages/index.js"
79
+ },
80
+ "./lib/messages": {
81
+ "types": "./lib/messages/index.d.ts",
82
+ "default": "./lib/messages/index.js"
75
83
  }
76
84
  },
77
85
  "main": "lib/index.js",
@@ -96,8 +104,8 @@
96
104
  "diff": "^5.2.0"
97
105
  },
98
106
  "devDependencies": {
99
- "@hydranium/langium": "1.0.0-next.11",
100
- "@hydranium/protocol": "1.0.0-next.11",
107
+ "@hydranium/langium": "1.0.0-next.112",
108
+ "@hydranium/protocol": "1.0.0-next.112",
101
109
  "@playwright/test": "^1.40.0",
102
110
  "@types/diff": "^5.2.0",
103
111
  "rimraf": "^5.0.0",
@@ -109,12 +117,12 @@
109
117
  "vscode-languageserver-types": "^3.17.5"
110
118
  },
111
119
  "peerDependencies": {
112
- "@hydranium/langium": "1.0.0-next.11",
113
- "@hydranium/protocol": "1.0.0-next.11",
120
+ "@hydranium/langium": "1.0.0-next.112",
121
+ "@hydranium/protocol": "1.0.0-next.112",
114
122
  "@playwright/test": "^1.40.0",
115
- "vscode-jsonrpc": "^8.0.0 || ^9.0.0",
116
- "vscode-languageserver": "^9.0.0 || ^10.0.0",
117
- "vscode-languageserver-protocol": "^3.17.5",
123
+ "vscode-jsonrpc": "9.0.1",
124
+ "vscode-languageserver": "~10.0.1",
125
+ "vscode-languageserver-protocol": "~3.18.1",
118
126
  "vscode-languageserver-textdocument": "^1.0.12",
119
127
  "vscode-languageserver-types": "^3.17.5"
120
128
  },
@@ -129,6 +137,7 @@
129
137
  "publishConfig": {
130
138
  "access": "public"
131
139
  },
140
+ "//peerDependencies": "`vscode-jsonrpc` is EXACT rather than a range, because it is one link of an atomic chain with no independently movable link: `vscode-languageserver-protocol` depends on it at exactly 9.0.1, so any other value an adopter supplies is a SECOND physical copy rather than an upgrade. This wire stack breaks on copy identity rather than on structure — `ParameterStructures.auto` is a singleton compared by `===` in connection.js, so a request type built by one copy and sent over a connection owned by the other throws `Unknown parameter structure auto`. A caret or union range was rejected because npm then resolves a `vscode-jsonrpc@8.2.0` tree SILENTLY, with no diagnostic at all, and the failure surfaces only later at server init. Exact does not fail the install either — npm downgrades an unsatisfiable peer to a warning — but it is a NAMED ERESOLVE warning printing the required version beside the found one, and a hard error for anyone installing with `--strict-peer-deps`. It does NOT prevent a NESTED copy — `@eclipse-glsp/*` carries its own exact `vscode-jsonrpc@8.2.0` dependency and root `overrides` do not ship — so a consumer of the GLSP head must pin the chain in its own manifest, and docs/adopting/requirements.md carries the block to paste. This manifest declares the two links ABOVE the transport as well, and they carry `~` for the same reason: each admits exactly what `langium@4.3.1` itself admits, and a wider range reaches a `vscode-languageserver@9` / `vscode-languageserver-protocol@3.17.x` that depends on the 8.x transport, which is the same split one level up. `vscode-languageserver-types` and `vscode-languageserver-textdocument` are deliberately NOT narrowed: both declare zero dependencies and expose structural APIs, so a duplicate of either drags no transport in and no identity check reads it.",
132
141
  "//prepack": "The publish guard, and it deliberately is NOT a `prepare`: npm runs a workspace `prepare` BEFORE the root `postinstall` that applies patches/vscode-jsonrpc+9.0.1.patch, so building there fails on a cold clone and npm rolls the entire install back. `prepack` runs only when a tarball is made (`npm pack`, `npm publish`) and never on install, so it cannot break the install it has no business touching. It FAILS rather than rebuilds, because the rebuild is exactly the part that ordering defeats. What it defends against: `files` lists `lib`, `lib` is gitignored, and a `files` entry matching nothing is skipped SILENTLY — so `npm publish` from an unbuilt tree emits a tarball of `src` and nothing else, with no error.",
133
142
  "//sideEffects": "NOT `false`: two barrels do work at module load that their re-exports do not account for, and a bundler skips an unflagged re-export barrel outright. `node/index.js` calls `installNodeLogFileSink()` and `installNodeWriteLockScope()`, which is how a Node host gets the log file-tee and write-lock reentrancy detection merely by importing `@hydranium/core/node`. `util/index.js` carries a bare `import '@hydranium/langium'` so the `UriUtils` namespace augmentation stays loaded for anything importing from here. Both failures are runtime-only and silent — a missing log file, a `UriUtils.toUri` that is `undefined`."
134
143
  }
@@ -12,7 +12,9 @@ import {
12
12
  type Tracer,
13
13
  type TransferSavedEvent,
14
14
  type TransferUpdatedEvent,
15
- type OpenModelArgs
15
+ type OpenModelArgs,
16
+ asSnapshotVersion,
17
+ type SnapshotVersion
16
18
  } from '@hydranium/protocol';
17
19
  import {
18
20
  type AstNode,
@@ -24,6 +26,7 @@ import {
24
26
  UriUtils
25
27
  } from '@hydranium/langium';
26
28
  import { type LogNameOptions } from '../langium/diagnostics/logger.js';
29
+ import { type AstDiagnostic } from '../langium/validation/document-validator.js';
27
30
 
28
31
  /**
29
32
  * File-system provider extension that supports writes. Langium's standard
@@ -102,19 +105,19 @@ export interface UpdateInfo {
102
105
  * twins; the type-system distinction is the generic constraint, and the
103
106
  * conversion seam between them is the framework `TransferEncoder`.
104
107
  */
105
- export interface AstDocument<TAst extends AstNode, TDiagnostic> {
108
+ export interface AstDocument<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> {
106
109
  root: TAst;
107
110
  diagnostics: TDiagnostic[];
108
111
  uri: string;
109
112
  /**
110
113
  * Text-document version this snapshot was taken at — read from
111
114
  * `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.
115
+ * `TransferDocument.version` on the wire side: an in-process caller that
116
+ * holds an `AstDocument` and mutates it sends this straight back as
117
+ * `TransferUpdateArgs.basedOn` / `TransferSaveArgs.basedOn`, and the
118
+ * conflict gate arms on it.
116
119
  */
117
- version: number;
120
+ version: SnapshotVersion;
118
121
  }
119
122
 
120
123
  export namespace AstDocument {
@@ -124,13 +127,13 @@ export namespace AstDocument {
124
127
  * don't need to repeat the empty array at every call site. Mirrors
125
128
  * `TransferDocument.create` on the wire side.
126
129
  */
127
- export function create<TAst extends AstNode, TDiagnostic = unknown>(
130
+ export function create<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic>(
128
131
  uri: string,
129
132
  version: number,
130
133
  root: TAst,
131
134
  diagnostics: TDiagnostic[] = []
132
135
  ): AstDocument<TAst, TDiagnostic> {
133
- return { uri, version, root, diagnostics };
136
+ return { uri, version: asSnapshotVersion(version), root, diagnostics };
134
137
  }
135
138
 
136
139
  /**
@@ -146,26 +149,82 @@ export namespace AstDocument {
146
149
  * carry that identity, not the subscriber's (possibly non-canonical) URI:
147
150
  * a subscriber already knows the URI it subscribed with, so the useful
148
151
  * thing to surface is the canonical one every other layer keys by.
152
+ *
153
+ * Narrowing `TDiagnostic` below the constraint asserts that the validators
154
+ * in play produce that shape, and nothing here checks it: the build fills the
155
+ * array, so a document carrying a diagnostic from elsewhere — a lexer error,
156
+ * another validator — satisfies the declared type and not the narrowed one.
149
157
  */
150
- export function from<TAst extends AstNode, TDiagnostic = unknown>(document: LangiumDocument): AstDocument<TAst, TDiagnostic> {
158
+ export function from<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic>(
159
+ document: LangiumDocument
160
+ ): AstDocument<TAst, TDiagnostic> {
151
161
  return create<TAst, TDiagnostic>(
152
162
  document.textDocument.uri,
153
163
  document.textDocument.version,
154
164
  document.parseResult.value as TAst,
155
- (document.diagnostics ?? []) as unknown as TDiagnostic[]
165
+ (document.diagnostics ?? []) as TDiagnostic[]
156
166
  );
157
167
  }
158
168
  }
159
169
 
160
170
  /** 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>>;
171
+ export type AstDocumentUpdatedEvent<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> = TransferUpdatedEvent<
172
+ AstDocument<TAst, TDiagnostic>
173
+ >;
162
174
 
163
175
  /** 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>>;
176
+ export type AstDocumentSavedEvent<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> = TransferSavedEvent<
177
+ AstDocument<TAst, TDiagnostic>
178
+ >;
165
179
 
166
180
  /** Construction options for {@link AstDocumentManager}. */
167
181
  export type AstDocumentManagerOptions = LogNameOptions;
168
182
 
183
+ /**
184
+ * The document slot the model server and the integrity service talk to:
185
+ * open/close/update/save plus the AST-typed event streams, with the LSP
186
+ * plumbing hidden.
187
+ *
188
+ * Generic over `<TAst extends AstNode, TDiagnostic>` so each consumer projects
189
+ * its own AST root type and diagnostic shape into the emitted
190
+ * {@link AstDocument} envelopes.
191
+ *
192
+ * **URI contract.** Every URI-accepting member takes a URI in *any* spelling
193
+ * (canonical, symlinked, `..`/case-divergent) and canonicalizes internally
194
+ * through the {@link DocumentUriPolicy}, so a caller never has to canonicalize
195
+ * first and an implementation may not require it.
196
+ */
197
+ export interface AstDocumentManager<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> {
198
+ open(args: OpenModelArgs): Promise<Disposable>;
199
+ close(args: CloseModelArgs): Promise<void>;
200
+ isOpen(uri: string): boolean;
201
+
202
+ /** Apply `text` as `clientId`'s edit. Resolves to the resulting text-document version. */
203
+ update(uri: string, text: string, clientId: string): Promise<number>;
204
+ save(uri: string, clientId: string): Promise<void>;
205
+
206
+ onUpdate(uri: string, listener: (event: AstDocumentUpdatedEvent<TAst, TDiagnostic>) => void): Disposable;
207
+ onSave(uri: string, listener: (event: AstDocumentSavedEvent<TAst, TDiagnostic>) => void | Promise<void>): Disposable;
208
+ onClientClosed(uri: string, clientId: string, listener: () => void): Disposable;
209
+
210
+ getDocument(uri: string): LangiumDocument | undefined;
211
+
212
+ /** Client id that authored the document's current version, or `undefined` for a framework-internal build. */
213
+ getAuthor(document: LangiumDocument): string | undefined;
214
+
215
+ /**
216
+ * Whether `uri` is one of the URIs the most recent build request named, as
217
+ * opposed to a document that build swept in as a dependent. Deletions are
218
+ * excluded: they never reach this layer, since a deleted document is
219
+ * removed before the build set is computed.
220
+ *
221
+ * The answer refers to the latest request, which may still be building, and
222
+ * it is retained between builds — so outside a build it describes whichever
223
+ * one ran last.
224
+ */
225
+ isTriggeringEdit(uri: string): boolean;
226
+ }
227
+
169
228
  /**
170
229
  * Higher-level facade over {@link HydraniumTextDocuments} that speaks the
171
230
  * model-server protocol (open/close/update/save with the transfer-model event
@@ -186,7 +245,10 @@ export type AstDocumentManagerOptions = LogNameOptions;
186
245
  * resolution (the egress `applyEditToLanguageClient`) stay on
187
246
  * {@link HydraniumTextDocuments}, their owner.
188
247
  */
189
- export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = unknown> {
248
+ export class DefaultAstDocumentManager<
249
+ TAst extends AstNode,
250
+ TDiagnostic extends AstDiagnostic = AstDiagnostic
251
+ > implements AstDocumentManager<TAst, TDiagnostic> {
190
252
  protected lastUpdate?: UpdateInfo;
191
253
 
192
254
  protected readonly textDocuments: HydraniumTextDocuments<TextDocument>;
@@ -311,11 +373,12 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
311
373
  const event: TransferUpdatedEvent<AstDocument<TAst, TDiagnostic>> = {
312
374
  document: this.toAstDocument(document),
313
375
  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'
376
+ // No `'deleted'` arm: `DocumentBuilder.update` drops a deleted
377
+ // document from `LangiumDocuments` before deriving the rebuild set
378
+ // from it, so a deleted URI is never built and never reaches this
379
+ // phase listener. A subscriber needing deletions has to be told on
380
+ // a channel that does not require a built document.
381
+ reason: this.lastUpdate?.changed.some(changed => UriUtils.equals(changed, document.uri)) ? 'changed' : 'rebuilt'
319
382
  };
320
383
  this.tracer.with(uri).trace(`emitUpdate start: source=${sourceClientId}, reason=${event.reason}`);
321
384
  listener(event);
@@ -334,7 +397,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
334
397
  * concrete value (the `onUpdate` event's `sourceClientId`, the data-server's
335
398
  * `resolveSourceClientId`).
336
399
  */
337
- getAuthor(document: LangiumDocument<AstNode>): string | undefined {
400
+ getAuthor(document: LangiumDocument): string | undefined {
338
401
  return this.textDocuments.getAuthor(document.textDocument.uri, document.textDocument.version);
339
402
  }
340
403
 
@@ -355,10 +418,17 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
355
418
  // transiently breaks cross-document linking mid-rebuild (a dependent briefly
356
419
  // seeing an `extends`/`type` reference unresolved). And because the constructor
357
420
  // 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.
421
+ // every first open.
422
+ //
423
+ // So an already-open `open()` records the attaching client's hold and nothing
424
+ // else. The hold is per `(uri, clientId)` and the last-close revert counts down
425
+ // to it, so skipping it lets the first holder's close tear down a document
426
+ // another client is still reading.
359
427
  if (!this.isOpen(args.uri)) {
360
428
  const textDocument = await this.createDocumentFromTextOrFileSystem(args.uri, args.languageId, args.version, args.text);
361
429
  this.textDocuments.notifyDidOpenTextDocument({ textDocument }, args.clientId);
430
+ } else {
431
+ this.textDocuments.attachClient(args.uri, args.clientId);
362
432
  }
363
433
  return Disposable.create(() => this.close(args));
364
434
  }
@@ -393,29 +463,56 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
393
463
  * callers don't need to pass it — the manager owns content and version
394
464
  * sequencing.
395
465
  *
466
+ * **The write is skipped when the file already holds that text; the
467
+ * notification is not.** A save announces that the content is on disk, which
468
+ * is true either way — so a subscriber clearing a dirty marker or reacting to
469
+ * a persist behaves the same, while an mtime is not moved for byte-identical
470
+ * content that a downstream mtime-keyed build would then read as new work.
471
+ *
396
472
  * Throws if no document is open for `uri`.
397
473
  */
398
474
  async save(uri: string, clientId: string): Promise<void> {
399
- const document = this.textDocuments.get(uri);
475
+ // Canonical throughout: the write and the read that gates it must address
476
+ // the same file the store was keyed by, or a divergent spelling compares
477
+ // one file and writes another.
478
+ const canonical = this.uriPolicy.canonicalUri(uri);
479
+ const document = this.textDocuments.get(canonical);
400
480
  if (!document) {
401
481
  throw new Error(`Document ${uri} hasn't been opened for saving yet`);
402
482
  }
403
483
  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
- );
410
- this.textDocuments.notifyDidSaveTextDocument({ textDocument: TextDocumentIdentifier.create(uri), text }, clientId);
484
+ if (!(await this.matchesDisk(canonical, text))) {
485
+ await this.tracer.with(canonical).time(
486
+ `Write file (${text.length} bytes, from ${clientId})`,
487
+ // Async write so a slow disk does not block the event loop for the duration of the fs call.
488
+ () => this.fileSystemProvider.writeFile(UriUtils.toUri(canonical), text),
489
+ 'debug'
490
+ );
491
+ }
492
+ this.textDocuments.notifyDidSaveTextDocument({ textDocument: TextDocumentIdentifier.create(canonical), text }, clientId);
493
+ }
494
+
495
+ /**
496
+ * Whether the file at `uri` already holds `text`.
497
+ *
498
+ * Compared by CONTENT rather than against a remembered version, so a write
499
+ * from outside this server is still corrected: a version this manager already
500
+ * saved says nothing about what is on disk now. `false` when the file cannot
501
+ * be read at all, which is the answer that writes — a document whose file does
502
+ * not exist yet is exactly the one a first save has to create.
503
+ */
504
+ protected async matchesDisk(uri: string, text: string): Promise<boolean> {
505
+ return this.fileSystemProvider
506
+ .readFile(UriUtils.toUri(uri))
507
+ .then(onDisk => onDisk === text)
508
+ .catch(() => false);
411
509
  }
412
510
 
413
511
  isOpen(uri: string): boolean {
414
512
  return !!this.textDocuments.get(uri);
415
513
  }
416
514
 
417
- /** True if the URI was in the directly-changed set of the most recent build (not just affected). */
418
- isDirectChange(uri: string): boolean {
515
+ isTriggeringEdit(uri: string): boolean {
419
516
  const canonical = this.uriPolicy.canonicalUri(uri);
420
517
  return this.lastUpdate?.changed.some(changed => this.uriPolicy.canonicalUri(changed) === canonical) ?? false;
421
518
  }
@@ -437,11 +534,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
437
534
  version = 0,
438
535
  text?: string
439
536
  ): 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));
537
+ return { uri, languageId, version, text: text ?? (await this.fileSystemProvider.readFile(UriUtils.toUri(uri))) };
445
538
  }
446
539
 
447
540
  /**
@@ -8,26 +8,9 @@
8
8
  ********************************************************************************/
9
9
 
10
10
  /**
11
- * Well-known client-kind identifiers used across the multi-client framework.
12
- *
13
- * The framework tracks each document as belonging to one or more "clients"
14
- * — typically an LSP-text-client (Monaco, VS Code, etc.), a GLSP diagram
15
- * client, and/or a structured-form client. Each kind carries a stable id so
16
- * the server can route outbound corrections, edits, and notifications to the
17
- * right transport.
18
- */
19
-
20
- /** Identifier for an LSP-text client (Monaco, VS Code, …). */
21
- export const LANGUAGE_CLIENT_ID = 'language-client';
22
-
23
- /** Fallback identifier when a document's author is unknown (e.g. cold workspace-init load). */
24
- export const UNKNOWN_CLIENT_ID = 'unknown';
25
-
26
- /**
27
- * Synthetic author id on the `onDocumentUpdated` broadcast a data-server
28
- * emits after the LAST client closed a document and the framework rebuilt it
29
- * from its disk content (discarding unsaved in-session edits). Not a real
30
- * client: it lets consumers distinguish the revert broadcast from
31
- * client-authored updates.
11
+ * Re-export, because these are WIRE values and the side that has to recognise
12
+ * them is the client. They are defined in `@hydranium/protocol` so a frontend
13
+ * can name them without depending on the server tier; this path stays so
14
+ * server-side code keeps importing them from where it already does.
32
15
  */
33
- export const REVERT_ON_CLOSE_CLIENT_ID = 'revert-on-close';
16
+ export { FRAMEWORK_CLIENT_IDS, LANGUAGE_CLIENT_ID, REVERT_ON_CLOSE_CLIENT_ID, UNKNOWN_CLIENT_ID } from '@hydranium/protocol';