@hydranium/core 1.0.0-next.19 → 1.0.0-next.193

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 (588) hide show
  1. package/README.md +6 -2
  2. package/lib/documents/ast-document-manager.d.ts +222 -63
  3. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  4. package/lib/documents/ast-document-manager.js +250 -83
  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 +523 -101
  23. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  24. package/lib/documents/hydranium-text-documents.js +961 -177
  25. package/lib/documents/hydranium-text-documents.js.map +1 -1
  26. package/lib/documents/index.d.ts +5 -0
  27. package/lib/documents/index.d.ts.map +1 -1
  28. package/lib/documents/index.js +5 -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/model-ledger.d.ts +47 -0
  35. package/lib/documents/model-ledger.d.ts.map +1 -0
  36. package/lib/documents/model-ledger.js +30 -0
  37. package/lib/documents/model-ledger.js.map +1 -0
  38. package/lib/documents/self-save-registry.d.ts +37 -6
  39. package/lib/documents/self-save-registry.d.ts.map +1 -1
  40. package/lib/documents/self-save-registry.js +28 -15
  41. package/lib/documents/self-save-registry.js.map +1 -1
  42. package/lib/documents/version-sync-service.d.ts +134 -0
  43. package/lib/documents/version-sync-service.d.ts.map +1 -0
  44. package/lib/documents/version-sync-service.js +171 -0
  45. package/lib/documents/version-sync-service.js.map +1 -0
  46. package/lib/index.d.ts +3 -0
  47. package/lib/index.d.ts.map +1 -1
  48. package/lib/index.js +6 -0
  49. package/lib/index.js.map +1 -1
  50. package/lib/langium/ast-extension/ast-extension-service.d.ts.map +1 -1
  51. package/lib/langium/ast-extension/ast-extension-service.js.map +1 -1
  52. package/lib/langium/ast-extension/ast-node-builder.d.ts +32 -9
  53. package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
  54. package/lib/langium/ast-extension/ast-node-builder.js +60 -22
  55. package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
  56. package/lib/langium/bootstrap.d.ts.map +1 -1
  57. package/lib/langium/bootstrap.js +32 -9
  58. package/lib/langium/bootstrap.js.map +1 -1
  59. package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts.map +1 -1
  60. package/lib/langium/build-phase-pass/build-phase-pass-service.js.map +1 -1
  61. package/lib/langium/config/configuration-provider.d.ts +81 -0
  62. package/lib/langium/config/configuration-provider.d.ts.map +1 -0
  63. package/lib/langium/config/configuration-provider.js +112 -0
  64. package/lib/langium/config/configuration-provider.js.map +1 -0
  65. package/lib/langium/config/index.d.ts +1 -0
  66. package/lib/langium/config/index.d.ts.map +1 -1
  67. package/lib/langium/config/index.js +1 -0
  68. package/lib/langium/config/index.js.map +1 -1
  69. package/lib/langium/config/settings.js.map +1 -1
  70. package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts.map +1 -1
  71. package/lib/langium/diagnostics/hydranium-langium-profiler.js.map +1 -1
  72. package/lib/langium/diagnostics/logger.d.ts +10 -3
  73. package/lib/langium/diagnostics/logger.d.ts.map +1 -1
  74. package/lib/langium/diagnostics/logger.js +12 -5
  75. package/lib/langium/diagnostics/logger.js.map +1 -1
  76. package/lib/langium/diagnostics/lsp-logger.d.ts +17 -0
  77. package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
  78. package/lib/langium/diagnostics/lsp-logger.js +56 -13
  79. package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
  80. package/lib/langium/diagnostics/server-tracer.d.ts.map +1 -1
  81. package/lib/langium/diagnostics/server-tracer.js.map +1 -1
  82. package/lib/langium/document-builder/build-pipeline-integration.d.ts +21 -1
  83. package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
  84. package/lib/langium/document-builder/build-pipeline-integration.js +32 -5
  85. package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
  86. package/lib/langium/document-builder/build-session.d.ts +93 -0
  87. package/lib/langium/document-builder/build-session.d.ts.map +1 -0
  88. package/lib/langium/document-builder/build-session.js +72 -0
  89. package/lib/langium/document-builder/build-session.js.map +1 -0
  90. package/lib/langium/document-builder/document-builder.d.ts +382 -29
  91. package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
  92. package/lib/langium/document-builder/document-builder.js +659 -61
  93. package/lib/langium/document-builder/document-builder.js.map +1 -1
  94. package/lib/langium/document-builder/index.d.ts +1 -0
  95. package/lib/langium/document-builder/index.d.ts.map +1 -1
  96. package/lib/langium/document-builder/index.js +1 -0
  97. package/lib/langium/document-builder/index.js.map +1 -1
  98. package/lib/langium/documentation/comment-provider.d.ts.map +1 -1
  99. package/lib/langium/documentation/comment-provider.js.map +1 -1
  100. package/lib/langium/integration-services.d.ts +45 -1
  101. package/lib/langium/integration-services.d.ts.map +1 -1
  102. package/lib/langium/integration-services.js +10 -5
  103. package/lib/langium/integration-services.js.map +1 -1
  104. package/lib/langium/integrity/integrity-rule.d.ts +13 -5
  105. package/lib/langium/integrity/integrity-rule.d.ts.map +1 -1
  106. package/lib/langium/integrity/integrity-rule.js.map +1 -1
  107. package/lib/langium/integrity/integrity-service.d.ts +58 -13
  108. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  109. package/lib/langium/integrity/integrity-service.js +204 -29
  110. package/lib/langium/integrity/integrity-service.js.map +1 -1
  111. package/lib/langium/keys/containment.d.ts +64 -0
  112. package/lib/langium/keys/containment.d.ts.map +1 -0
  113. package/lib/langium/keys/containment.js +53 -0
  114. package/lib/langium/keys/containment.js.map +1 -0
  115. package/lib/langium/keys/index.d.ts +1 -0
  116. package/lib/langium/keys/index.d.ts.map +1 -1
  117. package/lib/langium/keys/index.js +1 -0
  118. package/lib/langium/keys/index.js.map +1 -1
  119. package/lib/langium/keys/name-based-key-provider.d.ts +4 -0
  120. package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
  121. package/lib/langium/keys/name-based-key-provider.js +4 -0
  122. package/lib/langium/keys/name-based-key-provider.js.map +1 -1
  123. package/lib/langium/keys/positional-key-provider.d.ts.map +1 -1
  124. package/lib/langium/keys/positional-key-provider.js.map +1 -1
  125. package/lib/langium/labeling/label-provider.d.ts.map +1 -1
  126. package/lib/langium/labeling/label-provider.js.map +1 -1
  127. package/lib/langium/language-module.d.ts +27 -2
  128. package/lib/langium/language-module.d.ts.map +1 -1
  129. package/lib/langium/language-module.js +16 -2
  130. package/lib/langium/language-module.js.map +1 -1
  131. package/lib/langium/model-service/client-session.d.ts +330 -0
  132. package/lib/langium/model-service/client-session.d.ts.map +1 -0
  133. package/lib/langium/model-service/client-session.js +418 -0
  134. package/lib/langium/model-service/client-session.js.map +1 -0
  135. package/lib/langium/model-service/index.d.ts +1 -0
  136. package/lib/langium/model-service/index.d.ts.map +1 -1
  137. package/lib/langium/model-service/index.js +1 -0
  138. package/lib/langium/model-service/index.js.map +1 -1
  139. package/lib/langium/model-service/model-service.d.ts +353 -253
  140. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  141. package/lib/langium/model-service/model-service.js +361 -408
  142. package/lib/langium/model-service/model-service.js.map +1 -1
  143. package/lib/langium/module.d.ts +150 -35
  144. package/lib/langium/module.d.ts.map +1 -1
  145. package/lib/langium/module.js +50 -35
  146. package/lib/langium/module.js.map +1 -1
  147. package/lib/langium/naming/name-provider.d.ts +25 -4
  148. package/lib/langium/naming/name-provider.d.ts.map +1 -1
  149. package/lib/langium/naming/name-provider.js +2 -1
  150. package/lib/langium/naming/name-provider.js.map +1 -1
  151. package/lib/langium/naming/name-separator-validation.d.ts +23 -0
  152. package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
  153. package/lib/langium/naming/name-separator-validation.js +30 -1
  154. package/lib/langium/naming/name-separator-validation.js.map +1 -1
  155. package/lib/langium/project/abstract-project-manager.d.ts.map +1 -1
  156. package/lib/langium/project/abstract-project-manager.js +9 -2
  157. package/lib/langium/project/abstract-project-manager.js.map +1 -1
  158. package/lib/langium/project/project-change-event.d.ts +2 -2
  159. package/lib/langium/project/single-project-manager.d.ts.map +1 -1
  160. package/lib/langium/project/single-project-manager.js.map +1 -1
  161. package/lib/langium/residency/cst-residency-service.d.ts +31 -11
  162. package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
  163. package/lib/langium/residency/cst-residency-service.js +23 -57
  164. package/lib/langium/residency/cst-residency-service.js.map +1 -1
  165. package/lib/langium/scope/ast-node-description-provider.d.ts.map +1 -1
  166. package/lib/langium/scope/ast-node-description-provider.js.map +1 -1
  167. package/lib/langium/scope/hydranium-scope-computation.d.ts.map +1 -1
  168. package/lib/langium/scope/hydranium-scope-computation.js.map +1 -1
  169. package/lib/langium/scope/hydranium-scope-provider.d.ts +48 -13
  170. package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
  171. package/lib/langium/scope/hydranium-scope-provider.js +56 -20
  172. package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
  173. package/lib/langium/scope/reference-builder.d.ts.map +1 -1
  174. package/lib/langium/scope/reference-builder.js.map +1 -1
  175. package/lib/langium/scope/reference-candidate-provider.d.ts.map +1 -1
  176. package/lib/langium/scope/reference-candidate-provider.js.map +1 -1
  177. package/lib/langium/scope/scope-extension-service.d.ts.map +1 -1
  178. package/lib/langium/scope/scope-extension-service.js.map +1 -1
  179. package/lib/langium/serialization/abstract-serializer.d.ts +11 -20
  180. package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
  181. package/lib/langium/serialization/abstract-serializer.js +12 -21
  182. package/lib/langium/serialization/abstract-serializer.js.map +1 -1
  183. package/lib/langium/serialization/json-serializer.d.ts +1 -1
  184. package/lib/langium/serialization/json-serializer.d.ts.map +1 -1
  185. package/lib/langium/serialization/json-serializer.js.map +1 -1
  186. package/lib/langium/serialization/yaml-serializer.d.ts.map +1 -1
  187. package/lib/langium/serialization/yaml-serializer.js.map +1 -1
  188. package/lib/langium/service-registry.d.ts +15 -1
  189. package/lib/langium/service-registry.d.ts.map +1 -1
  190. package/lib/langium/service-registry.js +16 -0
  191. package/lib/langium/service-registry.js.map +1 -1
  192. package/lib/langium/shared-services.d.ts +21 -4
  193. package/lib/langium/shared-services.d.ts.map +1 -1
  194. package/lib/langium/shared-services.js.map +1 -1
  195. package/lib/langium/transfer/transfer-encoder.d.ts +75 -23
  196. package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
  197. package/lib/langium/transfer/transfer-encoder.js +44 -21
  198. package/lib/langium/transfer/transfer-encoder.js.map +1 -1
  199. package/lib/langium/trivia/comment-preserver.d.ts +423 -0
  200. package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
  201. package/lib/langium/trivia/comment-preserver.js +906 -0
  202. package/lib/langium/trivia/comment-preserver.js.map +1 -0
  203. package/lib/langium/trivia/document-ending-preserver.d.ts +43 -0
  204. package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
  205. package/lib/langium/trivia/document-ending-preserver.js +48 -0
  206. package/lib/langium/trivia/document-ending-preserver.js.map +1 -0
  207. package/lib/langium/trivia/index.d.ts +14 -0
  208. package/lib/langium/trivia/index.d.ts.map +1 -0
  209. package/lib/langium/trivia/index.js +14 -0
  210. package/lib/langium/trivia/index.js.map +1 -0
  211. package/lib/langium/trivia/trivia-contribution.d.ts +37 -0
  212. package/lib/langium/trivia/trivia-contribution.d.ts.map +1 -0
  213. package/lib/langium/trivia/trivia-contribution.js +10 -0
  214. package/lib/langium/trivia/trivia-contribution.js.map +1 -0
  215. package/lib/langium/trivia/trivia-preserver.d.ts +50 -0
  216. package/lib/langium/trivia/trivia-preserver.d.ts.map +1 -0
  217. package/lib/langium/trivia/trivia-preserver.js +10 -0
  218. package/lib/langium/trivia/trivia-preserver.js.map +1 -0
  219. package/lib/langium/trivia/trivia-service.d.ts +70 -0
  220. package/lib/langium/trivia/trivia-service.d.ts.map +1 -0
  221. package/lib/langium/trivia/trivia-service.js +56 -0
  222. package/lib/langium/trivia/trivia-service.js.map +1 -0
  223. package/lib/langium/update-rewrite/normalize-empty-strings.d.ts.map +1 -1
  224. package/lib/langium/update-rewrite/update-rewrite-service.d.ts.map +1 -1
  225. package/lib/langium/update-rewrite/update-rewrite-service.js.map +1 -1
  226. package/lib/langium/update-rewrite/update-rewrite.d.ts +1 -1
  227. package/lib/langium/validation/document-validator.d.ts +294 -10
  228. package/lib/langium/validation/document-validator.d.ts.map +1 -1
  229. package/lib/langium/validation/document-validator.js +448 -5
  230. package/lib/langium/validation/document-validator.js.map +1 -1
  231. package/lib/langium/validation/validation-contribution-collector.d.ts.map +1 -1
  232. package/lib/langium/validation/validation-contribution-collector.js.map +1 -1
  233. package/lib/langium/workspace/document-uri-policy.d.ts +17 -12
  234. package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
  235. package/lib/langium/workspace/document-uri-policy.js +10 -9
  236. package/lib/langium/workspace/document-uri-policy.js.map +1 -1
  237. package/lib/langium/workspace/file-not-found.d.ts +17 -0
  238. package/lib/langium/workspace/file-not-found.d.ts.map +1 -0
  239. package/lib/langium/workspace/file-not-found.js +20 -0
  240. package/lib/langium/workspace/file-not-found.js.map +1 -0
  241. package/lib/langium/workspace/file-system-provider.d.ts +84 -8
  242. package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
  243. package/lib/langium/workspace/file-system-provider.js +93 -14
  244. package/lib/langium/workspace/file-system-provider.js.map +1 -1
  245. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +56 -1
  246. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
  247. package/lib/langium/workspace/hydranium-langium-document-factory.js +79 -0
  248. package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
  249. package/lib/langium/workspace/hydranium-workspace-lock.d.ts +43 -1
  250. package/lib/langium/workspace/hydranium-workspace-lock.d.ts.map +1 -1
  251. package/lib/langium/workspace/hydranium-workspace-lock.js +58 -1
  252. package/lib/langium/workspace/hydranium-workspace-lock.js.map +1 -1
  253. package/lib/langium/workspace/hydranium-workspace-manager.d.ts +81 -8
  254. package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
  255. package/lib/langium/workspace/hydranium-workspace-manager.js +128 -10
  256. package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
  257. package/lib/langium/workspace/in-memory-file-system-provider.d.ts +25 -2
  258. package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
  259. package/lib/langium/workspace/in-memory-file-system-provider.js +41 -15
  260. package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
  261. package/lib/langium/workspace/index-manager.d.ts.map +1 -1
  262. package/lib/langium/workspace/index-manager.js.map +1 -1
  263. package/lib/langium/workspace/initialize-workspace.d.ts +31 -2
  264. package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
  265. package/lib/langium/workspace/initialize-workspace.js +13 -5
  266. package/lib/langium/workspace/initialize-workspace.js.map +1 -1
  267. package/lib/langium/workspace/langium-documents.d.ts +86 -17
  268. package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
  269. package/lib/langium/workspace/langium-documents.js +101 -29
  270. package/lib/langium/workspace/langium-documents.js.map +1 -1
  271. package/lib/langium/workspace/persistent-file-system-provider.d.ts +0 -7
  272. package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
  273. package/lib/langium/workspace/persistent-file-system-provider.js +0 -7
  274. package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
  275. package/lib/langium/workspace/virtual-document.d.ts +48 -15
  276. package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
  277. package/lib/langium/workspace/virtual-document.js +78 -18
  278. package/lib/langium/workspace/virtual-document.js.map +1 -1
  279. package/lib/langium/workspace/write-lock-scope.d.ts +20 -10
  280. package/lib/langium/workspace/write-lock-scope.d.ts.map +1 -1
  281. package/lib/langium/workspace/write-lock-scope.js +12 -4
  282. package/lib/langium/workspace/write-lock-scope.js.map +1 -1
  283. package/lib/locale/index.d.ts +10 -0
  284. package/lib/locale/index.d.ts.map +1 -0
  285. package/lib/locale/index.js +10 -0
  286. package/lib/locale/index.js.map +1 -0
  287. package/lib/locale/server-locale.d.ts +73 -0
  288. package/lib/locale/server-locale.d.ts.map +1 -0
  289. package/lib/locale/server-locale.js +61 -0
  290. package/lib/locale/server-locale.js.map +1 -0
  291. package/lib/lsp/completion/hydranium-completion-provider.d.ts +44 -2
  292. package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
  293. package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
  294. package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
  295. package/lib/lsp/connection-features.d.ts +23 -0
  296. package/lib/lsp/connection-features.d.ts.map +1 -0
  297. package/lib/lsp/connection-features.js +60 -0
  298. package/lib/lsp/connection-features.js.map +1 -0
  299. package/lib/lsp/diagnostics-connection.d.ts +27 -0
  300. package/lib/lsp/diagnostics-connection.d.ts.map +1 -0
  301. package/lib/lsp/diagnostics-connection.js +53 -0
  302. package/lib/lsp/diagnostics-connection.js.map +1 -0
  303. package/lib/lsp/hydranium-document-update-handler.d.ts +90 -79
  304. package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
  305. package/lib/lsp/hydranium-document-update-handler.js +153 -99
  306. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  307. package/lib/lsp/index.d.ts +3 -1
  308. package/lib/lsp/index.d.ts.map +1 -1
  309. package/lib/lsp/index.js +3 -1
  310. package/lib/lsp/index.js.map +1 -1
  311. package/lib/lsp/lsp-latency.d.ts +39 -0
  312. package/lib/lsp/lsp-latency.d.ts.map +1 -0
  313. package/lib/lsp/lsp-latency.js +58 -0
  314. package/lib/lsp/lsp-latency.js.map +1 -0
  315. package/lib/lsp/semantic-token-provider.d.ts +34 -1
  316. package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
  317. package/lib/lsp/semantic-token-provider.js +55 -8
  318. package/lib/lsp/semantic-token-provider.js.map +1 -1
  319. package/lib/lsp/shared-module.d.ts +4 -8
  320. package/lib/lsp/shared-module.d.ts.map +1 -1
  321. package/lib/lsp/shared-module.js.map +1 -1
  322. package/lib/lsp/start-language-server.d.ts +8 -7
  323. package/lib/lsp/start-language-server.d.ts.map +1 -1
  324. package/lib/lsp/start-language-server.js +13 -7
  325. package/lib/lsp/start-language-server.js.map +1 -1
  326. package/lib/messages/carriers.d.ts +54 -0
  327. package/lib/messages/carriers.d.ts.map +1 -0
  328. package/lib/messages/carriers.js +62 -0
  329. package/lib/messages/carriers.js.map +1 -0
  330. package/lib/messages/index.d.ts +25 -0
  331. package/lib/messages/index.d.ts.map +1 -0
  332. package/lib/messages/index.js +25 -0
  333. package/lib/messages/index.js.map +1 -0
  334. package/lib/messages/renderer.d.ts +142 -0
  335. package/lib/messages/renderer.d.ts.map +1 -0
  336. package/lib/messages/renderer.js +165 -0
  337. package/lib/messages/renderer.js.map +1 -0
  338. package/lib/node/event-loop-monitor.js.map +1 -1
  339. package/lib/node/heap-ceiling.d.ts +61 -0
  340. package/lib/node/heap-ceiling.d.ts.map +1 -0
  341. package/lib/node/heap-ceiling.js +72 -0
  342. package/lib/node/heap-ceiling.js.map +1 -0
  343. package/lib/node/index.d.ts +1 -0
  344. package/lib/node/index.d.ts.map +1 -1
  345. package/lib/node/index.js +1 -0
  346. package/lib/node/index.js.map +1 -1
  347. package/lib/node/latency-from-env.d.ts +1 -1
  348. package/lib/node/latency-from-env.js +1 -1
  349. package/lib/node/lint-grammar.js.map +1 -1
  350. package/lib/node/measure-memory.d.ts.map +1 -1
  351. package/lib/node/measure-memory.js +1 -0
  352. package/lib/node/measure-memory.js.map +1 -1
  353. package/lib/node/memory-monitor.js.map +1 -1
  354. package/lib/node/node-file-system-provider.d.ts +39 -4
  355. package/lib/node/node-file-system-provider.d.ts.map +1 -1
  356. package/lib/node/node-file-system-provider.js +109 -49
  357. package/lib/node/node-file-system-provider.js.map +1 -1
  358. package/lib/node/process-memory.js.map +1 -1
  359. package/lib/node/profile-capture.d.ts +8 -2
  360. package/lib/node/profile-capture.d.ts.map +1 -1
  361. package/lib/node/profile-capture.js.map +1 -1
  362. package/lib/node/profile-digest.js.map +1 -1
  363. package/lib/node/profiling-run.d.ts +13 -3
  364. package/lib/node/profiling-run.d.ts.map +1 -1
  365. package/lib/node/profiling-run.js +17 -8
  366. package/lib/node/profiling-run.js.map +1 -1
  367. package/lib/node/rename-over-open-readers.d.ts +52 -0
  368. package/lib/node/rename-over-open-readers.d.ts.map +1 -0
  369. package/lib/node/rename-over-open-readers.js +66 -0
  370. package/lib/node/rename-over-open-readers.js.map +1 -0
  371. package/lib/node/socket-launcher.d.ts +16 -1
  372. package/lib/node/socket-launcher.d.ts.map +1 -1
  373. package/lib/node/socket-launcher.js +4 -3
  374. package/lib/node/socket-launcher.js.map +1 -1
  375. package/lib/node/stdio-launcher.d.ts +1 -1
  376. package/lib/node/stdio-launcher.d.ts.map +1 -1
  377. package/lib/node/stdio-launcher.js +1 -1
  378. package/lib/node/stdio-launcher.js.map +1 -1
  379. package/lib/testing/document-uri-policy-conformance.js.map +1 -1
  380. package/lib/testing/fake-description.js.map +1 -1
  381. package/lib/testing/fake-document.d.ts +16 -4
  382. package/lib/testing/fake-document.d.ts.map +1 -1
  383. package/lib/testing/fake-document.js +18 -3
  384. package/lib/testing/fake-document.js.map +1 -1
  385. package/lib/testing/index.d.ts +1 -1
  386. package/lib/testing/index.d.ts.map +1 -1
  387. package/lib/testing/index.js +2 -1
  388. package/lib/testing/index.js.map +1 -1
  389. package/lib/testing/langium-test-helpers.d.ts.map +1 -1
  390. package/lib/testing/langium-test-helpers.js +1 -0
  391. package/lib/testing/langium-test-helpers.js.map +1 -1
  392. package/lib/testing/make-noop-language-services.js.map +1 -1
  393. package/lib/testing/make-noop-shared-services.d.ts +14 -0
  394. package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
  395. package/lib/testing/make-noop-shared-services.js +28 -2
  396. package/lib/testing/make-noop-shared-services.js.map +1 -1
  397. package/lib/testing/make-test-services.d.ts +69 -14
  398. package/lib/testing/make-test-services.d.ts.map +1 -1
  399. package/lib/testing/make-test-services.js +39 -10
  400. package/lib/testing/make-test-services.js.map +1 -1
  401. package/lib/testing/make-test-tracer.js.map +1 -1
  402. package/lib/testing/node/golden-corpus.js.map +1 -1
  403. package/lib/testing/node/index.d.ts +1 -0
  404. package/lib/testing/node/index.d.ts.map +1 -1
  405. package/lib/testing/node/index.js +1 -0
  406. package/lib/testing/node/index.js.map +1 -1
  407. package/lib/testing/node/lsp-harness.d.ts.map +1 -1
  408. package/lib/testing/node/lsp-harness.js +2 -0
  409. package/lib/testing/node/lsp-harness.js.map +1 -1
  410. package/lib/testing/node/lsp-server-connection.d.ts +11 -3
  411. package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
  412. package/lib/testing/node/lsp-server-connection.js +42 -9
  413. package/lib/testing/node/lsp-server-connection.js.map +1 -1
  414. package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
  415. package/lib/testing/node/scratch-workspace.js +10 -5
  416. package/lib/testing/node/scratch-workspace.js.map +1 -1
  417. package/lib/testing/node/spawned-server.d.ts +14 -0
  418. package/lib/testing/node/spawned-server.d.ts.map +1 -1
  419. package/lib/testing/node/spawned-server.js +33 -1
  420. package/lib/testing/node/spawned-server.js.map +1 -1
  421. package/lib/testing/node/unhandled-rejections.d.ts +20 -0
  422. package/lib/testing/node/unhandled-rejections.d.ts.map +1 -0
  423. package/lib/testing/node/unhandled-rejections.js +32 -0
  424. package/lib/testing/node/unhandled-rejections.js.map +1 -0
  425. package/lib/testing/playwright/browser-capture-bridge.js.map +1 -1
  426. package/lib/testing/playwright/e2e-profiling.js.map +1 -1
  427. package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
  428. package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
  429. package/lib/testing/playwright/flaky-network-proxy.js +164 -0
  430. package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
  431. package/lib/testing/playwright/index.d.ts +1 -0
  432. package/lib/testing/playwright/index.d.ts.map +1 -1
  433. package/lib/testing/playwright/index.js +1 -0
  434. package/lib/testing/playwright/index.js.map +1 -1
  435. package/lib/testing/playwright/server-log-capture.d.ts +24 -8
  436. package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
  437. package/lib/testing/playwright/server-log-capture.js +27 -6
  438. package/lib/testing/playwright/server-log-capture.js.map +1 -1
  439. package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
  440. package/lib/testing/playwright/server-log-rename-reporter.js +10 -1
  441. package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
  442. package/lib/testing/run-update-pipeline.d.ts +4 -4
  443. package/lib/testing/run-update-pipeline.d.ts.map +1 -1
  444. package/lib/testing/stub-ast-document-manager.d.ts +11 -9
  445. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  446. package/lib/testing/stub-ast-document-manager.js +25 -9
  447. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  448. package/lib/testing/stub-document-builder.d.ts +26 -11
  449. package/lib/testing/stub-document-builder.d.ts.map +1 -1
  450. package/lib/testing/stub-document-builder.js +57 -4
  451. package/lib/testing/stub-document-builder.js.map +1 -1
  452. package/lib/testing/stub-hydranium-text-documents.d.ts +22 -7
  453. package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
  454. package/lib/testing/stub-hydranium-text-documents.js +97 -15
  455. package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
  456. package/lib/testing/stub-index-manager.js.map +1 -1
  457. package/lib/testing/stub-langium-documents.d.ts +3 -2
  458. package/lib/testing/stub-langium-documents.d.ts.map +1 -1
  459. package/lib/testing/stub-langium-documents.js.map +1 -1
  460. package/lib/testing/stub-model-service.d.ts +7 -6
  461. package/lib/testing/stub-model-service.d.ts.map +1 -1
  462. package/lib/testing/stub-model-service.js +4 -4
  463. package/lib/testing/stub-model-service.js.map +1 -1
  464. package/lib/testing/stub-project-manager.js.map +1 -1
  465. package/lib/testing/stub-service-registry.js.map +1 -1
  466. package/lib/util/connection-liveness.d.ts +7 -6
  467. package/lib/util/connection-liveness.d.ts.map +1 -1
  468. package/lib/util/connection-liveness.js +35 -14
  469. package/lib/util/connection-liveness.js.map +1 -1
  470. package/lib/util/environment.d.ts.map +1 -1
  471. package/lib/util/environment.js.map +1 -1
  472. package/lib/util/registry.d.ts.map +1 -1
  473. package/package.json +35 -26
  474. package/src/documents/ast-document-manager.ts +395 -126
  475. package/src/documents/client-ids.ts +5 -22
  476. package/src/documents/client-session-errors.ts +24 -0
  477. package/src/documents/client-session-registry.ts +240 -0
  478. package/src/documents/file-system-task-queue.ts +68 -0
  479. package/src/documents/hydranium-text-documents.ts +1175 -225
  480. package/src/documents/index.ts +5 -0
  481. package/src/documents/language-client-text-shadow.ts +59 -11
  482. package/src/documents/model-ledger.ts +66 -0
  483. package/src/documents/self-save-registry.ts +52 -13
  484. package/src/documents/version-sync-service.ts +267 -0
  485. package/src/index.ts +6 -0
  486. package/src/langium/ast-extension/ast-node-builder.ts +66 -22
  487. package/src/langium/bootstrap.ts +32 -9
  488. package/src/langium/config/configuration-provider.ts +119 -0
  489. package/src/langium/config/index.ts +1 -0
  490. package/src/langium/diagnostics/logger.ts +12 -5
  491. package/src/langium/diagnostics/lsp-logger.ts +58 -12
  492. package/src/langium/document-builder/build-pipeline-integration.ts +50 -5
  493. package/src/langium/document-builder/build-session.ts +87 -0
  494. package/src/langium/document-builder/document-builder.ts +776 -59
  495. package/src/langium/document-builder/index.ts +1 -0
  496. package/src/langium/integration-services.ts +67 -6
  497. package/src/langium/integrity/integrity-rule.ts +13 -5
  498. package/src/langium/integrity/integrity-service.ts +220 -30
  499. package/src/langium/keys/containment.ts +87 -0
  500. package/src/langium/keys/index.ts +1 -0
  501. package/src/langium/keys/name-based-key-provider.ts +4 -0
  502. package/src/langium/language-module.ts +42 -4
  503. package/src/langium/model-service/client-session.ts +649 -0
  504. package/src/langium/model-service/index.ts +1 -0
  505. package/src/langium/model-service/model-service.ts +570 -433
  506. package/src/langium/module.ts +201 -64
  507. package/src/langium/naming/name-provider.ts +27 -5
  508. package/src/langium/naming/name-separator-validation.ts +34 -5
  509. package/src/langium/project/abstract-project-manager.ts +9 -1
  510. package/src/langium/project/project-change-event.ts +2 -2
  511. package/src/langium/residency/cst-residency-service.ts +46 -15
  512. package/src/langium/scope/hydranium-scope-provider.ts +60 -22
  513. package/src/langium/serialization/abstract-serializer.ts +13 -32
  514. package/src/langium/service-registry.ts +19 -2
  515. package/src/langium/shared-services.ts +25 -4
  516. package/src/langium/transfer/transfer-encoder.ts +102 -34
  517. package/src/langium/trivia/comment-preserver.ts +1100 -0
  518. package/src/langium/trivia/document-ending-preserver.ts +55 -0
  519. package/src/langium/trivia/index.ts +14 -0
  520. package/src/langium/trivia/trivia-contribution.ts +39 -0
  521. package/src/langium/trivia/trivia-preserver.ts +54 -0
  522. package/src/langium/trivia/trivia-service.ts +99 -0
  523. package/src/langium/update-rewrite/update-rewrite.ts +1 -1
  524. package/src/langium/validation/document-validator.ts +537 -11
  525. package/src/langium/workspace/document-uri-policy.ts +17 -12
  526. package/src/langium/workspace/file-not-found.ts +23 -0
  527. package/src/langium/workspace/file-system-provider.ts +153 -16
  528. package/src/langium/workspace/hydranium-langium-document-factory.ts +117 -0
  529. package/src/langium/workspace/hydranium-workspace-lock.ts +86 -2
  530. package/src/langium/workspace/hydranium-workspace-manager.ts +153 -13
  531. package/src/langium/workspace/in-memory-file-system-provider.ts +47 -16
  532. package/src/langium/workspace/initialize-workspace.ts +43 -5
  533. package/src/langium/workspace/langium-documents.ts +124 -33
  534. package/src/langium/workspace/persistent-file-system-provider.ts +0 -7
  535. package/src/langium/workspace/virtual-document.ts +96 -19
  536. package/src/langium/workspace/write-lock-scope.ts +24 -11
  537. package/src/locale/index.ts +10 -0
  538. package/src/locale/server-locale.ts +86 -0
  539. package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
  540. package/src/lsp/connection-features.ts +67 -0
  541. package/src/lsp/diagnostics-connection.ts +56 -0
  542. package/src/lsp/hydranium-document-update-handler.ts +185 -106
  543. package/src/lsp/index.ts +3 -1
  544. package/src/lsp/lsp-latency.ts +62 -0
  545. package/src/lsp/semantic-token-provider.ts +74 -7
  546. package/src/lsp/shared-module.ts +4 -8
  547. package/src/lsp/start-language-server.ts +13 -7
  548. package/src/messages/carriers.ts +78 -0
  549. package/src/messages/index.ts +36 -0
  550. package/src/messages/renderer.ts +212 -0
  551. package/src/node/heap-ceiling.ts +108 -0
  552. package/src/node/index.ts +1 -0
  553. package/src/node/latency-from-env.ts +1 -1
  554. package/src/node/measure-memory.ts +1 -0
  555. package/src/node/node-file-system-provider.ts +122 -51
  556. package/src/node/profile-capture.ts +8 -2
  557. package/src/node/profiling-run.ts +30 -8
  558. package/src/node/rename-over-open-readers.ts +78 -0
  559. package/src/node/socket-launcher.ts +19 -4
  560. package/src/node/stdio-launcher.ts +1 -2
  561. package/src/testing/fake-document.ts +24 -5
  562. package/src/testing/index.ts +2 -1
  563. package/src/testing/langium-test-helpers.ts +1 -0
  564. package/src/testing/make-noop-shared-services.ts +50 -2
  565. package/src/testing/make-test-services.ts +120 -31
  566. package/src/testing/node/index.ts +1 -0
  567. package/src/testing/node/lsp-harness.ts +2 -0
  568. package/src/testing/node/lsp-server-connection.ts +61 -11
  569. package/src/testing/node/scratch-workspace.ts +10 -5
  570. package/src/testing/node/spawned-server.ts +35 -1
  571. package/src/testing/node/unhandled-rejections.ts +31 -0
  572. package/src/testing/playwright/flaky-network-proxy.ts +240 -0
  573. package/src/testing/playwright/index.ts +1 -0
  574. package/src/testing/playwright/server-log-capture.ts +45 -11
  575. package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
  576. package/src/testing/run-update-pipeline.ts +4 -4
  577. package/src/testing/stub-ast-document-manager.ts +40 -23
  578. package/src/testing/stub-document-builder.ts +83 -17
  579. package/src/testing/stub-hydranium-text-documents.ts +133 -23
  580. package/src/testing/stub-langium-documents.ts +3 -2
  581. package/src/testing/stub-model-service.ts +9 -8
  582. package/src/util/connection-liveness.ts +37 -14
  583. package/src/util/environment.ts +9 -1
  584. package/lib/lsp/instrument-connection.d.ts +0 -36
  585. package/lib/lsp/instrument-connection.d.ts.map +0 -1
  586. package/lib/lsp/instrument-connection.js +0 -62
  587. package/lib/lsp/instrument-connection.js.map +0 -1
  588. package/src/lsp/instrument-connection.ts +0 -66
@@ -8,7 +8,12 @@
8
8
  ********************************************************************************/
9
9
 
10
10
  export * from './client-ids.js';
11
+ export * from './client-session-errors.js';
12
+ export * from './client-session-registry.js';
11
13
  export * from './language-client-text-shadow.js';
12
14
  export * from './hydranium-text-documents.js';
15
+ export * from './model-ledger.js';
16
+ export * from './version-sync-service.js';
13
17
  export * from './ast-document-manager.js';
14
18
  export * from './self-save-registry.js';
19
+ export * from './file-system-task-queue.js';
@@ -57,12 +57,23 @@ export function isFullReplace(edits: readonly TextEdit[]): boolean {
57
57
  * - {@link computeEdits} after each outgoing server→client sync (updates the shadow optimistically).
58
58
  * - {@link set} when the server receives a `didChange` from the language client (the client now
59
59
  * holds that text; we shouldn't resend it).
60
+ * - {@link setOpenedText} when the client opens a document the server did not baseline for it —
61
+ * an equality-only baseline, since that text is a snapshot rather than a tracked one.
60
62
  * - {@link invalidate} when the client rejects an edit (`applied=false`) or a doc is closed —
61
63
  * the shadow is now stale and the next sync must fall back to a full replace.
62
64
  */
63
65
  export class LanguageClientTextShadow {
64
66
  protected shadow = new Map<string, string>();
65
67
 
68
+ /**
69
+ * Per URI, the text the client declared it opened the document with, held
70
+ * only until a real baseline exists. Consulted by {@link computeEdits} when
71
+ * there is no shadow, and dropped on {@link invalidate}: a snapshot that
72
+ * outlived what the client holds would let the equality check skip an edit
73
+ * the client still needs.
74
+ */
75
+ protected opened = new Map<string, string>();
76
+
66
77
  /**
67
78
  * @param onFallback invoked when {@link computeEdits} falls back to a full-range replace due to
68
79
  * apply-verify mismatch. Useful for logging regressions.
@@ -85,23 +96,54 @@ export class LanguageClientTextShadow {
85
96
  }
86
97
 
87
98
  /**
88
- * The text the language client is believed to hold, or `undefined` when
89
- * there is no baseline (first sync, or after an {@link invalidate}).
99
+ * Record the buffer the language client declared at `didOpen`, for a URI
100
+ * with no baseline yet.
101
+ *
102
+ * Deliberately NOT a {@link set}: this text is only ever compared for
103
+ * EQUALITY, never diffed against. A line-keyed diff is position-dependent,
104
+ * so keying one to a `didOpen` snapshot the client may have moved past
105
+ * splices its buffer — the failure {@link computeEdits}'s full-replace
106
+ * fallback exists to avoid.
107
+ */
108
+ setOpenedText(uri: string, text: string): void {
109
+ this.opened.set(uri, text);
110
+ }
111
+
112
+ /**
113
+ * The text the language client is believed to hold: the tracked text, else
114
+ * the buffer it declared at `didOpen`.
90
115
  *
91
116
  * Read at the `workspace/applyEdit` egress BEFORE {@link computeEdits},
92
- * which overwrites it: a push's minimal edits are keyed to this text, so an
93
- * echo of that push carries ranges addressing it and nothing else. Losing
94
- * it is what makes an incremental echo unreconstructable, and applying such
95
- * an echo to the already-advanced synced text duplicates every inserted
96
- * line.
117
+ * which overwrites the tracked text and drops the opened snapshot. A change
118
+ * the client sends carries ranges addressing this text and nothing else, so
119
+ * losing it leaves that change unreconstructable — and applying its ranges
120
+ * to the already-advanced synced text splices lines they never addressed.
121
+ *
122
+ * Deliberately wider than what {@link computeEdits} may diff from: an
123
+ * opened snapshot is a position-dependent key to a buffer the client may
124
+ * have moved past, so keying a diff to it splices that buffer.
97
125
  */
98
- get(uri: string): string | undefined {
99
- return this.shadow.get(uri);
126
+ clientText(uri: string): string | undefined {
127
+ return this.shadow.get(uri) ?? this.opened.get(uri);
128
+ }
129
+
130
+ /**
131
+ * Whether a tracked text exists for `uri`, which is what decides whether a
132
+ * push can be diffed at all. Distinct from {@link clientText}, which also
133
+ * answers from the opened snapshot and so cannot settle this.
134
+ */
135
+ isTracked(uri: string): boolean {
136
+ return this.shadow.has(uri);
100
137
  }
101
138
 
102
139
  /** Forget the shadow for a URI; next {@link computeEdits} falls back to a full-document replace. */
103
140
  invalidate(uri: string): void {
104
141
  this.shadow.delete(uri);
142
+ // Drops the opened snapshot too, and this is the only place that has to:
143
+ // `computeEdits` clears it whenever it consults it, so the sole way it can
144
+ // outlive what the client holds is surviving under a live shadow until that
145
+ // shadow is dropped here.
146
+ this.opened.delete(uri);
105
147
  }
106
148
 
107
149
  /**
@@ -109,7 +151,9 @@ export class LanguageClientTextShadow {
109
151
  * the tracked shadow to `newText`. Updates the shadow to `newText` so subsequent calls diff
110
152
  * against it.
111
153
  *
112
- * - Empty array when the shadow already equals `newText` (caller should skip the RPC).
154
+ * - Empty array when the shadow already equals `newText` (caller should skip the RPC),
155
+ * or when there is no shadow and the client opened the document with exactly `newText`
156
+ * (see {@link setOpenedText}) — pushing it anyway dirties the client's buffer on open.
113
157
  * - Full-range replace when there is no shadow (first sync or post-{@link invalidate}).
114
158
  * - Line-level diff otherwise. Before returning, we locally reconstruct `newText` by applying
115
159
  * the diff to `old`; if that doesn't match, we fall back to a full-range replace and notify
@@ -124,7 +168,11 @@ export class LanguageClientTextShadow {
124
168
  this.shadow.set(uri, newText);
125
169
  const fullReplace: TextEdit = { range: FULL_RANGE, newText };
126
170
  if (old === undefined) {
127
- return [fullReplace];
171
+ // The opened snapshot has served its purpose either way: the shadow above
172
+ // is now the baseline, so leaving it would only risk a later stale match.
173
+ const openedText = this.opened.get(uri);
174
+ this.opened.delete(uri);
175
+ return openedText === newText ? [] : [fullReplace];
128
176
  }
129
177
  const edits = diffToEdits(old, newText);
130
178
  const verifyDoc = this.documents.create(uri, 'plaintext', 0, old);
@@ -0,0 +1,66 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 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 AstNode } from '@hydranium/langium';
11
+ import { asModelVersion, type ModelVersion, UNRECORDED_VERSION } from '@hydranium/protocol';
12
+
13
+ /** What {@link ModelLedger} holds for one root. */
14
+ export interface ModelRecord {
15
+ readonly version: ModelVersion;
16
+ /** For a root whose CST no longer is the text it describes: changed in place, or shed. */
17
+ readonly text?: string;
18
+ }
19
+
20
+ /**
21
+ * The version of the text each root was parsed from, and that text where the
22
+ * root's CST does not hold it. Stores what it is told; the rest of the
23
+ * framework relies on these:
24
+ *
25
+ * - every workspace root is recorded through `VersionSyncService.modelProduced` when produced;
26
+ * - a version is recorded only for text the store held at that version, else `STALE_VERSION`;
27
+ * - the builder's placeholder for a file it has not parsed carries no version;
28
+ * - re-recording a root without text keeps the text recorded before.
29
+ */
30
+ export interface ModelLedger {
31
+ record(root: AstNode, version: number, text?: string): void;
32
+ /** `UNRECORDED_VERSION`, which every write conflicts with, for a root nothing recorded. */
33
+ versionOf(root: AstNode): ModelVersion;
34
+ /** The recorded text, else the root's CST text; `undefined` for a root with neither. */
35
+ textOf(root: AstNode): string | undefined;
36
+ /** Mark `root`, registered before any parse, as no parse of any text, dropping its record. */
37
+ markPlaceholder(root: AstNode): void;
38
+ /** Keyed on the root, not its state: a rebuilt document is reset below `Parsed` but keeps its root. */
39
+ isPlaceholder(root: AstNode): boolean;
40
+ }
41
+
42
+ export class DefaultModelLedger implements ModelLedger {
43
+ protected readonly records = new WeakMap<AstNode, ModelRecord>();
44
+ protected readonly placeholders = new WeakSet<AstNode>();
45
+
46
+ record(root: AstNode, version: number, text?: string): void {
47
+ this.records.set(root, { version: asModelVersion(version), text: text ?? this.records.get(root)?.text });
48
+ }
49
+
50
+ versionOf(root: AstNode): ModelVersion {
51
+ return this.records.get(root)?.version ?? UNRECORDED_VERSION;
52
+ }
53
+
54
+ textOf(root: AstNode): string | undefined {
55
+ return this.records.get(root)?.text ?? root.$cstNode?.root.fullText;
56
+ }
57
+
58
+ markPlaceholder(root: AstNode): void {
59
+ this.placeholders.add(root);
60
+ this.records.delete(root);
61
+ }
62
+
63
+ isPlaceholder(root: AstNode): boolean {
64
+ return this.placeholders.has(root);
65
+ }
66
+ }
@@ -22,10 +22,32 @@ export interface SelfSaveRegistryOptions {
22
22
  /**
23
23
  * Tracks `mtime` of files written by the server itself so the echo
24
24
  * `didChangeWatchedFiles` event from the OS file watcher can be suppressed,
25
- * avoiding redundant rebuilds after each save. Entries are matched by mtime
26
- * (not by a time window) and expire after a TTL.
25
+ * avoiding redundant rebuilds after each save.
27
26
  */
28
- export class SelfSaveRegistry {
27
+ export interface SelfSaveRegistry {
28
+ /**
29
+ * Record a self-write, and drop any registration already past its TTL.
30
+ *
31
+ * Keyed by `fsPath` rather than URI string, because the two sides of a
32
+ * suppression see different URI forms for one file.
33
+ */
34
+ register(fsPath: string, mtimeMs: number): void;
35
+
36
+ /**
37
+ * Whether `fsPath` carries a live registration at exactly `mtimeMs`.
38
+ *
39
+ * A registration expires after the TTL, so a write recorded longer ago than
40
+ * that answers `false` — the caller's decision holds only while the echo it
41
+ * suppresses could still be in flight. A query never mutates the registry.
42
+ */
43
+ isRegistered(fsPath: string, mtimeMs: number): boolean;
44
+ }
45
+
46
+ /**
47
+ * Compares entries by mtime rather than by a time window, so the echo of a
48
+ * save whose content is unchanged is still recognised.
49
+ */
50
+ export class DefaultSelfSaveRegistry implements SelfSaveRegistry {
29
51
  protected readonly entries = new Map<string, { mtimeMs: number; registeredAt: number }>();
30
52
  /**
31
53
  * Read time through the shared {@link Clock} rather than `Date.now()`: the
@@ -59,23 +81,40 @@ export class SelfSaveRegistry {
59
81
  return isCaseInsensitiveFileSystem() ? fsPath.toLowerCase() : fsPath;
60
82
  }
61
83
 
62
- /** Record a self-write. Key by `fsPath` (not URI string) to avoid URI-form mismatches. */
63
84
  register(fsPath: string, mtimeMs: number): void {
85
+ this.evictExpired();
64
86
  this.entries.set(this.key(fsPath), { mtimeMs, registeredAt: this.clock.now() });
65
87
  }
66
88
 
67
- /** True if `mtimeMs` matches a recent self-write. Evicts stale entries. Not consumed on match. */
68
- matches(fsPath: string, mtimeMs: number): boolean {
69
- const key = this.key(fsPath);
70
- const entry = this.entries.get(key);
71
- if (!entry) {
72
- return false;
73
- }
74
- if (this.clock.now() - entry.registeredAt > this.ttlMs) {
75
- this.entries.delete(key);
89
+ isRegistered(fsPath: string, mtimeMs: number): boolean {
90
+ const entry = this.entries.get(this.key(fsPath));
91
+ if (!entry || this.isExpired(entry.registeredAt)) {
76
92
  return false;
77
93
  }
78
94
  // Accept mtime equality (some filesystems have 1-second precision).
79
95
  return entry.mtimeMs === mtimeMs;
80
96
  }
97
+
98
+ /**
99
+ * Drop every expired registration.
100
+ *
101
+ * On the WRITE path, so the query stays free of side effects. Evicting from
102
+ * the query instead reaches only the keys something happens to ask about,
103
+ * and a path written once and never queried again is then retained for the
104
+ * life of the process. Bounded by the paths self-written inside one TTL
105
+ * window, so the sweep is over a handful of entries and sits behind a file
106
+ * write either way.
107
+ */
108
+ protected evictExpired(): void {
109
+ for (const [key, entry] of this.entries) {
110
+ if (this.isExpired(entry.registeredAt)) {
111
+ this.entries.delete(key);
112
+ }
113
+ }
114
+ }
115
+
116
+ /** Strictly greater, so an entry aged exactly to the TTL is still eligible. */
117
+ protected isExpired(registeredAt: number): boolean {
118
+ return this.clock.now() - registeredAt > this.ttlMs;
119
+ }
81
120
  }
@@ -0,0 +1,267 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 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 { DocumentState, type LangiumDocument, type URI } from '@hydranium/langium';
11
+ import { type Tracer, UNRECORDED_VERSION } from '@hydranium/protocol';
12
+ import { Disposable, Emitter, type Event } from 'vscode-languageserver-protocol';
13
+ import { type LogNameOptions } from '../langium/diagnostics/logger.js';
14
+ import { type ServerSharedServices } from '../langium/module.js';
15
+ import { HydraniumWorkspaceLock } from '../langium/workspace/hydranium-workspace-lock.js';
16
+ import { HydraniumTextDocuments } from './hydranium-text-documents.js';
17
+
18
+ /** A build {@link VersionSyncService.requestRecoveryBuild} schedules. */
19
+ export interface RecoveryBuildRequest {
20
+ /** Remove the document instead of building it. */
21
+ readonly deleted?: boolean;
22
+ /** Staged for the build, as `HydraniumDocumentBuilder.scheduleUpdate` takes it. */
23
+ readonly reason?: string;
24
+ /** Asked again inside the lock, where a build that ran meanwhile may have made the request moot. */
25
+ readonly stillNeeded: () => boolean;
26
+ /** Build even while a {@link VersionSyncService.registerDeferredBuilds} check holds the URI back. */
27
+ readonly ignoreDeferred?: boolean;
28
+ }
29
+
30
+ /**
31
+ * Keeps each workspace root's `ModelLedger` record in step with the
32
+ * text store, and owns every build that syncs a root to its text or recovers
33
+ * one a build left behind.
34
+ */
35
+ export interface VersionSyncService {
36
+ /**
37
+ * Report a root a factory, registry, integrity repair or other producer
38
+ * made. Below `Parsed` it is marked a placeholder. Otherwise `origin.version`,
39
+ * the store's version read before the parse, is recorded; a registered
40
+ * document is then reconciled with the store, re-versioned and recorded at
41
+ * the store's version of its text, built if behind, and announced on
42
+ * {@link onDidRecordModel}. `origin.text` stands for a root whose CST is not
43
+ * the text it describes.
44
+ */
45
+ modelProduced(document: LangiumDocument, origin?: { version?: number; text?: string }): void;
46
+ /**
47
+ * Build `uri` from a `WorkspaceLock` read, so the build queues behind a
48
+ * running one rather than cancelling it. Requests made while one for `uri`
49
+ * is pending share its next build. Resolves `true` once a build that carried
50
+ * this request completed, or once a check before a build found it no longer
51
+ * needed or deferred. A build a later write cancelled does not count: the
52
+ * request rides the next one. Resolves `false` once builds carrying this
53
+ * request have failed more often than it may retry, so a caller waiting on
54
+ * the build can stop. Never rejects.
55
+ */
56
+ requestRecoveryBuild(uri: URI, request: RecoveryBuildRequest): Promise<boolean>;
57
+ /**
58
+ * Build `uri` unless it is {@link isSyncedTo synced to} `textVersion`, asked
59
+ * again inside the lock. `undefined` when no build is needed, else the
60
+ * {@link requestRecoveryBuild} answer.
61
+ */
62
+ syncTo(uri: URI, textVersion: number): Promise<boolean> | undefined;
63
+ /**
64
+ * Whether `uri`'s root was parsed from text at `textVersion` or later; requests
65
+ * nothing. A root with no recorded version or a placeholder counts as synced,
66
+ * since no build records a version for it, and so does a URI with no document.
67
+ */
68
+ isSyncedTo(uri: URI, textVersion: number): boolean;
69
+ /**
70
+ * Register `isDeferred`, which answers whether its caller holds back a build
71
+ * of a URI it will request later, as the update handler does for a debounced
72
+ * editor change. A caller that drops a held change has to leave the URI to
73
+ * another build.
74
+ */
75
+ registerDeferredBuilds(isDeferred: (uri: URI) => boolean): Disposable;
76
+ /**
77
+ * Fires for every reconciled root. A cancel cannot skip it, unlike a
78
+ * `Parsed` phase listener. It can fire inside a build's write lock, so a
79
+ * listener that requests a build must not await it.
80
+ */
81
+ readonly onDidRecordModel: Event<LangiumDocument>;
82
+ }
83
+
84
+ /** A request waiting in {@link PendingRecoveryBuilds}, with the failed builds that carried it. */
85
+ export interface QueuedRecoveryBuild {
86
+ readonly request: RecoveryBuildRequest;
87
+ failures: number;
88
+ readonly answer: (built: boolean) => void;
89
+ }
90
+
91
+ /** The requests waiting on one URI's builds in {@link DefaultVersionSyncService}. */
92
+ export interface PendingRecoveryBuilds {
93
+ readonly queued: QueuedRecoveryBuild[];
94
+ }
95
+
96
+ /**
97
+ * Collaborators are resolved per call: the registry and its document factory,
98
+ * which construct each other, report roots to this service.
99
+ */
100
+ export class DefaultVersionSyncService implements VersionSyncService {
101
+ protected readonly tracer: Tracer;
102
+ protected readonly recordedEmitter = new Emitter<LangiumDocument>();
103
+ protected readonly deferredBuildChecks = new Set<(uri: URI) => boolean>();
104
+ protected readonly pendingBuilds = new Map<string, PendingRecoveryBuilds>();
105
+ /** Retries of each request after a failed build before it is answered `false`. */
106
+ protected readonly maxBuildRetries: number = 1;
107
+
108
+ constructor(
109
+ protected readonly services: ServerSharedServices,
110
+ options: LogNameOptions = {}
111
+ ) {
112
+ this.tracer = services.Tracer.for(options.logName ?? 'VersionSyncService').trace('instantiated');
113
+ }
114
+
115
+ get onDidRecordModel(): Event<LangiumDocument> {
116
+ return this.recordedEmitter.event;
117
+ }
118
+
119
+ modelProduced(document: LangiumDocument, origin: { version?: number; text?: string } = {}): void {
120
+ const workspace = this.services.workspace;
121
+ const ledger = workspace.ModelLedger;
122
+ const root = document.parseResult.value;
123
+ if (document.state < DocumentState.Parsed) {
124
+ ledger.markPlaceholder(root);
125
+ return;
126
+ }
127
+ if (origin.version !== undefined) {
128
+ ledger.record(root, origin.version, origin.text);
129
+ }
130
+ const store = workspace.TextDocuments;
131
+ // Unregistered, it is a probe or a load whose registration reports it again.
132
+ if (!(store instanceof HydraniumTextDocuments) || workspace.LangiumDocuments.getDocument(document.uri) !== document) {
133
+ return;
134
+ }
135
+ const uri = document.uri.toString();
136
+ // Against the parsed text: the text document may already hold a newer edit.
137
+ const version = store.reconcileExternalContent(uri, origin.text ?? this.parsedText(document));
138
+ if (version !== undefined) {
139
+ if (document.textDocument.version !== version) {
140
+ // An empty-changes update only re-stamps the version.
141
+ store.update(document.textDocument, [], version);
142
+ }
143
+ ledger.record(root, version, origin.text);
144
+ }
145
+ void this.syncTo(document.uri, store.version(uri));
146
+ this.recordedEmitter.fire(document);
147
+ }
148
+
149
+ syncTo(uri: URI, textVersion: number): Promise<boolean> | undefined {
150
+ const behind = (): boolean => !this.isSyncedTo(uri, textVersion);
151
+ return behind() ? this.requestRecoveryBuild(uri, { stillNeeded: behind }) : undefined;
152
+ }
153
+
154
+ requestRecoveryBuild(uri: URI, request: RecoveryBuildRequest): Promise<boolean> {
155
+ return new Promise<boolean>(answer => {
156
+ const key = uri.toString();
157
+ const queued: QueuedRecoveryBuild = { request, failures: 0, answer };
158
+ const pending = this.pendingBuilds.get(key);
159
+ if (pending) {
160
+ // Not dropped: the pending build may have read the text before this request's change.
161
+ pending.queued.push(queued);
162
+ return;
163
+ }
164
+ const entry: PendingRecoveryBuilds = { queued: [queued] };
165
+ this.pendingBuilds.set(key, entry);
166
+ void this.runBuilds(key, uri, entry);
167
+ });
168
+ }
169
+
170
+ registerDeferredBuilds(isDeferred: (uri: URI) => boolean): Disposable {
171
+ this.deferredBuildChecks.add(isDeferred);
172
+ return Disposable.create(() => this.deferredBuildChecks.delete(isDeferred));
173
+ }
174
+
175
+ isSyncedTo(uri: URI, textVersion: number): boolean {
176
+ const root = this.services.workspace.LangiumDocuments.getDocument(uri)?.parseResult.value;
177
+ if (root === undefined) {
178
+ return true;
179
+ }
180
+ const ledger = this.services.workspace.ModelLedger;
181
+ const recorded = ledger.versionOf(root);
182
+ return recorded === UNRECORDED_VERSION || ledger.isPlaceholder(root) || recorded >= textVersion;
183
+ }
184
+
185
+ /** The text `document`'s root was parsed from, or for a root built without either record or CST, the document's own. */
186
+ protected parsedText(document: LangiumDocument): string {
187
+ return this.services.workspace.ModelLedger.textOf(document.parseResult.value) ?? document.textDocument.getText();
188
+ }
189
+
190
+ /**
191
+ * Run `entry`'s requests, one build per batch, until none is queued, and
192
+ * answer each. A request a failed build carried is queued again
193
+ * {@link maxBuildRetries} times, then answered `false`; one a cancelled
194
+ * build carried is queued again without counting. The entry is dropped
195
+ * in the same tick as the last check of the queue, so no request lands in
196
+ * an entry nothing runs any more.
197
+ */
198
+ protected async runBuilds(key: string, uri: URI, entry: PendingRecoveryBuilds): Promise<void> {
199
+ const tracer = this.tracer.withUri(key);
200
+ const lock = this.services.workspace.WorkspaceLock;
201
+ // Any other lock resolves a cancelled write as if it had completed, unnoticed.
202
+ const counting = lock instanceof HydraniumWorkspaceLock ? lock : undefined;
203
+ while (entry.queued.length > 0) {
204
+ let carried: QueuedRecoveryBuild[] = [];
205
+ let build: Promise<void> | undefined;
206
+ let cancellations: number | undefined;
207
+ try {
208
+ // The read waits until no write runs or is queued. It must not await
209
+ // the build, a write that queues behind it.
210
+ await lock.read(() => {
211
+ carried = entry.queued.splice(0);
212
+ const needed = carried.filter(queued => this.isStillNeeded(uri, queued.request));
213
+ carried.filter(queued => !needed.includes(queued)).forEach(queued => queued.answer(true));
214
+ carried = needed;
215
+ if (needed.length > 0) {
216
+ build = this.scheduleBatch(
217
+ uri,
218
+ needed.map(queued => queued.request)
219
+ );
220
+ // Read after the build is queued, which cancels the write before it.
221
+ cancellations = counting?.writeCancellations;
222
+ }
223
+ });
224
+ await build;
225
+ // A write cancelled the build, before it ran or while it did.
226
+ if (cancellations !== undefined && counting?.writeCancellations !== cancellations) {
227
+ entry.queued.unshift(...carried);
228
+ continue;
229
+ }
230
+ carried.forEach(queued => queued.answer(true));
231
+ } catch (err: unknown) {
232
+ const detail = err instanceof Error ? (err.stack ?? err.message) : String(err);
233
+ const retried = carried.filter(queued => queued.failures++ < this.maxBuildRetries);
234
+ const givenUp = carried.filter(queued => !retried.includes(queued));
235
+ if (retried.length > 0) {
236
+ tracer.warn(`Requested build failed; retrying. ${detail}`);
237
+ entry.queued.unshift(...retried);
238
+ }
239
+ if (givenUp.length > 0) {
240
+ tracer.error(`Requested build failed again; giving up. ${detail}`);
241
+ givenUp.forEach(queued => queued.answer(false));
242
+ }
243
+ }
244
+ }
245
+ this.pendingBuilds.delete(key);
246
+ }
247
+
248
+ /** Whether `request` still needs its build, and no deferral it heeds holds it back. Runs inside the lock read. */
249
+ protected isStillNeeded(uri: URI, request: RecoveryBuildRequest): boolean {
250
+ return request.stillNeeded() && (request.ignoreDeferred === true || !this.isDeferred(uri));
251
+ }
252
+
253
+ /**
254
+ * One build for every request of `batch`, removing the document when the
255
+ * latest of them asks to, as `HydraniumDocumentBuilder.scheduleUpdate`
256
+ * merges a change and a deletion. Runs inside the lock read.
257
+ */
258
+ protected scheduleBatch(uri: URI, batch: readonly RecoveryBuildRequest[]): Promise<void> {
259
+ const deleted = batch.at(-1)?.deleted === true;
260
+ const reason = batch.find(request => request.reason !== undefined)?.reason;
261
+ return this.services.workspace.DocumentBuilder.scheduleUpdate(deleted ? [] : [uri], deleted ? [uri] : [], reason);
262
+ }
263
+
264
+ protected isDeferred(uri: URI): boolean {
265
+ return [...this.deferredBuildChecks].some(isDeferred => isDeferred(uri));
266
+ }
267
+ }
package/src/index.ts CHANGED
@@ -28,6 +28,7 @@ export * from './langium/project/index.js';
28
28
  export * from './langium/residency/index.js';
29
29
  export * from './langium/scope/index.js';
30
30
  export * from './langium/serialization/index.js';
31
+ export * from './langium/trivia/index.js';
31
32
  export * from './langium/transfer/index.js';
32
33
  export * from './langium/update-rewrite/index.js';
33
34
  export * from './langium/validation/index.js';
@@ -35,5 +36,10 @@ export * from './langium/workspace/index.js';
35
36
  export * from './langium/service-registry.js';
36
37
  export * from './langium/language-types.js';
37
38
  export * from './launcher/index.js';
39
+ export * from './locale/index.js';
40
+ // The renderer only. The `./messages` subpath additionally enumerates this
41
+ // package's own declarations, which the root barrel already re-exports through
42
+ // the modules that raise them.
43
+ export * from './messages/renderer.js';
38
44
  export * from './documents/index.js';
39
45
  export * from './util/index.js';
@@ -78,15 +78,13 @@ export type AstNodeBuilder<TMap> = <TType extends string & keyof TMap>(
78
78
  * AST-interface mapping, so call sites get full inference from the type
79
79
  * constant alone — no explicit generic parameter at every call site.
80
80
  *
81
- * Runtime behaviour: reads `reflection.getTypeMetaData(type).properties` and,
82
- * for every property whose metadata carries a `defaultValue`, pre-fills the
83
- * result before merging the caller's `init`. Array defaults are materialised
84
- * as a fresh `[]` per call (never shared with the metadata's array instance,
85
- * which downstream callers mutate); scalar defaults (`false`, `0`, `''`, …)
86
- * are copied as-is since they're immutable. Grammar-generated containment
87
- * lists and `?=`-style boolean flags therefore default automatically;
88
- * TS-augmented fields (declared via `declare module './generated/ast.js'`)
89
- * are unaffected by the runtime defaulting but remain typed at call sites.
81
+ * Runtime behaviour: pre-fills every grammar-declared default (see
82
+ * {@link withTypeDefaults}) before merging the caller's `init`, so containment
83
+ * lists and `?=`-style boolean flags default automatically. TS-augmented fields
84
+ * (declared via `declare module './generated/ast.js'`) are unaffected by the
85
+ * runtime defaulting but remain typed at call sites.
86
+ *
87
+ * Use {@link buildAstNode} instead when the type name is only known at runtime.
90
88
  *
91
89
  * The init shape only relaxes array-typed fields to optional (via
92
90
  * {@link ArrayKeys}) — there is no equivalent structural signal for "this
@@ -101,19 +99,7 @@ export function makeAstNodeBuilder<TMap>(reflection: AstReflection): AstNodeBuil
101
99
  init: AstNodeInit<Extract<TMap[TType], AstNode>>,
102
100
  extras?: Record<string, unknown>
103
101
  ): Extract<TMap[TType], AstNode> {
104
- const meta = reflection.getTypeMetaData(typeConstant.$type);
105
- const result: Record<string, unknown> = { $type: typeConstant.$type };
106
- if (meta?.properties) {
107
- for (const [propName, propInfo] of Object.entries(meta.properties)) {
108
- const defaultValue = propInfo.defaultValue;
109
- if (defaultValue === undefined) {
110
- continue;
111
- }
112
- // Arrays are duplicated so each node carries its own mutable instance;
113
- // scalars are immutable and safe to copy by reference.
114
- result[propName] = Array.isArray(defaultValue) ? [...defaultValue] : defaultValue;
115
- }
116
- }
102
+ const result = withTypeDefaults(reflection, typeConstant.$type);
117
103
  Object.assign(result, init);
118
104
  if (extras) {
119
105
  // Extras win over init: this is the explicit escape hatch, so when a
@@ -123,3 +109,61 @@ export function makeAstNodeBuilder<TMap>(reflection: AstReflection): AstNodeBuil
123
109
  return result as unknown as Extract<TMap[TType], AstNode>;
124
110
  };
125
111
  }
112
+
113
+ /**
114
+ * Build a node whose type is only known as a RUNTIME string.
115
+ *
116
+ * The typed {@link makeAstNodeBuilder} cannot express this: its `TMap` generic
117
+ * resolves the AST interface from a `$type` literal, and a type name that
118
+ * arrives over the wire — a protocol-layer reference request naming a node that
119
+ * does not exist yet — has no literal to resolve from. Callers that DO know the
120
+ * type at compile time want the typed builder, which checks their mandatory
121
+ * fields; this one checks nothing beyond the reflection lookup.
122
+ *
123
+ * Applies the same reflection-driven defaulting, so a node built here carries
124
+ * grammar-declared containment arrays rather than leaving them `undefined`. An
125
+ * unknown type name yields a node with `$type` and whatever `init` supplied,
126
+ * because reflection answers no metadata for it and refusing would turn a
127
+ * permissive lookup into a throw at a call site that can only guess.
128
+ *
129
+ * **The `type` argument is authoritative: `init` cannot rebind `$type`.** The
130
+ * typed builder gets this for free — `AstNodeInit` omits `$type`, so a call site
131
+ * cannot reach it — but here `init` is loosely typed, and the case that needs
132
+ * the guarantee is RETYPING: a caller spreading an existing node to produce one
133
+ * of a different type (`{ ...source }`) carries the SOURCE's `$type` in, which
134
+ * would silently win over the type actually requested and hand back a node of
135
+ * the wrong type with no error anywhere.
136
+ */
137
+ export function buildAstNode<TAst extends AstNode = AstNode>(
138
+ reflection: AstReflection,
139
+ type: string,
140
+ init?: Partial<AstNode> & Record<string, unknown>
141
+ ): TAst {
142
+ const result = withTypeDefaults(reflection, type);
143
+ if (init) {
144
+ Object.assign(result, init);
145
+ result.$type = type;
146
+ }
147
+ return result as unknown as TAst;
148
+ }
149
+
150
+ /**
151
+ * Seed a node with `$type` plus every property the grammar declares a default
152
+ * for. Array defaults are materialised as a fresh `[]` per call — never shared
153
+ * with the metadata's own array instance, which downstream callers mutate —
154
+ * while scalar defaults are copied as-is since they are immutable.
155
+ */
156
+ function withTypeDefaults(reflection: AstReflection, type: string): Record<string, unknown> {
157
+ const result: Record<string, unknown> = { $type: type };
158
+ const meta = reflection.getTypeMetaData(type);
159
+ if (meta?.properties) {
160
+ for (const [propName, propInfo] of Object.entries(meta.properties)) {
161
+ const defaultValue = propInfo.defaultValue;
162
+ if (defaultValue === undefined) {
163
+ continue;
164
+ }
165
+ result[propName] = Array.isArray(defaultValue) ? [...defaultValue] : defaultValue;
166
+ }
167
+ }
168
+ return result;
169
+ }