@hydranium/core 1.0.0-next.115 → 1.0.0-next.117

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 (62) hide show
  1. package/README.md +3 -1
  2. package/lib/documents/ast-document-manager.d.ts +52 -2
  3. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  4. package/lib/documents/ast-document-manager.js +67 -5
  5. package/lib/documents/ast-document-manager.js.map +1 -1
  6. package/lib/documents/client-session-errors.d.ts +44 -0
  7. package/lib/documents/client-session-errors.d.ts.map +1 -0
  8. package/lib/documents/client-session-errors.js +57 -0
  9. package/lib/documents/client-session-errors.js.map +1 -0
  10. package/lib/documents/client-session-registry.d.ts +118 -0
  11. package/lib/documents/client-session-registry.d.ts.map +1 -0
  12. package/lib/documents/client-session-registry.js +171 -0
  13. package/lib/documents/client-session-registry.js.map +1 -0
  14. package/lib/documents/hydranium-text-documents.d.ts +69 -17
  15. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  16. package/lib/documents/hydranium-text-documents.js +135 -44
  17. package/lib/documents/hydranium-text-documents.js.map +1 -1
  18. package/lib/documents/index.d.ts +2 -0
  19. package/lib/documents/index.d.ts.map +1 -1
  20. package/lib/documents/index.js +2 -0
  21. package/lib/documents/index.js.map +1 -1
  22. package/lib/langium/integrity/integrity-service.d.ts +8 -7
  23. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  24. package/lib/langium/integrity/integrity-service.js +35 -27
  25. package/lib/langium/integrity/integrity-service.js.map +1 -1
  26. package/lib/langium/model-service/client-session.d.ts +120 -0
  27. package/lib/langium/model-service/client-session.d.ts.map +1 -0
  28. package/lib/langium/model-service/client-session.js +175 -0
  29. package/lib/langium/model-service/client-session.js.map +1 -0
  30. package/lib/langium/model-service/index.d.ts +1 -0
  31. package/lib/langium/model-service/index.d.ts.map +1 -1
  32. package/lib/langium/model-service/index.js +1 -0
  33. package/lib/langium/model-service/index.js.map +1 -1
  34. package/lib/langium/model-service/model-service.d.ts +57 -1
  35. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  36. package/lib/langium/model-service/model-service.js +123 -9
  37. package/lib/langium/model-service/model-service.js.map +1 -1
  38. package/lib/lsp/hydranium-document-update-handler.d.ts +6 -0
  39. package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
  40. package/lib/lsp/hydranium-document-update-handler.js +20 -3
  41. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  42. package/lib/testing/stub-ast-document-manager.d.ts +4 -3
  43. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  44. package/lib/testing/stub-ast-document-manager.js +3 -0
  45. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  46. package/lib/testing/stub-hydranium-text-documents.d.ts +13 -5
  47. package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
  48. package/lib/testing/stub-hydranium-text-documents.js +45 -14
  49. package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
  50. package/package.json +5 -5
  51. package/src/documents/ast-document-manager.ts +107 -6
  52. package/src/documents/client-session-errors.ts +54 -0
  53. package/src/documents/client-session-registry.ts +211 -0
  54. package/src/documents/hydranium-text-documents.ts +150 -47
  55. package/src/documents/index.ts +2 -0
  56. package/src/langium/integrity/integrity-service.ts +36 -26
  57. package/src/langium/model-service/client-session.ts +257 -0
  58. package/src/langium/model-service/index.ts +1 -0
  59. package/src/langium/model-service/model-service.ts +151 -9
  60. package/src/lsp/hydranium-document-update-handler.ts +22 -4
  61. package/src/testing/stub-ast-document-manager.ts +7 -2
  62. package/src/testing/stub-hydranium-text-documents.ts +62 -18
@@ -12,6 +12,7 @@ import type { ApplyWorkspaceEditResult } from 'vscode-languageserver';
12
12
  import { Disposable } from 'vscode-languageserver';
13
13
  import type { TextDocument } from 'vscode-languageserver-textdocument';
14
14
  import { LANGUAGE_CLIENT_ID } from '../documents/client-ids.js';
15
+ import { ClientSessionRegistry } from '../documents/client-session-registry.js';
15
16
  import type { ClientTextDocumentChangeEvent, HydraniumTextDocuments } from '../documents/hydranium-text-documents.js';
16
17
 
17
18
  /** Snapshot of an open document tracked by the stub. */
@@ -27,9 +28,11 @@ export interface StubTextDocumentEntry {
27
28
  * reads from on test paths — the content channel
28
29
  * (`notifyDidChangeTextDocument` / `applyContentChange` / `version` /
29
30
  * `getAuthor`), the open-state probes (`isOpenInLanguageClient` /
30
- * `isOpenInAnyClient` / `openDocuments`), the push channel to the language
31
- * client (`applyEditToLanguageClient` / `stagePendingContent`) and the
32
- * save / close notifications — plus test-only helpers:
31
+ * `isOpenInAnyClient` / `isOpenInClient` / `openDocuments`), the push channel
32
+ * to the language client (`applyEditToLanguageClient` / `stagePendingContent`),
33
+ * the save / close notifications, and the client-session table
34
+ * (`registerSession` / `closeSession` / `onDidCloseSession` and the open
35
+ * options), which is a real `ClientSessionRegistry` — plus test-only helpers:
33
36
  *
34
37
  * - {@link seedOpen} — pre-populate an open document without firing change
35
38
  * events. Use to set up a baseline version before exercising an `update`.
@@ -69,6 +72,12 @@ export interface StubHydraniumTextDocuments extends Pick<
69
72
  | 'applyEditToLanguageClient'
70
73
  | 'stagePendingContent'
71
74
  | 'openDocuments'
75
+ | 'isOpenInClient'
76
+ | 'registerSession'
77
+ | 'closeSession'
78
+ | 'onDidCloseSession'
79
+ | 'openOptions'
80
+ | 'setOpenOptions'
72
81
  > {
73
82
  /**
74
83
  * Stub-tailored read accessor. Returns just the surface the framework's
@@ -93,7 +102,13 @@ export interface StubHydraniumTextDocuments extends Pick<
93
102
  seedOpenInLanguageClient(uri: string): void;
94
103
  /** Synchronously deliver `onDidClose` to subscribers. */
95
104
  fireClose(uri: string, clientId: string): void;
96
- /** Drop recorded state. Useful for `beforeEach` resets. */
105
+ /**
106
+ * Drop recorded state. Useful for `beforeEach` resets.
107
+ *
108
+ * Sessions end without announcing it, so a model service built on this
109
+ * stub still holds the handles it started before the reset. Build a fresh
110
+ * service after a reset rather than reusing one across it.
111
+ */
97
112
  reset(): void;
98
113
  readonly changes: readonly StubTextDocumentEntry[];
99
114
  readonly saves: readonly { uri: string; clientId: string }[];
@@ -125,8 +140,13 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
125
140
  let applyEditHandler: (uri: string, text: string) => ApplyWorkspaceEditResult | undefined = () => ({ applied: true });
126
141
  const saveListeners: Array<(event: { document: { uri: string }; clientId: string }) => void> = [];
127
142
  const closeListeners: Array<(event: ClientTextDocumentChangeEvent<TextDocument>) => void> = [];
143
+ // The real registry, so the session table, the opens, the closing state and
144
+ // the open options behave as the store's do. The stub's plain-string keys
145
+ // stand in for canonical URIs (one stub-boundary cast, like `fireClose`).
146
+ const sessions = new ClientSessionRegistry();
147
+ const key = (uri: string): CanonicalUri => uri as CanonicalUri;
128
148
 
129
- return {
149
+ const stub: StubHydraniumTextDocuments = {
130
150
  get changes() {
131
151
  return changes;
132
152
  },
@@ -207,21 +227,37 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
207
227
  isOpenInAnyClient(uri) {
208
228
  return docs.has(uri) || languageClientOpen.has(uri);
209
229
  },
210
- openDocuments() {
211
- // Merge the two seeding channels: `seedOpen` records the holding client
212
- // on the doc entry, `seedOpenInLanguageClient` marks the LSP client.
213
- const clientsByUri = new Map<string, Set<string>>();
214
- for (const [uri, entry] of docs) {
215
- clientsByUri.set(uri, new Set([entry.clientId]));
230
+ isOpenInClient(uri, clientId) {
231
+ return sessions.isOpenIn(key(uri), clientId);
232
+ },
233
+ registerSession(clientId) {
234
+ sessions.register(clientId);
235
+ },
236
+ closeSession(clientId) {
237
+ if (!sessions.isRegistered(clientId)) {
238
+ return;
216
239
  }
217
- for (const uri of languageClientOpen) {
218
- const clients = clientsByUri.get(uri) ?? new Set<string>();
219
- clients.add(LANGUAGE_CLIENT_ID);
220
- clientsByUri.set(uri, clients);
240
+ try {
241
+ for (const uri of sessions.beginClose(clientId)) {
242
+ stub.fireClose(uri, clientId);
243
+ }
244
+ } finally {
245
+ sessions.unregister(clientId);
221
246
  }
222
- // The real store keys by canonical identity; the stub's plain-string
223
- // keys stand in for it (single stub-boundary cast, like `fireClose`).
224
- return [...clientsByUri].map(([uri, clients]) => ({ uri: uri as CanonicalUri, clients: [...clients] }));
247
+ },
248
+ get onDidCloseSession() {
249
+ return sessions.onDidCloseSession;
250
+ },
251
+ openOptions(uri, clientId) {
252
+ return sessions.openOptions(key(uri), clientId);
253
+ },
254
+ setOpenOptions(uri, clientId, options) {
255
+ sessions.setOpenOptions(key(uri), clientId, options);
256
+ },
257
+ openDocuments() {
258
+ // From the registry that also answers `isOpenInClient`, which both
259
+ // seeding channels feed, so the two never disagree about an open.
260
+ return sessions.openDocuments();
225
261
  },
226
262
  setApplyEditHandler(handler) {
227
263
  applyEditHandler = handler;
@@ -234,9 +270,11 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
234
270
  staged.push({ uri, text });
235
271
  },
236
272
  seedOpen(uri, text, clientId) {
273
+ sessions.addOpen(key(uri), clientId);
237
274
  docs.set(uri, { uri, version: 1, text, clientId });
238
275
  },
239
276
  seedOpenInLanguageClient(uri) {
277
+ sessions.addOpen(key(uri), LANGUAGE_CLIENT_ID);
240
278
  languageClientOpen.add(uri);
241
279
  },
242
280
  fireClose(uri, clientId) {
@@ -247,6 +285,7 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
247
285
  if (holder && holder.clientId === clientId) {
248
286
  docs.delete(uri);
249
287
  }
288
+ sessions.removeOpen(key(uri), clientId);
250
289
  if (clientId === LANGUAGE_CLIENT_ID) {
251
290
  languageClientOpen.delete(uri);
252
291
  }
@@ -265,6 +304,11 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
265
304
  saveListeners.length = 0;
266
305
  closeListeners.length = 0;
267
306
  applyEditHandler = () => ({ applied: true });
307
+ // Cleared in place rather than replaced: a model service built on the
308
+ // stub subscribed to `onDidCloseSession` once, and a new registry would
309
+ // leave that subscription on one nothing fires.
310
+ sessions.clear();
268
311
  }
269
312
  };
313
+ return stub;
270
314
  }