@hydranium/glsp-server 1.0.0-next.10

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 (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/lib/browser/index.d.ts +10 -0
  4. package/lib/browser/index.d.ts.map +1 -0
  5. package/lib/browser/index.js +15 -0
  6. package/lib/browser/index.js.map +1 -0
  7. package/lib/browser/start-glsp-server-in-worker.d.ts +121 -0
  8. package/lib/browser/start-glsp-server-in-worker.d.ts.map +1 -0
  9. package/lib/browser/start-glsp-server-in-worker.js +102 -0
  10. package/lib/browser/start-glsp-server-in-worker.js.map +1 -0
  11. package/lib/command/hydranium-glsp-recording-command.d.ts +132 -0
  12. package/lib/command/hydranium-glsp-recording-command.d.ts.map +1 -0
  13. package/lib/command/hydranium-glsp-recording-command.js +159 -0
  14. package/lib/command/hydranium-glsp-recording-command.js.map +1 -0
  15. package/lib/command/index.d.ts +10 -0
  16. package/lib/command/index.d.ts.map +1 -0
  17. package/lib/command/index.js +10 -0
  18. package/lib/command/index.js.map +1 -0
  19. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts +61 -0
  20. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts.map +1 -0
  21. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js +93 -0
  22. package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js.map +1 -0
  23. package/lib/computed-bounds/index.d.ts +10 -0
  24. package/lib/computed-bounds/index.d.ts.map +1 -0
  25. package/lib/computed-bounds/index.js +10 -0
  26. package/lib/computed-bounds/index.js.map +1 -0
  27. package/lib/dispatcher/index.d.ts +10 -0
  28. package/lib/dispatcher/index.d.ts.map +1 -0
  29. package/lib/dispatcher/index.js +10 -0
  30. package/lib/dispatcher/index.js.map +1 -0
  31. package/lib/dispatcher/server-action-dispatcher.d.ts +52 -0
  32. package/lib/dispatcher/server-action-dispatcher.d.ts.map +1 -0
  33. package/lib/dispatcher/server-action-dispatcher.js +79 -0
  34. package/lib/dispatcher/server-action-dispatcher.js.map +1 -0
  35. package/lib/index.d.ts +19 -0
  36. package/lib/index.d.ts.map +1 -0
  37. package/lib/index.js +20 -0
  38. package/lib/index.js.map +1 -0
  39. package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts +75 -0
  40. package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts.map +1 -0
  41. package/lib/launcher/abstract-hydranium-glsp-diagram-module.js +100 -0
  42. package/lib/launcher/abstract-hydranium-glsp-diagram-module.js.map +1 -0
  43. package/lib/launcher/glsp-app-module.d.ts +87 -0
  44. package/lib/launcher/glsp-app-module.d.ts.map +1 -0
  45. package/lib/launcher/glsp-app-module.js +71 -0
  46. package/lib/launcher/glsp-app-module.js.map +1 -0
  47. package/lib/launcher/glsp-framework-overrides.d.ts +32 -0
  48. package/lib/launcher/glsp-framework-overrides.d.ts.map +1 -0
  49. package/lib/launcher/glsp-framework-overrides.js +49 -0
  50. package/lib/launcher/glsp-framework-overrides.js.map +1 -0
  51. package/lib/launcher/glsp-server-overrides.d.ts +39 -0
  52. package/lib/launcher/glsp-server-overrides.d.ts.map +1 -0
  53. package/lib/launcher/glsp-server-overrides.js +45 -0
  54. package/lib/launcher/glsp-server-overrides.js.map +1 -0
  55. package/lib/launcher/hydranium-glsp-server.d.ts +62 -0
  56. package/lib/launcher/hydranium-glsp-server.d.ts.map +1 -0
  57. package/lib/launcher/hydranium-glsp-server.js +101 -0
  58. package/lib/launcher/hydranium-glsp-server.js.map +1 -0
  59. package/lib/launcher/index.d.ts +12 -0
  60. package/lib/launcher/index.d.ts.map +1 -0
  61. package/lib/launcher/index.js +22 -0
  62. package/lib/launcher/index.js.map +1 -0
  63. package/lib/logging/glsp-client-logger.d.ts +110 -0
  64. package/lib/logging/glsp-client-logger.d.ts.map +1 -0
  65. package/lib/logging/glsp-client-logger.js +151 -0
  66. package/lib/logging/glsp-client-logger.js.map +1 -0
  67. package/lib/logging/index.d.ts +10 -0
  68. package/lib/logging/index.d.ts.map +1 -0
  69. package/lib/logging/index.js +10 -0
  70. package/lib/logging/index.js.map +1 -0
  71. package/lib/node/index.d.ts +10 -0
  72. package/lib/node/index.d.ts.map +1 -0
  73. package/lib/node/index.js +13 -0
  74. package/lib/node/index.js.map +1 -0
  75. package/lib/node/start-glsp-server.d.ts +122 -0
  76. package/lib/node/start-glsp-server.d.ts.map +1 -0
  77. package/lib/node/start-glsp-server.js +103 -0
  78. package/lib/node/start-glsp-server.js.map +1 -0
  79. package/lib/state/abstract-hydranium-glsp-state.d.ts +333 -0
  80. package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -0
  81. package/lib/state/abstract-hydranium-glsp-state.js +451 -0
  82. package/lib/state/abstract-hydranium-glsp-state.js.map +1 -0
  83. package/lib/state/full-text-hydranium-glsp-state.d.ts +43 -0
  84. package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -0
  85. package/lib/state/full-text-hydranium-glsp-state.js +60 -0
  86. package/lib/state/full-text-hydranium-glsp-state.js.map +1 -0
  87. package/lib/state/hydranium-glsp-index.d.ts +220 -0
  88. package/lib/state/hydranium-glsp-index.d.ts.map +1 -0
  89. package/lib/state/hydranium-glsp-index.js +320 -0
  90. package/lib/state/hydranium-glsp-index.js.map +1 -0
  91. package/lib/state/hydranium-shared-core-services.d.ts +90 -0
  92. package/lib/state/hydranium-shared-core-services.d.ts.map +1 -0
  93. package/lib/state/hydranium-shared-core-services.js +89 -0
  94. package/lib/state/hydranium-shared-core-services.js.map +1 -0
  95. package/lib/state/index.d.ts +17 -0
  96. package/lib/state/index.d.ts.map +1 -0
  97. package/lib/state/index.js +17 -0
  98. package/lib/state/index.js.map +1 -0
  99. package/lib/state/model-ready-timeout-error.d.ts +28 -0
  100. package/lib/state/model-ready-timeout-error.d.ts.map +1 -0
  101. package/lib/state/model-ready-timeout-error.js +36 -0
  102. package/lib/state/model-ready-timeout-error.js.map +1 -0
  103. package/lib/state/reconcile-source-model-write.d.ts +43 -0
  104. package/lib/state/reconcile-source-model-write.d.ts.map +1 -0
  105. package/lib/state/reconcile-source-model-write.js +47 -0
  106. package/lib/state/reconcile-source-model-write.js.map +1 -0
  107. package/lib/state/reconciling-multi-document-glsp-state.d.ts +164 -0
  108. package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -0
  109. package/lib/state/reconciling-multi-document-glsp-state.js +222 -0
  110. package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -0
  111. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +91 -0
  112. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -0
  113. package/lib/state/reconciling-transfer-hydranium-glsp-state.js +129 -0
  114. package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -0
  115. package/lib/storage/hydranium-glsp-storage.d.ts +348 -0
  116. package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -0
  117. package/lib/storage/hydranium-glsp-storage.js +634 -0
  118. package/lib/storage/hydranium-glsp-storage.js.map +1 -0
  119. package/lib/storage/index.d.ts +11 -0
  120. package/lib/storage/index.d.ts.map +1 -0
  121. package/lib/storage/index.js +11 -0
  122. package/lib/storage/index.js.map +1 -0
  123. package/lib/storage/save-conflict-policy.d.ts +56 -0
  124. package/lib/storage/save-conflict-policy.d.ts.map +1 -0
  125. package/lib/storage/save-conflict-policy.js +19 -0
  126. package/lib/storage/save-conflict-policy.js.map +1 -0
  127. package/lib/submission/hydranium-glsp-submission-handler.d.ts +109 -0
  128. package/lib/submission/hydranium-glsp-submission-handler.d.ts.map +1 -0
  129. package/lib/submission/hydranium-glsp-submission-handler.js +157 -0
  130. package/lib/submission/hydranium-glsp-submission-handler.js.map +1 -0
  131. package/lib/submission/index.d.ts +10 -0
  132. package/lib/submission/index.d.ts.map +1 -0
  133. package/lib/submission/index.js +10 -0
  134. package/lib/submission/index.js.map +1 -0
  135. package/lib/testing/glsp-harness.d.ts +170 -0
  136. package/lib/testing/glsp-harness.d.ts.map +1 -0
  137. package/lib/testing/glsp-harness.js +231 -0
  138. package/lib/testing/glsp-harness.js.map +1 -0
  139. package/lib/testing/index.d.ts +11 -0
  140. package/lib/testing/index.d.ts.map +1 -0
  141. package/lib/testing/index.js +13 -0
  142. package/lib/testing/index.js.map +1 -0
  143. package/lib/testing/make-noop-glsp-logger.d.ts +42 -0
  144. package/lib/testing/make-noop-glsp-logger.d.ts.map +1 -0
  145. package/lib/testing/make-noop-glsp-logger.js +47 -0
  146. package/lib/testing/make-noop-glsp-logger.js.map +1 -0
  147. package/lib/util/index.d.ts +10 -0
  148. package/lib/util/index.d.ts.map +1 -0
  149. package/lib/util/index.js +10 -0
  150. package/lib/util/index.js.map +1 -0
  151. package/lib/util/service-identifier.d.ts +46 -0
  152. package/lib/util/service-identifier.d.ts.map +1 -0
  153. package/lib/util/service-identifier.js +47 -0
  154. package/lib/util/service-identifier.js.map +1 -0
  155. package/lib/validation/diagnostic-markers.d.ts +48 -0
  156. package/lib/validation/diagnostic-markers.d.ts.map +1 -0
  157. package/lib/validation/diagnostic-markers.js +68 -0
  158. package/lib/validation/diagnostic-markers.js.map +1 -0
  159. package/lib/validation/hydranium-glsp-model-validator.d.ts +51 -0
  160. package/lib/validation/hydranium-glsp-model-validator.d.ts.map +1 -0
  161. package/lib/validation/hydranium-glsp-model-validator.js +118 -0
  162. package/lib/validation/hydranium-glsp-model-validator.js.map +1 -0
  163. package/lib/validation/index.d.ts +11 -0
  164. package/lib/validation/index.d.ts.map +1 -0
  165. package/lib/validation/index.js +11 -0
  166. package/lib/validation/index.js.map +1 -0
  167. package/package.json +111 -0
  168. package/src/browser/index.ts +15 -0
  169. package/src/browser/start-glsp-server-in-worker.ts +202 -0
  170. package/src/command/hydranium-glsp-recording-command.ts +183 -0
  171. package/src/command/index.ts +10 -0
  172. package/src/computed-bounds/hydranium-glsp-computed-bounds-action-handler.ts +103 -0
  173. package/src/computed-bounds/index.ts +10 -0
  174. package/src/dispatcher/index.ts +10 -0
  175. package/src/dispatcher/server-action-dispatcher.ts +72 -0
  176. package/src/index.ts +20 -0
  177. package/src/launcher/abstract-hydranium-glsp-diagram-module.ts +117 -0
  178. package/src/launcher/glsp-app-module.ts +106 -0
  179. package/src/launcher/glsp-framework-overrides.ts +51 -0
  180. package/src/launcher/glsp-server-overrides.ts +46 -0
  181. package/src/launcher/hydranium-glsp-server.ts +104 -0
  182. package/src/launcher/index.ts +22 -0
  183. package/src/logging/glsp-client-logger.ts +184 -0
  184. package/src/logging/index.ts +10 -0
  185. package/src/node/index.ts +13 -0
  186. package/src/node/start-glsp-server.ts +214 -0
  187. package/src/state/abstract-hydranium-glsp-state.ts +503 -0
  188. package/src/state/full-text-hydranium-glsp-state.ts +63 -0
  189. package/src/state/hydranium-glsp-index.ts +337 -0
  190. package/src/state/hydranium-shared-core-services.ts +92 -0
  191. package/src/state/index.ts +17 -0
  192. package/src/state/model-ready-timeout-error.ts +33 -0
  193. package/src/state/reconcile-source-model-write.ts +77 -0
  194. package/src/state/reconciling-multi-document-glsp-state.ts +248 -0
  195. package/src/state/reconciling-transfer-hydranium-glsp-state.ts +132 -0
  196. package/src/storage/hydranium-glsp-storage.ts +660 -0
  197. package/src/storage/index.ts +11 -0
  198. package/src/storage/save-conflict-policy.ts +52 -0
  199. package/src/submission/hydranium-glsp-submission-handler.ts +170 -0
  200. package/src/submission/index.ts +10 -0
  201. package/src/testing/glsp-harness.ts +422 -0
  202. package/src/testing/index.ts +14 -0
  203. package/src/testing/make-noop-glsp-logger.ts +66 -0
  204. package/src/util/index.ts +10 -0
  205. package/src/util/service-identifier.ts +49 -0
  206. package/src/validation/diagnostic-markers.ts +93 -0
  207. package/src/validation/hydranium-glsp-model-validator.ts +105 -0
  208. package/src/validation/index.ts +11 -0
@@ -0,0 +1,231 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import 'reflect-metadata';
10
+ import { ClientSessionManager, EndProgressAction, GLSPClientProxy, GLSPServer, ModelState, RequestBoundsAction, RequestModelAction, SOURCE_URI_ARG, SetDirtyStateAction, SetModelAction, StartProgressAction, StatusAction, UpdateModelAction, UpdateProgressAction } from '@eclipse-glsp/server';
11
+ import { DefaultGLSPServer, InjectionContainer, Logger as GlspLogger, LoggerFactory, NodeActionDispatchScope, getRequestParentName } from '@eclipse-glsp/server/node.js';
12
+ import { ActionDispatchScope } from '@eclipse-glsp/server';
13
+ import { Container, ContainerModule } from 'inversify';
14
+ import { HydraniumTypes } from '../state/hydranium-shared-core-services.js';
15
+ import { createGlspServerOverrides } from '../launcher/glsp-server-overrides.js';
16
+ import { makeNoopGlspLogger } from './make-noop-glsp-logger.js';
17
+ /**
18
+ * The standard client-bound action kinds a real GLSP client handles — the
19
+ * minimal set needed for any model round-trip. The harness declares these on
20
+ * the session by default so the capturing {@link GLSPClientProxy} receives
21
+ * them and the action dispatcher never errors with "no handler registered"
22
+ * for an ordinary server→client action. Adopter-specific kinds are added via
23
+ * {@link MakeGlspHarnessOptions.additionalClientActionKinds}.
24
+ */
25
+ const DEFAULT_CLIENT_ACTION_KINDS = [
26
+ SetModelAction.KIND,
27
+ UpdateModelAction.KIND,
28
+ RequestBoundsAction.KIND,
29
+ SetDirtyStateAction.KIND,
30
+ StatusAction.KIND,
31
+ StartProgressAction.KIND,
32
+ UpdateProgressAction.KIND,
33
+ EndProgressAction.KIND
34
+ ];
35
+ /**
36
+ * The actions that mean "the server published a model".
37
+ *
38
+ * Which one arrives depends on the diagram's `DiagramConfiguration`, not on
39
+ * what the test did: a server-laid-out diagram gets `SetModelAction`, a
40
+ * client-laid-out one (`needsClientLayout`) gets `RequestBoundsAction`, and a
41
+ * re-submit after an operation may be `UpdateModelAction`. Tests that only care
42
+ * *that* the model was published should not have to encode that choice — see
43
+ * {@link GlspHarness.nextModelSubmission}.
44
+ *
45
+ * Exported for the tests that must COUNT submissions rather than await the next
46
+ * one (asserting that nothing further was published, say). Re-listing the kinds
47
+ * in such a test is a false-green shape: a kind added here would leave the copy
48
+ * silently under-counting.
49
+ */
50
+ export const MODEL_SUBMISSION_KINDS = [SetModelAction.KIND, UpdateModelAction.KIND, RequestBoundsAction.KIND];
51
+ /**
52
+ * Wire a real {@link GLSPServer} in-process and drive a GLSP action
53
+ * round-trip against it — dispatch an action → operation/request handler →
54
+ * GModel mutation → response action, captured via a stub
55
+ * {@link GLSPClientProxy}.
56
+ *
57
+ * The harness composes ONE container, collapsing production's parent
58
+ * app-container / per-connection child split, which exists only to share the
59
+ * app container across socket connections.
60
+ */
61
+ export function makeGlspHarness(options) {
62
+ const applicationId = options.applicationId ?? 'test-app';
63
+ const clientSessionId = options.clientSessionId ?? 'test-session';
64
+ const clientActionKinds = [...DEFAULT_CLIENT_ACTION_KINDS, ...(options.additionalClientActionKinds ?? [])];
65
+ const createLogger = options.createLogger ?? (() => makeNoopGlspLogger());
66
+ const actions = [];
67
+ const consumed = new WeakSet();
68
+ const waiters = [];
69
+ const captureProxy = {
70
+ process(message) {
71
+ const { action } = message;
72
+ actions.push(action);
73
+ const index = waiters.findIndex(waiter => waiter.kinds.includes(action.kind));
74
+ if (index >= 0) {
75
+ const [waiter] = waiters.splice(index, 1);
76
+ consumed.add(action);
77
+ clearTimeout(waiter.timer);
78
+ waiter.resolve(action);
79
+ }
80
+ }
81
+ };
82
+ /**
83
+ * Resolve with the first unconsumed action matching any of `kinds` — one
84
+ * already captured resolves immediately, otherwise the next arrival wins.
85
+ *
86
+ * `rejectOnTimeout` is what lets a caller distinguish the two questions a
87
+ * test asks. `true` (the default) is "this must happen", and a timeout is a
88
+ * failure naming the kinds. `false` is "did this happen?", resolving
89
+ * `undefined` — needed because a **rejected** operation produces no action
90
+ * at all, so the only observable is the absence of one. Mirrors GLSP's own
91
+ * `ActionDispatcher.requestUntil(action, timeoutMs, rejectOnTimeout)`.
92
+ */
93
+ function waitFor(kinds, timeoutMs, rejectOnTimeout) {
94
+ const existing = actions.find(action => kinds.includes(action.kind) && !consumed.has(action));
95
+ if (existing) {
96
+ consumed.add(existing);
97
+ return Promise.resolve(existing);
98
+ }
99
+ return new Promise((resolve, reject) => {
100
+ const waiter = {
101
+ kinds,
102
+ resolve,
103
+ timer: setTimeout(() => {
104
+ const index = waiters.indexOf(waiter);
105
+ if (index >= 0) {
106
+ waiters.splice(index, 1);
107
+ }
108
+ if (rejectOnTimeout) {
109
+ // Name what DID arrive. A bare "no X within 2000ms" reads as a
110
+ // hang and points at the transport, when the usual cause is an
111
+ // operation handler that threw or declined: the server then
112
+ // emits nothing, or emits only a status/dirty-state action.
113
+ // Distinguishing "nothing happened" from "something else
114
+ // happened" is the difference between a five-minute hunt and a
115
+ // one-line diagnosis.
116
+ const seen = actions.map(captured => captured.kind);
117
+ const context = seen.length === 0 ? 'no actions were captured at all' : `captured since start: ${seen.join(', ')}`;
118
+ reject(new Error(`makeGlspHarness: no ${kinds.map(kind => `'${kind}'`).join(' / ')} action within ${timeoutMs}ms — ${context}`));
119
+ }
120
+ else {
121
+ resolve(undefined);
122
+ }
123
+ }, timeoutMs)
124
+ };
125
+ waiters.push(waiter);
126
+ });
127
+ }
128
+ const defaultAppModule = new ContainerModule(bind => {
129
+ bind(InjectionContainer).toDynamicValue(ctx => ctx.container);
130
+ bind(GlspLogger).toDynamicValue(ctx => createLogger(getRequestParentName(ctx)));
131
+ bind(LoggerFactory).toFactory(() => (caller) => createLogger(caller));
132
+ // `DefaultActionDispatcher` injects this to tell a reentrant dispatch (from
133
+ // inside a running handler, which must run inline) from an external one
134
+ // (which queues). Mirrors GLSP's own `createAppModule`; without it every
135
+ // dispatch throws on `dispatchScope.isReentrant`.
136
+ bind(ActionDispatchScope).to(NodeActionDispatchScope).inSingletonScope();
137
+ bind(HydraniumTypes.Tracer).toDynamicValue(ctx => {
138
+ const tracer = ctx.container.get(HydraniumTypes.SharedCoreServices).Tracer;
139
+ const caller = getRequestParentName(ctx);
140
+ return caller ? tracer.for(caller) : tracer;
141
+ });
142
+ });
143
+ const captureProxyModule = new ContainerModule(bind => {
144
+ bind(GLSPClientProxy).toConstantValue(captureProxy);
145
+ });
146
+ const container = new Container();
147
+ container.load(defaultAppModule, ...(options.appModules ?? []), captureProxyModule);
148
+ container.load(options.serverModule);
149
+ // After the serverModule, which binds `GLSPServer`: the override rebinds that
150
+ // symbol, so it needs the binding to exist. The launchers reach the same tier
151
+ // by passing this to `configure` — a harness that skipped it would answer
152
+ // request failures differently from every real bringup.
153
+ container.load(createGlspServerOverrides());
154
+ const server = container.get(GLSPServer);
155
+ let sessionContainer;
156
+ let state;
157
+ let disposed = false;
158
+ return {
159
+ server,
160
+ container,
161
+ actions,
162
+ get sessionContainer() {
163
+ if (!sessionContainer) {
164
+ throw new Error('makeGlspHarness: sessionContainer is only available after start()');
165
+ }
166
+ return sessionContainer;
167
+ },
168
+ get state() {
169
+ if (!state) {
170
+ throw new Error('makeGlspHarness: state is only available after start()');
171
+ }
172
+ return state;
173
+ },
174
+ async start() {
175
+ await server.initialize({ applicationId, protocolVersion: DefaultGLSPServer.PROTOCOL_VERSION });
176
+ await server.initializeClientSession({ clientSessionId, diagramType: options.diagramType, clientActionKinds });
177
+ const session = container.get(ClientSessionManager).getSession(clientSessionId);
178
+ if (!session) {
179
+ throw new Error(`makeGlspHarness: no client session '${clientSessionId}' after initializeClientSession`);
180
+ }
181
+ // `session.container` is inversify's concrete `Container`, a nominal type via its
182
+ // private fields — so it clashes across inversify's CJS/ESM dual-package
183
+ // declarations. Typing the harness's container fields as the structural
184
+ // `interfaces.Container` reconciles them with no cast (interfaces compare
185
+ // structurally; the concrete `Container` is only needed for `new Container()`).
186
+ const resolved = session.container;
187
+ sessionContainer = resolved;
188
+ state = resolved.get(ModelState);
189
+ },
190
+ async shutdown() {
191
+ server.shutdown();
192
+ },
193
+ dispatch(action) {
194
+ server.process({ clientId: clientSessionId, action });
195
+ },
196
+ nextAction(kind, timeoutMs = 2000) {
197
+ return waitFor([kind], timeoutMs, true);
198
+ },
199
+ async openDocument(sourceUri, timeoutMs = 2000) {
200
+ if (!state) {
201
+ throw new Error('makeGlspHarness: openDocument() is only valid after start()');
202
+ }
203
+ server.process({
204
+ clientId: clientSessionId,
205
+ action: RequestModelAction.create({ options: { [SOURCE_URI_ARG]: sourceUri } })
206
+ });
207
+ const submission = await waitFor(MODEL_SUBMISSION_KINDS, timeoutMs, true);
208
+ // `waitFor` with rejectOnTimeout only resolves with a real action.
209
+ return submission;
210
+ },
211
+ nextModelSubmission(options = {}) {
212
+ const { timeoutMs = 2000, rejectOnTimeout = true } = options;
213
+ return waitFor(MODEL_SUBMISSION_KINDS, timeoutMs, rejectOnTimeout);
214
+ },
215
+ seedSourceRoot(uri, root) {
216
+ if (!state) {
217
+ throw new Error('makeGlspHarness: seedSourceRoot() is only valid after start()');
218
+ }
219
+ state.setSourceRoot(uri, root);
220
+ },
221
+ dispose() {
222
+ if (disposed) {
223
+ return;
224
+ }
225
+ disposed = true;
226
+ server.shutdown();
227
+ container.unbindAll();
228
+ }
229
+ };
230
+ }
231
+ //# sourceMappingURL=glsp-harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glsp-harness.js","sourceRoot":"","sources":["../../src/testing/glsp-harness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ export * from './glsp-harness.js';
10
+ export * from './make-noop-glsp-logger.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAKlF,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,13 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ // Subpath barrel for `@hydranium/glsp-server/testing` — `makeGlspHarness`,
10
+ // which drives a real GLSP server in-process against a capturing client proxy.
11
+ export * from './glsp-harness.js';
12
+ export * from './make-noop-glsp-logger.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,2EAA2E;AAC3E,+EAA+E;AAE/E,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC"}
@@ -0,0 +1,42 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import { type Logger as GlspLogger } from '@eclipse-glsp/server';
10
+ /**
11
+ * No-op GLSP {@link GlspLogger} for tests — discards every message. GLSP's
12
+ * `Logger` is an abstract class declaring `logLevel` / `caller` alongside the
13
+ * emit methods, so an object literal never structurally satisfies it and each
14
+ * test otherwise writes `{ info, warn, error, debug } as unknown as Logger`.
15
+ * This returns GLSP's shipped {@link NullLogger}, so call sites fill a
16
+ * `GlspLogger` slot cast-free — the GLSP-server sibling of `makeNoopLogger`.
17
+ */
18
+ export declare function makeNoopGlspLogger(): GlspLogger;
19
+ /** GLSP emit level a {@link CapturedGlspLine} was recorded at. */
20
+ export type GlspLogLevel = 'info' | 'warn' | 'error' | 'debug';
21
+ /** A captured GLSP emission: level, rendered message, and trailing params. */
22
+ export interface CapturedGlspLine {
23
+ readonly level: GlspLogLevel;
24
+ readonly message: string;
25
+ readonly params: readonly unknown[];
26
+ }
27
+ /** A GLSP {@link GlspLogger} whose emitted lines are captured for assertions. */
28
+ export interface CapturingGlspLogger {
29
+ readonly logger: GlspLogger;
30
+ /** Every line emitted through the logger, in order. */
31
+ readonly lines: CapturedGlspLine[];
32
+ }
33
+ /**
34
+ * Capturing GLSP {@link GlspLogger} for tests that assert on emitted output
35
+ * (e.g. an error surfaced through the logger). Backed by a {@link NullLogger}
36
+ * subclass so it is a complete `Logger`; each emit records into
37
+ * {@link CapturingGlspLogger.lines}. Filter by `level` to assert on one tier —
38
+ * `lines.filter(line => line.level === 'error')`. Prefer this over hand-rolling
39
+ * an `{ error } as unknown as Logger` stub.
40
+ */
41
+ export declare function makeCapturingGlspLogger(): CapturingGlspLogger;
42
+ //# sourceMappingURL=make-noop-glsp-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-noop-glsp-logger.d.ts","sourceRoot":"","sources":["../../src/testing/make-noop-glsp-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,MAAM,IAAI,UAAU,EAAc,MAAM,sBAAsB,CAAC;AAE7E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAE/C;AAED,kEAAkE;AAClE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAE/D,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACtC;AAED,iFAAiF;AACjF,MAAM,WAAW,mBAAmB;IACjC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,mBAAmB,CAiB7D"}
@@ -0,0 +1,47 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import { NullLogger } from '@eclipse-glsp/server';
10
+ /**
11
+ * No-op GLSP {@link GlspLogger} for tests — discards every message. GLSP's
12
+ * `Logger` is an abstract class declaring `logLevel` / `caller` alongside the
13
+ * emit methods, so an object literal never structurally satisfies it and each
14
+ * test otherwise writes `{ info, warn, error, debug } as unknown as Logger`.
15
+ * This returns GLSP's shipped {@link NullLogger}, so call sites fill a
16
+ * `GlspLogger` slot cast-free — the GLSP-server sibling of `makeNoopLogger`.
17
+ */
18
+ export function makeNoopGlspLogger() {
19
+ return new NullLogger();
20
+ }
21
+ /**
22
+ * Capturing GLSP {@link GlspLogger} for tests that assert on emitted output
23
+ * (e.g. an error surfaced through the logger). Backed by a {@link NullLogger}
24
+ * subclass so it is a complete `Logger`; each emit records into
25
+ * {@link CapturingGlspLogger.lines}. Filter by `level` to assert on one tier —
26
+ * `lines.filter(line => line.level === 'error')`. Prefer this over hand-rolling
27
+ * an `{ error } as unknown as Logger` stub.
28
+ */
29
+ export function makeCapturingGlspLogger() {
30
+ const lines = [];
31
+ class Capturing extends NullLogger {
32
+ info(message, ...params) {
33
+ lines.push({ level: 'info', message, params });
34
+ }
35
+ warn(message, ...params) {
36
+ lines.push({ level: 'warn', message, params });
37
+ }
38
+ error(message, ...params) {
39
+ lines.push({ level: 'error', message, params });
40
+ }
41
+ debug(message, ...params) {
42
+ lines.push({ level: 'debug', message, params });
43
+ }
44
+ }
45
+ return { logger: new Capturing(), lines };
46
+ }
47
+ //# sourceMappingURL=make-noop-glsp-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-noop-glsp-logger.js","sourceRoot":"","sources":["../../src/testing/make-noop-glsp-logger.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAA6B,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE7E;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAC/B,OAAO,IAAI,UAAU,EAAE,CAAC;AAC3B,CAAC;AAmBD;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB;IACpC,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,MAAM,SAAU,SAAQ,UAAU;QACtB,IAAI,CAAC,OAAe,EAAE,GAAG,MAAiB;YAChD,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAClD,CAAC;QACQ,IAAI,CAAC,OAAe,EAAE,GAAG,MAAiB;YAChD,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QAClD,CAAC;QACQ,KAAK,CAAC,OAAe,EAAE,GAAG,MAAiB;YACjD,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC;QACQ,KAAK,CAAC,OAAe,EAAE,GAAG,MAAiB;YACjD,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC;KACH;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,10 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ export * from './service-identifier.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ export * from './service-identifier.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,46 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import type { interfaces } from 'inversify';
10
+ /**
11
+ * Create an Inversify service identifier for type `T`.
12
+ *
13
+ * Returns a fresh Symbol cast to Inversify's typed
14
+ * {@link interfaces.ServiceIdentifier} shape. The cast is necessary
15
+ * because TypeScript cannot infer the generic parameter from a Symbol
16
+ * literal alone — Symbols carry no type information at the value level,
17
+ * so `bind` and `@inject` would receive `any` without it. The cast lets
18
+ * Inversify type-check the bound value at `bind(...).toConstantValue(x)`
19
+ * sites and infer the field type at `@inject(...)` declarations.
20
+ *
21
+ * **Why a Symbol + cast, not a class or string token.**
22
+ *
23
+ * - **Class-as-token** doesn't work for interface-typed services —
24
+ * interfaces have no runtime value to bind against. Using a concrete
25
+ * class as the token would force adopters to extend that specific
26
+ * class rather than implement the interface.
27
+ * - **String tokens** carry cross-package collision risk; two packages
28
+ * that independently bind the same name would clash in a shared
29
+ * container.
30
+ * - **`Symbol.for(name)`** uses Node's cross-realm registry — that sharing
31
+ * is rarely needed, and it makes module-reload behaviour a foot-gun.
32
+ *
33
+ * Fresh `Symbol(description)` per token is the right primitive; this
34
+ * helper centralises the cast so consumers don't repeat the
35
+ * `as interfaces.ServiceIdentifier<T>` boilerplate at every binding
36
+ * site declaration.
37
+ *
38
+ * Only the GLSP head uses Inversify, which is why this lives here; LSP /
39
+ * data-server / `@hydranium/core` use Langium's plain constructor-arg DI
40
+ * through the typed services tree, where binding tokens aren't needed. Adopters
41
+ * mint a token per service they expose to their `@injectable()` GLSP components;
42
+ * the framework's own are grouped in `HydraniumTypes` so token identity
43
+ * stays decoupled from the implementation class name.
44
+ */
45
+ export declare function serviceIdentifier<T>(description: string): interfaces.ServiceIdentifier<T>;
46
+ //# sourceMappingURL=service-identifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-identifier.d.ts","sourceRoot":"","sources":["../../src/util/service-identifier.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAEzF"}
@@ -0,0 +1,47 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ /**
10
+ * Create an Inversify service identifier for type `T`.
11
+ *
12
+ * Returns a fresh Symbol cast to Inversify's typed
13
+ * {@link interfaces.ServiceIdentifier} shape. The cast is necessary
14
+ * because TypeScript cannot infer the generic parameter from a Symbol
15
+ * literal alone — Symbols carry no type information at the value level,
16
+ * so `bind` and `@inject` would receive `any` without it. The cast lets
17
+ * Inversify type-check the bound value at `bind(...).toConstantValue(x)`
18
+ * sites and infer the field type at `@inject(...)` declarations.
19
+ *
20
+ * **Why a Symbol + cast, not a class or string token.**
21
+ *
22
+ * - **Class-as-token** doesn't work for interface-typed services —
23
+ * interfaces have no runtime value to bind against. Using a concrete
24
+ * class as the token would force adopters to extend that specific
25
+ * class rather than implement the interface.
26
+ * - **String tokens** carry cross-package collision risk; two packages
27
+ * that independently bind the same name would clash in a shared
28
+ * container.
29
+ * - **`Symbol.for(name)`** uses Node's cross-realm registry — that sharing
30
+ * is rarely needed, and it makes module-reload behaviour a foot-gun.
31
+ *
32
+ * Fresh `Symbol(description)` per token is the right primitive; this
33
+ * helper centralises the cast so consumers don't repeat the
34
+ * `as interfaces.ServiceIdentifier<T>` boilerplate at every binding
35
+ * site declaration.
36
+ *
37
+ * Only the GLSP head uses Inversify, which is why this lives here; LSP /
38
+ * data-server / `@hydranium/core` use Langium's plain constructor-arg DI
39
+ * through the typed services tree, where binding tokens aren't needed. Adopters
40
+ * mint a token per service they expose to their `@injectable()` GLSP components;
41
+ * the framework's own are grouped in `HydraniumTypes` so token identity
42
+ * stays decoupled from the implementation class name.
43
+ */
44
+ export function serviceIdentifier(description) {
45
+ return Symbol(description);
46
+ }
47
+ //# sourceMappingURL=service-identifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-identifier.js","sourceRoot":"","sources":["../../src/util/service-identifier.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAIlF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,iBAAiB,CAAI,WAAmB;IACrD,OAAO,MAAM,CAAC,WAAW,CAAoC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,48 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import { type Marker } from '@eclipse-glsp/protocol';
10
+ import { type AstNode } from '@hydranium/langium';
11
+ import { type TransferLspDiagnostic } from '@hydranium/core';
12
+ /**
13
+ * The model-shaped lookups the diagnostic→marker translation needs, injected so
14
+ * the pure mapping can be unit-tested without GLSP/Langium DI. The validator
15
+ * wires them to the live services.
16
+ */
17
+ export interface DiagnosticMarkerLookups {
18
+ /**
19
+ * Resolve a diagnostic's `element` AST-path (as produced by
20
+ * `AstNodeLocator.getAstNodePath`) to its node in the current source root,
21
+ * or `undefined` if it no longer resolves.
22
+ */
23
+ resolveElement(elementPath: string): AstNode | undefined;
24
+ /**
25
+ * The GModel ids that currently render `node` on this diagram. Usually one,
26
+ * but a single AST element can be drawn as several nodes, and then every
27
+ * representing node is marked. Empty when `node` is not drawn here.
28
+ */
29
+ renderedIdsFor(node: AstNode): readonly string[];
30
+ }
31
+ /**
32
+ * Translate the current document's LSP diagnostics into GLSP {@link Marker}s
33
+ * for the diagram.
34
+ *
35
+ * Each diagnostic's `element` path is resolved to an AST node; if that node is
36
+ * not drawn on this diagram, the mapping walks up the `$container` chain to the
37
+ * nearest ancestor that is, and marks every GModel node representing it — so a
38
+ * deeply nested error still surfaces, on the innermost drawn container, at each
39
+ * of its occurrences. A diagnostic whose element — and every ancestor — is
40
+ * absent from this diagram is dropped: the model may span several diagrams, and
41
+ * the text editor / Problems view still report it.
42
+ *
43
+ * The full set is recomputed on every call; callers dispatch it under a single
44
+ * `MarkersReason` so a fresh `SetMarkersAction` replaces the previous markers
45
+ * (an empty result clears them when all errors are fixed).
46
+ */
47
+ export declare function diagnosticsToMarkers(diagnostics: readonly TransferLspDiagnostic[], lookups: DiagnosticMarkerLookups): Marker[];
48
+ //# sourceMappingURL=diagnostic-markers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostic-markers.d.ts","sourceRoot":"","sources":["../../src/validation/diagnostic-markers.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,MAAM,EAAc,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACrC;;;;OAIG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACzD;;;;OAIG;IACH,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAAC;CACnD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,SAAS,qBAAqB,EAAE,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,EAAE,CAW9H"}
@@ -0,0 +1,68 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the MIT License which is available in the project root.
6
+ *
7
+ * SPDX-License-Identifier: MIT
8
+ ********************************************************************************/
9
+ import { MarkerKind } from '@eclipse-glsp/protocol';
10
+ import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver-types';
11
+ /**
12
+ * Translate the current document's LSP diagnostics into GLSP {@link Marker}s
13
+ * for the diagram.
14
+ *
15
+ * Each diagnostic's `element` path is resolved to an AST node; if that node is
16
+ * not drawn on this diagram, the mapping walks up the `$container` chain to the
17
+ * nearest ancestor that is, and marks every GModel node representing it — so a
18
+ * deeply nested error still surfaces, on the innermost drawn container, at each
19
+ * of its occurrences. A diagnostic whose element — and every ancestor — is
20
+ * absent from this diagram is dropped: the model may span several diagrams, and
21
+ * the text editor / Problems view still report it.
22
+ *
23
+ * The full set is recomputed on every call; callers dispatch it under a single
24
+ * `MarkersReason` so a fresh `SetMarkersAction` replaces the previous markers
25
+ * (an empty result clears them when all errors are fixed).
26
+ */
27
+ export function diagnosticsToMarkers(diagnostics, lookups) {
28
+ const markers = [];
29
+ for (const diagnostic of diagnostics) {
30
+ const kind = markerKind(diagnostic.severity);
31
+ // LSP 3.18 allows a `MarkupContent` message; GLSP markers are plain text.
32
+ const message = Diagnostic.getMessageString(diagnostic);
33
+ for (const elementId of renderedElementIds(diagnostic.element, lookups)) {
34
+ markers.push({ elementId, kind, label: message, description: message });
35
+ }
36
+ }
37
+ return markers;
38
+ }
39
+ /**
40
+ * The ids of the elements drawn on this diagram for the diagnostic's target,
41
+ * starting at the node it points at and walking up its containers; empty when
42
+ * the path does not resolve or nothing on the chain is rendered.
43
+ */
44
+ function renderedElementIds(elementPath, lookups) {
45
+ let node = lookups.resolveElement(elementPath);
46
+ while (node !== undefined) {
47
+ const ids = lookups.renderedIdsFor(node);
48
+ if (ids.length > 0) {
49
+ return ids;
50
+ }
51
+ node = node.$container;
52
+ }
53
+ return [];
54
+ }
55
+ /** Map an LSP {@link DiagnosticSeverity} to a GLSP {@link MarkerKind}; unset severity is treated as an error. */
56
+ function markerKind(severity) {
57
+ switch (severity) {
58
+ case DiagnosticSeverity.Warning:
59
+ return MarkerKind.WARNING;
60
+ case DiagnosticSeverity.Information:
61
+ case DiagnosticSeverity.Hint:
62
+ return MarkerKind.INFO;
63
+ case DiagnosticSeverity.Error:
64
+ default:
65
+ return MarkerKind.ERROR;
66
+ }
67
+ }
68
+ //# sourceMappingURL=diagnostic-markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostic-markers.js","sourceRoot":"","sources":["../../src/validation/diagnostic-markers.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAe,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAuB7E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAA6C,EAAE,OAAgC;IACjH,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC7C,0EAA0E;QAC1E,MAAM,OAAO,GAAG,UAAU,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACxD,KAAK,MAAM,SAAS,IAAI,kBAAkB,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;YACvE,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3E,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,WAAmB,EAAE,OAAgC;IAC9E,IAAI,IAAI,GAAwB,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IACpE,OAAO,IAAI,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,GAAG,CAAC;QACd,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,CAAC;AACb,CAAC;AAED,iHAAiH;AACjH,SAAS,UAAU,CAAC,QAAwC;IACzD,QAAQ,QAAQ,EAAE,CAAC;QAChB,KAAK,kBAAkB,CAAC,OAAO;YAC5B,OAAO,UAAU,CAAC,OAAO,CAAC;QAC7B,KAAK,kBAAkB,CAAC,WAAW,CAAC;QACpC,KAAK,kBAAkB,CAAC,IAAI;YACzB,OAAO,UAAU,CAAC,IAAI,CAAC;QAC1B,KAAK,kBAAkB,CAAC,KAAK,CAAC;QAC9B;YACG,OAAO,UAAU,CAAC,KAAK,CAAC;IAC9B,CAAC;AACJ,CAAC"}