@hydranium/core 1.0.0-next.16 → 1.0.0-next.168

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 (505) hide show
  1. package/README.md +5 -1
  2. package/lib/documents/ast-document-manager.d.ts +190 -29
  3. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  4. package/lib/documents/ast-document-manager.js +235 -38
  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 +439 -82
  23. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  24. package/lib/documents/hydranium-text-documents.js +769 -159
  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-node-builder.d.ts +32 -9
  43. package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
  44. package/lib/langium/ast-extension/ast-node-builder.js +60 -22
  45. package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
  46. package/lib/langium/bootstrap.d.ts.map +1 -1
  47. package/lib/langium/bootstrap.js +16 -9
  48. package/lib/langium/bootstrap.js.map +1 -1
  49. package/lib/langium/config/configuration-provider.d.ts +81 -0
  50. package/lib/langium/config/configuration-provider.d.ts.map +1 -0
  51. package/lib/langium/config/configuration-provider.js +112 -0
  52. package/lib/langium/config/configuration-provider.js.map +1 -0
  53. package/lib/langium/config/index.d.ts +1 -0
  54. package/lib/langium/config/index.d.ts.map +1 -1
  55. package/lib/langium/config/index.js +1 -0
  56. package/lib/langium/config/index.js.map +1 -1
  57. package/lib/langium/diagnostics/lsp-logger.d.ts +17 -0
  58. package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
  59. package/lib/langium/diagnostics/lsp-logger.js +40 -6
  60. package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
  61. package/lib/langium/document-builder/build-pipeline-integration.d.ts +21 -1
  62. package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
  63. package/lib/langium/document-builder/build-pipeline-integration.js +32 -5
  64. package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
  65. package/lib/langium/document-builder/build-session.d.ts +93 -0
  66. package/lib/langium/document-builder/build-session.d.ts.map +1 -0
  67. package/lib/langium/document-builder/build-session.js +72 -0
  68. package/lib/langium/document-builder/build-session.js.map +1 -0
  69. package/lib/langium/document-builder/document-builder.d.ts +365 -19
  70. package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
  71. package/lib/langium/document-builder/document-builder.js +637 -44
  72. package/lib/langium/document-builder/document-builder.js.map +1 -1
  73. package/lib/langium/document-builder/index.d.ts +1 -0
  74. package/lib/langium/document-builder/index.d.ts.map +1 -1
  75. package/lib/langium/document-builder/index.js +1 -0
  76. package/lib/langium/document-builder/index.js.map +1 -1
  77. package/lib/langium/integration-services.d.ts +45 -1
  78. package/lib/langium/integration-services.d.ts.map +1 -1
  79. package/lib/langium/integration-services.js +10 -5
  80. package/lib/langium/integration-services.js.map +1 -1
  81. package/lib/langium/integrity/integrity-rule.d.ts +13 -5
  82. package/lib/langium/integrity/integrity-rule.d.ts.map +1 -1
  83. package/lib/langium/integrity/integrity-rule.js.map +1 -1
  84. package/lib/langium/integrity/integrity-service.d.ts +50 -6
  85. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  86. package/lib/langium/integrity/integrity-service.js +193 -17
  87. package/lib/langium/integrity/integrity-service.js.map +1 -1
  88. package/lib/langium/keys/containment.d.ts +64 -0
  89. package/lib/langium/keys/containment.d.ts.map +1 -0
  90. package/lib/langium/keys/containment.js +53 -0
  91. package/lib/langium/keys/containment.js.map +1 -0
  92. package/lib/langium/keys/index.d.ts +1 -0
  93. package/lib/langium/keys/index.d.ts.map +1 -1
  94. package/lib/langium/keys/index.js +1 -0
  95. package/lib/langium/keys/index.js.map +1 -1
  96. package/lib/langium/keys/name-based-key-provider.d.ts +4 -0
  97. package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
  98. package/lib/langium/keys/name-based-key-provider.js +4 -0
  99. package/lib/langium/keys/name-based-key-provider.js.map +1 -1
  100. package/lib/langium/language-module.d.ts +27 -2
  101. package/lib/langium/language-module.d.ts.map +1 -1
  102. package/lib/langium/language-module.js +16 -2
  103. package/lib/langium/language-module.js.map +1 -1
  104. package/lib/langium/model-service/client-session.d.ts +307 -0
  105. package/lib/langium/model-service/client-session.d.ts.map +1 -0
  106. package/lib/langium/model-service/client-session.js +395 -0
  107. package/lib/langium/model-service/client-session.js.map +1 -0
  108. package/lib/langium/model-service/index.d.ts +1 -0
  109. package/lib/langium/model-service/index.d.ts.map +1 -1
  110. package/lib/langium/model-service/index.js +1 -0
  111. package/lib/langium/model-service/index.js.map +1 -1
  112. package/lib/langium/model-service/model-service.d.ts +261 -198
  113. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  114. package/lib/langium/model-service/model-service.js +234 -346
  115. package/lib/langium/model-service/model-service.js.map +1 -1
  116. package/lib/langium/module.d.ts +144 -35
  117. package/lib/langium/module.d.ts.map +1 -1
  118. package/lib/langium/module.js +45 -34
  119. package/lib/langium/module.js.map +1 -1
  120. package/lib/langium/naming/name-provider.d.ts +25 -4
  121. package/lib/langium/naming/name-provider.d.ts.map +1 -1
  122. package/lib/langium/naming/name-provider.js +2 -1
  123. package/lib/langium/naming/name-provider.js.map +1 -1
  124. package/lib/langium/naming/name-separator-validation.d.ts +23 -0
  125. package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
  126. package/lib/langium/naming/name-separator-validation.js +30 -1
  127. package/lib/langium/naming/name-separator-validation.js.map +1 -1
  128. package/lib/langium/project/abstract-project-manager.d.ts.map +1 -1
  129. package/lib/langium/project/abstract-project-manager.js +9 -2
  130. package/lib/langium/project/abstract-project-manager.js.map +1 -1
  131. package/lib/langium/project/project-change-event.d.ts +2 -2
  132. package/lib/langium/residency/cst-residency-service.d.ts +31 -11
  133. package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
  134. package/lib/langium/residency/cst-residency-service.js +13 -56
  135. package/lib/langium/residency/cst-residency-service.js.map +1 -1
  136. package/lib/langium/scope/hydranium-scope-provider.d.ts +48 -13
  137. package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
  138. package/lib/langium/scope/hydranium-scope-provider.js +56 -20
  139. package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
  140. package/lib/langium/serialization/abstract-serializer.d.ts +11 -20
  141. package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
  142. package/lib/langium/serialization/abstract-serializer.js +12 -21
  143. package/lib/langium/serialization/abstract-serializer.js.map +1 -1
  144. package/lib/langium/service-registry.d.ts +15 -1
  145. package/lib/langium/service-registry.d.ts.map +1 -1
  146. package/lib/langium/service-registry.js +16 -0
  147. package/lib/langium/service-registry.js.map +1 -1
  148. package/lib/langium/shared-services.d.ts +15 -2
  149. package/lib/langium/shared-services.d.ts.map +1 -1
  150. package/lib/langium/shared-services.js.map +1 -1
  151. package/lib/langium/transfer/transfer-encoder.d.ts +60 -17
  152. package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
  153. package/lib/langium/transfer/transfer-encoder.js +38 -16
  154. package/lib/langium/transfer/transfer-encoder.js.map +1 -1
  155. package/lib/langium/trivia/comment-preserver.d.ts +423 -0
  156. package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
  157. package/lib/langium/trivia/comment-preserver.js +906 -0
  158. package/lib/langium/trivia/comment-preserver.js.map +1 -0
  159. package/lib/langium/trivia/document-ending-preserver.d.ts +43 -0
  160. package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
  161. package/lib/langium/trivia/document-ending-preserver.js +48 -0
  162. package/lib/langium/trivia/document-ending-preserver.js.map +1 -0
  163. package/lib/langium/trivia/index.d.ts +14 -0
  164. package/lib/langium/trivia/index.d.ts.map +1 -0
  165. package/lib/langium/trivia/index.js +14 -0
  166. package/lib/langium/trivia/index.js.map +1 -0
  167. package/lib/langium/trivia/trivia-contribution.d.ts +37 -0
  168. package/lib/langium/trivia/trivia-contribution.d.ts.map +1 -0
  169. package/lib/langium/trivia/trivia-contribution.js +10 -0
  170. package/lib/langium/trivia/trivia-contribution.js.map +1 -0
  171. package/lib/langium/trivia/trivia-preserver.d.ts +50 -0
  172. package/lib/langium/trivia/trivia-preserver.d.ts.map +1 -0
  173. package/lib/langium/trivia/trivia-preserver.js +10 -0
  174. package/lib/langium/trivia/trivia-preserver.js.map +1 -0
  175. package/lib/langium/trivia/trivia-service.d.ts +70 -0
  176. package/lib/langium/trivia/trivia-service.d.ts.map +1 -0
  177. package/lib/langium/trivia/trivia-service.js +56 -0
  178. package/lib/langium/trivia/trivia-service.js.map +1 -0
  179. package/lib/langium/update-rewrite/update-rewrite.d.ts +1 -1
  180. package/lib/langium/validation/document-validator.d.ts +294 -10
  181. package/lib/langium/validation/document-validator.d.ts.map +1 -1
  182. package/lib/langium/validation/document-validator.js +448 -5
  183. package/lib/langium/validation/document-validator.js.map +1 -1
  184. package/lib/langium/workspace/document-uri-policy.d.ts +17 -12
  185. package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
  186. package/lib/langium/workspace/document-uri-policy.js +10 -9
  187. package/lib/langium/workspace/document-uri-policy.js.map +1 -1
  188. package/lib/langium/workspace/file-not-found.d.ts +17 -0
  189. package/lib/langium/workspace/file-not-found.d.ts.map +1 -0
  190. package/lib/langium/workspace/file-not-found.js +20 -0
  191. package/lib/langium/workspace/file-not-found.js.map +1 -0
  192. package/lib/langium/workspace/file-system-provider.d.ts +84 -8
  193. package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
  194. package/lib/langium/workspace/file-system-provider.js +93 -14
  195. package/lib/langium/workspace/file-system-provider.js.map +1 -1
  196. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +25 -0
  197. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
  198. package/lib/langium/workspace/hydranium-langium-document-factory.js +25 -0
  199. package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
  200. package/lib/langium/workspace/hydranium-workspace-lock.d.ts +13 -0
  201. package/lib/langium/workspace/hydranium-workspace-lock.d.ts.map +1 -1
  202. package/lib/langium/workspace/hydranium-workspace-lock.js +18 -0
  203. package/lib/langium/workspace/hydranium-workspace-lock.js.map +1 -1
  204. package/lib/langium/workspace/hydranium-workspace-manager.d.ts +77 -8
  205. package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
  206. package/lib/langium/workspace/hydranium-workspace-manager.js +115 -9
  207. package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
  208. package/lib/langium/workspace/in-memory-file-system-provider.d.ts +25 -2
  209. package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
  210. package/lib/langium/workspace/in-memory-file-system-provider.js +41 -15
  211. package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
  212. package/lib/langium/workspace/initialize-workspace.d.ts +31 -2
  213. package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
  214. package/lib/langium/workspace/initialize-workspace.js +13 -5
  215. package/lib/langium/workspace/initialize-workspace.js.map +1 -1
  216. package/lib/langium/workspace/langium-documents.d.ts +79 -17
  217. package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
  218. package/lib/langium/workspace/langium-documents.js +91 -29
  219. package/lib/langium/workspace/langium-documents.js.map +1 -1
  220. package/lib/langium/workspace/persistent-file-system-provider.d.ts +0 -7
  221. package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
  222. package/lib/langium/workspace/persistent-file-system-provider.js +0 -7
  223. package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
  224. package/lib/langium/workspace/virtual-document.d.ts +48 -15
  225. package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
  226. package/lib/langium/workspace/virtual-document.js +78 -18
  227. package/lib/langium/workspace/virtual-document.js.map +1 -1
  228. package/lib/langium/workspace/write-lock-scope.d.ts +4 -3
  229. package/lib/langium/workspace/write-lock-scope.d.ts.map +1 -1
  230. package/lib/langium/workspace/write-lock-scope.js +4 -3
  231. package/lib/langium/workspace/write-lock-scope.js.map +1 -1
  232. package/lib/locale/index.d.ts +10 -0
  233. package/lib/locale/index.d.ts.map +1 -0
  234. package/lib/locale/index.js +10 -0
  235. package/lib/locale/index.js.map +1 -0
  236. package/lib/locale/server-locale.d.ts +73 -0
  237. package/lib/locale/server-locale.d.ts.map +1 -0
  238. package/lib/locale/server-locale.js +61 -0
  239. package/lib/locale/server-locale.js.map +1 -0
  240. package/lib/lsp/completion/hydranium-completion-provider.d.ts +44 -2
  241. package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
  242. package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
  243. package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
  244. package/lib/lsp/connection-features.d.ts +23 -0
  245. package/lib/lsp/connection-features.d.ts.map +1 -0
  246. package/lib/lsp/connection-features.js +60 -0
  247. package/lib/lsp/connection-features.js.map +1 -0
  248. package/lib/lsp/diagnostics-connection.d.ts +27 -0
  249. package/lib/lsp/diagnostics-connection.d.ts.map +1 -0
  250. package/lib/lsp/diagnostics-connection.js +53 -0
  251. package/lib/lsp/diagnostics-connection.js.map +1 -0
  252. package/lib/lsp/hydranium-document-update-handler.d.ts +90 -79
  253. package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
  254. package/lib/lsp/hydranium-document-update-handler.js +152 -99
  255. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  256. package/lib/lsp/index.d.ts +3 -1
  257. package/lib/lsp/index.d.ts.map +1 -1
  258. package/lib/lsp/index.js +3 -1
  259. package/lib/lsp/index.js.map +1 -1
  260. package/lib/lsp/lsp-latency.d.ts +39 -0
  261. package/lib/lsp/lsp-latency.d.ts.map +1 -0
  262. package/lib/lsp/lsp-latency.js +58 -0
  263. package/lib/lsp/lsp-latency.js.map +1 -0
  264. package/lib/lsp/semantic-token-provider.d.ts +34 -1
  265. package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
  266. package/lib/lsp/semantic-token-provider.js +55 -8
  267. package/lib/lsp/semantic-token-provider.js.map +1 -1
  268. package/lib/lsp/shared-module.d.ts +4 -8
  269. package/lib/lsp/shared-module.d.ts.map +1 -1
  270. package/lib/lsp/shared-module.js.map +1 -1
  271. package/lib/lsp/start-language-server.d.ts +8 -7
  272. package/lib/lsp/start-language-server.d.ts.map +1 -1
  273. package/lib/lsp/start-language-server.js +13 -7
  274. package/lib/lsp/start-language-server.js.map +1 -1
  275. package/lib/messages/carriers.d.ts +54 -0
  276. package/lib/messages/carriers.d.ts.map +1 -0
  277. package/lib/messages/carriers.js +62 -0
  278. package/lib/messages/carriers.js.map +1 -0
  279. package/lib/messages/index.d.ts +25 -0
  280. package/lib/messages/index.d.ts.map +1 -0
  281. package/lib/messages/index.js +25 -0
  282. package/lib/messages/index.js.map +1 -0
  283. package/lib/messages/renderer.d.ts +142 -0
  284. package/lib/messages/renderer.d.ts.map +1 -0
  285. package/lib/messages/renderer.js +165 -0
  286. package/lib/messages/renderer.js.map +1 -0
  287. package/lib/node/heap-ceiling.d.ts +61 -0
  288. package/lib/node/heap-ceiling.d.ts.map +1 -0
  289. package/lib/node/heap-ceiling.js +72 -0
  290. package/lib/node/heap-ceiling.js.map +1 -0
  291. package/lib/node/index.d.ts +1 -0
  292. package/lib/node/index.d.ts.map +1 -1
  293. package/lib/node/index.js +1 -0
  294. package/lib/node/index.js.map +1 -1
  295. package/lib/node/latency-from-env.d.ts +1 -1
  296. package/lib/node/latency-from-env.js +1 -1
  297. package/lib/node/measure-memory.d.ts.map +1 -1
  298. package/lib/node/measure-memory.js +1 -0
  299. package/lib/node/measure-memory.js.map +1 -1
  300. package/lib/node/node-file-system-provider.d.ts +39 -4
  301. package/lib/node/node-file-system-provider.d.ts.map +1 -1
  302. package/lib/node/node-file-system-provider.js +109 -49
  303. package/lib/node/node-file-system-provider.js.map +1 -1
  304. package/lib/node/profile-capture.d.ts +8 -2
  305. package/lib/node/profile-capture.d.ts.map +1 -1
  306. package/lib/node/profile-capture.js.map +1 -1
  307. package/lib/node/profiling-run.d.ts +2 -2
  308. package/lib/node/profiling-run.js +1 -1
  309. package/lib/node/profiling-run.js.map +1 -1
  310. package/lib/node/rename-over-open-readers.d.ts +52 -0
  311. package/lib/node/rename-over-open-readers.d.ts.map +1 -0
  312. package/lib/node/rename-over-open-readers.js +66 -0
  313. package/lib/node/rename-over-open-readers.js.map +1 -0
  314. package/lib/node/socket-launcher.d.ts +16 -1
  315. package/lib/node/socket-launcher.d.ts.map +1 -1
  316. package/lib/node/socket-launcher.js +4 -3
  317. package/lib/node/socket-launcher.js.map +1 -1
  318. package/lib/node/stdio-launcher.d.ts +1 -1
  319. package/lib/node/stdio-launcher.d.ts.map +1 -1
  320. package/lib/node/stdio-launcher.js +1 -1
  321. package/lib/node/stdio-launcher.js.map +1 -1
  322. package/lib/testing/fake-document.d.ts +16 -4
  323. package/lib/testing/fake-document.d.ts.map +1 -1
  324. package/lib/testing/fake-document.js +18 -3
  325. package/lib/testing/fake-document.js.map +1 -1
  326. package/lib/testing/make-noop-shared-services.d.ts +14 -0
  327. package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
  328. package/lib/testing/make-noop-shared-services.js +28 -2
  329. package/lib/testing/make-noop-shared-services.js.map +1 -1
  330. package/lib/testing/make-test-services.d.ts +62 -14
  331. package/lib/testing/make-test-services.d.ts.map +1 -1
  332. package/lib/testing/make-test-services.js +27 -6
  333. package/lib/testing/make-test-services.js.map +1 -1
  334. package/lib/testing/node/index.d.ts +1 -0
  335. package/lib/testing/node/index.d.ts.map +1 -1
  336. package/lib/testing/node/index.js +1 -0
  337. package/lib/testing/node/index.js.map +1 -1
  338. package/lib/testing/node/lsp-harness.d.ts.map +1 -1
  339. package/lib/testing/node/lsp-harness.js +2 -0
  340. package/lib/testing/node/lsp-harness.js.map +1 -1
  341. package/lib/testing/node/lsp-server-connection.d.ts +11 -3
  342. package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
  343. package/lib/testing/node/lsp-server-connection.js +42 -9
  344. package/lib/testing/node/lsp-server-connection.js.map +1 -1
  345. package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
  346. package/lib/testing/node/scratch-workspace.js +10 -5
  347. package/lib/testing/node/scratch-workspace.js.map +1 -1
  348. package/lib/testing/node/spawned-server.d.ts +14 -0
  349. package/lib/testing/node/spawned-server.d.ts.map +1 -1
  350. package/lib/testing/node/spawned-server.js +33 -1
  351. package/lib/testing/node/spawned-server.js.map +1 -1
  352. package/lib/testing/node/unhandled-rejections.d.ts +20 -0
  353. package/lib/testing/node/unhandled-rejections.d.ts.map +1 -0
  354. package/lib/testing/node/unhandled-rejections.js +32 -0
  355. package/lib/testing/node/unhandled-rejections.js.map +1 -0
  356. package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
  357. package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
  358. package/lib/testing/playwright/flaky-network-proxy.js +164 -0
  359. package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
  360. package/lib/testing/playwright/index.d.ts +1 -0
  361. package/lib/testing/playwright/index.d.ts.map +1 -1
  362. package/lib/testing/playwright/index.js +1 -0
  363. package/lib/testing/playwright/index.js.map +1 -1
  364. package/lib/testing/playwright/server-log-capture.d.ts +14 -4
  365. package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
  366. package/lib/testing/playwright/server-log-capture.js +21 -4
  367. package/lib/testing/playwright/server-log-capture.js.map +1 -1
  368. package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
  369. package/lib/testing/playwright/server-log-rename-reporter.js +10 -1
  370. package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
  371. package/lib/testing/run-update-pipeline.d.ts +4 -4
  372. package/lib/testing/run-update-pipeline.d.ts.map +1 -1
  373. package/lib/testing/stub-ast-document-manager.d.ts +10 -9
  374. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  375. package/lib/testing/stub-ast-document-manager.js +17 -9
  376. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  377. package/lib/testing/stub-document-builder.d.ts +26 -11
  378. package/lib/testing/stub-document-builder.d.ts.map +1 -1
  379. package/lib/testing/stub-document-builder.js +57 -4
  380. package/lib/testing/stub-document-builder.js.map +1 -1
  381. package/lib/testing/stub-hydranium-text-documents.d.ts +22 -7
  382. package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
  383. package/lib/testing/stub-hydranium-text-documents.js +92 -15
  384. package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
  385. package/lib/testing/stub-langium-documents.d.ts +3 -2
  386. package/lib/testing/stub-langium-documents.d.ts.map +1 -1
  387. package/lib/testing/stub-langium-documents.js.map +1 -1
  388. package/lib/testing/stub-model-service.d.ts +7 -6
  389. package/lib/testing/stub-model-service.d.ts.map +1 -1
  390. package/lib/testing/stub-model-service.js +4 -4
  391. package/lib/testing/stub-model-service.js.map +1 -1
  392. package/lib/util/connection-liveness.d.ts +7 -6
  393. package/lib/util/connection-liveness.d.ts.map +1 -1
  394. package/lib/util/connection-liveness.js +35 -14
  395. package/lib/util/connection-liveness.js.map +1 -1
  396. package/package.json +17 -8
  397. package/src/documents/ast-document-manager.ts +348 -64
  398. package/src/documents/client-ids.ts +5 -22
  399. package/src/documents/client-session-errors.ts +24 -0
  400. package/src/documents/client-session-registry.ts +240 -0
  401. package/src/documents/file-system-task-queue.ts +68 -0
  402. package/src/documents/hydranium-text-documents.ts +959 -201
  403. package/src/documents/index.ts +3 -0
  404. package/src/documents/language-client-text-shadow.ts +59 -11
  405. package/src/documents/self-save-registry.ts +52 -13
  406. package/src/index.ts +6 -0
  407. package/src/langium/ast-extension/ast-node-builder.ts +66 -22
  408. package/src/langium/bootstrap.ts +16 -9
  409. package/src/langium/config/configuration-provider.ts +119 -0
  410. package/src/langium/config/index.ts +1 -0
  411. package/src/langium/diagnostics/lsp-logger.ts +41 -6
  412. package/src/langium/document-builder/build-pipeline-integration.ts +50 -5
  413. package/src/langium/document-builder/build-session.ts +87 -0
  414. package/src/langium/document-builder/document-builder.ts +720 -43
  415. package/src/langium/document-builder/index.ts +1 -0
  416. package/src/langium/integration-services.ts +67 -6
  417. package/src/langium/integrity/integrity-rule.ts +13 -5
  418. package/src/langium/integrity/integrity-service.ts +202 -17
  419. package/src/langium/keys/containment.ts +87 -0
  420. package/src/langium/keys/index.ts +1 -0
  421. package/src/langium/keys/name-based-key-provider.ts +4 -0
  422. package/src/langium/language-module.ts +42 -4
  423. package/src/langium/model-service/client-session.ts +606 -0
  424. package/src/langium/model-service/index.ts +1 -0
  425. package/src/langium/model-service/model-service.ts +395 -351
  426. package/src/langium/module.ts +192 -63
  427. package/src/langium/naming/name-provider.ts +27 -5
  428. package/src/langium/naming/name-separator-validation.ts +34 -5
  429. package/src/langium/project/abstract-project-manager.ts +9 -1
  430. package/src/langium/project/project-change-event.ts +2 -2
  431. package/src/langium/residency/cst-residency-service.ts +36 -14
  432. package/src/langium/scope/hydranium-scope-provider.ts +60 -22
  433. package/src/langium/serialization/abstract-serializer.ts +13 -32
  434. package/src/langium/service-registry.ts +19 -2
  435. package/src/langium/shared-services.ts +19 -2
  436. package/src/langium/transfer/transfer-encoder.ts +85 -24
  437. package/src/langium/trivia/comment-preserver.ts +1100 -0
  438. package/src/langium/trivia/document-ending-preserver.ts +55 -0
  439. package/src/langium/trivia/index.ts +14 -0
  440. package/src/langium/trivia/trivia-contribution.ts +39 -0
  441. package/src/langium/trivia/trivia-preserver.ts +54 -0
  442. package/src/langium/trivia/trivia-service.ts +99 -0
  443. package/src/langium/update-rewrite/update-rewrite.ts +1 -1
  444. package/src/langium/validation/document-validator.ts +537 -11
  445. package/src/langium/workspace/document-uri-policy.ts +17 -12
  446. package/src/langium/workspace/file-not-found.ts +23 -0
  447. package/src/langium/workspace/file-system-provider.ts +153 -16
  448. package/src/langium/workspace/hydranium-langium-document-factory.ts +34 -0
  449. package/src/langium/workspace/hydranium-workspace-lock.ts +21 -0
  450. package/src/langium/workspace/hydranium-workspace-manager.ts +133 -12
  451. package/src/langium/workspace/in-memory-file-system-provider.ts +47 -16
  452. package/src/langium/workspace/initialize-workspace.ts +43 -5
  453. package/src/langium/workspace/langium-documents.ts +113 -33
  454. package/src/langium/workspace/persistent-file-system-provider.ts +0 -7
  455. package/src/langium/workspace/virtual-document.ts +96 -19
  456. package/src/langium/workspace/write-lock-scope.ts +4 -3
  457. package/src/locale/index.ts +10 -0
  458. package/src/locale/server-locale.ts +86 -0
  459. package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
  460. package/src/lsp/connection-features.ts +67 -0
  461. package/src/lsp/diagnostics-connection.ts +56 -0
  462. package/src/lsp/hydranium-document-update-handler.ts +182 -106
  463. package/src/lsp/index.ts +3 -1
  464. package/src/lsp/lsp-latency.ts +62 -0
  465. package/src/lsp/semantic-token-provider.ts +74 -7
  466. package/src/lsp/shared-module.ts +4 -8
  467. package/src/lsp/start-language-server.ts +13 -7
  468. package/src/messages/carriers.ts +78 -0
  469. package/src/messages/index.ts +36 -0
  470. package/src/messages/renderer.ts +212 -0
  471. package/src/node/heap-ceiling.ts +108 -0
  472. package/src/node/index.ts +1 -0
  473. package/src/node/latency-from-env.ts +1 -1
  474. package/src/node/measure-memory.ts +1 -0
  475. package/src/node/node-file-system-provider.ts +122 -51
  476. package/src/node/profile-capture.ts +8 -2
  477. package/src/node/profiling-run.ts +3 -3
  478. package/src/node/rename-over-open-readers.ts +78 -0
  479. package/src/node/socket-launcher.ts +19 -4
  480. package/src/node/stdio-launcher.ts +1 -2
  481. package/src/testing/fake-document.ts +24 -5
  482. package/src/testing/make-noop-shared-services.ts +50 -2
  483. package/src/testing/make-test-services.ts +103 -27
  484. package/src/testing/node/index.ts +1 -0
  485. package/src/testing/node/lsp-harness.ts +2 -0
  486. package/src/testing/node/lsp-server-connection.ts +61 -11
  487. package/src/testing/node/scratch-workspace.ts +10 -5
  488. package/src/testing/node/spawned-server.ts +35 -1
  489. package/src/testing/node/unhandled-rejections.ts +31 -0
  490. package/src/testing/playwright/flaky-network-proxy.ts +240 -0
  491. package/src/testing/playwright/index.ts +1 -0
  492. package/src/testing/playwright/server-log-capture.ts +24 -5
  493. package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
  494. package/src/testing/run-update-pipeline.ts +4 -4
  495. package/src/testing/stub-ast-document-manager.ts +28 -21
  496. package/src/testing/stub-document-builder.ts +83 -17
  497. package/src/testing/stub-hydranium-text-documents.ts +127 -22
  498. package/src/testing/stub-langium-documents.ts +3 -2
  499. package/src/testing/stub-model-service.ts +9 -8
  500. package/src/util/connection-liveness.ts +37 -14
  501. package/lib/lsp/instrument-connection.d.ts +0 -36
  502. package/lib/lsp/instrument-connection.d.ts.map +0 -1
  503. package/lib/lsp/instrument-connection.js +0 -62
  504. package/lib/lsp/instrument-connection.js.map +0 -1
  505. package/src/lsp/instrument-connection.ts +0 -66
@@ -0,0 +1,23 @@
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 { type URI } from '@hydranium/langium';
11
+
12
+ // Not re-exported from the workspace barrel: the framework's providers share
13
+ // it, and it is no API of theirs.
14
+
15
+ /**
16
+ * A missing-file error shaped as a Node file system raises it, with code
17
+ * `ENOENT` and the path: callers tell a missing file from any other failure by
18
+ * those two fields, whichever provider is bound. The last close relies on it to
19
+ * tell a document gone meanwhile from any other failed rebuild.
20
+ */
21
+ export function notFound(message: string, uri: URI): Error {
22
+ return Object.assign(new Error(message), { code: 'ENOENT', path: uri.fsPath });
23
+ }
@@ -9,18 +9,18 @@
9
9
 
10
10
  import { type Tracer } from '@hydranium/protocol';
11
11
  import { EmptyFileSystemProvider } from '@hydranium/langium';
12
- import type { URI } from '@hydranium/langium';
12
+ import type { FileSystemNode, URI } from '@hydranium/langium';
13
13
  import { type WritableFileSystemProvider } from '../../documents/ast-document-manager.js';
14
14
  import { type LogNameOptions } from '../diagnostics/logger.js';
15
15
  import { type ServerSharedServicesMinimal } from '../shared-services.js';
16
- import { serveVirtualDocument } from './virtual-document.js';
17
16
 
18
17
  /**
19
- * Empty-filesystem default {@link WritableFileSystemProvider}. For
20
- * in-memory / browser / test / CLI hosts that don't have a real filesystem.
21
- * All writes are no-ops. This is the portable `.`-entry default; the
22
- * Node-backed `DefaultFileSystemProvider`
23
- * lives in `@hydranium/core/node` (it pulls `node:fs`).
18
+ * Empty-filesystem {@link WritableFileSystemProvider}. For browser / test / CLI
19
+ * hosts that don't have a real filesystem. All writes are no-ops. On the
20
+ * portable `.` entry it is the {@link FileSystemProviderRegistry.host} when
21
+ * `context.fileSystemProvider` gives no writable provider; the Node-backed
22
+ * `DefaultFileSystemProvider` lives in `@hydranium/core/node` (it pulls
23
+ * `node:fs`).
24
24
  */
25
25
  export class DefaultEmptyFileSystemProvider extends EmptyFileSystemProvider implements WritableFileSystemProvider {
26
26
  protected readonly tracer: Tracer;
@@ -37,16 +37,153 @@ export class DefaultEmptyFileSystemProvider extends EmptyFileSystemProvider impl
37
37
  // no-op
38
38
  }
39
39
 
40
- // Serve virtual documents from the registered document (there is no disk to
41
- // read); delegate everything else to the empty base (which throws). The
42
- // base declares these param-less, so the param is optional here.
43
- override readFile(uri?: URI): Promise<string> {
44
- const served = uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
45
- return served !== undefined ? Promise.resolve(served) : super.readFile();
40
+ // `async` so the base's refusal becomes a rejection: it throws
41
+ // SYNCHRONOUSLY from a method declared to return a promise, and a
42
+ // synchronous throw escapes the promise chain — `.catch()` never attaches
43
+ // and `Promise.all` dies while its argument array is still being built, so
44
+ // a caller reading several URIs cannot handle the miss it asked about. The
45
+ // base declares `readFile` and `readBinary` param-less, so the param is
46
+ // optional there.
47
+ override async readFile(_uri?: URI): Promise<string> {
48
+ return super.readFile();
46
49
  }
47
50
 
48
- override readFileSync(uri?: URI): string {
49
- const served = uri !== undefined ? serveVirtualDocument(this.services, uri) : undefined;
50
- return served !== undefined ? served : super.readFileSync();
51
+ override async readBinary(_uri?: URI): Promise<Uint8Array> {
52
+ return super.readBinary();
53
+ }
54
+
55
+ override async stat(uri: URI): Promise<FileSystemNode> {
56
+ return super.stat(uri);
57
+ }
58
+ }
59
+
60
+ /**
61
+ * The provider bound on `workspace.FileSystemProvider`: it dispatches each call
62
+ * by the URI's scheme to the provider registered for it in the shared
63
+ * `fileSystemProviders` group, and to the {@link host} for any scheme without
64
+ * one.
65
+ *
66
+ * So one provider answers for each scheme, and a host's provider needs to know
67
+ * only its own: the framework registers `virtual:` there, and an adopter adds a
68
+ * scheme by contributing to the group. The host takes every unclaimed scheme
69
+ * rather than `file:` alone, which keeps an in-memory workspace under `memory:`
70
+ * or any other scheme on the host's provider.
71
+ *
72
+ * `THost` types the host, so an adopter whose own provider has more members
73
+ * than the base declares the slot as `FileSystemProviderRegistry<MyProvider>`,
74
+ * binds a {@link DefaultFileSystemProviderRegistry} with that host, and reads
75
+ * those members through `services.workspace.FileSystemProvider.host`.
76
+ */
77
+ export interface FileSystemProviderRegistry<
78
+ THost extends WritableFileSystemProvider = WritableFileSystemProvider
79
+ > extends WritableFileSystemProvider {
80
+ /** The provider for every scheme no entry of `fileSystemProviders` claims. */
81
+ readonly host: THost;
82
+ /** The provider that answers for `uri`. */
83
+ providerFor(uri: URI): WritableFileSystemProvider;
84
+ }
85
+
86
+ /** Options for {@link DefaultFileSystemProviderRegistry}. */
87
+ export interface FileSystemProviderRegistryOptions<
88
+ THost extends WritableFileSystemProvider = WritableFileSystemProvider
89
+ > extends LogNameOptions {
90
+ /**
91
+ * The provider for every scheme no entry of `fileSystemProviders` claims.
92
+ * The framework passes the provider `context.fileSystemProvider` returns,
93
+ * or a {@link DefaultEmptyFileSystemProvider} when that is not writable.
94
+ */
95
+ host: THost;
96
+ }
97
+
98
+ /**
99
+ * The framework's {@link FileSystemProviderRegistry}.
100
+ *
101
+ * A directory is listed by the provider of its own scheme, so a workspace
102
+ * root's tree comes from that provider alone.
103
+ *
104
+ * `realpath` and `mtimeMs` are always present and forward to the scheme's
105
+ * provider. Where that provider lacks one, `realpath` returns the URI unchanged
106
+ * and `mtimeMs` returns `undefined`: the answers `RealpathDocumentUriPolicy`
107
+ * and the self-save filter already give a provider without them.
108
+ */
109
+ export class DefaultFileSystemProviderRegistry<
110
+ THost extends WritableFileSystemProvider = WritableFileSystemProvider
111
+ > implements FileSystemProviderRegistry<THost> {
112
+ readonly host: THost;
113
+ protected readonly tracer: Tracer;
114
+
115
+ constructor(
116
+ protected readonly services: ServerSharedServicesMinimal & { fileSystemProviders: Record<string, WritableFileSystemProvider> },
117
+ options: FileSystemProviderRegistryOptions<THost>
118
+ ) {
119
+ this.host = options.host;
120
+ this.tracer = services.Tracer.for(options.logName ?? this.constructor.name).trace('instantiated');
121
+ }
122
+
123
+ /**
124
+ * The group is read per call, not in the constructor, so a registered
125
+ * provider is built on first use and may read slots that reach back to this
126
+ * one. Only an OWN key of the group counts: the DI container resolves any
127
+ * key found on the prototype chain, so a scheme such as `constructor` would
128
+ * otherwise dispatch to a function.
129
+ */
130
+ providerFor(uri: URI): WritableFileSystemProvider {
131
+ const providers = this.services.fileSystemProviders;
132
+ return Object.hasOwn(providers, uri.scheme) ? providers[uri.scheme] : this.host;
133
+ }
134
+
135
+ // The async methods are `async` so a provider that throws synchronously from
136
+ // one still rejects, for the reason `DefaultEmptyFileSystemProvider` gives.
137
+ async writeFile(uri: URI, content: string): Promise<void> {
138
+ return this.providerFor(uri).writeFile(uri, content);
139
+ }
140
+
141
+ async mtimeMs(uri: URI): Promise<number | undefined> {
142
+ return this.providerFor(uri).mtimeMs?.(uri);
143
+ }
144
+
145
+ realpath(uri: URI): URI | undefined {
146
+ const provider = this.providerFor(uri);
147
+ return provider.realpath ? provider.realpath(uri) : uri;
148
+ }
149
+
150
+ async stat(uri: URI): Promise<FileSystemNode> {
151
+ return this.providerFor(uri).stat(uri);
152
+ }
153
+
154
+ statSync(uri: URI): FileSystemNode {
155
+ return this.providerFor(uri).statSync(uri);
156
+ }
157
+
158
+ async exists(uri: URI): Promise<boolean> {
159
+ return this.providerFor(uri).exists(uri);
160
+ }
161
+
162
+ existsSync(uri: URI): boolean {
163
+ return this.providerFor(uri).existsSync(uri);
164
+ }
165
+
166
+ async readBinary(uri: URI): Promise<Uint8Array> {
167
+ return this.providerFor(uri).readBinary(uri);
168
+ }
169
+
170
+ readBinarySync(uri: URI): Uint8Array {
171
+ return this.providerFor(uri).readBinarySync(uri);
172
+ }
173
+
174
+ async readFile(uri: URI): Promise<string> {
175
+ return this.providerFor(uri).readFile(uri);
176
+ }
177
+
178
+ readFileSync(uri: URI): string {
179
+ return this.providerFor(uri).readFileSync(uri);
180
+ }
181
+
182
+ async readDirectory(uri: URI): Promise<FileSystemNode[]> {
183
+ return this.providerFor(uri).readDirectory(uri);
184
+ }
185
+
186
+ readDirectorySync(uri: URI): FileSystemNode[] {
187
+ return this.providerFor(uri).readDirectorySync(uri);
51
188
  }
52
189
  }
@@ -15,6 +15,7 @@ import {
15
15
  type ParseResult,
16
16
  type URI
17
17
  } from '@hydranium/langium';
18
+ import { type ExtendedServiceRegistry } from '../service-registry.js';
18
19
  import { type Serializer } from '../serialization/serializer.js';
19
20
 
20
21
  /** Structural view of the per-language serializer slot on the resolved services. */
@@ -49,6 +50,39 @@ interface WithSerializer {
49
50
  * node identity is preserved.
50
51
  */
51
52
  export class HydraniumLangiumDocumentFactory extends DefaultLangiumDocumentFactory {
53
+ /**
54
+ * Narrows the inherited Langium `ServiceRegistry` field to the framework's
55
+ * {@link ExtendedServiceRegistry}, so the by-id lookup below needs no
56
+ * per-callsite cast. The framework's shared module binds that class.
57
+ */
58
+ declare protected readonly serviceRegistry: ExtendedServiceRegistry;
59
+
60
+ /**
61
+ * Parse `text` for `uri` under the grammar `languageId` names, instead of
62
+ * the one `uri` routes to.
63
+ *
64
+ * For a URI that routes to no grammar at all: a directory, or any other URI
65
+ * that names no file and so carries no extension. Langium's ladder ends at
66
+ * the extension, so it reports `no services for the extension ''` from
67
+ * inside the parse — naming neither the URI nor the caller that could have
68
+ * said which grammar it meant.
69
+ *
70
+ * The caller supplies the language because nothing else can. A URI with no
71
+ * extension carries no routing signal, and choosing on its behalf would be a
72
+ * guess the moment a second grammar is registered — which is why this takes
73
+ * the id rather than falling back to a sole registered language.
74
+ *
75
+ * @throws when `languageId` names no registered grammar.
76
+ */
77
+ fromStringInLanguage<T extends AstNode = AstNode>(text: string, uri: URI, languageId: string): LangiumDocument<T> {
78
+ const services = this.serviceRegistry.getServicesById(languageId);
79
+ if (!services) {
80
+ throw new Error(`No grammar is registered for the language id '${languageId}' (parsing ${uri.toString()}).`);
81
+ }
82
+ const parseResult: ParseResult<T> = services.parser.LangiumParser.parse<T>(text);
83
+ return this.createLangiumDocument<T>(parseResult, uri, undefined, text);
84
+ }
85
+
52
86
  override fromModel<T extends AstNode = AstNode>(model: T, uri: URI): LangiumDocument<T> {
53
87
  // Make the code-built AST as structurally complete as a parsed one — the
54
88
  // parser links containers, `fromModel` does not. In place (identity kept).
@@ -29,7 +29,28 @@ import { runInWriteLockScope } from './write-lock-scope.js';
29
29
  * would turn ordinary read-then-write sequences into false positives.
30
30
  */
31
31
  export class HydraniumWorkspaceLock extends DefaultWorkspaceLock {
32
+ /** Backs {@link writeCancellations}. */
33
+ protected cancelledWriteCount = 0;
34
+
35
+ /**
36
+ * How many calls have cancelled the lock's latest write: every `write`,
37
+ * which cancels the write before it, and every `cancelWrite`. A caller that
38
+ * reads this right after queuing a write, and reads the same number later,
39
+ * holds a write nothing has cancelled, whether it is still queued or
40
+ * already running. Its token answers that only once the write runs, since
41
+ * a queued write has not been handed it yet.
42
+ */
43
+ get writeCancellations(): number {
44
+ return this.cancelledWriteCount;
45
+ }
46
+
32
47
  override write(action: (token: CancellationToken) => MaybePromise<void>): Promise<void> {
33
48
  return super.write(token => runInWriteLockScope(() => action(token)));
34
49
  }
50
+
51
+ /** Counted here rather than in {@link write}, because Langium's `write` cancels through this method too. */
52
+ override cancelWrite(): void {
53
+ this.cancelledWriteCount++;
54
+ super.cancelWrite();
55
+ }
35
56
  }
@@ -8,10 +8,11 @@
8
8
  ********************************************************************************/
9
9
 
10
10
  import { Deferred, type Logger, type Tracer } from '@hydranium/protocol';
11
- import { DefaultWorkspaceManager, DocumentState, type LangiumDocument, UriUtils, type URI } from '@hydranium/langium';
12
- import { type CancellationToken } from 'vscode-languageserver';
11
+ import { DefaultWorkspaceManager, DocumentState, type LangiumDocument, type Stream, UriUtils, type URI } from '@hydranium/langium';
12
+ import { type CancellationToken, type InitializeParams } from 'vscode-languageserver';
13
13
  import type { WorkspaceFolder } from 'vscode-languageserver-types';
14
14
  import { type LogNameOptions, resolveLogFilePlaceholder, toLogFileWorkspaceToken } from '../diagnostics/logger.js';
15
+ import type { ServerLocale } from '../../locale/server-locale.js';
15
16
  import type { ProjectChangeEvent } from '../project/project-change-event.js';
16
17
  import type { ProjectManager } from '../project/project-manager.js';
17
18
  import type { ServerSharedServicesMinimal } from '../shared-services.js';
@@ -92,6 +93,18 @@ export function installOperationCancelledSuppression(logger: Logger): void {
92
93
  });
93
94
  }
94
95
 
96
+ /** Options for {@link HydraniumWorkspaceManager}. */
97
+ export interface HydraniumWorkspaceManagerOptions extends LogNameOptions {
98
+ /**
99
+ * Whether startup warns about seeded documents the bound
100
+ * `FileSystemProvider` cannot serve (see
101
+ * {@link HydraniumWorkspaceManager.warnIfDocumentsUnserved}). Defaults to
102
+ * `true`; turn it off for a host that drops such documents at their last
103
+ * close on purpose.
104
+ */
105
+ warnUnservedDocuments?: boolean;
106
+ }
107
+
95
108
  /**
96
109
  * Framework {@link DefaultWorkspaceManager} subclass that integrates the
97
110
  * project tier with Langium's workspace startup.
@@ -124,8 +137,8 @@ export function installOperationCancelledSuppression(logger: Logger): void {
124
137
  * URIs (its own members plus any transitive dependents per the
125
138
  * `getAffectedProjects` hook). This manager re-runs
126
139
  * `DocumentBuilder.resetToState(doc, DocumentState.Changed)` on each
127
- * affected document so the next build cycle re-links them with the new
128
- * visibility scope.
140
+ * affected document so the build of the update that changed the descriptor
141
+ * re-links them with the new visibility scope.
129
142
  *
130
143
  * Descriptor URIs that triggered the cycle are intentionally excluded
131
144
  * from the affected set by `AbstractProjectManager.onBuildUpdate` —
@@ -156,19 +169,27 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
156
169
  readonly workspaceInitialized: Promise<unknown> = this.workspaceInitializedDeferred.promise;
157
170
 
158
171
  protected readonly uriPolicy: DocumentUriPolicy;
172
+ /** Handed the client's locale at init; read by whoever renders in it. */
173
+ protected readonly serverLocale: ServerLocale;
159
174
  protected readonly writableFileSystemProvider: WritableFileSystemProvider;
160
175
  protected readonly additionalDocuments: Record<string, AdditionalDocumentContribution>;
161
176
  /** Registry consulted by {@link warnIfUnroutable} to check a seeded document routes. */
162
177
  protected readonly languageRegistry: ServerSharedServicesMinimal['ServiceRegistry'];
178
+ /** Whether startup runs {@link warnIfDocumentsUnserved}. */
179
+ protected readonly warnUnservedDocuments: boolean;
180
+ /** URIs of the documents the running startup's file traversal loaded; see {@link loadWorkspaceDocuments}. */
181
+ protected readonly traversedUris = new Set<string>();
163
182
 
164
- constructor(services: ServerSharedServicesMinimal, options: LogNameOptions = {}) {
183
+ constructor(services: ServerSharedServicesMinimal, options: HydraniumWorkspaceManagerOptions = {}) {
165
184
  super(services);
166
185
  this.projectManager = services.workspace.ProjectManager;
167
186
  this.projectManager.onProjectsChanged(event => this.onProjectsChanged(event));
168
187
  this.uriPolicy = services.workspace.DocumentUriPolicy;
188
+ this.serverLocale = services.ServerLocale;
169
189
  this.writableFileSystemProvider = services.workspace.FileSystemProvider;
170
190
  this.additionalDocuments = services.additionalDocuments;
171
191
  this.languageRegistry = services.ServiceRegistry;
192
+ this.warnUnservedDocuments = options.warnUnservedDocuments ?? true;
172
193
  this.tracer = services.Tracer.for(options.logName ?? 'WorkspaceManager').trace('instantiated');
173
194
  installOperationCancelledSuppression(this.tracer);
174
195
  }
@@ -197,16 +218,16 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
197
218
  // seeded. `tags` is read at the done-emit, so the document count pushed
198
219
  // inside the callback appears in the log line.
199
220
  const tags: string[] = [`${contributions.length} contributions`];
200
- let documentCount = 0;
221
+ const seeded: LangiumDocument[] = [];
201
222
  await this.tracer.time(
202
223
  'Load additional documents',
203
224
  async () => {
204
225
  await collectAdditionalDocuments(this.additionalDocuments, folders, document => {
205
- documentCount++;
226
+ seeded.push(document);
206
227
  this.warnIfUnroutable(document);
207
228
  collector(document);
208
229
  });
209
- tags.push(`${documentCount} documents`);
230
+ tags.push(`${seeded.length} documents`);
210
231
  },
211
232
  'info',
212
233
  { logAfterMs: 0, tags }
@@ -268,11 +289,86 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
268
289
  discovered.push(document);
269
290
  }
270
291
  }
271
- const documents = await super.performStartup(folders);
292
+ this.traversedUris.clear();
293
+ let documents: LangiumDocument[];
294
+ try {
295
+ documents = await super.performStartup(folders);
296
+ if (this.warnUnservedDocuments) {
297
+ await this.warnIfDocumentsUnserved(documents.filter(document => !this.traversedUris.has(document.uri.toString())));
298
+ }
299
+ } finally {
300
+ this.traversedUris.clear();
301
+ }
272
302
  this.probePathDivergence(folders);
273
303
  return this.withDiscoveredDescriptors(documents, discovered);
274
304
  }
275
305
 
306
+ /**
307
+ * Record each document the file traversal loads, so startup can tell them
308
+ * from the documents `loadAdditionalDocuments` seeded, through the
309
+ * `additionalDocuments` group or an override of its own.
310
+ *
311
+ * The traversal found each of its documents through the provider, so asking
312
+ * it again whether they exist costs one call per workspace file and cannot
313
+ * come out false. Telling them apart by scheme does not work either: the
314
+ * registry's host answers every scheme no other provider claims, a seeded
315
+ * scheme nobody serves included. An override that loads documents without
316
+ * delegating here leaves them unrecorded, so startup asks the provider
317
+ * about each of them.
318
+ */
319
+ protected override async loadWorkspaceDocuments(uris: Stream<URI>, collector: (document: LangiumDocument) => void): Promise<void> {
320
+ await super.loadWorkspaceDocuments(uris, document => {
321
+ this.traversedUris.add(document.uri.toString());
322
+ collector(document);
323
+ });
324
+ }
325
+
326
+ /**
327
+ * Warn once when the bound `FileSystemProvider` cannot serve a seeded
328
+ * document, naming each such document's scheme.
329
+ *
330
+ * The last close keeps a document only if the provider says it `exists`, so
331
+ * each such document leaves the workspace the first time an editor closes
332
+ * it, and whatever resolved against it breaks. The framework's registry
333
+ * serves `virtual:` through the `fileSystemProviders` group and every other
334
+ * scheme through its host, which knows nothing of a scheme an adopter
335
+ * invented for its seeded documents, and nothing else reports the loss. A
336
+ * provider that throws counts as not serving the document, since a startup
337
+ * that failed on a diagnostic would be worse than the loss.
338
+ *
339
+ * Runs over every document startup collected outside the file traversal,
340
+ * which is what `loadAdditionalDocuments` seeded, through the
341
+ * `additionalDocuments` group or an override of that method, once startup
342
+ * has added them to the workspace, unless `warnUnservedDocuments` is
343
+ * `false`.
344
+ */
345
+ protected async warnIfDocumentsUnserved(documents: readonly LangiumDocument[]): Promise<void> {
346
+ const unserved: URI[] = [];
347
+ for (const document of documents) {
348
+ let served = false;
349
+ try {
350
+ served = await this.writableFileSystemProvider.exists(document.uri);
351
+ } catch {
352
+ // Counted as unserved, below.
353
+ }
354
+ if (!served) {
355
+ unserved.push(document.uri);
356
+ }
357
+ }
358
+ if (unserved.length === 0) {
359
+ return;
360
+ }
361
+ const schemes = [...new Set(unserved.map(uri => uri.scheme))];
362
+ const named = unserved.slice(0, 3).map(uri => uri.toString());
363
+ this.tracer.warn(
364
+ `${unserved.length} seeded document(s) under ${schemes.map(scheme => `${scheme}:`).join(', ')} cannot be served by the bound workspace.FileSystemProvider ` +
365
+ `(${named.join(', ')}${unserved.length > 3 ? ', …' : ''}), so each leaves the workspace at its ` +
366
+ `last close. Register a provider under the key ${schemes.map(scheme => `'${scheme}'`).join(', ')} in the shared ` +
367
+ 'fileSystemProviders group, or serve the scheme from the host provider; set warnUnservedDocuments: false ' +
368
+ 'to accept the loss.'
369
+ );
370
+ }
371
+
276
372
  /**
277
373
  * Add back the documents project discovery created that Langium's file
278
374
  * traversal then filtered out.
@@ -360,6 +456,31 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
360
456
  }
361
457
  }
362
458
 
459
+ /**
460
+ * Forward the locale the client declared, then Langium's own read of the
461
+ * params. `DefaultWorkspaceManager.initialize` reads `workspaceFolders`
462
+ * alone, so `params.locale` would otherwise be discarded — and this is the
463
+ * only place it arrives, which the headless init seams route through too.
464
+ *
465
+ * **The ABSENT case is reported from here rather than from `ServerLocale`,
466
+ * because this is the only end that can see it.** `accept` is not called
467
+ * when no locale was declared — nor should it be, since `''` is a claim
468
+ * about a language rather than the absence of one — so a log written there
469
+ * covers one of the two outcomes and leaves the other looking like a server
470
+ * that never reached init. Both lines are at `info` for the reason `accept`
471
+ * gives: the framework ships no catalogue, so an undeclared locale and an
472
+ * untranslated code produce the same English and the log is what separates
473
+ * them.
474
+ */
475
+ override initialize(params: InitializeParams): void {
476
+ if (params.locale) {
477
+ this.serverLocale.accept(params.locale);
478
+ } else {
479
+ this.tracer.info("no locale declared at init — rendering messages in the framework's English");
480
+ }
481
+ super.initialize(params);
482
+ }
483
+
363
484
  /**
364
485
  * Override of Langium's workspace setup to resolve / reject
365
486
  * {@link workspaceInitializedDeferred} once setup completes. Adopters with
@@ -380,9 +501,9 @@ export class HydraniumWorkspaceManager extends DefaultWorkspaceManager {
380
501
 
381
502
  /**
382
503
  * Default cascade-rebuild handler. Iterates {@link ProjectChangeEvent.affectedDocuments}
383
- * and resets each to {@link DocumentState.Changed} so the next build cycle
384
- * re-runs the pipeline (parse → link → validate) under the new project
385
- * visibility scope.
504
+ * and resets each to {@link DocumentState.Changed} so the build of the update
505
+ * that changed the descriptor re-runs the pipeline (parse → link → validate)
506
+ * under the new project visibility scope.
386
507
  *
387
508
  * Subclasses can override for additional behaviour (e.g. logging,
388
509
  * telemetry, custom rebuild policies); call `super` to preserve the
@@ -8,11 +8,40 @@
8
8
  ********************************************************************************/
9
9
 
10
10
  import { type FileSystemNode, URI } from '@hydranium/langium';
11
- import { type Tracer } from '@hydranium/protocol';
11
+ import { defineMessage, type Tracer } from '@hydranium/protocol';
12
12
  import { type WritableFileSystemProvider } from '../../documents/ast-document-manager.js';
13
13
  import { type LogNameOptions } from '../diagnostics/logger.js';
14
14
  import { serverSharedFactory, type ServerSharedServicesMinimal } from '../shared-services.js';
15
- import { serveVirtualDocument } from './virtual-document.js';
15
+ import { notFound } from './file-not-found.js';
16
+
17
+ /**
18
+ * A provider's spelling of "the document is not there", raised wherever a read
19
+ * finds no content — this filesystem, or a URI naming no location a disk-backed
20
+ * provider can reach. Distinct from `NO_LOADABLE_CONTENT`, which the URI policy
21
+ * raises when it can settle the question AHEAD of the read; a provider with no
22
+ * `realpath` cannot, so the miss surfaces here instead.
23
+ */
24
+ export const NO_SUCH_FILE = defineMessage('hydranium/core/no-such-file', 'No such file: {uri}');
25
+
26
+ /** The same for a node of any kind, so it also covers a directory. */
27
+ export const NO_SUCH_PATH = defineMessage('hydranium/core/no-such-path', 'No such file or directory: {uri}');
28
+
29
+ /**
30
+ * A write addressed a URI the provider cannot reach on disk.
31
+ *
32
+ * Deliberately not a not-found code: {@link NO_SUCH_FILE} reports something
33
+ * missing, which a caller may reasonably answer by creating it — exactly the
34
+ * wrong reading here. The destination is not missing; the URI names no disk
35
+ * location at all, and no retry makes it one.
36
+ *
37
+ * Declared here rather than beside the Node provider that raises it, so the
38
+ * message catalog stays reachable from the portable `.` entry — the Node
39
+ * module pulls `node:fs` and is server-only.
40
+ */
41
+ export const UNSUPPORTED_WRITE = defineMessage(
42
+ 'hydranium/core/unsupported-write',
43
+ 'Cannot write {uri}: the scheme names no location on disk'
44
+ );
16
45
 
17
46
  /**
18
47
  * File content keyed by path, for seeding an {@link InMemoryFileSystemProvider}.
@@ -116,32 +145,34 @@ export class InMemoryFileSystemProvider implements WritableFileSystemProvider {
116
145
  this.setFile(uri, content);
117
146
  }
118
147
 
119
- readFile(uri: URI): Promise<string> {
120
- return Promise.resolve(this.readFileSync(uri));
148
+ // `async` on each read whose sync twin can throw, rather than
149
+ // `Promise.resolve(this.<x>Sync(uri))`. That form evaluates the sync call
150
+ // FIRST, so a miss throws before `Promise.resolve` is ever reached — and a
151
+ // synchronous throw escapes the promise chain: `.catch()` never attaches and
152
+ // `Promise.all` dies while its argument array is still being built, so a
153
+ // caller reading several URIs cannot handle the miss it asked about.
154
+ async readFile(uri: URI): Promise<string> {
155
+ return this.readFileSync(uri);
121
156
  }
122
157
 
123
158
  readFileSync(uri: URI): string {
124
- const served = serveVirtualDocument(this.services, uri);
125
- if (served !== undefined) {
126
- return served;
127
- }
128
159
  const content = this.files.get(normalize(uri));
129
160
  if (content === undefined) {
130
- throw new Error(`No such file: ${uri.toString()}`);
161
+ throw notFound(NO_SUCH_FILE.format({ uri: uri.toString() }), uri);
131
162
  }
132
163
  return content;
133
164
  }
134
165
 
135
- readBinary(uri: URI): Promise<Uint8Array> {
136
- return Promise.resolve(this.readBinarySync(uri));
166
+ async readBinary(uri: URI): Promise<Uint8Array> {
167
+ return this.readBinarySync(uri);
137
168
  }
138
169
 
139
170
  readBinarySync(uri: URI): Uint8Array {
140
171
  return new TextEncoder().encode(this.readFileSync(uri));
141
172
  }
142
173
 
143
- stat(uri: URI): Promise<FileSystemNode> {
144
- return Promise.resolve(this.statSync(uri));
174
+ async stat(uri: URI): Promise<FileSystemNode> {
175
+ return this.statSync(uri);
145
176
  }
146
177
 
147
178
  statSync(uri: URI): FileSystemNode {
@@ -152,7 +183,7 @@ export class InMemoryFileSystemProvider implements WritableFileSystemProvider {
152
183
  if (this.hasChildren(path)) {
153
184
  return { isFile: false, isDirectory: true, uri };
154
185
  }
155
- throw new Error(`No such file or directory: ${uri.toString()}`);
186
+ throw notFound(NO_SUCH_PATH.format({ uri: uri.toString() }), uri);
156
187
  }
157
188
 
158
189
  exists(uri: URI): Promise<boolean> {
@@ -229,8 +260,8 @@ function normalize(uri: URI | string): string {
229
260
  * services context exactly where a Node host spreads `NodeFileSystem`.
230
261
  *
231
262
  * A host that needs to reach the provider afterwards — to seed or mutate it
232
- * mid-test — reads it back off `shared.workspace.FileSystemProvider`, since the
233
- * slot owns construction.
263
+ * mid-test — narrows `shared.workspace.FileSystemProvider.host` to this
264
+ * class, since the slot owns construction.
234
265
  */
235
266
  export function inMemoryFileSystem(options: InMemoryFileSystemOptions = {}): {
236
267
  fileSystemProvider: (services: unknown) => WritableFileSystemProvider;