@hydranium/core 1.0.0-next.6 → 1.0.0-next.61

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 (262) hide show
  1. package/lib/documents/ast-document-manager.d.ts +42 -5
  2. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  3. package/lib/documents/ast-document-manager.js +18 -13
  4. package/lib/documents/ast-document-manager.js.map +1 -1
  5. package/lib/documents/hydranium-text-documents.d.ts +42 -17
  6. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  7. package/lib/documents/hydranium-text-documents.js +118 -39
  8. package/lib/documents/hydranium-text-documents.js.map +1 -1
  9. package/lib/documents/language-client-text-shadow.d.ts +41 -9
  10. package/lib/documents/language-client-text-shadow.d.ts.map +1 -1
  11. package/lib/documents/language-client-text-shadow.js +56 -11
  12. package/lib/documents/language-client-text-shadow.js.map +1 -1
  13. package/lib/documents/self-save-registry.d.ts +37 -6
  14. package/lib/documents/self-save-registry.d.ts.map +1 -1
  15. package/lib/documents/self-save-registry.js +28 -15
  16. package/lib/documents/self-save-registry.js.map +1 -1
  17. package/lib/index.d.ts +2 -0
  18. package/lib/index.d.ts.map +1 -1
  19. package/lib/index.js +5 -0
  20. package/lib/index.js.map +1 -1
  21. package/lib/langium/ast-extension/ast-node-builder.d.ts +32 -9
  22. package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
  23. package/lib/langium/ast-extension/ast-node-builder.js +60 -22
  24. package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
  25. package/lib/langium/bootstrap.d.ts.map +1 -1
  26. package/lib/langium/bootstrap.js +16 -9
  27. package/lib/langium/bootstrap.js.map +1 -1
  28. package/lib/langium/config/configuration-provider.d.ts +61 -0
  29. package/lib/langium/config/configuration-provider.d.ts.map +1 -0
  30. package/lib/langium/config/configuration-provider.js +89 -0
  31. package/lib/langium/config/configuration-provider.js.map +1 -0
  32. package/lib/langium/config/index.d.ts +1 -0
  33. package/lib/langium/config/index.d.ts.map +1 -1
  34. package/lib/langium/config/index.js +1 -0
  35. package/lib/langium/config/index.js.map +1 -1
  36. package/lib/langium/diagnostics/lsp-logger.d.ts +17 -0
  37. package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
  38. package/lib/langium/diagnostics/lsp-logger.js +40 -6
  39. package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
  40. package/lib/langium/document-builder/build-pipeline-integration.d.ts +13 -1
  41. package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
  42. package/lib/langium/document-builder/build-pipeline-integration.js +1 -1
  43. package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
  44. package/lib/langium/document-builder/build-session.d.ts +93 -0
  45. package/lib/langium/document-builder/build-session.d.ts.map +1 -0
  46. package/lib/langium/document-builder/build-session.js +72 -0
  47. package/lib/langium/document-builder/build-session.js.map +1 -0
  48. package/lib/langium/document-builder/document-builder.d.ts +150 -7
  49. package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
  50. package/lib/langium/document-builder/document-builder.js +298 -11
  51. package/lib/langium/document-builder/document-builder.js.map +1 -1
  52. package/lib/langium/document-builder/index.d.ts +1 -0
  53. package/lib/langium/document-builder/index.d.ts.map +1 -1
  54. package/lib/langium/document-builder/index.js +1 -0
  55. package/lib/langium/document-builder/index.js.map +1 -1
  56. package/lib/langium/integration-services.d.ts +45 -1
  57. package/lib/langium/integration-services.d.ts.map +1 -1
  58. package/lib/langium/integration-services.js +10 -5
  59. package/lib/langium/integration-services.js.map +1 -1
  60. package/lib/langium/integrity/integrity-service.d.ts +5 -0
  61. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  62. package/lib/langium/integrity/integrity-service.js +34 -1
  63. package/lib/langium/integrity/integrity-service.js.map +1 -1
  64. package/lib/langium/keys/containment.d.ts +64 -0
  65. package/lib/langium/keys/containment.d.ts.map +1 -0
  66. package/lib/langium/keys/containment.js +53 -0
  67. package/lib/langium/keys/containment.js.map +1 -0
  68. package/lib/langium/keys/index.d.ts +1 -0
  69. package/lib/langium/keys/index.d.ts.map +1 -1
  70. package/lib/langium/keys/index.js +1 -0
  71. package/lib/langium/keys/index.js.map +1 -1
  72. package/lib/langium/keys/name-based-key-provider.d.ts +4 -0
  73. package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
  74. package/lib/langium/keys/name-based-key-provider.js +4 -0
  75. package/lib/langium/keys/name-based-key-provider.js.map +1 -1
  76. package/lib/langium/model-service/model-service.d.ts +103 -7
  77. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  78. package/lib/langium/model-service/model-service.js +70 -89
  79. package/lib/langium/model-service/model-service.js.map +1 -1
  80. package/lib/langium/module.d.ts +82 -13
  81. package/lib/langium/module.d.ts.map +1 -1
  82. package/lib/langium/module.js +26 -12
  83. package/lib/langium/module.js.map +1 -1
  84. package/lib/langium/naming/name-provider.d.ts +10 -0
  85. package/lib/langium/naming/name-provider.d.ts.map +1 -1
  86. package/lib/langium/naming/name-provider.js.map +1 -1
  87. package/lib/langium/naming/name-separator-validation.d.ts +23 -0
  88. package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
  89. package/lib/langium/naming/name-separator-validation.js +30 -1
  90. package/lib/langium/naming/name-separator-validation.js.map +1 -1
  91. package/lib/langium/residency/cst-residency-service.d.ts +31 -9
  92. package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
  93. package/lib/langium/residency/cst-residency-service.js +13 -56
  94. package/lib/langium/residency/cst-residency-service.js.map +1 -1
  95. package/lib/langium/scope/hydranium-scope-provider.d.ts +32 -13
  96. package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
  97. package/lib/langium/scope/hydranium-scope-provider.js +37 -20
  98. package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
  99. package/lib/langium/shared-services.d.ts +15 -2
  100. package/lib/langium/shared-services.d.ts.map +1 -1
  101. package/lib/langium/shared-services.js.map +1 -1
  102. package/lib/langium/transfer/transfer-encoder.d.ts +33 -2
  103. package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
  104. package/lib/langium/transfer/transfer-encoder.js +14 -3
  105. package/lib/langium/transfer/transfer-encoder.js.map +1 -1
  106. package/lib/langium/validation/document-validator.d.ts +145 -6
  107. package/lib/langium/validation/document-validator.d.ts.map +1 -1
  108. package/lib/langium/validation/document-validator.js +211 -4
  109. package/lib/langium/validation/document-validator.js.map +1 -1
  110. package/lib/langium/workspace/document-uri-policy.d.ts +3 -4
  111. package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
  112. package/lib/langium/workspace/document-uri-policy.js +3 -4
  113. package/lib/langium/workspace/document-uri-policy.js.map +1 -1
  114. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +25 -0
  115. package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
  116. package/lib/langium/workspace/hydranium-langium-document-factory.js +25 -0
  117. package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
  118. package/lib/langium/workspace/hydranium-workspace-manager.d.ts +21 -1
  119. package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
  120. package/lib/langium/workspace/hydranium-workspace-manager.js +28 -0
  121. package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
  122. package/lib/langium/workspace/in-memory-file-system-provider.d.ts +8 -0
  123. package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
  124. package/lib/langium/workspace/in-memory-file-system-provider.js +11 -2
  125. package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
  126. package/lib/langium/workspace/initialize-workspace.d.ts +22 -2
  127. package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
  128. package/lib/langium/workspace/initialize-workspace.js +13 -5
  129. package/lib/langium/workspace/initialize-workspace.js.map +1 -1
  130. package/lib/langium/workspace/langium-documents.d.ts +79 -17
  131. package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
  132. package/lib/langium/workspace/langium-documents.js +83 -28
  133. package/lib/langium/workspace/langium-documents.js.map +1 -1
  134. package/lib/locale/index.d.ts +10 -0
  135. package/lib/locale/index.d.ts.map +1 -0
  136. package/lib/locale/index.js +10 -0
  137. package/lib/locale/index.js.map +1 -0
  138. package/lib/locale/server-locale.d.ts +73 -0
  139. package/lib/locale/server-locale.d.ts.map +1 -0
  140. package/lib/locale/server-locale.js +61 -0
  141. package/lib/locale/server-locale.js.map +1 -0
  142. package/lib/lsp/hydranium-document-update-handler.js +1 -1
  143. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  144. package/lib/messages/carriers.d.ts +54 -0
  145. package/lib/messages/carriers.d.ts.map +1 -0
  146. package/lib/messages/carriers.js +62 -0
  147. package/lib/messages/carriers.js.map +1 -0
  148. package/lib/messages/index.d.ts +25 -0
  149. package/lib/messages/index.d.ts.map +1 -0
  150. package/lib/messages/index.js +25 -0
  151. package/lib/messages/index.js.map +1 -0
  152. package/lib/messages/renderer.d.ts +136 -0
  153. package/lib/messages/renderer.d.ts.map +1 -0
  154. package/lib/messages/renderer.js +159 -0
  155. package/lib/messages/renderer.js.map +1 -0
  156. package/lib/node/node-file-system-provider.d.ts.map +1 -1
  157. package/lib/node/node-file-system-provider.js +1 -40
  158. package/lib/node/node-file-system-provider.js.map +1 -1
  159. package/lib/node/profiling-run.js +1 -1
  160. package/lib/node/profiling-run.js.map +1 -1
  161. package/lib/node/rename-over-open-readers.d.ts +52 -0
  162. package/lib/node/rename-over-open-readers.d.ts.map +1 -0
  163. package/lib/node/rename-over-open-readers.js +66 -0
  164. package/lib/node/rename-over-open-readers.js.map +1 -0
  165. package/lib/testing/fake-document.d.ts +14 -3
  166. package/lib/testing/fake-document.d.ts.map +1 -1
  167. package/lib/testing/fake-document.js +18 -3
  168. package/lib/testing/fake-document.js.map +1 -1
  169. package/lib/testing/make-noop-shared-services.d.ts +14 -0
  170. package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
  171. package/lib/testing/make-noop-shared-services.js +28 -2
  172. package/lib/testing/make-noop-shared-services.js.map +1 -1
  173. package/lib/testing/make-test-services.d.ts +31 -4
  174. package/lib/testing/make-test-services.d.ts.map +1 -1
  175. package/lib/testing/make-test-services.js +19 -3
  176. package/lib/testing/make-test-services.js.map +1 -1
  177. package/lib/testing/node/spawned-server.d.ts +14 -0
  178. package/lib/testing/node/spawned-server.d.ts.map +1 -1
  179. package/lib/testing/node/spawned-server.js +33 -1
  180. package/lib/testing/node/spawned-server.js.map +1 -1
  181. package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
  182. package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
  183. package/lib/testing/playwright/flaky-network-proxy.js +164 -0
  184. package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
  185. package/lib/testing/playwright/index.d.ts +1 -0
  186. package/lib/testing/playwright/index.d.ts.map +1 -1
  187. package/lib/testing/playwright/index.js +1 -0
  188. package/lib/testing/playwright/index.js.map +1 -1
  189. package/lib/testing/playwright/server-log-capture.d.ts +14 -4
  190. package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
  191. package/lib/testing/playwright/server-log-capture.js +21 -4
  192. package/lib/testing/playwright/server-log-capture.js.map +1 -1
  193. package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
  194. package/lib/testing/playwright/server-log-rename-reporter.js +10 -1
  195. package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
  196. package/lib/testing/stub-ast-document-manager.d.ts +3 -4
  197. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  198. package/lib/testing/stub-ast-document-manager.js +2 -5
  199. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  200. package/lib/testing/stub-document-builder.d.ts +8 -0
  201. package/lib/testing/stub-document-builder.d.ts.map +1 -1
  202. package/lib/testing/stub-document-builder.js +22 -3
  203. package/lib/testing/stub-document-builder.js.map +1 -1
  204. package/lib/testing/stub-model-service.d.ts +1 -1
  205. package/lib/testing/stub-model-service.d.ts.map +1 -1
  206. package/lib/testing/stub-model-service.js +2 -2
  207. package/lib/testing/stub-model-service.js.map +1 -1
  208. package/package.json +17 -8
  209. package/src/documents/ast-document-manager.ts +63 -15
  210. package/src/documents/hydranium-text-documents.ts +135 -54
  211. package/src/documents/language-client-text-shadow.ts +59 -11
  212. package/src/documents/self-save-registry.ts +52 -13
  213. package/src/index.ts +5 -0
  214. package/src/langium/ast-extension/ast-node-builder.ts +66 -22
  215. package/src/langium/bootstrap.ts +16 -9
  216. package/src/langium/config/configuration-provider.ts +96 -0
  217. package/src/langium/config/index.ts +1 -0
  218. package/src/langium/diagnostics/lsp-logger.ts +41 -6
  219. package/src/langium/document-builder/build-pipeline-integration.ts +14 -1
  220. package/src/langium/document-builder/build-session.ts +87 -0
  221. package/src/langium/document-builder/document-builder.ts +339 -11
  222. package/src/langium/document-builder/index.ts +1 -0
  223. package/src/langium/integration-services.ts +67 -6
  224. package/src/langium/integrity/integrity-service.ts +35 -1
  225. package/src/langium/keys/containment.ts +87 -0
  226. package/src/langium/keys/index.ts +1 -0
  227. package/src/langium/keys/name-based-key-provider.ts +4 -0
  228. package/src/langium/model-service/model-service.ts +145 -22
  229. package/src/langium/module.ts +104 -19
  230. package/src/langium/naming/name-provider.ts +10 -0
  231. package/src/langium/naming/name-separator-validation.ts +34 -5
  232. package/src/langium/residency/cst-residency-service.ts +36 -12
  233. package/src/langium/scope/hydranium-scope-provider.ts +40 -22
  234. package/src/langium/shared-services.ts +19 -2
  235. package/src/langium/transfer/transfer-encoder.ts +45 -3
  236. package/src/langium/validation/document-validator.ts +255 -8
  237. package/src/langium/workspace/document-uri-policy.ts +3 -4
  238. package/src/langium/workspace/hydranium-langium-document-factory.ts +34 -0
  239. package/src/langium/workspace/hydranium-workspace-manager.ts +30 -1
  240. package/src/langium/workspace/in-memory-file-system-provider.ts +13 -3
  241. package/src/langium/workspace/initialize-workspace.ts +34 -5
  242. package/src/langium/workspace/langium-documents.ts +106 -33
  243. package/src/locale/index.ts +10 -0
  244. package/src/locale/server-locale.ts +86 -0
  245. package/src/lsp/hydranium-document-update-handler.ts +1 -1
  246. package/src/messages/carriers.ts +78 -0
  247. package/src/messages/index.ts +27 -0
  248. package/src/messages/renderer.ts +204 -0
  249. package/src/node/node-file-system-provider.ts +1 -41
  250. package/src/node/profiling-run.ts +1 -1
  251. package/src/node/rename-over-open-readers.ts +78 -0
  252. package/src/testing/fake-document.ts +22 -4
  253. package/src/testing/make-noop-shared-services.ts +50 -2
  254. package/src/testing/make-test-services.ts +49 -7
  255. package/src/testing/node/spawned-server.ts +35 -1
  256. package/src/testing/playwright/flaky-network-proxy.ts +240 -0
  257. package/src/testing/playwright/index.ts +1 -0
  258. package/src/testing/playwright/server-log-capture.ts +24 -5
  259. package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
  260. package/src/testing/stub-ast-document-manager.ts +5 -10
  261. package/src/testing/stub-document-builder.ts +32 -3
  262. package/src/testing/stub-model-service.ts +2 -2
@@ -34,6 +34,7 @@ function reraise(result) {
34
34
  */
35
35
  export function makeStubDocumentBuilder() {
36
36
  const phaseListeners = new Map();
37
+ const buildPhaseListeners = new Map();
37
38
  const onUpdateListeners = [];
38
39
  const gates = [];
39
40
  const updateCalls = [];
@@ -95,6 +96,27 @@ export function makeStubDocumentBuilder() {
95
96
  reraise(listener(changed, deleted));
96
97
  }
97
98
  },
99
+ onBuildPhase(state, listener) {
100
+ const list = buildPhaseListeners.get(state) ?? [];
101
+ list.push(listener);
102
+ buildPhaseListeners.set(state, list);
103
+ return Disposable.create(() => {
104
+ const idx = list.indexOf(listener);
105
+ if (idx >= 0) {
106
+ list.splice(idx, 1);
107
+ }
108
+ });
109
+ },
110
+ fireBuildPhase(state, built, cancelToken) {
111
+ const token = cancelToken ??
112
+ {
113
+ isCancellationRequested: false,
114
+ onCancellationRequested: () => Disposable.create(() => undefined)
115
+ };
116
+ for (const listener of buildPhaseListeners.get(state) ?? []) {
117
+ reraise(listener(built, token));
118
+ }
119
+ },
98
120
  gateNextWaitUntil() {
99
121
  let release;
100
122
  const entry = {
@@ -123,9 +145,6 @@ export function makeStubDocumentBuilder() {
123
145
  build() {
124
146
  return notSupported('build');
125
147
  },
126
- onBuildPhase() {
127
- return notSupported('onBuildPhase');
128
- },
129
148
  resetToState() {
130
149
  return notSupported('resetToState');
131
150
  },
@@ -1 +1 @@
1
- {"version":3,"file":"stub-document-builder.js","sourceRoot":"","sources":["../../src/testing/stub-document-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stub-document-builder.js","sourceRoot":"","sources":["../../src/testing/stub-document-builder.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@
8
8
  ********************************************************************************/
9
9
  import type { TransferDiagnostic, TransferElement } from '@hydranium/protocol';
10
10
  import type { AstNode } from '@hydranium/langium';
11
- import { ModelService, type ModelServiceOptions } from '../langium/model-service/model-service.js';
11
+ import { type ModelService, type ModelServiceOptions } from '../langium/model-service/model-service.js';
12
12
  import type { ServerSharedServices } from '../langium/module.js';
13
13
  /** The type of the model-service test double produced by {@link makeStubModelService}. */
14
14
  export type StubModelService<TAst extends AstNode, TDiagnostic extends TransferDiagnostic = TransferDiagnostic, TTransfer extends TransferElement = TransferElement> = ModelService<TAst, TDiagnostic, TTransfer>;
@@ -1 +1 @@
1
- {"version":3,"file":"stub-model-service.d.ts","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AACnG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,0FAA0F;AAC1F,MAAM,MAAM,gBAAgB,CACzB,IAAI,SAAS,OAAO,EACpB,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,SAAS,SAAS,eAAe,GAAG,eAAe,IAClD,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CACjC,IAAI,SAAS,OAAO,EACpB,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,SAAS,SAAS,eAAe,GAAG,eAAe,EAEnD,QAAQ,EAAE,oBAAoB,EAC9B,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,MAAM,EACnD,OAAO,CAAC,EAAE,mBAAmB,GAC7B,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,CAEhD"}
1
+ {"version":3,"file":"stub-model-service.d.ts","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAuB,KAAK,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAC7H,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,0FAA0F;AAC1F,MAAM,MAAM,gBAAgB,CACzB,IAAI,SAAS,OAAO,EACpB,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,SAAS,SAAS,eAAe,GAAG,eAAe,IAClD,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CACjC,IAAI,SAAS,OAAO,EACpB,WAAW,SAAS,kBAAkB,GAAG,kBAAkB,EAC3D,SAAS,SAAS,eAAe,GAAG,eAAe,EAEnD,QAAQ,EAAE,oBAAoB,EAC9B,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,MAAM,EACnD,OAAO,CAAC,EAAE,mBAAmB,GAC7B,gBAAgB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,CAEhD"}
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * SPDX-License-Identifier: MIT
8
8
  ********************************************************************************/
9
- import { ModelService } from '../langium/model-service/model-service.js';
9
+ import { DefaultModelService } from '../langium/model-service/model-service.js';
10
10
  /**
11
11
  * Implementation detail of {@link makeStubModelService}. A {@link ModelService}
12
12
  * subclass that takes `serialize` as a constructor callback — the test stub
@@ -14,7 +14,7 @@ import { ModelService } from '../langium/model-service/model-service.js';
14
14
  * path would fail. Construct it through the factory; the {@link StubModelService}
15
15
  * type alias is the public type name.
16
16
  */
17
- class StubModelServiceImpl extends ModelService {
17
+ class StubModelServiceImpl extends DefaultModelService {
18
18
  serializeFn;
19
19
  constructor(services, serializeFn, options) {
20
20
  super(services, options);
@@ -1 +1 @@
1
- {"version":3,"file":"stub-model-service.js","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,EAAE,YAAY,EAA4B,MAAM,2CAA2C,CAAC;AAGnG;;;;;;GAMG;AACH,MAAM,oBAIJ,SAAQ,YAA0C;IAG3B;IAFtB,YACG,QAA8B,EACX,WAAqD,EACxE,OAA6B;QAE7B,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAHN,gBAAW,GAAX,WAAW,CAA0C;IAI3E,CAAC;IAEkB,SAAS,CAAC,GAAW,EAAE,IAAe;QACtD,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;CACH;AASD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAKjC,QAA8B,EAC9B,SAAmD,EACnD,OAA6B;IAE7B,OAAO,IAAI,oBAAoB,CAA+B,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/F,CAAC"}
1
+ {"version":3,"file":"stub-model-service.js","sourceRoot":"","sources":["../../src/testing/stub-model-service.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF,OAAO,EAAE,mBAAmB,EAA+C,MAAM,2CAA2C,CAAC;AAG7H;;;;;;GAMG;AACH,MAAM,oBAIJ,SAAQ,mBAAiD;IAGlC;IAFtB,YACG,QAA8B,EACX,WAAqD,EACxE,OAA6B;QAE7B,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAHN,gBAAW,GAAX,WAAW,CAA0C;IAI3E,CAAC;IAEkB,SAAS,CAAC,GAAW,EAAE,IAAe;QACtD,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;CACH;AASD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAKjC,QAA8B,EAC9B,SAAmD,EACnD,OAA6B;IAE7B,OAAO,IAAI,oBAAoB,CAA+B,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAC/F,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydranium/core",
3
- "version": "1.0.0-next.6",
3
+ "version": "1.0.0-next.61",
4
4
  "description": "Foundational runtime of the hydranium framework: AST coordination layer (services, integrity, AST extension, serialization, multi-client documents) plus the LSP textual head at the /lsp subpath. Consumed by protocol-head packages (@hydranium/data-server, @hydranium/glsp-server).",
5
5
  "keywords": [
6
6
  "hydranium",
@@ -72,6 +72,14 @@
72
72
  "./lib/testing/playwright": {
73
73
  "types": "./lib/testing/playwright/index.d.ts",
74
74
  "default": "./lib/testing/playwright/index.js"
75
+ },
76
+ "./messages": {
77
+ "types": "./lib/messages/index.d.ts",
78
+ "default": "./lib/messages/index.js"
79
+ },
80
+ "./lib/messages": {
81
+ "types": "./lib/messages/index.d.ts",
82
+ "default": "./lib/messages/index.js"
75
83
  }
76
84
  },
77
85
  "main": "lib/index.js",
@@ -96,8 +104,8 @@
96
104
  "diff": "^5.2.0"
97
105
  },
98
106
  "devDependencies": {
99
- "@hydranium/langium": "1.0.0-next.6",
100
- "@hydranium/protocol": "1.0.0-next.6",
107
+ "@hydranium/langium": "1.0.0-next.61",
108
+ "@hydranium/protocol": "1.0.0-next.61",
101
109
  "@playwright/test": "^1.40.0",
102
110
  "@types/diff": "^5.2.0",
103
111
  "rimraf": "^5.0.0",
@@ -109,12 +117,12 @@
109
117
  "vscode-languageserver-types": "^3.17.5"
110
118
  },
111
119
  "peerDependencies": {
112
- "@hydranium/langium": "1.0.0-next.6",
113
- "@hydranium/protocol": "1.0.0-next.6",
120
+ "@hydranium/langium": "1.0.0-next.61",
121
+ "@hydranium/protocol": "1.0.0-next.61",
114
122
  "@playwright/test": "^1.40.0",
115
- "vscode-jsonrpc": "^8.0.0 || ^9.0.0",
116
- "vscode-languageserver": "^9.0.0 || ^10.0.0",
117
- "vscode-languageserver-protocol": "^3.17.5",
123
+ "vscode-jsonrpc": "9.0.1",
124
+ "vscode-languageserver": "~10.0.1",
125
+ "vscode-languageserver-protocol": "~3.18.1",
118
126
  "vscode-languageserver-textdocument": "^1.0.12",
119
127
  "vscode-languageserver-types": "^3.17.5"
120
128
  },
@@ -129,6 +137,7 @@
129
137
  "publishConfig": {
130
138
  "access": "public"
131
139
  },
140
+ "//peerDependencies": "`vscode-jsonrpc` is EXACT rather than a range, because it is one link of an atomic chain with no independently movable link: `vscode-languageserver-protocol` depends on it at exactly 9.0.1, so any other value an adopter supplies is a SECOND physical copy rather than an upgrade. This wire stack breaks on copy identity rather than on structure — `ParameterStructures.auto` is a singleton compared by `===` in connection.js, so a request type built by one copy and sent over a connection owned by the other throws `Unknown parameter structure auto`. A caret or union range was rejected because npm then resolves a `vscode-jsonrpc@8.2.0` tree SILENTLY, with no diagnostic at all, and the failure surfaces only later at server init. Exact does not fail the install either — npm downgrades an unsatisfiable peer to a warning — but it is a NAMED ERESOLVE warning printing the required version beside the found one, and a hard error for anyone installing with `--strict-peer-deps`. It does NOT prevent a NESTED copy — `@eclipse-glsp/*` carries its own exact `vscode-jsonrpc@8.2.0` dependency and root `overrides` do not ship — so a consumer of the GLSP head must pin the chain in its own manifest, and docs/adopting/requirements.md carries the block to paste. This manifest declares the two links ABOVE the transport as well, and they carry `~` for the same reason: each admits exactly what `langium@4.3.1` itself admits, and a wider range reaches a `vscode-languageserver@9` / `vscode-languageserver-protocol@3.17.x` that depends on the 8.x transport, which is the same split one level up. `vscode-languageserver-types` and `vscode-languageserver-textdocument` are deliberately NOT narrowed: both declare zero dependencies and expose structural APIs, so a duplicate of either drags no transport in and no identity check reads it.",
132
141
  "//prepack": "The publish guard, and it deliberately is NOT a `prepare`: npm runs a workspace `prepare` BEFORE the root `postinstall` that applies patches/vscode-jsonrpc+9.0.1.patch, so building there fails on a cold clone and npm rolls the entire install back. `prepack` runs only when a tarball is made (`npm pack`, `npm publish`) and never on install, so it cannot break the install it has no business touching. It FAILS rather than rebuilds, because the rebuild is exactly the part that ordering defeats. What it defends against: `files` lists `lib`, `lib` is gitignored, and a `files` entry matching nothing is skipped SILENTLY — so `npm publish` from an unbuilt tree emits a tarball of `src` and nothing else, with no error.",
133
142
  "//sideEffects": "NOT `false`: two barrels do work at module load that their re-exports do not account for, and a bundler skips an unflagged re-export barrel outright. `node/index.js` calls `installNodeLogFileSink()` and `installNodeWriteLockScope()`, which is how a Node host gets the log file-tee and write-lock reentrancy detection merely by importing `@hydranium/core/node`. `util/index.js` carries a bare `import '@hydranium/langium'` so the `UriUtils` namespace augmentation stays loaded for anything importing from here. Both failures are runtime-only and silent — a missing log file, a `UriUtils.toUri` that is `undefined`."
134
143
  }
@@ -166,6 +166,51 @@ export type AstDocumentSavedEvent<TAst extends AstNode, TDiagnostic> = TransferS
166
166
  /** Construction options for {@link AstDocumentManager}. */
167
167
  export type AstDocumentManagerOptions = LogNameOptions;
168
168
 
169
+ /**
170
+ * The document slot the model server and the integrity service talk to:
171
+ * open/close/update/save plus the AST-typed event streams, with the LSP
172
+ * plumbing hidden.
173
+ *
174
+ * Generic over `<TAst extends AstNode, TDiagnostic>` so each consumer projects
175
+ * its own AST root type and diagnostic shape into the emitted
176
+ * {@link AstDocument} envelopes.
177
+ *
178
+ * **URI contract.** Every URI-accepting member takes a URI in *any* spelling
179
+ * (canonical, symlinked, `..`/case-divergent) and canonicalizes internally
180
+ * through the {@link DocumentUriPolicy}, so a caller never has to canonicalize
181
+ * first and an implementation may not require it.
182
+ */
183
+ export interface AstDocumentManager<TAst extends AstNode, TDiagnostic = unknown> {
184
+ open(args: OpenModelArgs): Promise<Disposable>;
185
+ close(args: CloseModelArgs): Promise<void>;
186
+ isOpen(uri: string): boolean;
187
+
188
+ /** Apply `text` as `clientId`'s edit. Resolves to the resulting text-document version. */
189
+ update(uri: string, text: string, clientId: string): Promise<number>;
190
+ save(uri: string, clientId: string): Promise<void>;
191
+
192
+ onUpdate(uri: string, listener: (event: AstDocumentUpdatedEvent<TAst, TDiagnostic>) => void): Disposable;
193
+ onSave(uri: string, listener: (event: AstDocumentSavedEvent<TAst, TDiagnostic>) => void | Promise<void>): Disposable;
194
+ onClientClosed(uri: string, clientId: string, listener: () => void): Disposable;
195
+
196
+ getDocument(uri: string): LangiumDocument | undefined;
197
+
198
+ /** Client id that authored the document's current version, or `undefined` for a framework-internal build. */
199
+ getAuthor(document: LangiumDocument): string | undefined;
200
+
201
+ /**
202
+ * Whether `uri` is one of the URIs the most recent build request named, as
203
+ * opposed to a document that build swept in as a dependent. Deletions are
204
+ * excluded: they never reach this layer, since a deleted document is
205
+ * removed before the build set is computed.
206
+ *
207
+ * The answer refers to the latest request, which may still be building, and
208
+ * it is retained between builds — so outside a build it describes whichever
209
+ * one ran last.
210
+ */
211
+ isTriggeringEdit(uri: string): boolean;
212
+ }
213
+
169
214
  /**
170
215
  * Higher-level facade over {@link HydraniumTextDocuments} that speaks the
171
216
  * model-server protocol (open/close/update/save with the transfer-model event
@@ -186,7 +231,7 @@ export type AstDocumentManagerOptions = LogNameOptions;
186
231
  * resolution (the egress `applyEditToLanguageClient`) stay on
187
232
  * {@link HydraniumTextDocuments}, their owner.
188
233
  */
189
- export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = unknown> {
234
+ export class DefaultAstDocumentManager<TAst extends AstNode, TDiagnostic = unknown> implements AstDocumentManager<TAst, TDiagnostic> {
190
235
  protected lastUpdate?: UpdateInfo;
191
236
 
192
237
  protected readonly textDocuments: HydraniumTextDocuments<TextDocument>;
@@ -311,11 +356,12 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
311
356
  const event: TransferUpdatedEvent<AstDocument<TAst, TDiagnostic>> = {
312
357
  document: this.toAstDocument(document),
313
358
  sourceClientId,
314
- reason: this.lastUpdate?.changed.find(changed => UriUtils.equals(changed, document.uri))
315
- ? 'changed'
316
- : this.lastUpdate?.deleted.find(deleted => UriUtils.equals(deleted, document.uri))
317
- ? 'deleted'
318
- : 'rebuilt'
359
+ // No `'deleted'` arm: `DocumentBuilder.update` drops a deleted
360
+ // document from `LangiumDocuments` before deriving the rebuild set
361
+ // from it, so a deleted URI is never built and never reaches this
362
+ // phase listener. A subscriber needing deletions has to be told on
363
+ // a channel that does not require a built document.
364
+ reason: this.lastUpdate?.changed.some(changed => UriUtils.equals(changed, document.uri)) ? 'changed' : 'rebuilt'
319
365
  };
320
366
  this.tracer.with(uri).trace(`emitUpdate start: source=${sourceClientId}, reason=${event.reason}`);
321
367
  listener(event);
@@ -334,7 +380,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
334
380
  * concrete value (the `onUpdate` event's `sourceClientId`, the data-server's
335
381
  * `resolveSourceClientId`).
336
382
  */
337
- getAuthor(document: LangiumDocument<AstNode>): string | undefined {
383
+ getAuthor(document: LangiumDocument): string | undefined {
338
384
  return this.textDocuments.getAuthor(document.textDocument.uri, document.textDocument.version);
339
385
  }
340
386
 
@@ -355,10 +401,17 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
355
401
  // transiently breaks cross-document linking mid-rebuild (a dependent briefly
356
402
  // seeing an `extends`/`type` reference unresolved). And because the constructor
357
403
  // wires `onDidOpen -> this.open`, it would fire a second, identical rebuild on
358
- // every first open. So an already-open `open()` is a no-op.
404
+ // every first open.
405
+ //
406
+ // So an already-open `open()` records the attaching client's hold and nothing
407
+ // else. The hold is per `(uri, clientId)` and the last-close revert counts down
408
+ // to it, so skipping it lets the first holder's close tear down a document
409
+ // another client is still reading.
359
410
  if (!this.isOpen(args.uri)) {
360
411
  const textDocument = await this.createDocumentFromTextOrFileSystem(args.uri, args.languageId, args.version, args.text);
361
412
  this.textDocuments.notifyDidOpenTextDocument({ textDocument }, args.clientId);
413
+ } else {
414
+ this.textDocuments.attachClient(args.uri, args.clientId);
362
415
  }
363
416
  return Disposable.create(() => this.close(args));
364
417
  }
@@ -414,8 +467,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
414
467
  return !!this.textDocuments.get(uri);
415
468
  }
416
469
 
417
- /** True if the URI was in the directly-changed set of the most recent build (not just affected). */
418
- isDirectChange(uri: string): boolean {
470
+ isTriggeringEdit(uri: string): boolean {
419
471
  const canonical = this.uriPolicy.canonicalUri(uri);
420
472
  return this.lastUpdate?.changed.some(changed => this.uriPolicy.canonicalUri(changed) === canonical) ?? false;
421
473
  }
@@ -437,11 +489,7 @@ export class AstDocumentManager<TAst extends AstNode = AstNode, TDiagnostic = un
437
489
  version = 0,
438
490
  text?: string
439
491
  ): Promise<TextDocumentItem> {
440
- return { uri, languageId, version, text: text ?? (await this.readFile(uri)) };
441
- }
442
-
443
- async readFile(uri: string): Promise<string> {
444
- return this.fileSystemProvider.readFile(UriUtils.toUri(uri));
492
+ return { uri, languageId, version, text: text ?? (await this.fileSystemProvider.readFile(UriUtils.toUri(uri))) };
445
493
  }
446
494
 
447
495
  /**
@@ -165,15 +165,15 @@ interface ConnectionWithTextDocumentSync {
165
165
  */
166
166
  interface PendingPush {
167
167
  /**
168
- * The text the client held BEFORE this push — the shadow baseline the
169
- * push's edits were diffed against, and therefore the text the client's
170
- * echo addresses with its ranges.
168
+ * The text the client held BEFORE this push, and therefore the text its
169
+ * echo addresses with its ranges. Wider than the baseline the push's edits
170
+ * were diffed against: a full replace is sent with no diff baseline and
171
+ * still lands on a buffer the echo is keyed to.
171
172
  *
172
- * `undefined` when the push was a full replace sent with no baseline (a
173
- * first sync, or the recovery push after a rejection). There is then no
174
- * knowing what the client held, so the echo is reconstructed against the
175
- * synced text instead — which is sound for a full replace, whose
176
- * application is position-independent.
173
+ * `undefined` only when that buffer is unknown — the client never declared
174
+ * one, or a rejection invalidated what was tracked. The echo is then
175
+ * reconstructed against the synced text, which is sound only for a
176
+ * position-independent (full-text) change.
177
177
  */
178
178
  readonly before: string | undefined;
179
179
  /** {@link contentHash} of the text this push moves the client to. */
@@ -182,16 +182,16 @@ interface PendingPush {
182
182
 
183
183
  /**
184
184
  * What an incoming language-client change turns out to be once reconstructed
185
- * against the pushes still in flight — the return of
185
+ * against the buffer its ranges address — the return of
186
186
  * {@link HydraniumTextDocuments.classifyLanguageClientChange}.
187
187
  */
188
188
  type LanguageClientChangeOrigin =
189
189
  /** The client is reporting a text we pushed it. The synced document is already there. */
190
190
  | { readonly kind: 'echo' }
191
191
  /**
192
- * The client's buffer has moved somewhere we did not push it — it coalesced
193
- * a genuine keystroke into the echo, or typed before the push arrived. The
194
- * reconstructed text is what it now holds, and is authoritative.
192
+ * The client's buffer holds a text we did not push it — a keystroke that
193
+ * raced a push, or an edit to a buffer the store has already been written
194
+ * past. The reconstructed text is what it now holds, and is authoritative.
195
195
  */
196
196
  | { readonly kind: 'divergent'; readonly text: string };
197
197
 
@@ -471,15 +471,16 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
471
471
  }
472
472
  record.clientVersions.set(clientId, td.version);
473
473
 
474
- // A language-client change arriving while one of our own pushes is in
475
- // flight is keyed to the buffer the client held BEFORE that push, NOT
476
- // to the synced text — the authored write already advanced the latter.
474
+ // A language-client change is keyed to the buffer that client holds,
475
+ // which is the synced text only while the two agree — an authored
476
+ // write advances the synced text without the client knowing, and a
477
+ // push in flight moves the client without the store knowing.
477
478
  // Resolve which it is, and against what, before touching anything.
478
- const inFlight =
479
+ const origin =
479
480
  clientId === LANGUAGE_CLIENT_ID
480
481
  ? this.classifyLanguageClientChange(this.toLanguageClientUri(td.uri), document, changes)
481
482
  : undefined;
482
- if (inFlight?.kind === 'echo') {
483
+ if (origin?.kind === 'echo') {
483
484
  // The client is reporting a text we pushed it, so the synced
484
485
  // document is ALREADY there and the changes must not be applied a
485
486
  // second time. Nothing is minted and no rebuild fires. The
@@ -498,12 +499,12 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
498
499
  // apply at a tentative +1 and roll the version back on an identical
499
500
  // result (an empty-changes update only re-stamps the version).
500
501
  //
501
- // A divergent in-flight change is applied as its RECONSTRUCTED text
502
- // rather than as its own ranges: the ranges address the pre-push
503
- // baseline, so applying them here would splice the wrong lines.
502
+ // A divergent change is applied as its RECONSTRUCTED text rather than
503
+ // as its own ranges: those ranges address the client's own buffer, so
504
+ // applying them here would splice the wrong lines.
504
505
  const previousText = document.getText();
505
506
  const sharedVersion = document.version;
506
- document = this.configuration.update(document, inFlight === undefined ? changes : [{ text: inFlight.text }], sharedVersion + 1);
507
+ document = this.configuration.update(document, origin === undefined ? changes : [{ text: origin.text }], sharedVersion + 1);
507
508
  const changed = document.getText() !== previousText;
508
509
  if (!changed) {
509
510
  document = this.configuration.update(document, [], sharedVersion);
@@ -644,18 +645,20 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
644
645
  if (this.isOpenInClient(uri, clientId)) {
645
646
  // Already open for this client under this canonical identity. If this is a
646
647
  // NEW client-facing URI for the same file (a second tab reached via a
647
- // divergent path, e.g. a symlink and its real path), record it and baseline
648
- // its shadow so outbound edits reach this tab too — but do NOT re-fire
649
- // open/rebuild; the document is already live.
648
+ // divergent path, e.g. a symlink and its real path), record it so outbound
649
+ // edits reach this tab too — but do NOT re-fire open/rebuild; the document
650
+ // is already live.
650
651
  if (clientId === LANGUAGE_CLIENT_ID) {
651
652
  const clientFacing = this.toLanguageClientUri(td.uri);
652
653
  const record = this.__documents.get(uri);
653
654
  if (record && !record.languageClientUris?.has(clientFacing)) {
654
655
  (record.languageClientUris ??= new Set<LanguageClientUri>()).add(clientFacing);
655
- const open = this.__syncedDocuments.get(uri);
656
- if (open) {
657
- this.__shadow.set(clientFacing, open.getText());
658
- }
656
+ // This tab's own buffer, NOT the synced text: a second tab is a second
657
+ // client model, read from disk, so a server-authored write already
658
+ // applied to the first tab leaves it BEHIND the synced document. Keying
659
+ // a diff to the synced text here addresses lines this tab does not have
660
+ // and drops content it does.
661
+ this.__shadow.setOpenedText(clientFacing, td.text);
659
662
  }
660
663
  }
661
664
  return;
@@ -694,22 +697,77 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
694
697
  // Baseline the shadow to what Monaco just opened so the next outbound
695
698
  // applyEditToLanguageClient diffs against the right starting point. Keyed by the
696
699
  // language-client URI (what Monaco holds), not the canonical document key.
697
- this.__shadow.set(this.toLanguageClientUri(td.uri), document.getText());
700
+ //
701
+ // The CLIENT's declared text, never the synced document: staged content
702
+ // consumed above leaves the two different, and a baseline asserting the
703
+ // client already holds the staged text suppresses the one sync that would
704
+ // deliver it. Skipped entirely when a push is already outstanding for this
705
+ // URI — an `applyEdit` to a closed file has the client open from disk and
706
+ // apply afterwards, so that shadow records what it is about to hold and
707
+ // disk text would key the next diff to a buffer nobody has.
708
+ const clientFacing = this.toLanguageClientUri(td.uri);
709
+ if (!this.__shadow.isTracked(clientFacing)) {
710
+ this.__shadow.set(clientFacing, td.text);
711
+ }
698
712
  }
699
713
  const toFire = Object.freeze({ document, clientId });
700
714
  this.__onDidOpen.fire(toFire);
701
715
  this.__onDidChangeContent.fire(toFire);
702
716
  } else {
703
717
  // An additional client attaches to a document already open by another client.
704
- this.log(
705
- uri,
706
- `Attach client: ${clientId} joined existing document (version ${document.version}, ` +
707
- `now open in: ${[...existingClients, clientId].join(', ')})`
708
- );
718
+ this.logClientJoined(uri, clientId, document.version, existingClients);
719
+ if (clientId === LANGUAGE_CLIENT_ID) {
720
+ // Monaco's own buffer, which on this path is NOT the synced text — another
721
+ // client opened the document and may already have changed it. Recorded as
722
+ // an equality-only baseline (never a diff one, see `setOpenedText`) so the
723
+ // refresh below does not push a full replace of content Monaco already
724
+ // holds, which would dirty the file on open.
725
+ this.__shadow.setOpenedText(this.toLanguageClientUri(td.uri), td.text);
726
+ }
709
727
  this.refreshContent(uri, clientId);
710
728
  }
711
729
  }
712
730
 
731
+ /**
732
+ * Record `clientId` as an additional holder of a document another client
733
+ * already has open.
734
+ *
735
+ * Unlike the attach branch of {@link notifyDidOpenTextDocument} this does
736
+ * not refresh. That branch re-renders an attaching TEXTUAL view; a client
737
+ * reaching a document through a non-textual route has nothing to re-render,
738
+ * and refreshing per attach turns each into a Langium rebuild and dependent
739
+ * relink cascade.
740
+ *
741
+ * The staleness guard baselines at the SYNCED version, not a declared buffer
742
+ * version, because a client arriving this way holds no buffer of its own.
743
+ * Unifying the two routes therefore rebaselines a textual client's guard to a
744
+ * version it never declared.
745
+ *
746
+ * Returns whether a hold was added — `false` when `uri` is not open, or
747
+ * `clientId` already holds it.
748
+ */
749
+ attachClient(uri: DocumentUri, clientId: string): boolean {
750
+ const key = this.documentKey(uri);
751
+ const document = this.__syncedDocuments.get(key);
752
+ if (!document || this.isOpenInClient(key, clientId)) {
753
+ return false;
754
+ }
755
+ const record = this.trackingFor(key);
756
+ const existingClients = [...record.clients];
757
+ record.clients.add(clientId);
758
+ record.clientVersions.set(clientId, document.version);
759
+ this.logClientJoined(key, clientId, document.version, existingClients);
760
+ return true;
761
+ }
762
+
763
+ protected logClientJoined(uri: DocumentUri, clientId: string, version: number, existingClients: readonly string[]): void {
764
+ this.log(
765
+ uri,
766
+ `Attach client: ${clientId} joined existing document (version ${version}, ` +
767
+ `now open in: ${[...existingClients, clientId].join(', ')})`
768
+ );
769
+ }
770
+
713
771
  refreshContent(uri: DocumentUri, clientId: string): void {
714
772
  const syncedDocument = this.__syncedDocuments.get(this.documentKey(uri));
715
773
  if (syncedDocument) {
@@ -967,10 +1025,11 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
967
1025
  const targets: Iterable<LanguageClientUri> = recorded && recorded.size > 0 ? recorded : [this.toLanguageClientUri(uri)];
968
1026
  let lastResult: ApplyWorkspaceEditResult | undefined;
969
1027
  for (const targetUri of targets) {
970
- // Read BEFORE computeEdits, which overwrites it. This is the text the
971
- // edits below are keyed to, and therefore the only text the client's
972
- // echo of them can be reconstructed against.
973
- const before = this.__shadow.get(targetUri);
1028
+ // Read BEFORE computeEdits, which overwrites the baseline and drops
1029
+ // the opened snapshot. This is the text the client holds, and
1030
+ // therefore the only text its echo of this push can be reconstructed
1031
+ // against — whether or not the push below is keyed to it.
1032
+ const before = this.__shadow.clientText(targetUri);
974
1033
  const edits = this.__shadow.computeEdits(targetUri, newText);
975
1034
  if (edits.length === 0) {
976
1035
  continue;
@@ -985,9 +1044,20 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
985
1044
  // it is exactly what the caller retries with after a rejection, so
986
1045
  // gating it there would refuse the recovery too.
987
1046
  const version = isFullReplace(edits) ? UNKNOWN_CLIENT_VERSION : this.languageClientVersion(uri);
1047
+ // A full `ApplyWorkspaceEditParams`, `edit` and all — NOT a bare
1048
+ // `WorkspaceEdit` with a `label` beside it. `applyEdit` takes
1049
+ // `ApplyWorkspaceEditParams | WorkspaceEdit` and discriminates on
1050
+ // `!!value.edit`, so `{ label, documentChanges }` is wrapped as
1051
+ // `{ edit: { label, documentChanges } }` — putting the label inside
1052
+ // the edit, where LSP defines no such field and no client reads it.
1053
+ // The union is also what hides it at compile time: excess-property
1054
+ // checking admits a property present in EITHER member, so an object
1055
+ // matching neither type-checks against the union.
988
1056
  const result = await connection.workspace.applyEdit({
989
1057
  label: options?.label,
990
- documentChanges: [TextDocumentEdit.create(OptionalVersionedTextDocumentIdentifier.create(targetUri, version), edits)]
1058
+ edit: {
1059
+ documentChanges: [TextDocumentEdit.create(OptionalVersionedTextDocumentIdentifier.create(targetUri, version), edits)]
1060
+ }
991
1061
  });
992
1062
  if (result && result.applied === false) {
993
1063
  this.__shadow.invalidate(targetUri);
@@ -1043,12 +1113,17 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
1043
1113
 
1044
1114
  /**
1045
1115
  * Decide what an incoming language-client change actually is, by
1046
- * reconstructing the client's resulting buffer against the OLDEST push still
1047
- * in flight for `clientFacing`.
1116
+ * reconstructing the client's resulting buffer against the text its ranges
1117
+ * address — the pre-push buffer of the OLDEST push still in flight for
1118
+ * `clientFacing`, else whatever that client is believed to hold.
1048
1119
  *
1049
- * `undefined` when nothing of ours is in flight, which is the ordinary path:
1050
- * the client's ranges then address the synced text and the caller applies
1051
- * them to it directly.
1120
+ * `undefined` when the client's ranges address the synced text itself —
1121
+ * nothing in flight, and no evidence the client holds anything else. That
1122
+ * is the ordinary path, and the caller then applies the ranges directly.
1123
+ * The two texts part company without a push in flight whenever a client
1124
+ * attaches to a document another client has already written: it opened
1125
+ * from disk, so applying its ranges to the synced text splices lines they
1126
+ * never addressed.
1052
1127
  *
1053
1128
  * **Why the oldest, and why reconstruct at all.** The client applies our
1054
1129
  * pushes in order and echoes each against the buffer it held before that
@@ -1079,22 +1154,28 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
1079
1154
  document: T,
1080
1155
  changes: TextDocumentContentChangeEvent[]
1081
1156
  ): LanguageClientChangeOrigin | undefined {
1082
- const pending = this.__pendingPushes.get(clientFacing);
1083
- if (pending === undefined || pending.length === 0) {
1157
+ const queued = this.__pendingPushes.get(clientFacing);
1158
+ const pending = queued?.length ? queued : undefined;
1159
+ // The text the client's ranges address: the buffer it held before the
1160
+ // oldest push still in flight, else the buffer it is believed to hold.
1161
+ const clientText = pending?.[0].before ?? this.__shadow.clientText(clientFacing);
1162
+ if (pending === undefined && (clientText === undefined || clientText === document.getText())) {
1084
1163
  return undefined;
1085
1164
  }
1086
1165
  // Through the configured factories, not `TextDocument` directly, so an
1087
1166
  // adopter's custom text-document type governs how the ranges are applied
1088
1167
  // here exactly as it does on the synced document.
1089
- const probe = this.create(clientFacing, document.languageId, 0, pending[0].before ?? document.getText());
1090
- const clientText = this.update(probe, changes, 0).getText();
1091
- const matchIndex = pending.findIndex(push => push.afterHash === contentHash(clientText));
1092
- if (matchIndex >= 0) {
1093
- pending.splice(0, matchIndex + 1);
1094
- return { kind: 'echo' };
1168
+ const probe = this.create(clientFacing, document.languageId, 0, clientText ?? document.getText());
1169
+ const reconstructed = this.update(probe, changes, 0).getText();
1170
+ if (pending !== undefined) {
1171
+ const matchIndex = pending.findIndex(push => push.afterHash === contentHash(reconstructed));
1172
+ if (matchIndex >= 0) {
1173
+ pending.splice(0, matchIndex + 1);
1174
+ return { kind: 'echo' };
1175
+ }
1176
+ pending.length = 0;
1095
1177
  }
1096
- pending.length = 0;
1097
- return { kind: 'divergent', text: clientText };
1178
+ return { kind: 'divergent', text: reconstructed };
1098
1179
  }
1099
1180
 
1100
1181
  /**