@hydranium/core 1.0.0-next.18 → 1.0.0-next.181

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 (572) hide show
  1. package/README.md +5 -1
  2. package/lib/documents/ast-document-manager.d.ts +190 -30
  3. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  4. package/lib/documents/ast-document-manager.js +236 -40
  5. package/lib/documents/ast-document-manager.js.map +1 -1
  6. package/lib/documents/client-ids.d.ts +5 -19
  7. package/lib/documents/client-ids.d.ts.map +1 -1
  8. package/lib/documents/client-ids.js +5 -19
  9. package/lib/documents/client-ids.js.map +1 -1
  10. package/lib/documents/client-session-errors.d.ts +15 -0
  11. package/lib/documents/client-session-errors.d.ts.map +1 -0
  12. package/lib/documents/client-session-errors.js +15 -0
  13. package/lib/documents/client-session-errors.js.map +1 -0
  14. package/lib/documents/client-session-registry.d.ts +138 -0
  15. package/lib/documents/client-session-registry.d.ts.map +1 -0
  16. package/lib/documents/client-session-registry.js +187 -0
  17. package/lib/documents/client-session-registry.js.map +1 -0
  18. package/lib/documents/file-system-task-queue.d.ts +49 -0
  19. package/lib/documents/file-system-task-queue.d.ts.map +1 -0
  20. package/lib/documents/file-system-task-queue.js +34 -0
  21. package/lib/documents/file-system-task-queue.js.map +1 -0
  22. package/lib/documents/hydranium-text-documents.d.ts +447 -82
  23. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  24. package/lib/documents/hydranium-text-documents.js +780 -160
  25. package/lib/documents/hydranium-text-documents.js.map +1 -1
  26. package/lib/documents/index.d.ts +3 -0
  27. package/lib/documents/index.d.ts.map +1 -1
  28. package/lib/documents/index.js +3 -0
  29. package/lib/documents/index.js.map +1 -1
  30. package/lib/documents/language-client-text-shadow.d.ts +41 -9
  31. package/lib/documents/language-client-text-shadow.d.ts.map +1 -1
  32. package/lib/documents/language-client-text-shadow.js +56 -11
  33. package/lib/documents/language-client-text-shadow.js.map +1 -1
  34. package/lib/documents/self-save-registry.d.ts +37 -6
  35. package/lib/documents/self-save-registry.d.ts.map +1 -1
  36. package/lib/documents/self-save-registry.js +28 -15
  37. package/lib/documents/self-save-registry.js.map +1 -1
  38. package/lib/index.d.ts +3 -0
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +6 -0
  41. package/lib/index.js.map +1 -1
  42. package/lib/langium/ast-extension/ast-extension-service.d.ts.map +1 -1
  43. package/lib/langium/ast-extension/ast-extension-service.js.map +1 -1
  44. package/lib/langium/ast-extension/ast-node-builder.d.ts +32 -9
  45. package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
  46. package/lib/langium/ast-extension/ast-node-builder.js +60 -22
  47. package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
  48. package/lib/langium/bootstrap.d.ts.map +1 -1
  49. package/lib/langium/bootstrap.js +16 -9
  50. package/lib/langium/bootstrap.js.map +1 -1
  51. package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts.map +1 -1
  52. package/lib/langium/build-phase-pass/build-phase-pass-service.js.map +1 -1
  53. package/lib/langium/config/configuration-provider.d.ts +81 -0
  54. package/lib/langium/config/configuration-provider.d.ts.map +1 -0
  55. package/lib/langium/config/configuration-provider.js +112 -0
  56. package/lib/langium/config/configuration-provider.js.map +1 -0
  57. package/lib/langium/config/index.d.ts +1 -0
  58. package/lib/langium/config/index.d.ts.map +1 -1
  59. package/lib/langium/config/index.js +1 -0
  60. package/lib/langium/config/index.js.map +1 -1
  61. package/lib/langium/config/settings.js.map +1 -1
  62. package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts.map +1 -1
  63. package/lib/langium/diagnostics/hydranium-langium-profiler.js.map +1 -1
  64. package/lib/langium/diagnostics/lsp-logger.d.ts +17 -0
  65. package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
  66. package/lib/langium/diagnostics/lsp-logger.js +40 -6
  67. package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
  68. package/lib/langium/diagnostics/server-tracer.d.ts.map +1 -1
  69. package/lib/langium/diagnostics/server-tracer.js.map +1 -1
  70. package/lib/langium/document-builder/build-pipeline-integration.d.ts +21 -1
  71. package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
  72. package/lib/langium/document-builder/build-pipeline-integration.js +32 -5
  73. package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
  74. package/lib/langium/document-builder/build-session.d.ts +93 -0
  75. package/lib/langium/document-builder/build-session.d.ts.map +1 -0
  76. package/lib/langium/document-builder/build-session.js +72 -0
  77. package/lib/langium/document-builder/build-session.js.map +1 -0
  78. package/lib/langium/document-builder/document-builder.d.ts +368 -21
  79. package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
  80. package/lib/langium/document-builder/document-builder.js +641 -47
  81. package/lib/langium/document-builder/document-builder.js.map +1 -1
  82. package/lib/langium/document-builder/index.d.ts +1 -0
  83. package/lib/langium/document-builder/index.d.ts.map +1 -1
  84. package/lib/langium/document-builder/index.js +1 -0
  85. package/lib/langium/document-builder/index.js.map +1 -1
  86. package/lib/langium/documentation/comment-provider.d.ts.map +1 -1
  87. package/lib/langium/documentation/comment-provider.js.map +1 -1
  88. package/lib/langium/integration-services.d.ts +45 -1
  89. package/lib/langium/integration-services.d.ts.map +1 -1
  90. package/lib/langium/integration-services.js +10 -5
  91. package/lib/langium/integration-services.js.map +1 -1
  92. package/lib/langium/integrity/integrity-rule.d.ts +13 -5
  93. package/lib/langium/integrity/integrity-rule.d.ts.map +1 -1
  94. package/lib/langium/integrity/integrity-rule.js.map +1 -1
  95. package/lib/langium/integrity/integrity-service.d.ts +58 -13
  96. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  97. package/lib/langium/integrity/integrity-service.js +213 -29
  98. package/lib/langium/integrity/integrity-service.js.map +1 -1
  99. package/lib/langium/keys/containment.d.ts +64 -0
  100. package/lib/langium/keys/containment.d.ts.map +1 -0
  101. package/lib/langium/keys/containment.js +53 -0
  102. package/lib/langium/keys/containment.js.map +1 -0
  103. package/lib/langium/keys/index.d.ts +1 -0
  104. package/lib/langium/keys/index.d.ts.map +1 -1
  105. package/lib/langium/keys/index.js +1 -0
  106. package/lib/langium/keys/index.js.map +1 -1
  107. package/lib/langium/keys/name-based-key-provider.d.ts +4 -0
  108. package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
  109. package/lib/langium/keys/name-based-key-provider.js +4 -0
  110. package/lib/langium/keys/name-based-key-provider.js.map +1 -1
  111. package/lib/langium/keys/positional-key-provider.d.ts.map +1 -1
  112. package/lib/langium/keys/positional-key-provider.js.map +1 -1
  113. package/lib/langium/labeling/label-provider.d.ts.map +1 -1
  114. package/lib/langium/labeling/label-provider.js.map +1 -1
  115. package/lib/langium/language-module.d.ts +27 -2
  116. package/lib/langium/language-module.d.ts.map +1 -1
  117. package/lib/langium/language-module.js +16 -2
  118. package/lib/langium/language-module.js.map +1 -1
  119. package/lib/langium/model-service/client-session.d.ts +307 -0
  120. package/lib/langium/model-service/client-session.d.ts.map +1 -0
  121. package/lib/langium/model-service/client-session.js +395 -0
  122. package/lib/langium/model-service/client-session.js.map +1 -0
  123. package/lib/langium/model-service/index.d.ts +1 -0
  124. package/lib/langium/model-service/index.d.ts.map +1 -1
  125. package/lib/langium/model-service/index.js +1 -0
  126. package/lib/langium/model-service/index.js.map +1 -1
  127. package/lib/langium/model-service/model-service.d.ts +276 -226
  128. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  129. package/lib/langium/model-service/model-service.js +251 -375
  130. package/lib/langium/model-service/model-service.js.map +1 -1
  131. package/lib/langium/module.d.ts +144 -35
  132. package/lib/langium/module.d.ts.map +1 -1
  133. package/lib/langium/module.js +46 -35
  134. package/lib/langium/module.js.map +1 -1
  135. package/lib/langium/naming/name-provider.d.ts +25 -4
  136. package/lib/langium/naming/name-provider.d.ts.map +1 -1
  137. package/lib/langium/naming/name-provider.js +2 -1
  138. package/lib/langium/naming/name-provider.js.map +1 -1
  139. package/lib/langium/naming/name-separator-validation.d.ts +23 -0
  140. package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
  141. package/lib/langium/naming/name-separator-validation.js +30 -1
  142. package/lib/langium/naming/name-separator-validation.js.map +1 -1
  143. package/lib/langium/project/abstract-project-manager.d.ts.map +1 -1
  144. package/lib/langium/project/abstract-project-manager.js +9 -2
  145. package/lib/langium/project/abstract-project-manager.js.map +1 -1
  146. package/lib/langium/project/project-change-event.d.ts +2 -2
  147. package/lib/langium/project/single-project-manager.d.ts.map +1 -1
  148. package/lib/langium/project/single-project-manager.js.map +1 -1
  149. package/lib/langium/residency/cst-residency-service.d.ts +31 -11
  150. package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
  151. package/lib/langium/residency/cst-residency-service.js +13 -56
  152. package/lib/langium/residency/cst-residency-service.js.map +1 -1
  153. package/lib/langium/scope/ast-node-description-provider.d.ts.map +1 -1
  154. package/lib/langium/scope/ast-node-description-provider.js.map +1 -1
  155. package/lib/langium/scope/hydranium-scope-computation.d.ts.map +1 -1
  156. package/lib/langium/scope/hydranium-scope-computation.js.map +1 -1
  157. package/lib/langium/scope/hydranium-scope-provider.d.ts +48 -13
  158. package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
  159. package/lib/langium/scope/hydranium-scope-provider.js +56 -20
  160. package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
  161. package/lib/langium/scope/reference-builder.d.ts.map +1 -1
  162. package/lib/langium/scope/reference-builder.js.map +1 -1
  163. package/lib/langium/scope/reference-candidate-provider.d.ts.map +1 -1
  164. package/lib/langium/scope/reference-candidate-provider.js.map +1 -1
  165. package/lib/langium/scope/scope-extension-service.d.ts.map +1 -1
  166. package/lib/langium/scope/scope-extension-service.js.map +1 -1
  167. package/lib/langium/serialization/abstract-serializer.d.ts +11 -20
  168. package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
  169. package/lib/langium/serialization/abstract-serializer.js +12 -21
  170. package/lib/langium/serialization/abstract-serializer.js.map +1 -1
  171. package/lib/langium/serialization/json-serializer.d.ts +1 -1
  172. package/lib/langium/serialization/json-serializer.d.ts.map +1 -1
  173. package/lib/langium/serialization/json-serializer.js.map +1 -1
  174. package/lib/langium/serialization/yaml-serializer.d.ts.map +1 -1
  175. package/lib/langium/serialization/yaml-serializer.js.map +1 -1
  176. package/lib/langium/service-registry.d.ts +15 -1
  177. package/lib/langium/service-registry.d.ts.map +1 -1
  178. package/lib/langium/service-registry.js +16 -0
  179. package/lib/langium/service-registry.js.map +1 -1
  180. package/lib/langium/shared-services.d.ts +15 -2
  181. package/lib/langium/shared-services.d.ts.map +1 -1
  182. package/lib/langium/shared-services.js.map +1 -1
  183. package/lib/langium/transfer/transfer-encoder.d.ts +60 -17
  184. package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
  185. package/lib/langium/transfer/transfer-encoder.js +38 -16
  186. package/lib/langium/transfer/transfer-encoder.js.map +1 -1
  187. package/lib/langium/trivia/comment-preserver.d.ts +423 -0
  188. package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
  189. package/lib/langium/trivia/comment-preserver.js +906 -0
  190. package/lib/langium/trivia/comment-preserver.js.map +1 -0
  191. package/lib/langium/trivia/document-ending-preserver.d.ts +43 -0
  192. package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
  193. package/lib/langium/trivia/document-ending-preserver.js +48 -0
  194. package/lib/langium/trivia/document-ending-preserver.js.map +1 -0
  195. package/lib/langium/trivia/index.d.ts +14 -0
  196. package/lib/langium/trivia/index.d.ts.map +1 -0
  197. package/lib/langium/trivia/index.js +14 -0
  198. package/lib/langium/trivia/index.js.map +1 -0
  199. package/lib/langium/trivia/trivia-contribution.d.ts +37 -0
  200. package/lib/langium/trivia/trivia-contribution.d.ts.map +1 -0
  201. package/lib/langium/trivia/trivia-contribution.js +10 -0
  202. package/lib/langium/trivia/trivia-contribution.js.map +1 -0
  203. package/lib/langium/trivia/trivia-preserver.d.ts +50 -0
  204. package/lib/langium/trivia/trivia-preserver.d.ts.map +1 -0
  205. package/lib/langium/trivia/trivia-preserver.js +10 -0
  206. package/lib/langium/trivia/trivia-preserver.js.map +1 -0
  207. package/lib/langium/trivia/trivia-service.d.ts +70 -0
  208. package/lib/langium/trivia/trivia-service.d.ts.map +1 -0
  209. package/lib/langium/trivia/trivia-service.js +56 -0
  210. package/lib/langium/trivia/trivia-service.js.map +1 -0
  211. package/lib/langium/update-rewrite/normalize-empty-strings.d.ts.map +1 -1
  212. package/lib/langium/update-rewrite/update-rewrite-service.d.ts.map +1 -1
  213. package/lib/langium/update-rewrite/update-rewrite-service.js.map +1 -1
  214. package/lib/langium/update-rewrite/update-rewrite.d.ts +1 -1
  215. package/lib/langium/validation/document-validator.d.ts +294 -10
  216. package/lib/langium/validation/document-validator.d.ts.map +1 -1
  217. package/lib/langium/validation/document-validator.js +448 -5
  218. package/lib/langium/validation/document-validator.js.map +1 -1
  219. package/lib/langium/validation/validation-contribution-collector.d.ts.map +1 -1
  220. package/lib/langium/validation/validation-contribution-collector.js.map +1 -1
  221. package/lib/langium/workspace/document-uri-policy.d.ts +17 -12
  222. package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
  223. package/lib/langium/workspace/document-uri-policy.js +10 -9
  224. package/lib/langium/workspace/document-uri-policy.js.map +1 -1
  225. package/lib/langium/workspace/file-not-found.d.ts +17 -0
  226. package/lib/langium/workspace/file-not-found.d.ts.map +1 -0
  227. package/lib/langium/workspace/file-not-found.js +20 -0
  228. package/lib/langium/workspace/file-not-found.js.map +1 -0
  229. package/lib/langium/workspace/file-system-provider.d.ts +84 -8
  230. package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
  231. package/lib/langium/workspace/file-system-provider.js +93 -14
  232. package/lib/langium/workspace/file-system-provider.js.map +1 -1
  233. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +25 -0
  234. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
  235. package/lib/langium/workspace/hydranium-langium-document-factory.js +25 -0
  236. package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
  237. package/lib/langium/workspace/hydranium-workspace-lock.d.ts +43 -1
  238. package/lib/langium/workspace/hydranium-workspace-lock.d.ts.map +1 -1
  239. package/lib/langium/workspace/hydranium-workspace-lock.js +58 -1
  240. package/lib/langium/workspace/hydranium-workspace-lock.js.map +1 -1
  241. package/lib/langium/workspace/hydranium-workspace-manager.d.ts +81 -8
  242. package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
  243. package/lib/langium/workspace/hydranium-workspace-manager.js +128 -10
  244. package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
  245. package/lib/langium/workspace/in-memory-file-system-provider.d.ts +25 -2
  246. package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
  247. package/lib/langium/workspace/in-memory-file-system-provider.js +41 -15
  248. package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
  249. package/lib/langium/workspace/index-manager.d.ts.map +1 -1
  250. package/lib/langium/workspace/index-manager.js.map +1 -1
  251. package/lib/langium/workspace/initialize-workspace.d.ts +31 -2
  252. package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
  253. package/lib/langium/workspace/initialize-workspace.js +13 -5
  254. package/lib/langium/workspace/initialize-workspace.js.map +1 -1
  255. package/lib/langium/workspace/langium-documents.d.ts +79 -17
  256. package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
  257. package/lib/langium/workspace/langium-documents.js +91 -29
  258. package/lib/langium/workspace/langium-documents.js.map +1 -1
  259. package/lib/langium/workspace/persistent-file-system-provider.d.ts +0 -7
  260. package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
  261. package/lib/langium/workspace/persistent-file-system-provider.js +0 -7
  262. package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
  263. package/lib/langium/workspace/virtual-document.d.ts +48 -15
  264. package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
  265. package/lib/langium/workspace/virtual-document.js +78 -18
  266. package/lib/langium/workspace/virtual-document.js.map +1 -1
  267. package/lib/langium/workspace/write-lock-scope.d.ts +20 -10
  268. package/lib/langium/workspace/write-lock-scope.d.ts.map +1 -1
  269. package/lib/langium/workspace/write-lock-scope.js +12 -4
  270. package/lib/langium/workspace/write-lock-scope.js.map +1 -1
  271. package/lib/locale/index.d.ts +10 -0
  272. package/lib/locale/index.d.ts.map +1 -0
  273. package/lib/locale/index.js +10 -0
  274. package/lib/locale/index.js.map +1 -0
  275. package/lib/locale/server-locale.d.ts +73 -0
  276. package/lib/locale/server-locale.d.ts.map +1 -0
  277. package/lib/locale/server-locale.js +61 -0
  278. package/lib/locale/server-locale.js.map +1 -0
  279. package/lib/lsp/completion/hydranium-completion-provider.d.ts +44 -2
  280. package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
  281. package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
  282. package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
  283. package/lib/lsp/connection-features.d.ts +23 -0
  284. package/lib/lsp/connection-features.d.ts.map +1 -0
  285. package/lib/lsp/connection-features.js +60 -0
  286. package/lib/lsp/connection-features.js.map +1 -0
  287. package/lib/lsp/diagnostics-connection.d.ts +27 -0
  288. package/lib/lsp/diagnostics-connection.d.ts.map +1 -0
  289. package/lib/lsp/diagnostics-connection.js +53 -0
  290. package/lib/lsp/diagnostics-connection.js.map +1 -0
  291. package/lib/lsp/hydranium-document-update-handler.d.ts +90 -79
  292. package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
  293. package/lib/lsp/hydranium-document-update-handler.js +152 -99
  294. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  295. package/lib/lsp/index.d.ts +3 -1
  296. package/lib/lsp/index.d.ts.map +1 -1
  297. package/lib/lsp/index.js +3 -1
  298. package/lib/lsp/index.js.map +1 -1
  299. package/lib/lsp/lsp-latency.d.ts +39 -0
  300. package/lib/lsp/lsp-latency.d.ts.map +1 -0
  301. package/lib/lsp/lsp-latency.js +58 -0
  302. package/lib/lsp/lsp-latency.js.map +1 -0
  303. package/lib/lsp/semantic-token-provider.d.ts +34 -1
  304. package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
  305. package/lib/lsp/semantic-token-provider.js +55 -8
  306. package/lib/lsp/semantic-token-provider.js.map +1 -1
  307. package/lib/lsp/shared-module.d.ts +4 -8
  308. package/lib/lsp/shared-module.d.ts.map +1 -1
  309. package/lib/lsp/shared-module.js.map +1 -1
  310. package/lib/lsp/start-language-server.d.ts +8 -7
  311. package/lib/lsp/start-language-server.d.ts.map +1 -1
  312. package/lib/lsp/start-language-server.js +13 -7
  313. package/lib/lsp/start-language-server.js.map +1 -1
  314. package/lib/messages/carriers.d.ts +54 -0
  315. package/lib/messages/carriers.d.ts.map +1 -0
  316. package/lib/messages/carriers.js +62 -0
  317. package/lib/messages/carriers.js.map +1 -0
  318. package/lib/messages/index.d.ts +25 -0
  319. package/lib/messages/index.d.ts.map +1 -0
  320. package/lib/messages/index.js +25 -0
  321. package/lib/messages/index.js.map +1 -0
  322. package/lib/messages/renderer.d.ts +142 -0
  323. package/lib/messages/renderer.d.ts.map +1 -0
  324. package/lib/messages/renderer.js +165 -0
  325. package/lib/messages/renderer.js.map +1 -0
  326. package/lib/node/event-loop-monitor.js.map +1 -1
  327. package/lib/node/heap-ceiling.d.ts +61 -0
  328. package/lib/node/heap-ceiling.d.ts.map +1 -0
  329. package/lib/node/heap-ceiling.js +72 -0
  330. package/lib/node/heap-ceiling.js.map +1 -0
  331. package/lib/node/index.d.ts +1 -0
  332. package/lib/node/index.d.ts.map +1 -1
  333. package/lib/node/index.js +1 -0
  334. package/lib/node/index.js.map +1 -1
  335. package/lib/node/latency-from-env.d.ts +1 -1
  336. package/lib/node/latency-from-env.js +1 -1
  337. package/lib/node/lint-grammar.js.map +1 -1
  338. package/lib/node/measure-memory.d.ts.map +1 -1
  339. package/lib/node/measure-memory.js +1 -0
  340. package/lib/node/measure-memory.js.map +1 -1
  341. package/lib/node/memory-monitor.js.map +1 -1
  342. package/lib/node/node-file-system-provider.d.ts +39 -4
  343. package/lib/node/node-file-system-provider.d.ts.map +1 -1
  344. package/lib/node/node-file-system-provider.js +109 -49
  345. package/lib/node/node-file-system-provider.js.map +1 -1
  346. package/lib/node/process-memory.js.map +1 -1
  347. package/lib/node/profile-capture.d.ts +8 -2
  348. package/lib/node/profile-capture.d.ts.map +1 -1
  349. package/lib/node/profile-capture.js.map +1 -1
  350. package/lib/node/profile-digest.js.map +1 -1
  351. package/lib/node/profiling-run.d.ts +2 -2
  352. package/lib/node/profiling-run.d.ts.map +1 -1
  353. package/lib/node/profiling-run.js +1 -1
  354. package/lib/node/profiling-run.js.map +1 -1
  355. package/lib/node/rename-over-open-readers.d.ts +52 -0
  356. package/lib/node/rename-over-open-readers.d.ts.map +1 -0
  357. package/lib/node/rename-over-open-readers.js +66 -0
  358. package/lib/node/rename-over-open-readers.js.map +1 -0
  359. package/lib/node/socket-launcher.d.ts +16 -1
  360. package/lib/node/socket-launcher.d.ts.map +1 -1
  361. package/lib/node/socket-launcher.js +4 -3
  362. package/lib/node/socket-launcher.js.map +1 -1
  363. package/lib/node/stdio-launcher.d.ts +1 -1
  364. package/lib/node/stdio-launcher.d.ts.map +1 -1
  365. package/lib/node/stdio-launcher.js +1 -1
  366. package/lib/node/stdio-launcher.js.map +1 -1
  367. package/lib/testing/document-uri-policy-conformance.js.map +1 -1
  368. package/lib/testing/fake-description.js.map +1 -1
  369. package/lib/testing/fake-document.d.ts +16 -4
  370. package/lib/testing/fake-document.d.ts.map +1 -1
  371. package/lib/testing/fake-document.js +18 -3
  372. package/lib/testing/fake-document.js.map +1 -1
  373. package/lib/testing/index.d.ts.map +1 -1
  374. package/lib/testing/index.js +1 -0
  375. package/lib/testing/index.js.map +1 -1
  376. package/lib/testing/langium-test-helpers.d.ts.map +1 -1
  377. package/lib/testing/langium-test-helpers.js +1 -0
  378. package/lib/testing/langium-test-helpers.js.map +1 -1
  379. package/lib/testing/make-noop-language-services.js.map +1 -1
  380. package/lib/testing/make-noop-shared-services.d.ts +14 -0
  381. package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
  382. package/lib/testing/make-noop-shared-services.js +28 -2
  383. package/lib/testing/make-noop-shared-services.js.map +1 -1
  384. package/lib/testing/make-test-services.d.ts +62 -14
  385. package/lib/testing/make-test-services.d.ts.map +1 -1
  386. package/lib/testing/make-test-services.js +30 -9
  387. package/lib/testing/make-test-services.js.map +1 -1
  388. package/lib/testing/make-test-tracer.js.map +1 -1
  389. package/lib/testing/node/golden-corpus.js.map +1 -1
  390. package/lib/testing/node/index.d.ts +1 -0
  391. package/lib/testing/node/index.d.ts.map +1 -1
  392. package/lib/testing/node/index.js +1 -0
  393. package/lib/testing/node/index.js.map +1 -1
  394. package/lib/testing/node/lsp-harness.d.ts.map +1 -1
  395. package/lib/testing/node/lsp-harness.js +2 -0
  396. package/lib/testing/node/lsp-harness.js.map +1 -1
  397. package/lib/testing/node/lsp-server-connection.d.ts +11 -3
  398. package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
  399. package/lib/testing/node/lsp-server-connection.js +42 -9
  400. package/lib/testing/node/lsp-server-connection.js.map +1 -1
  401. package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
  402. package/lib/testing/node/scratch-workspace.js +10 -5
  403. package/lib/testing/node/scratch-workspace.js.map +1 -1
  404. package/lib/testing/node/spawned-server.d.ts +14 -0
  405. package/lib/testing/node/spawned-server.d.ts.map +1 -1
  406. package/lib/testing/node/spawned-server.js +33 -1
  407. package/lib/testing/node/spawned-server.js.map +1 -1
  408. package/lib/testing/node/unhandled-rejections.d.ts +20 -0
  409. package/lib/testing/node/unhandled-rejections.d.ts.map +1 -0
  410. package/lib/testing/node/unhandled-rejections.js +32 -0
  411. package/lib/testing/node/unhandled-rejections.js.map +1 -0
  412. package/lib/testing/playwright/browser-capture-bridge.js.map +1 -1
  413. package/lib/testing/playwright/e2e-profiling.js.map +1 -1
  414. package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
  415. package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
  416. package/lib/testing/playwright/flaky-network-proxy.js +164 -0
  417. package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
  418. package/lib/testing/playwright/index.d.ts +1 -0
  419. package/lib/testing/playwright/index.d.ts.map +1 -1
  420. package/lib/testing/playwright/index.js +1 -0
  421. package/lib/testing/playwright/index.js.map +1 -1
  422. package/lib/testing/playwright/server-log-capture.d.ts +14 -4
  423. package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
  424. package/lib/testing/playwright/server-log-capture.js +21 -4
  425. package/lib/testing/playwright/server-log-capture.js.map +1 -1
  426. package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
  427. package/lib/testing/playwright/server-log-rename-reporter.js +10 -1
  428. package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
  429. package/lib/testing/run-update-pipeline.d.ts +4 -4
  430. package/lib/testing/run-update-pipeline.d.ts.map +1 -1
  431. package/lib/testing/stub-ast-document-manager.d.ts +10 -9
  432. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  433. package/lib/testing/stub-ast-document-manager.js +17 -9
  434. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  435. package/lib/testing/stub-document-builder.d.ts +26 -11
  436. package/lib/testing/stub-document-builder.d.ts.map +1 -1
  437. package/lib/testing/stub-document-builder.js +57 -4
  438. package/lib/testing/stub-document-builder.js.map +1 -1
  439. package/lib/testing/stub-hydranium-text-documents.d.ts +22 -7
  440. package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
  441. package/lib/testing/stub-hydranium-text-documents.js +92 -15
  442. package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
  443. package/lib/testing/stub-index-manager.js.map +1 -1
  444. package/lib/testing/stub-langium-documents.d.ts +3 -2
  445. package/lib/testing/stub-langium-documents.d.ts.map +1 -1
  446. package/lib/testing/stub-langium-documents.js.map +1 -1
  447. package/lib/testing/stub-model-service.d.ts +7 -6
  448. package/lib/testing/stub-model-service.d.ts.map +1 -1
  449. package/lib/testing/stub-model-service.js +4 -4
  450. package/lib/testing/stub-model-service.js.map +1 -1
  451. package/lib/testing/stub-project-manager.js.map +1 -1
  452. package/lib/testing/stub-service-registry.js.map +1 -1
  453. package/lib/util/connection-liveness.d.ts +7 -6
  454. package/lib/util/connection-liveness.d.ts.map +1 -1
  455. package/lib/util/connection-liveness.js +35 -14
  456. package/lib/util/connection-liveness.js.map +1 -1
  457. package/lib/util/environment.d.ts.map +1 -1
  458. package/lib/util/environment.js.map +1 -1
  459. package/lib/util/registry.d.ts.map +1 -1
  460. package/package.json +35 -26
  461. package/src/documents/ast-document-manager.ts +349 -65
  462. package/src/documents/client-ids.ts +5 -22
  463. package/src/documents/client-session-errors.ts +24 -0
  464. package/src/documents/client-session-registry.ts +240 -0
  465. package/src/documents/file-system-task-queue.ts +68 -0
  466. package/src/documents/hydranium-text-documents.ts +973 -202
  467. package/src/documents/index.ts +3 -0
  468. package/src/documents/language-client-text-shadow.ts +59 -11
  469. package/src/documents/self-save-registry.ts +52 -13
  470. package/src/index.ts +6 -0
  471. package/src/langium/ast-extension/ast-node-builder.ts +66 -22
  472. package/src/langium/bootstrap.ts +16 -9
  473. package/src/langium/config/configuration-provider.ts +119 -0
  474. package/src/langium/config/index.ts +1 -0
  475. package/src/langium/diagnostics/lsp-logger.ts +41 -6
  476. package/src/langium/document-builder/build-pipeline-integration.ts +50 -5
  477. package/src/langium/document-builder/build-session.ts +87 -0
  478. package/src/langium/document-builder/document-builder.ts +724 -46
  479. package/src/langium/document-builder/index.ts +1 -0
  480. package/src/langium/integration-services.ts +67 -6
  481. package/src/langium/integrity/integrity-rule.ts +13 -5
  482. package/src/langium/integrity/integrity-service.ts +229 -30
  483. package/src/langium/keys/containment.ts +87 -0
  484. package/src/langium/keys/index.ts +1 -0
  485. package/src/langium/keys/name-based-key-provider.ts +4 -0
  486. package/src/langium/language-module.ts +42 -4
  487. package/src/langium/model-service/client-session.ts +606 -0
  488. package/src/langium/model-service/index.ts +1 -0
  489. package/src/langium/model-service/model-service.ts +418 -399
  490. package/src/langium/module.ts +193 -64
  491. package/src/langium/naming/name-provider.ts +27 -5
  492. package/src/langium/naming/name-separator-validation.ts +34 -5
  493. package/src/langium/project/abstract-project-manager.ts +9 -1
  494. package/src/langium/project/project-change-event.ts +2 -2
  495. package/src/langium/residency/cst-residency-service.ts +36 -14
  496. package/src/langium/scope/hydranium-scope-provider.ts +60 -22
  497. package/src/langium/serialization/abstract-serializer.ts +13 -32
  498. package/src/langium/service-registry.ts +19 -2
  499. package/src/langium/shared-services.ts +19 -2
  500. package/src/langium/transfer/transfer-encoder.ts +85 -24
  501. package/src/langium/trivia/comment-preserver.ts +1100 -0
  502. package/src/langium/trivia/document-ending-preserver.ts +55 -0
  503. package/src/langium/trivia/index.ts +14 -0
  504. package/src/langium/trivia/trivia-contribution.ts +39 -0
  505. package/src/langium/trivia/trivia-preserver.ts +54 -0
  506. package/src/langium/trivia/trivia-service.ts +99 -0
  507. package/src/langium/update-rewrite/update-rewrite.ts +1 -1
  508. package/src/langium/validation/document-validator.ts +537 -11
  509. package/src/langium/workspace/document-uri-policy.ts +17 -12
  510. package/src/langium/workspace/file-not-found.ts +23 -0
  511. package/src/langium/workspace/file-system-provider.ts +153 -16
  512. package/src/langium/workspace/hydranium-langium-document-factory.ts +34 -0
  513. package/src/langium/workspace/hydranium-workspace-lock.ts +86 -2
  514. package/src/langium/workspace/hydranium-workspace-manager.ts +153 -13
  515. package/src/langium/workspace/in-memory-file-system-provider.ts +47 -16
  516. package/src/langium/workspace/initialize-workspace.ts +43 -5
  517. package/src/langium/workspace/langium-documents.ts +113 -33
  518. package/src/langium/workspace/persistent-file-system-provider.ts +0 -7
  519. package/src/langium/workspace/virtual-document.ts +96 -19
  520. package/src/langium/workspace/write-lock-scope.ts +24 -11
  521. package/src/locale/index.ts +10 -0
  522. package/src/locale/server-locale.ts +86 -0
  523. package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
  524. package/src/lsp/connection-features.ts +67 -0
  525. package/src/lsp/diagnostics-connection.ts +56 -0
  526. package/src/lsp/hydranium-document-update-handler.ts +182 -106
  527. package/src/lsp/index.ts +3 -1
  528. package/src/lsp/lsp-latency.ts +62 -0
  529. package/src/lsp/semantic-token-provider.ts +74 -7
  530. package/src/lsp/shared-module.ts +4 -8
  531. package/src/lsp/start-language-server.ts +13 -7
  532. package/src/messages/carriers.ts +78 -0
  533. package/src/messages/index.ts +36 -0
  534. package/src/messages/renderer.ts +212 -0
  535. package/src/node/heap-ceiling.ts +108 -0
  536. package/src/node/index.ts +1 -0
  537. package/src/node/latency-from-env.ts +1 -1
  538. package/src/node/measure-memory.ts +1 -0
  539. package/src/node/node-file-system-provider.ts +122 -51
  540. package/src/node/profile-capture.ts +8 -2
  541. package/src/node/profiling-run.ts +3 -3
  542. package/src/node/rename-over-open-readers.ts +78 -0
  543. package/src/node/socket-launcher.ts +19 -4
  544. package/src/node/stdio-launcher.ts +1 -2
  545. package/src/testing/fake-document.ts +24 -5
  546. package/src/testing/index.ts +1 -0
  547. package/src/testing/langium-test-helpers.ts +1 -0
  548. package/src/testing/make-noop-shared-services.ts +50 -2
  549. package/src/testing/make-test-services.ts +106 -30
  550. package/src/testing/node/index.ts +1 -0
  551. package/src/testing/node/lsp-harness.ts +2 -0
  552. package/src/testing/node/lsp-server-connection.ts +61 -11
  553. package/src/testing/node/scratch-workspace.ts +10 -5
  554. package/src/testing/node/spawned-server.ts +35 -1
  555. package/src/testing/node/unhandled-rejections.ts +31 -0
  556. package/src/testing/playwright/flaky-network-proxy.ts +240 -0
  557. package/src/testing/playwright/index.ts +1 -0
  558. package/src/testing/playwright/server-log-capture.ts +24 -5
  559. package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
  560. package/src/testing/run-update-pipeline.ts +4 -4
  561. package/src/testing/stub-ast-document-manager.ts +28 -21
  562. package/src/testing/stub-document-builder.ts +83 -17
  563. package/src/testing/stub-hydranium-text-documents.ts +127 -22
  564. package/src/testing/stub-langium-documents.ts +3 -2
  565. package/src/testing/stub-model-service.ts +9 -8
  566. package/src/util/connection-liveness.ts +37 -14
  567. package/src/util/environment.ts +9 -1
  568. package/lib/lsp/instrument-connection.d.ts +0 -36
  569. package/lib/lsp/instrument-connection.d.ts.map +0 -1
  570. package/lib/lsp/instrument-connection.js +0 -62
  571. package/lib/lsp/instrument-connection.js.map +0 -1
  572. package/src/lsp/instrument-connection.ts +0 -66
@@ -0,0 +1,240 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+
10
+ import { createServer as createHttpServer, type Server as HttpServer } from 'node:http';
11
+ import { connect, createServer as createTcpServer, type Server as TcpServer, type Socket } from 'node:net';
12
+
13
+ /**
14
+ * A TCP proxy that can half-close a connection, so an e2e suite can reproduce a
15
+ * flaky network against a real browser session.
16
+ *
17
+ * Toggling the browser offline is not enough. On localhost the server sees the
18
+ * close immediately and reaps the socket before the browser reconnects, so the
19
+ * window where both sides disagree about the session — the one where reconnect
20
+ * defects live — never opens. Reaching it needs the browser's socket to die
21
+ * while the server still believes it is alive, and nothing inside the app or in
22
+ * Playwright's offline emulation can produce that asymmetry: both close cleanly
23
+ * at both ends.
24
+ *
25
+ * The proxy holds both halves of every connection and lets a test kill them
26
+ * independently:
27
+ *
28
+ * `break` destroy the BROWSER-side sockets, keep the server-side ones open.
29
+ * The browser reconnects through a fresh pair while the server
30
+ * still holds the old one.
31
+ * `release` destroy the orphaned server-side sockets `break` left. The
32
+ * server's disconnect handler fires at once, rather than whenever
33
+ * its next heartbeat write would have failed.
34
+ */
35
+
36
+ /** Where the proxy listens, and the application it fronts. */
37
+ export interface FlakyNetworkProxyOptions {
38
+ /** Port the browser connects to. */
39
+ readonly listenPort: number;
40
+ /** Port of the application being proxied. */
41
+ readonly targetPort: number;
42
+ /** Host of the application being proxied. Defaults to loopback. */
43
+ readonly targetHost?: string;
44
+ /** Port the HTTP control channel listens on. Defaults to `listenPort + 1000`. */
45
+ readonly controlPort?: number;
46
+ }
47
+
48
+ /** The commands the control channel accepts, and the proxy's own vocabulary. */
49
+ export type FlakyNetworkCommand = 'break' | 'release' | 'status';
50
+
51
+ /** Drives a running proxy. Implemented both in-process and over HTTP. */
52
+ export interface FlakyNetworkControl {
53
+ /** Kill the browser side of every live connection; leave the server side up. */
54
+ break(): Promise<string>;
55
+ /** Kill the server side of every connection `break` orphaned. */
56
+ release(): Promise<string>;
57
+ /** How many connections are live and how many are orphaned. */
58
+ status(): Promise<string>;
59
+ }
60
+
61
+ export interface FlakyNetworkProxy extends FlakyNetworkControl {
62
+ /** Base URL a browser should be pointed at, i.e. Playwright's `baseURL`. */
63
+ readonly url: string;
64
+ /** Control channel, for workers that cannot reach this object directly. */
65
+ readonly controlUrl: string;
66
+ close(): Promise<void>;
67
+ }
68
+
69
+ interface ConnectionPair {
70
+ readonly id: number;
71
+ readonly browserSocket: Socket;
72
+ readonly targetSocket: Socket;
73
+ orphaned: boolean;
74
+ }
75
+
76
+ /**
77
+ * Starts the proxy in the calling process.
78
+ *
79
+ * Call it from a Playwright config, which runs in the main process before any
80
+ * worker forks. Workers are separate processes and cannot reach the returned
81
+ * object, which is what {@link controlUrl} and {@link flakyNetworkControlClient}
82
+ * are for.
83
+ */
84
+ export async function startFlakyNetworkProxy(options: FlakyNetworkProxyOptions): Promise<FlakyNetworkProxy> {
85
+ const targetHost = options.targetHost ?? '127.0.0.1';
86
+ const controlPort = options.controlPort ?? options.listenPort + 1000;
87
+ const pairs = new Set<ConnectionPair>();
88
+ let sequence = 0;
89
+ let transcript: string[] = [];
90
+
91
+ const log = (message: string): void => {
92
+ transcript.push(message);
93
+ console.log(`[flaky-network] ${message}`);
94
+ };
95
+
96
+ const proxyServer: TcpServer = createTcpServer(browserSocket => {
97
+ const id = ++sequence;
98
+ const targetSocket = connect(options.targetPort, targetHost);
99
+ const pair: ConnectionPair = { id, browserSocket, targetSocket, orphaned: false };
100
+ pairs.add(pair);
101
+
102
+ // Forwarded by hand rather than with `pipe()`, so killing one side does not
103
+ // tear the other down — which is the entire point of the proxy.
104
+ browserSocket.on('data', chunk => {
105
+ if (!targetSocket.destroyed) {
106
+ targetSocket.write(chunk);
107
+ }
108
+ });
109
+ targetSocket.on('data', chunk => {
110
+ if (!pair.orphaned && !browserSocket.destroyed) {
111
+ browserSocket.write(chunk);
112
+ }
113
+ });
114
+
115
+ const teardown = (origin: 'browser' | 'target'): void => {
116
+ if (pair.orphaned && origin === 'browser') {
117
+ // Expected: `break` killed this side deliberately. The server side
118
+ // stays up until `release`.
119
+ return;
120
+ }
121
+ pairs.delete(pair);
122
+ browserSocket.destroy();
123
+ targetSocket.destroy();
124
+ };
125
+
126
+ browserSocket.on('close', () => teardown('browser'));
127
+ targetSocket.on('close', () => teardown('target'));
128
+ // A half-killed pair reliably raises ECONNRESET on the surviving side; an
129
+ // unhandled 'error' would take the whole runner down with it.
130
+ browserSocket.on('error', () => undefined);
131
+ targetSocket.on('error', () => undefined);
132
+ });
133
+
134
+ const commands: Record<FlakyNetworkCommand, () => void> = {
135
+ break: () => {
136
+ const live = [...pairs].filter(pair => !pair.orphaned);
137
+ if (live.length === 0) {
138
+ log('nothing to break');
139
+ return;
140
+ }
141
+ for (const pair of live) {
142
+ pair.orphaned = true;
143
+ pair.browserSocket.destroy();
144
+ }
145
+ log(`${live.length} connection(s) broken; the browser should reconnect shortly`);
146
+ },
147
+ release: () => {
148
+ const orphans = [...pairs].filter(pair => pair.orphaned);
149
+ if (orphans.length === 0) {
150
+ log('no orphaned connections; run `break` first');
151
+ return;
152
+ }
153
+ for (const pair of orphans) {
154
+ pairs.delete(pair);
155
+ pair.targetSocket.destroy();
156
+ }
157
+ log(`${orphans.length} orphaned connection(s) destroyed; their late disconnect fires now`);
158
+ },
159
+ status: () => {
160
+ const live = [...pairs].filter(pair => !pair.orphaned).length;
161
+ const orphaned = pairs.size - live;
162
+ log(`${live} live, ${orphaned} orphaned`);
163
+ }
164
+ };
165
+
166
+ const run = (name: string): string => {
167
+ transcript = [];
168
+ const command = commands[name as FlakyNetworkCommand];
169
+ if (command) {
170
+ command();
171
+ } else {
172
+ log(`unknown command '${name}'; use: ${Object.keys(commands).join(' | ')}`);
173
+ }
174
+ return transcript.join('\n');
175
+ };
176
+
177
+ const controlServer: HttpServer = createHttpServer((request, response) => {
178
+ const output = run((request.url ?? '').replace(/^\//, '').split('?')[0]);
179
+ response.writeHead(200, { 'content-type': 'text/plain' });
180
+ response.end(`${output}\n`);
181
+ });
182
+
183
+ await Promise.all([listen(proxyServer, options.listenPort), listen(controlServer, controlPort)]);
184
+ // Neither server keeps the process alive, so a runner that starts one from a
185
+ // config does not need a teardown hook to exit — and a caller that wants a
186
+ // deterministic shutdown still has `close()`.
187
+ proxyServer.unref();
188
+ controlServer.unref();
189
+
190
+ return {
191
+ url: `http://localhost:${options.listenPort}`,
192
+ controlUrl: `http://localhost:${controlPort}`,
193
+ break: async () => run('break'),
194
+ release: async () => run('release'),
195
+ status: async () => run('status'),
196
+ close: async () => {
197
+ for (const pair of pairs) {
198
+ pair.browserSocket.destroy();
199
+ pair.targetSocket.destroy();
200
+ }
201
+ pairs.clear();
202
+ await Promise.all([close(proxyServer), close(controlServer)]);
203
+ }
204
+ };
205
+ }
206
+
207
+ /**
208
+ * Drives a proxy running in another process, over its control channel.
209
+ *
210
+ * This is what a spec uses: Playwright workers are separate processes from the
211
+ * config that started the proxy.
212
+ */
213
+ export function flakyNetworkControlClient(controlUrl: string): FlakyNetworkControl {
214
+ const send = async (command: FlakyNetworkCommand): Promise<string> => {
215
+ const response = await fetch(`${controlUrl}/${command}`);
216
+ if (!response.ok) {
217
+ throw new Error(`flaky-network proxy rejected '${command}': ${response.status}`);
218
+ }
219
+ return (await response.text()).trim();
220
+ };
221
+ return {
222
+ break: () => send('break'),
223
+ release: () => send('release'),
224
+ status: () => send('status')
225
+ };
226
+ }
227
+
228
+ function listen(server: TcpServer | HttpServer, port: number): Promise<void> {
229
+ return new Promise((resolve, reject) => {
230
+ server.once('error', reject);
231
+ server.listen(port, () => {
232
+ server.off('error', reject);
233
+ resolve();
234
+ });
235
+ });
236
+ }
237
+
238
+ function close(server: TcpServer | HttpServer): Promise<void> {
239
+ return new Promise(resolve => server.close(() => resolve()));
240
+ }
@@ -11,6 +11,7 @@
11
11
  // `@hydranium/core/testing` barrel) so importing the framework's unit-test
12
12
  // helpers never pulls in `@playwright/test` — which is an OPTIONAL peer here.
13
13
  export * from './e2e-profiling.js';
14
+ export * from './flaky-network-proxy.js';
14
15
  export * from './browser-capture-bridge.js';
15
16
  export * from './server-log-capture.js';
16
17
  export * from './server-log-fixture.js';
@@ -160,16 +160,28 @@ export function serverLogSpecName(file: string): string {
160
160
  * Rename each `<token>.log` (backend) and `<token>.browser.log` (forwarded
161
161
  * browser console) to the spec name recorded in its `<token>.spec` sidecar
162
162
  * (written by {@link markServerLog}), then delete the sidecar. Colliding names —
163
- * a spec that opened more than one workspace — get a `-2`, `-3`, … suffix. Token
164
- * logs without a sidecar are left untouched. Run once, after all server processes
165
- * have exited (e.g. a reporter's `onEnd`). Best-effort.
163
+ * a spec that opened more than one workspace — get a `-2`, `-3`, … suffix. Run
164
+ * once, after all server processes have exited (e.g. a reporter's `onEnd`).
165
+ * Best-effort.
166
+ *
167
+ * Returns the workspace tokens left UNATTRIBUTED — a log the capture wrote that
168
+ * no test claimed, because that spec never reached
169
+ * {@link markServerLog} (no `serverLog` fixture, no `beforeEach` call).
170
+ *
171
+ * **Returned rather than ignored, because the unattributed state is the
172
+ * misleading one.** Such a log still exists, still has content, and is named by
173
+ * an opaque token with no test boundaries in it — so a capture run that covered
174
+ * nothing looks exactly like one that covered everything, and the logs are
175
+ * there to be read. A caller that can warn should warn.
166
176
  */
167
- export function renameServerLogs(dir: string): void {
177
+ export function renameServerLogs(dir: string): string[] {
168
178
  let entries: string[];
169
179
  try {
170
180
  entries = readdirSync(dir);
171
181
  } catch {
172
- return;
182
+ // An unreadable capture dir has nothing to report — including nothing
183
+ // unattributed, since no log was observed at all.
184
+ return [];
173
185
  }
174
186
  // Per suffix (`.log`, `.browser.log`) a `taken` set guards collisions, so the
175
187
  // backend and browser logs for one spec share the same friendly base name.
@@ -190,6 +202,11 @@ export function renameServerLogs(dir: string): void {
190
202
  // ignore
191
203
  }
192
204
  };
205
+ // Every token the capture produced a backend log for, so the ones no sidecar
206
+ // claims can be reported rather than silently left behind.
207
+ const unattributed = new Set(
208
+ entries.filter(entry => entry.endsWith('.log') && !entry.endsWith('.browser.log')).map(entry => entry.slice(0, -'.log'.length))
209
+ );
193
210
  for (const entry of entries) {
194
211
  if (!entry.endsWith('.spec')) {
195
212
  continue;
@@ -210,9 +227,11 @@ export function renameServerLogs(dir: string): void {
210
227
  if (!name) {
211
228
  continue;
212
229
  }
230
+ unattributed.delete(token);
213
231
  rename(token, name, '.log');
214
232
  rename(token, name, '.browser.log');
215
233
  }
234
+ return [...unattributed];
216
235
  }
217
236
 
218
237
  /**
@@ -24,6 +24,17 @@ export default class ServerLogRenameReporter {
24
24
  }
25
25
 
26
26
  onEnd(): void {
27
- renameServerLogs(this.dir);
27
+ const unattributed = renameServerLogs(this.dir);
28
+ if (unattributed.length > 0) {
29
+ // Loud, because the alternative is a capture run that reads as
30
+ // complete: these logs exist and have content, but are named by an
31
+ // opaque workspace token and carry no test boundaries, so nothing
32
+ // about them says which spec they belong to.
33
+ console.warn(
34
+ `[server-log] ${unattributed.length} captured log(s) belong to no test: ${unattributed.join(', ')}.\n` +
35
+ '[server-log] Those specs never marked a boundary — apply the `serverLog` fixture, ' +
36
+ 'or call `markServerLog`/`attachServerLog` from the suite, or their logs cannot be read per test.'
37
+ );
38
+ }
28
39
  }
29
40
  }
@@ -9,7 +9,7 @@
9
9
 
10
10
  /**
11
11
  * Driver for the structured-write transform chain — the rewrite registry plus
12
- * the serializer — run the way `ModelService.update` runs it.
12
+ * the serializer — run the way a session's `update` runs it.
13
13
  *
14
14
  * # Why a driver and not a documented recipe
15
15
  *
@@ -38,7 +38,7 @@
38
38
  * This runs rewrite → serialize and stops. It does NOT open the document, push
39
39
  * text into the multi-client store, drive a build or return an
40
40
  * {@link AstDocument}: those need a live workspace, and a test that wants them
41
- * should call `ModelService.update` itself rather than a driver standing in for
41
+ * should call a session's `update` itself rather than a driver standing in for
42
42
  * it. What is left is the part with no observable of its own — the text and the
43
43
  * rewritten model — which is why it needed lifting.
44
44
  *
@@ -61,7 +61,7 @@ export interface UpdatePipelineArgs<TTransfer extends TransferElement = Transfer
61
61
  * rather than merely labelling it.
62
62
  */
63
63
  readonly uri: string;
64
- /** Transfer-model payload, as an adopter caller would hand it to `ModelService.update`. */
64
+ /** Transfer-model payload, as an adopter caller would hand it to a session's `update`. */
65
65
  readonly model: TTransfer;
66
66
  /**
67
67
  * Previous AST root threaded into every rewrite, so a diff-based rewrite can
@@ -90,7 +90,7 @@ export interface UpdatePipelineResult<TTransfer extends TransferElement = Transf
90
90
  * surface but it makes the precise assertion unavailable.
91
91
  */
92
92
  readonly rewritten: TTransfer;
93
- /** The serialized text, which is what `ModelService.update` applies to the store. */
93
+ /** The serialized text, which is what a session's `update` applies to the store. */
94
94
  readonly text: string;
95
95
  }
96
96
 
@@ -9,27 +9,30 @@
9
9
 
10
10
  import { type AstNode, type LangiumDocument, UriUtils } from '@hydranium/langium';
11
11
  import { Disposable } from 'vscode-languageserver';
12
+ import { type AstDiagnostic } from '../langium/validation/document-validator.js';
12
13
  import {
13
- type AstDocument,
14
+ AstDocument,
14
15
  type AstDocumentManager,
15
16
  type AstDocumentUpdatedEvent,
17
+ type UpdateAttribution,
16
18
  type WritableFileSystemProvider
17
19
  } from '../documents/ast-document-manager.js';
20
+ import { UNKNOWN_CLIENT_ID } from '../documents/client-ids.js';
18
21
  import type { CloseModelArgs, OpenModelArgs } from '@hydranium/protocol';
19
22
  import type { StubHydraniumTextDocuments } from './stub-hydranium-text-documents.js';
20
23
  import type { StubLangiumDocuments } from './stub-langium-documents.js';
21
24
 
22
25
  /**
23
26
  * Minimal stub of {@link AstDocumentManager} for use in test
24
- * harnesses. Implements just the methods the framework's
25
- * `ModelService` calls (`open` / `close` / `update` / `save` /
26
- * `isOpen` / `getDocument`); `onSave` / `onClientClosed` forward to the
27
- * underlying stub text-document manager, `onUpdate` is driven explicitly
27
+ * harnesses. Implements just the methods the model service and client
28
+ * sessions call (`open` / `close` / `update` / `save` / `isOpen` /
29
+ * `getDocument`);
30
+ * `onSave` / `onClientClosed` forward to the underlying stub text store,
31
+ * `onUpdate` is driven explicitly
28
32
  * through {@link StubAstDocumentManager.emitUpdate} because the stub tree runs
29
33
  * no build phases to emit from, and the remaining read helpers
30
- * (`isDirectChange`, `getAuthor`, `readFile`) throw if invoked — tests that
31
- * need them should wire a richer stub or use the real
32
- * {@link AstDocumentManager}.
34
+ * (`getAuthor`) throw if invoked — tests that need them
35
+ * should wire a richer stub or use the real {@link AstDocumentManager}.
33
36
  *
34
37
  * Open state is tracked per URI as the set of holding client ids, so a
35
38
  * document stays open until its last client closes. The stub forwards
@@ -45,7 +48,7 @@ import type { StubLangiumDocuments } from './stub-langium-documents.js';
45
48
  * are still picked so signature drift on them produces a compile
46
49
  * error rather than silent divergence.
47
50
  */
48
- export interface StubAstDocumentManager<TAst extends AstNode, TDiagnostic = unknown> extends Pick<
51
+ export interface StubAstDocumentManager<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> extends Pick<
49
52
  AstDocumentManager<TAst, TDiagnostic>,
50
53
  | 'open'
51
54
  | 'close'
@@ -57,8 +60,7 @@ export interface StubAstDocumentManager<TAst extends AstNode, TDiagnostic = unkn
57
60
  | 'onClientClosed'
58
61
  | 'getAuthor'
59
62
  | 'getDocument'
60
- | 'isDirectChange'
61
- | 'readFile'
63
+ | 'attributeUpdate'
62
64
  > {
63
65
  readonly openClients: Map<string, Set<string>>;
64
66
 
@@ -104,7 +106,7 @@ export interface StubAstDocumentManager<TAst extends AstNode, TDiagnostic = unkn
104
106
  updateSubscriptions(uri?: string): number;
105
107
  }
106
108
 
107
- export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic = unknown>(
109
+ export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic>(
108
110
  textDocuments: StubHydraniumTextDocuments,
109
111
  fileSystem: Pick<WritableFileSystemProvider, 'writeFile'>,
110
112
  documents?: StubLangiumDocuments<TAst, TDiagnostic>
@@ -131,10 +133,13 @@ export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic = u
131
133
  clients.add(args.clientId);
132
134
  openClients.set(args.uri, clients);
133
135
  // The real `open` materialises the synced document (from the payload
134
- // text or the filesystem); mirror that so a subsequent `update` finds
135
- // an open document to apply its content change to.
136
+ // text or the filesystem), or attaches the client to the one that is
137
+ // there; mirror both so a subsequent `update` finds the document open
138
+ // for this client.
136
139
  if (!textDocuments.get(args.uri)) {
137
140
  textDocuments.seedOpen(args.uri, args.text ?? '', args.clientId);
141
+ } else {
142
+ textDocuments.attachClient(args.uri, args.clientId);
138
143
  }
139
144
  return Disposable.create(() => close({ uri: args.uri, clientId: args.clientId }));
140
145
  },
@@ -193,7 +198,7 @@ export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic = u
193
198
  return;
194
199
  }
195
200
  listener({
196
- document: { uri, version: textDocuments.version(uri), root: undefined as unknown as TAst, diagnostics: [] as TDiagnostic[] },
201
+ document: AstDocument.create<TAst, TDiagnostic>(uri, textDocuments.version(uri), undefined as unknown as TAst),
197
202
  sourceClientId: event.clientId
198
203
  });
199
204
  });
@@ -208,17 +213,19 @@ export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic = u
208
213
  getAuthor(): string {
209
214
  return notSupported('getAuthor');
210
215
  },
216
+ // Reports every event as a change by the version's author: the stub
217
+ // tree runs no builds, so there is no delivery to tell a rebuild by. A
218
+ // test of the rebuilt branch replaces this method or uses the real
219
+ // manager.
220
+ attributeUpdate(document: LangiumDocument): UpdateAttribution {
221
+ const author = textDocuments.getAuthor(document.textDocument.uri, document.textDocument.version) ?? UNKNOWN_CLIENT_ID;
222
+ return { reason: 'changed', sourceClientId: author, causedBy: author };
223
+ },
211
224
  // Canonicalizing document gateway. The stub has no canonicalizer, so it looks
212
225
  // the document up in the seeded `StubLangiumDocuments` by its given URI (tests
213
226
  // that need real symlink canonicalization wire the real AstDocumentManager).
214
227
  getDocument(uri: string): LangiumDocument | undefined {
215
228
  return documents?.getDocument(UriUtils.toUri(uri));
216
- },
217
- isDirectChange(): boolean {
218
- return notSupported('isDirectChange');
219
- },
220
- async readFile(uri: string): Promise<string> {
221
- return notSupported(`readFile(${uri})`);
222
229
  }
223
230
  };
224
231
  }
@@ -9,13 +9,16 @@
9
9
 
10
10
  import {
11
11
  type DocumentBuilder,
12
+ type DocumentBuildListener,
12
13
  type DocumentPhaseListener,
13
14
  type DocumentState,
14
15
  type DocumentUpdateListener,
15
16
  type LangiumDocument,
16
- type URI
17
+ type URI,
18
+ type WorkspaceLock
17
19
  } from '@hydranium/langium';
18
20
  import { type CancellationToken, Disposable } from 'vscode-languageserver';
21
+ import { type HydraniumDocumentBuilder } from '../langium/document-builder/document-builder.js';
19
22
 
20
23
  /** Recorded call to a stubbed {@link DocumentBuilder} method. */
21
24
  export interface RecordedBuilderCall<TArgs extends unknown[]> {
@@ -45,8 +48,7 @@ export interface StubWaitUntilGate {
45
48
 
46
49
  /**
47
50
  * Stub for Langium's {@link DocumentBuilder}. Implements the slice production
48
- * code reads from on the framework's test paths (`update` / `waitUntil` /
49
- * `onDocumentPhase` / `onUpdate`) plus test-only helpers:
51
+ * code reads on the framework's test paths, plus test-only helpers:
50
52
  *
51
53
  * - {@link firePhase} — synchronously dispatch the registered phase
52
54
  * listener(s) for a document, simulating a build completing.
@@ -64,16 +66,17 @@ export interface StubWaitUntilGate {
64
66
  * Picks the methods the framework reads from {@link DocumentBuilder} on
65
67
  * the slot path — the compiler enforces those signatures stay aligned.
66
68
  * `update`, `onDocumentPhase`, `onUpdate`, and `waitUntil` carry stubbed
67
- * implementations; `build`, `onBuildPhase`, and `resetToState` are
68
- * implemented as loud-failing `notSupported` throwers so production code
69
- * that goes through the cast at the bind site (i.e. accesses methods the
69
+ * implementations, and `scheduleUpdate` calls `update` in one lock write per
70
+ * call (see {@link makeStubDocumentBuilder}); `build`, `onBuildPhase`, and
71
+ * `resetToState` are implemented as loud-failing `notSupported` throwers
72
+ * so production code that goes through the cast at the bind site (i.e. accesses methods the
70
73
  * stub claims but doesn't meaningfully implement) fails with a clear
71
74
  * message instead of "undefined is not a function".
72
75
  */
73
- export interface StubDocumentBuilder extends Pick<
74
- DocumentBuilder,
75
- 'update' | 'onDocumentPhase' | 'onUpdate' | 'build' | 'onBuildPhase' | 'resetToState'
76
- > {
76
+ export interface StubDocumentBuilder
77
+ extends
78
+ Pick<DocumentBuilder, 'update' | 'onDocumentPhase' | 'onUpdate' | 'build' | 'onBuildPhase' | 'resetToState' | 'updateBuildOptions'>,
79
+ Pick<HydraniumDocumentBuilder, 'onDocumentPhaseDelivered' | 'scheduleUpdate'> {
77
80
  /**
78
81
  * Single-overload stub of {@link DocumentBuilder.waitUntil}. Real has
79
82
  * two overloads (`(state, cancelToken?): Promise<void>` and
@@ -87,13 +90,22 @@ export interface StubDocumentBuilder extends Pick<
87
90
  readonly waitUntilCalls: ReadonlyArray<RecordedBuilderCall<[DocumentState, URI | undefined]>>;
88
91
  /**
89
92
  * Synchronously fire the phase listener(s) registered for `state` with
90
- * `document`. `cancelToken` defaults to a non-cancelled token; pass a
91
- * cancelled token to simulate a build preempted by a concurrent write
92
- * lock.
93
+ * `document`, then, unless `cancelToken` is cancelled, the
94
+ * `onDocumentPhaseDelivered` listeners. `cancelToken` defaults to a
95
+ * non-cancelled token; pass a cancelled token to simulate a build preempted
96
+ * by a concurrent write lock.
93
97
  */
94
98
  firePhase(state: DocumentState, document: LangiumDocument, cancelToken?: CancellationToken): void;
95
99
  /** Synchronously fire every registered `onUpdate` listener. */
96
100
  fireOnUpdate(changed: URI[], deleted: URI[]): void;
101
+ /**
102
+ * Synchronously fire the BUILD-phase listener(s) for `state` with the whole
103
+ * batch. The per-build counterpart of {@link firePhase}: a subject that
104
+ * reports once per build rather than once per document subscribes here, and
105
+ * a stub that only fired {@link firePhase} would leave it silent while
106
+ * looking wired.
107
+ */
108
+ fireBuildPhase(state: DocumentState, built: LangiumDocument[], cancelToken?: CancellationToken): void;
97
109
  /**
98
110
  * Hold the next {@link waitUntil} call. The returned handle releases it;
99
111
  * the call's return value resolves on the next tick after `resolve` runs.
@@ -128,9 +140,16 @@ function reraise(result: unknown): void {
128
140
  * want to observe rebuilt state should `set` the new root on the document
129
141
  * registry and then call `firePhase` to trigger the framework's post-build
130
142
  * read path.
143
+ *
144
+ * `workspaceLock` is the lock `scheduleUpdate` writes under, without the real
145
+ * builder's sharing: pass the services tree's own, so a caller's lock ordering
146
+ * and reentrancy behave as against the real builder. Without one,
147
+ * `scheduleUpdate` records the update unlocked.
131
148
  */
132
- export function makeStubDocumentBuilder(): StubDocumentBuilder {
149
+ export function makeStubDocumentBuilder(workspaceLock?: WorkspaceLock): StubDocumentBuilder {
133
150
  const phaseListeners = new Map<DocumentState, DocumentPhaseListener[]>();
151
+ const deliveredListeners = new Map<DocumentState, Array<(document: LangiumDocument, version: number) => void>>();
152
+ const buildPhaseListeners = new Map<DocumentState, DocumentBuildListener[]>();
134
153
  const onUpdateListeners: DocumentUpdateListener[] = [];
135
154
  const gates: Array<{ take(release: () => void): void }> = [];
136
155
  const updateCalls: RecordedBuilderCall<[URI[], URI[]]>[] = [];
@@ -140,6 +159,9 @@ export function makeStubDocumentBuilder(): StubDocumentBuilder {
140
159
  throw new Error(`StubDocumentBuilder.${method} is not implemented; wire a real DocumentBuilder if your test needs it.`);
141
160
  };
142
161
  const stub: StubDocumentBuilder = {
162
+ // Langium's own default, so a session write waits for `Validated` here
163
+ // as it does against the real builder.
164
+ updateBuildOptions: { validation: { categories: ['built-in', 'fast'] } },
143
165
  get updateCalls() {
144
166
  return updateCalls;
145
167
  },
@@ -149,6 +171,9 @@ export function makeStubDocumentBuilder(): StubDocumentBuilder {
149
171
  async update(changed: URI[], deleted: URI[]) {
150
172
  updateCalls.push({ args: [changed, deleted] });
151
173
  },
174
+ scheduleUpdate(changed: URI[], deleted: URI[]) {
175
+ return workspaceLock ? workspaceLock.write(() => stub.update(changed, deleted)) : stub.update(changed, deleted);
176
+ },
152
177
  async waitUntil(state: DocumentState, uri?: URI) {
153
178
  waitUntilCalls.push({ args: [state, uri] });
154
179
  const gate = gates.shift();
@@ -185,15 +210,58 @@ export function makeStubDocumentBuilder(): StubDocumentBuilder {
185
210
  onCancellationRequested: () => Disposable.create(() => undefined)
186
211
  } as CancellationToken);
187
212
  const listeners = phaseListeners.get(state) ?? [];
213
+ const delivered = deliveredListeners.get(state) ?? [];
214
+ // Taken before the listeners, as the real builder does: one of them
215
+ // may stand in for a write that moves the version on. Read only when
216
+ // someone is told, since many fakes carry no text document.
217
+ const version = delivered.length > 0 ? document.textDocument.version : 0;
188
218
  for (const listener of listeners) {
189
219
  reraise(listener(document, token));
190
220
  }
221
+ if (!token.isCancellationRequested) {
222
+ for (const listener of delivered) {
223
+ listener(document, version);
224
+ }
225
+ }
226
+ },
227
+ onDocumentPhaseDelivered(state: DocumentState, listener: (document: LangiumDocument, version: number) => void) {
228
+ const list = deliveredListeners.get(state) ?? [];
229
+ list.push(listener);
230
+ deliveredListeners.set(state, list);
231
+ return Disposable.create(() => {
232
+ const idx = list.indexOf(listener);
233
+ if (idx >= 0) {
234
+ list.splice(idx, 1);
235
+ }
236
+ });
191
237
  },
192
238
  fireOnUpdate(changed: URI[], deleted: URI[]) {
193
239
  for (const listener of onUpdateListeners.slice()) {
194
240
  reraise(listener(changed, deleted));
195
241
  }
196
242
  },
243
+ onBuildPhase(state: DocumentState, listener: DocumentBuildListener) {
244
+ const list = buildPhaseListeners.get(state) ?? [];
245
+ list.push(listener);
246
+ buildPhaseListeners.set(state, list);
247
+ return Disposable.create(() => {
248
+ const idx = list.indexOf(listener);
249
+ if (idx >= 0) {
250
+ list.splice(idx, 1);
251
+ }
252
+ });
253
+ },
254
+ fireBuildPhase(state: DocumentState, built: LangiumDocument[], cancelToken?: CancellationToken) {
255
+ const token =
256
+ cancelToken ??
257
+ ({
258
+ isCancellationRequested: false,
259
+ onCancellationRequested: () => Disposable.create(() => undefined)
260
+ } as CancellationToken);
261
+ for (const listener of buildPhaseListeners.get(state) ?? []) {
262
+ reraise(listener(built, token));
263
+ }
264
+ },
197
265
  gateNextWaitUntil(): StubWaitUntilGate {
198
266
  let release: (() => void) | undefined;
199
267
  const entry = {
@@ -224,14 +292,12 @@ export function makeStubDocumentBuilder(): StubDocumentBuilder {
224
292
  build() {
225
293
  return notSupported('build');
226
294
  },
227
- onBuildPhase() {
228
- return notSupported('onBuildPhase');
229
- },
230
295
  resetToState() {
231
296
  return notSupported('resetToState');
232
297
  },
233
298
  reset() {
234
299
  phaseListeners.clear();
300
+ deliveredListeners.clear();
235
301
  onUpdateListeners.length = 0;
236
302
  gates.length = 0;
237
303
  updateCalls.length = 0;