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

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 (108) hide show
  1. package/lib/documents/ast-document-manager.d.ts +8 -44
  2. package/lib/documents/ast-document-manager.d.ts.map +1 -1
  3. package/lib/documents/ast-document-manager.js +22 -41
  4. package/lib/documents/ast-document-manager.js.map +1 -1
  5. package/lib/documents/client-session-errors.d.ts +4 -33
  6. package/lib/documents/client-session-errors.d.ts.map +1 -1
  7. package/lib/documents/client-session-errors.js +4 -46
  8. package/lib/documents/client-session-errors.js.map +1 -1
  9. package/lib/documents/client-session-registry.d.ts +40 -20
  10. package/lib/documents/client-session-registry.d.ts.map +1 -1
  11. package/lib/documents/client-session-registry.js +33 -20
  12. package/lib/documents/client-session-registry.js.map +1 -1
  13. package/lib/documents/file-system-task-queue.d.ts +49 -0
  14. package/lib/documents/file-system-task-queue.d.ts.map +1 -0
  15. package/lib/documents/file-system-task-queue.js +34 -0
  16. package/lib/documents/file-system-task-queue.js.map +1 -0
  17. package/lib/documents/hydranium-text-documents.d.ts +138 -13
  18. package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
  19. package/lib/documents/hydranium-text-documents.js +283 -40
  20. package/lib/documents/hydranium-text-documents.js.map +1 -1
  21. package/lib/documents/index.d.ts +1 -0
  22. package/lib/documents/index.d.ts.map +1 -1
  23. package/lib/documents/index.js +1 -0
  24. package/lib/documents/index.js.map +1 -1
  25. package/lib/langium/document-builder/document-builder.d.ts +15 -2
  26. package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
  27. package/lib/langium/document-builder/document-builder.js +15 -2
  28. package/lib/langium/document-builder/document-builder.js.map +1 -1
  29. package/lib/langium/integrity/integrity-service.d.ts +3 -2
  30. package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
  31. package/lib/langium/integrity/integrity-service.js +9 -6
  32. package/lib/langium/integrity/integrity-service.js.map +1 -1
  33. package/lib/langium/language-module.d.ts +2 -2
  34. package/lib/langium/language-module.js +2 -2
  35. package/lib/langium/language-module.js.map +1 -1
  36. package/lib/langium/model-service/client-session.d.ts +203 -24
  37. package/lib/langium/model-service/client-session.d.ts.map +1 -1
  38. package/lib/langium/model-service/client-session.js +233 -29
  39. package/lib/langium/model-service/client-session.js.map +1 -1
  40. package/lib/langium/model-service/model-service.d.ts +62 -217
  41. package/lib/langium/model-service/model-service.d.ts.map +1 -1
  42. package/lib/langium/model-service/model-service.js +54 -357
  43. package/lib/langium/model-service/model-service.js.map +1 -1
  44. package/lib/langium/module.d.ts +11 -1
  45. package/lib/langium/module.d.ts.map +1 -1
  46. package/lib/langium/module.js +5 -1
  47. package/lib/langium/module.js.map +1 -1
  48. package/lib/langium/update-rewrite/update-rewrite.d.ts +1 -1
  49. package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
  50. package/lib/langium/workspace/in-memory-file-system-provider.js +10 -2
  51. package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
  52. package/lib/langium/workspace/write-lock-scope.d.ts +1 -1
  53. package/lib/langium/workspace/write-lock-scope.js +1 -1
  54. package/lib/lsp/hydranium-document-update-handler.d.ts +69 -67
  55. package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
  56. package/lib/lsp/hydranium-document-update-handler.js +111 -89
  57. package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
  58. package/lib/lsp/shared-module.d.ts +4 -8
  59. package/lib/lsp/shared-module.d.ts.map +1 -1
  60. package/lib/lsp/shared-module.js.map +1 -1
  61. package/lib/lsp/start-language-server.d.ts +3 -4
  62. package/lib/lsp/start-language-server.d.ts.map +1 -1
  63. package/lib/lsp/start-language-server.js +3 -4
  64. package/lib/lsp/start-language-server.js.map +1 -1
  65. package/lib/testing/make-test-services.d.ts +16 -4
  66. package/lib/testing/make-test-services.d.ts.map +1 -1
  67. package/lib/testing/make-test-services.js +6 -2
  68. package/lib/testing/make-test-services.js.map +1 -1
  69. package/lib/testing/node/lsp-server-connection.d.ts +1 -1
  70. package/lib/testing/node/scratch-workspace.js +1 -1
  71. package/lib/testing/run-update-pipeline.d.ts +4 -4
  72. package/lib/testing/run-update-pipeline.d.ts.map +1 -1
  73. package/lib/testing/stub-ast-document-manager.d.ts +5 -5
  74. package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
  75. package/lib/testing/stub-ast-document-manager.js +6 -8
  76. package/lib/testing/stub-ast-document-manager.js.map +1 -1
  77. package/lib/testing/stub-hydranium-text-documents.d.ts +10 -5
  78. package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
  79. package/lib/testing/stub-hydranium-text-documents.js +16 -9
  80. package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
  81. package/lib/testing/stub-model-service.d.ts +2 -2
  82. package/lib/testing/stub-model-service.js +2 -2
  83. package/package.json +5 -5
  84. package/src/documents/ast-document-manager.ts +27 -78
  85. package/src/documents/client-session-errors.ts +11 -43
  86. package/src/documents/client-session-registry.ts +54 -28
  87. package/src/documents/file-system-task-queue.ts +68 -0
  88. package/src/documents/hydranium-text-documents.ts +348 -44
  89. package/src/documents/index.ts +1 -0
  90. package/src/langium/document-builder/document-builder.ts +16 -2
  91. package/src/langium/integrity/integrity-service.ts +9 -6
  92. package/src/langium/language-module.ts +4 -4
  93. package/src/langium/model-service/client-session.ts +363 -39
  94. package/src/langium/model-service/model-service.ts +91 -420
  95. package/src/langium/module.ts +14 -2
  96. package/src/langium/update-rewrite/update-rewrite.ts +1 -1
  97. package/src/langium/workspace/in-memory-file-system-provider.ts +11 -2
  98. package/src/langium/workspace/write-lock-scope.ts +1 -1
  99. package/src/lsp/hydranium-document-update-handler.ts +138 -92
  100. package/src/lsp/shared-module.ts +4 -8
  101. package/src/lsp/start-language-server.ts +3 -4
  102. package/src/testing/make-test-services.ts +25 -6
  103. package/src/testing/node/lsp-server-connection.ts +1 -1
  104. package/src/testing/node/scratch-workspace.ts +1 -1
  105. package/src/testing/run-update-pipeline.ts +4 -4
  106. package/src/testing/stub-ast-document-manager.ts +10 -24
  107. package/src/testing/stub-hydranium-text-documents.ts +29 -16
  108. package/src/testing/stub-model-service.ts +2 -2
@@ -22,14 +22,14 @@ import type { StubLangiumDocuments } from './stub-langium-documents.js';
22
22
 
23
23
  /**
24
24
  * Minimal stub of {@link AstDocumentManager} for use in test
25
- * harnesses. Implements just the methods the framework's
26
- * `ModelService` calls (`open` / `close` / `update` / `save` /
27
- * `isOpen` / `getDocument`) and a disk queue that runs each task at once;
25
+ * harnesses. Implements just the methods the model service and client
26
+ * sessions call (`open` / `close` / `update` / `save` / `isOpen` /
27
+ * `getDocument`);
28
28
  * `onSave` / `onClientClosed` forward to the underlying stub text store,
29
29
  * `onUpdate` is driven explicitly
30
30
  * through {@link StubAstDocumentManager.emitUpdate} because the stub tree runs
31
31
  * no build phases to emit from, and the remaining read helpers
32
- * (`isTriggeringEdit`, `getAuthor`) throw if invoked — tests that need them
32
+ * (`getAuthor`) throw if invoked — tests that need them
33
33
  * should wire a richer stub or use the real {@link AstDocumentManager}.
34
34
  *
35
35
  * Open state is tracked per URI as the set of holding client ids, so a
@@ -48,18 +48,7 @@ import type { StubLangiumDocuments } from './stub-langium-documents.js';
48
48
  */
49
49
  export interface StubAstDocumentManager<TAst extends AstNode, TDiagnostic extends AstDiagnostic = AstDiagnostic> extends Pick<
50
50
  AstDocumentManager<TAst, TDiagnostic>,
51
- | 'open'
52
- | 'close'
53
- | 'isOpen'
54
- | 'update'
55
- | 'save'
56
- | 'queueDiskTask'
57
- | 'onUpdate'
58
- | 'onSave'
59
- | 'onClientClosed'
60
- | 'getAuthor'
61
- | 'getDocument'
62
- | 'isTriggeringEdit'
51
+ 'open' | 'close' | 'isOpen' | 'update' | 'save' | 'onUpdate' | 'onSave' | 'onClientClosed' | 'getAuthor' | 'getDocument'
63
52
  > {
64
53
  readonly openClients: Map<string, Set<string>>;
65
54
 
@@ -132,10 +121,13 @@ export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic ext
132
121
  clients.add(args.clientId);
133
122
  openClients.set(args.uri, clients);
134
123
  // The real `open` materialises the synced document (from the payload
135
- // text or the filesystem); mirror that so a subsequent `update` finds
136
- // an open document to apply its content change to.
124
+ // text or the filesystem), or attaches the client to the one that is
125
+ // there; mirror both so a subsequent `update` finds the document open
126
+ // for this client.
137
127
  if (!textDocuments.get(args.uri)) {
138
128
  textDocuments.seedOpen(args.uri, args.text ?? '', args.clientId);
129
+ } else {
130
+ textDocuments.attachClient(args.uri, args.clientId);
139
131
  }
140
132
  return Disposable.create(() => close({ uri: args.uri, clientId: args.clientId }));
141
133
  },
@@ -153,9 +145,6 @@ export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic ext
153
145
  await fileSystem.writeFile(UriUtils.toUri(uri), text);
154
146
  textDocuments.notifyDidSaveTextDocument({ textDocument: { uri }, text }, clientId);
155
147
  },
156
- queueDiskTask<T>(_uri: string, task: () => Promise<T>): Promise<T> {
157
- return task();
158
- },
159
148
  // Registers the listener but never calls it by itself — the real manager
160
149
  // emits from a `DocumentBuilder.onDocumentPhase(Validated)` hook and the
161
150
  // stub tree runs no phases. `emitUpdate` is the only thing that fires it;
@@ -217,9 +206,6 @@ export function makeStubAstDocumentManager<TAst extends AstNode, TDiagnostic ext
217
206
  // that need real symlink canonicalization wire the real AstDocumentManager).
218
207
  getDocument(uri: string): LangiumDocument | undefined {
219
208
  return documents?.getDocument(UriUtils.toUri(uri));
220
- },
221
- isTriggeringEdit(): boolean {
222
- return notSupported('isTriggeringEdit');
223
209
  }
224
210
  };
225
211
  }
@@ -9,11 +9,11 @@
9
9
 
10
10
  import type { CanonicalUri } from '@hydranium/protocol';
11
11
  import type { ApplyWorkspaceEditResult } from 'vscode-languageserver';
12
- import { Disposable } from 'vscode-languageserver';
12
+ import { Disposable, Emitter } from 'vscode-languageserver';
13
13
  import type { TextDocument } from 'vscode-languageserver-textdocument';
14
14
  import { LANGUAGE_CLIENT_ID } from '../documents/client-ids.js';
15
15
  import { ClientSessionRegistry } from '../documents/client-session-registry.js';
16
- import type { ClientTextDocumentChangeEvent, HydraniumTextDocuments } from '../documents/hydranium-text-documents.js';
16
+ import type { ClientTextDocumentChangeEvent, HydraniumTextDocuments, LastOpenClosedEvent } from '../documents/hydranium-text-documents.js';
17
17
 
18
18
  /** Snapshot of an open document tracked by the stub. */
19
19
  export interface StubTextDocumentEntry {
@@ -28,11 +28,12 @@ export interface StubTextDocumentEntry {
28
28
  * reads from on test paths — the content channel
29
29
  * (`notifyDidChangeTextDocument` / `applyContentChange` / `version` /
30
30
  * `getAuthor`), the open-state probes (`isOpenInLanguageClient` /
31
- * `isOpenInAnyClient` / `isOpenInClient` / `openDocuments`), the push channel
31
+ * `isOpenInAnyClient` / `isOpenInClient` / `isRevertPending` /
32
+ * `openDocuments`), the push channel
32
33
  * to the language client (`applyEditToLanguageClient` / `stagePendingContent`),
33
34
  * 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:
35
+ * (`registerSession` / `closeSession` / `onDidCloseSession`), which is a real
36
+ * `ClientSessionRegistry` — plus test-only helpers:
36
37
  *
37
38
  * - {@link seedOpen} — pre-populate an open document without firing change
38
39
  * events. Use to set up a baseline version before exercising an `update`.
@@ -69,15 +70,16 @@ export interface StubHydraniumTextDocuments extends Pick<
69
70
  | 'getAuthor'
70
71
  | 'isOpenInLanguageClient'
71
72
  | 'isOpenInAnyClient'
73
+ | 'isRevertPending'
72
74
  | 'applyEditToLanguageClient'
73
75
  | 'stagePendingContent'
74
76
  | 'openDocuments'
75
77
  | 'isOpenInClient'
78
+ | 'attachClient'
76
79
  | 'registerSession'
77
80
  | 'closeSession'
78
81
  | 'onDidCloseSession'
79
- | 'openOptions'
80
- | 'setOpenOptions'
82
+ | 'onDidCloseLastOpen'
81
83
  > {
82
84
  /**
83
85
  * Stub-tailored read accessor. Returns just the surface the framework's
@@ -100,7 +102,11 @@ export interface StubHydraniumTextDocuments extends Pick<
100
102
  seedOpen(uri: string, text: string, clientId: string): void;
101
103
  /** Mark `uri` as open in the LSP textual language client (drives {@link isOpenInLanguageClient}). */
102
104
  seedOpenInLanguageClient(uri: string): void;
103
- /** Synchronously deliver `onDidClose` to subscribers. */
105
+ /**
106
+ * Synchronously deliver `onDidClose` to subscribers, then `onDidCloseLastOpen`
107
+ * when no client has `uri` open any more. The stub keeps no revert grace, so
108
+ * a last close is announced at once.
109
+ */
104
110
  fireClose(uri: string, clientId: string): void;
105
111
  /**
106
112
  * Drop recorded state. Useful for `beforeEach` resets.
@@ -140,11 +146,12 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
140
146
  let applyEditHandler: (uri: string, text: string) => ApplyWorkspaceEditResult | undefined = () => ({ applied: true });
141
147
  const saveListeners: Array<(event: { document: { uri: string }; clientId: string }) => void> = [];
142
148
  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
149
+ // The real registry, so the session table, the opens and the closing state
150
+ // behave as the store's do. The stub's plain-string keys
145
151
  // stand in for canonical URIs (one stub-boundary cast, like `fireClose`).
146
152
  const sessions = new ClientSessionRegistry();
147
153
  const key = (uri: string): CanonicalUri => uri as CanonicalUri;
154
+ const lastOpenClosed = new Emitter<LastOpenClosedEvent>();
148
155
 
149
156
  const stub: StubHydraniumTextDocuments = {
150
157
  get changes() {
@@ -230,6 +237,12 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
230
237
  isOpenInClient(uri, clientId) {
231
238
  return sessions.isOpenIn(key(uri), clientId);
232
239
  },
240
+ isRevertPending(uri) {
241
+ return sessions.isRevertPending(key(uri));
242
+ },
243
+ attachClient(uri, clientId) {
244
+ return docs.has(uri) && sessions.addOpen(key(uri), clientId);
245
+ },
233
246
  registerSession(clientId) {
234
247
  sessions.register(clientId);
235
248
  },
@@ -248,11 +261,8 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
248
261
  get onDidCloseSession() {
249
262
  return sessions.onDidCloseSession;
250
263
  },
251
- openOptions(uri, clientId) {
252
- return sessions.openOptions(key(uri), clientId);
253
- },
254
- setOpenOptions(uri, clientId, options) {
255
- sessions.setOpenOptions(key(uri), clientId, options);
264
+ get onDidCloseLastOpen() {
265
+ return lastOpenClosed.event;
256
266
  },
257
267
  openDocuments() {
258
268
  // From the registry that also answers `isOpenInClient`, which both
@@ -285,7 +295,7 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
285
295
  if (holder && holder.clientId === clientId) {
286
296
  docs.delete(uri);
287
297
  }
288
- sessions.removeOpen(key(uri), clientId);
298
+ const removed = sessions.removeOpen(key(uri), clientId);
289
299
  if (clientId === LANGUAGE_CLIENT_ID) {
290
300
  languageClientOpen.delete(uri);
291
301
  }
@@ -293,6 +303,9 @@ export function makeStubHydraniumTextDocuments(): StubHydraniumTextDocuments {
293
303
  for (const listener of closeListeners.slice()) {
294
304
  listener(event);
295
305
  }
306
+ if (removed && !sessions.isOpen(key(uri))) {
307
+ lastOpenClosed.fire({ uri: key(uri) });
308
+ }
296
309
  },
297
310
  reset() {
298
311
  docs.clear();
@@ -53,8 +53,8 @@ export type StubModelService<
53
53
  * `makeTestServices` wires this stub automatically.
54
54
  *
55
55
  * `options` are the framework {@link ModelServiceOptions}, forwarded verbatim, so
56
- * a test can exercise an option-gated code path (`serializeBuilds`, the slow-warn
57
- * threshold) without hand-rolling a subclass just to reach the constructor.
56
+ * a test can exercise an option-gated code path (`serializeBuilds`) without
57
+ * hand-rolling a subclass just to reach the constructor.
58
58
  *
59
59
  * Adopters that need richer override behaviour — the framework's own extension
60
60
  * surface is {@link ModelService.rewriteModel} alongside `serialize` — should