@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.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/lib/browser/index.d.ts +10 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +15 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/start-glsp-server-in-worker.d.ts +121 -0
- package/lib/browser/start-glsp-server-in-worker.d.ts.map +1 -0
- package/lib/browser/start-glsp-server-in-worker.js +102 -0
- package/lib/browser/start-glsp-server-in-worker.js.map +1 -0
- package/lib/command/hydranium-glsp-recording-command.d.ts +132 -0
- package/lib/command/hydranium-glsp-recording-command.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-recording-command.js +159 -0
- package/lib/command/hydranium-glsp-recording-command.js.map +1 -0
- package/lib/command/index.d.ts +10 -0
- package/lib/command/index.d.ts.map +1 -0
- package/lib/command/index.js +10 -0
- package/lib/command/index.js.map +1 -0
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts +61 -0
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts.map +1 -0
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js +93 -0
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js.map +1 -0
- package/lib/computed-bounds/index.d.ts +10 -0
- package/lib/computed-bounds/index.d.ts.map +1 -0
- package/lib/computed-bounds/index.js +10 -0
- package/lib/computed-bounds/index.js.map +1 -0
- package/lib/dispatcher/index.d.ts +10 -0
- package/lib/dispatcher/index.d.ts.map +1 -0
- package/lib/dispatcher/index.js +10 -0
- package/lib/dispatcher/index.js.map +1 -0
- package/lib/dispatcher/server-action-dispatcher.d.ts +52 -0
- package/lib/dispatcher/server-action-dispatcher.d.ts.map +1 -0
- package/lib/dispatcher/server-action-dispatcher.js +79 -0
- package/lib/dispatcher/server-action-dispatcher.js.map +1 -0
- package/lib/index.d.ts +19 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +20 -0
- package/lib/index.js.map +1 -0
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts +75 -0
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts.map +1 -0
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js +100 -0
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js.map +1 -0
- package/lib/launcher/glsp-app-module.d.ts +87 -0
- package/lib/launcher/glsp-app-module.d.ts.map +1 -0
- package/lib/launcher/glsp-app-module.js +71 -0
- package/lib/launcher/glsp-app-module.js.map +1 -0
- package/lib/launcher/glsp-framework-overrides.d.ts +32 -0
- package/lib/launcher/glsp-framework-overrides.d.ts.map +1 -0
- package/lib/launcher/glsp-framework-overrides.js +49 -0
- package/lib/launcher/glsp-framework-overrides.js.map +1 -0
- package/lib/launcher/glsp-server-overrides.d.ts +39 -0
- package/lib/launcher/glsp-server-overrides.d.ts.map +1 -0
- package/lib/launcher/glsp-server-overrides.js +45 -0
- package/lib/launcher/glsp-server-overrides.js.map +1 -0
- package/lib/launcher/hydranium-glsp-server.d.ts +62 -0
- package/lib/launcher/hydranium-glsp-server.d.ts.map +1 -0
- package/lib/launcher/hydranium-glsp-server.js +101 -0
- package/lib/launcher/hydranium-glsp-server.js.map +1 -0
- package/lib/launcher/index.d.ts +12 -0
- package/lib/launcher/index.d.ts.map +1 -0
- package/lib/launcher/index.js +22 -0
- package/lib/launcher/index.js.map +1 -0
- package/lib/logging/glsp-client-logger.d.ts +110 -0
- package/lib/logging/glsp-client-logger.d.ts.map +1 -0
- package/lib/logging/glsp-client-logger.js +151 -0
- package/lib/logging/glsp-client-logger.js.map +1 -0
- package/lib/logging/index.d.ts +10 -0
- package/lib/logging/index.d.ts.map +1 -0
- package/lib/logging/index.js +10 -0
- package/lib/logging/index.js.map +1 -0
- package/lib/node/index.d.ts +10 -0
- package/lib/node/index.d.ts.map +1 -0
- package/lib/node/index.js +13 -0
- package/lib/node/index.js.map +1 -0
- package/lib/node/start-glsp-server.d.ts +122 -0
- package/lib/node/start-glsp-server.d.ts.map +1 -0
- package/lib/node/start-glsp-server.js +103 -0
- package/lib/node/start-glsp-server.js.map +1 -0
- package/lib/state/abstract-hydranium-glsp-state.d.ts +333 -0
- package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -0
- package/lib/state/abstract-hydranium-glsp-state.js +451 -0
- package/lib/state/abstract-hydranium-glsp-state.js.map +1 -0
- package/lib/state/full-text-hydranium-glsp-state.d.ts +43 -0
- package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -0
- package/lib/state/full-text-hydranium-glsp-state.js +60 -0
- package/lib/state/full-text-hydranium-glsp-state.js.map +1 -0
- package/lib/state/hydranium-glsp-index.d.ts +220 -0
- package/lib/state/hydranium-glsp-index.d.ts.map +1 -0
- package/lib/state/hydranium-glsp-index.js +320 -0
- package/lib/state/hydranium-glsp-index.js.map +1 -0
- package/lib/state/hydranium-shared-core-services.d.ts +90 -0
- package/lib/state/hydranium-shared-core-services.d.ts.map +1 -0
- package/lib/state/hydranium-shared-core-services.js +89 -0
- package/lib/state/hydranium-shared-core-services.js.map +1 -0
- package/lib/state/index.d.ts +17 -0
- package/lib/state/index.d.ts.map +1 -0
- package/lib/state/index.js +17 -0
- package/lib/state/index.js.map +1 -0
- package/lib/state/model-ready-timeout-error.d.ts +28 -0
- package/lib/state/model-ready-timeout-error.d.ts.map +1 -0
- package/lib/state/model-ready-timeout-error.js +36 -0
- package/lib/state/model-ready-timeout-error.js.map +1 -0
- package/lib/state/reconcile-source-model-write.d.ts +43 -0
- package/lib/state/reconcile-source-model-write.d.ts.map +1 -0
- package/lib/state/reconcile-source-model-write.js +47 -0
- package/lib/state/reconcile-source-model-write.js.map +1 -0
- package/lib/state/reconciling-multi-document-glsp-state.d.ts +164 -0
- package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -0
- package/lib/state/reconciling-multi-document-glsp-state.js +222 -0
- package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -0
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +91 -0
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -0
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js +129 -0
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -0
- package/lib/storage/hydranium-glsp-storage.d.ts +348 -0
- package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -0
- package/lib/storage/hydranium-glsp-storage.js +634 -0
- package/lib/storage/hydranium-glsp-storage.js.map +1 -0
- package/lib/storage/index.d.ts +11 -0
- package/lib/storage/index.d.ts.map +1 -0
- package/lib/storage/index.js +11 -0
- package/lib/storage/index.js.map +1 -0
- package/lib/storage/save-conflict-policy.d.ts +56 -0
- package/lib/storage/save-conflict-policy.d.ts.map +1 -0
- package/lib/storage/save-conflict-policy.js +19 -0
- package/lib/storage/save-conflict-policy.js.map +1 -0
- package/lib/submission/hydranium-glsp-submission-handler.d.ts +109 -0
- package/lib/submission/hydranium-glsp-submission-handler.d.ts.map +1 -0
- package/lib/submission/hydranium-glsp-submission-handler.js +157 -0
- package/lib/submission/hydranium-glsp-submission-handler.js.map +1 -0
- package/lib/submission/index.d.ts +10 -0
- package/lib/submission/index.d.ts.map +1 -0
- package/lib/submission/index.js +10 -0
- package/lib/submission/index.js.map +1 -0
- package/lib/testing/glsp-harness.d.ts +170 -0
- package/lib/testing/glsp-harness.d.ts.map +1 -0
- package/lib/testing/glsp-harness.js +231 -0
- package/lib/testing/glsp-harness.js.map +1 -0
- package/lib/testing/index.d.ts +11 -0
- package/lib/testing/index.d.ts.map +1 -0
- package/lib/testing/index.js +13 -0
- package/lib/testing/index.js.map +1 -0
- package/lib/testing/make-noop-glsp-logger.d.ts +42 -0
- package/lib/testing/make-noop-glsp-logger.d.ts.map +1 -0
- package/lib/testing/make-noop-glsp-logger.js +47 -0
- package/lib/testing/make-noop-glsp-logger.js.map +1 -0
- package/lib/util/index.d.ts +10 -0
- package/lib/util/index.d.ts.map +1 -0
- package/lib/util/index.js +10 -0
- package/lib/util/index.js.map +1 -0
- package/lib/util/service-identifier.d.ts +46 -0
- package/lib/util/service-identifier.d.ts.map +1 -0
- package/lib/util/service-identifier.js +47 -0
- package/lib/util/service-identifier.js.map +1 -0
- package/lib/validation/diagnostic-markers.d.ts +48 -0
- package/lib/validation/diagnostic-markers.d.ts.map +1 -0
- package/lib/validation/diagnostic-markers.js +68 -0
- package/lib/validation/diagnostic-markers.js.map +1 -0
- package/lib/validation/hydranium-glsp-model-validator.d.ts +51 -0
- package/lib/validation/hydranium-glsp-model-validator.d.ts.map +1 -0
- package/lib/validation/hydranium-glsp-model-validator.js +118 -0
- package/lib/validation/hydranium-glsp-model-validator.js.map +1 -0
- package/lib/validation/index.d.ts +11 -0
- package/lib/validation/index.d.ts.map +1 -0
- package/lib/validation/index.js +11 -0
- package/lib/validation/index.js.map +1 -0
- package/package.json +111 -0
- package/src/browser/index.ts +15 -0
- package/src/browser/start-glsp-server-in-worker.ts +202 -0
- package/src/command/hydranium-glsp-recording-command.ts +183 -0
- package/src/command/index.ts +10 -0
- package/src/computed-bounds/hydranium-glsp-computed-bounds-action-handler.ts +103 -0
- package/src/computed-bounds/index.ts +10 -0
- package/src/dispatcher/index.ts +10 -0
- package/src/dispatcher/server-action-dispatcher.ts +72 -0
- package/src/index.ts +20 -0
- package/src/launcher/abstract-hydranium-glsp-diagram-module.ts +117 -0
- package/src/launcher/glsp-app-module.ts +106 -0
- package/src/launcher/glsp-framework-overrides.ts +51 -0
- package/src/launcher/glsp-server-overrides.ts +46 -0
- package/src/launcher/hydranium-glsp-server.ts +104 -0
- package/src/launcher/index.ts +22 -0
- package/src/logging/glsp-client-logger.ts +184 -0
- package/src/logging/index.ts +10 -0
- package/src/node/index.ts +13 -0
- package/src/node/start-glsp-server.ts +214 -0
- package/src/state/abstract-hydranium-glsp-state.ts +503 -0
- package/src/state/full-text-hydranium-glsp-state.ts +63 -0
- package/src/state/hydranium-glsp-index.ts +337 -0
- package/src/state/hydranium-shared-core-services.ts +92 -0
- package/src/state/index.ts +17 -0
- package/src/state/model-ready-timeout-error.ts +33 -0
- package/src/state/reconcile-source-model-write.ts +77 -0
- package/src/state/reconciling-multi-document-glsp-state.ts +248 -0
- package/src/state/reconciling-transfer-hydranium-glsp-state.ts +132 -0
- package/src/storage/hydranium-glsp-storage.ts +660 -0
- package/src/storage/index.ts +11 -0
- package/src/storage/save-conflict-policy.ts +52 -0
- package/src/submission/hydranium-glsp-submission-handler.ts +170 -0
- package/src/submission/index.ts +10 -0
- package/src/testing/glsp-harness.ts +422 -0
- package/src/testing/index.ts +14 -0
- package/src/testing/make-noop-glsp-logger.ts +66 -0
- package/src/util/index.ts +10 -0
- package/src/util/service-identifier.ts +49 -0
- package/src/validation/diagnostic-markers.ts +93 -0
- package/src/validation/hydranium-glsp-model-validator.ts +105 -0
- package/src/validation/index.ts +11 -0
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
import { type Logger as GlspLogger, NullLogger } from '@eclipse-glsp/server';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* No-op GLSP {@link GlspLogger} for tests — discards every message. GLSP's
|
|
14
|
+
* `Logger` is an abstract class declaring `logLevel` / `caller` alongside the
|
|
15
|
+
* emit methods, so an object literal never structurally satisfies it and each
|
|
16
|
+
* test otherwise writes `{ info, warn, error, debug } as unknown as Logger`.
|
|
17
|
+
* This returns GLSP's shipped {@link NullLogger}, so call sites fill a
|
|
18
|
+
* `GlspLogger` slot cast-free — the GLSP-server sibling of `makeNoopLogger`.
|
|
19
|
+
*/
|
|
20
|
+
export function makeNoopGlspLogger(): GlspLogger {
|
|
21
|
+
return new NullLogger();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** GLSP emit level a {@link CapturedGlspLine} was recorded at. */
|
|
25
|
+
export type GlspLogLevel = 'info' | 'warn' | 'error' | 'debug';
|
|
26
|
+
|
|
27
|
+
/** A captured GLSP emission: level, rendered message, and trailing params. */
|
|
28
|
+
export interface CapturedGlspLine {
|
|
29
|
+
readonly level: GlspLogLevel;
|
|
30
|
+
readonly message: string;
|
|
31
|
+
readonly params: readonly unknown[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A GLSP {@link GlspLogger} whose emitted lines are captured for assertions. */
|
|
35
|
+
export interface CapturingGlspLogger {
|
|
36
|
+
readonly logger: GlspLogger;
|
|
37
|
+
/** Every line emitted through the logger, in order. */
|
|
38
|
+
readonly lines: CapturedGlspLine[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Capturing GLSP {@link GlspLogger} for tests that assert on emitted output
|
|
43
|
+
* (e.g. an error surfaced through the logger). Backed by a {@link NullLogger}
|
|
44
|
+
* subclass so it is a complete `Logger`; each emit records into
|
|
45
|
+
* {@link CapturingGlspLogger.lines}. Filter by `level` to assert on one tier —
|
|
46
|
+
* `lines.filter(line => line.level === 'error')`. Prefer this over hand-rolling
|
|
47
|
+
* an `{ error } as unknown as Logger` stub.
|
|
48
|
+
*/
|
|
49
|
+
export function makeCapturingGlspLogger(): CapturingGlspLogger {
|
|
50
|
+
const lines: CapturedGlspLine[] = [];
|
|
51
|
+
class Capturing extends NullLogger {
|
|
52
|
+
override info(message: string, ...params: unknown[]): void {
|
|
53
|
+
lines.push({ level: 'info', message, params });
|
|
54
|
+
}
|
|
55
|
+
override warn(message: string, ...params: unknown[]): void {
|
|
56
|
+
lines.push({ level: 'warn', message, params });
|
|
57
|
+
}
|
|
58
|
+
override error(message: string, ...params: unknown[]): void {
|
|
59
|
+
lines.push({ level: 'error', message, params });
|
|
60
|
+
}
|
|
61
|
+
override debug(message: string, ...params: unknown[]): void {
|
|
62
|
+
lines.push({ level: 'debug', message, params });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { logger: new Capturing(), lines };
|
|
66
|
+
}
|
|
@@ -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
|
+
|
|
10
|
+
export * from './service-identifier.js';
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
import type { interfaces } from 'inversify';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create an Inversify service identifier for type `T`.
|
|
14
|
+
*
|
|
15
|
+
* Returns a fresh Symbol cast to Inversify's typed
|
|
16
|
+
* {@link interfaces.ServiceIdentifier} shape. The cast is necessary
|
|
17
|
+
* because TypeScript cannot infer the generic parameter from a Symbol
|
|
18
|
+
* literal alone — Symbols carry no type information at the value level,
|
|
19
|
+
* so `bind` and `@inject` would receive `any` without it. The cast lets
|
|
20
|
+
* Inversify type-check the bound value at `bind(...).toConstantValue(x)`
|
|
21
|
+
* sites and infer the field type at `@inject(...)` declarations.
|
|
22
|
+
*
|
|
23
|
+
* **Why a Symbol + cast, not a class or string token.**
|
|
24
|
+
*
|
|
25
|
+
* - **Class-as-token** doesn't work for interface-typed services —
|
|
26
|
+
* interfaces have no runtime value to bind against. Using a concrete
|
|
27
|
+
* class as the token would force adopters to extend that specific
|
|
28
|
+
* class rather than implement the interface.
|
|
29
|
+
* - **String tokens** carry cross-package collision risk; two packages
|
|
30
|
+
* that independently bind the same name would clash in a shared
|
|
31
|
+
* container.
|
|
32
|
+
* - **`Symbol.for(name)`** uses Node's cross-realm registry — that sharing
|
|
33
|
+
* is rarely needed, and it makes module-reload behaviour a foot-gun.
|
|
34
|
+
*
|
|
35
|
+
* Fresh `Symbol(description)` per token is the right primitive; this
|
|
36
|
+
* helper centralises the cast so consumers don't repeat the
|
|
37
|
+
* `as interfaces.ServiceIdentifier<T>` boilerplate at every binding
|
|
38
|
+
* site declaration.
|
|
39
|
+
*
|
|
40
|
+
* Only the GLSP head uses Inversify, which is why this lives here; LSP /
|
|
41
|
+
* data-server / `@hydranium/core` use Langium's plain constructor-arg DI
|
|
42
|
+
* through the typed services tree, where binding tokens aren't needed. Adopters
|
|
43
|
+
* mint a token per service they expose to their `@injectable()` GLSP components;
|
|
44
|
+
* the framework's own are grouped in `HydraniumTypes` so token identity
|
|
45
|
+
* stays decoupled from the implementation class name.
|
|
46
|
+
*/
|
|
47
|
+
export function serviceIdentifier<T>(description: string): interfaces.ServiceIdentifier<T> {
|
|
48
|
+
return Symbol(description) as interfaces.ServiceIdentifier<T>;
|
|
49
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
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
|
+
import { type Marker, MarkerKind } from '@eclipse-glsp/protocol';
|
|
11
|
+
import { type AstNode } from '@hydranium/langium';
|
|
12
|
+
import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver-types';
|
|
13
|
+
import { type TransferLspDiagnostic } from '@hydranium/core';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The model-shaped lookups the diagnostic→marker translation needs, injected so
|
|
17
|
+
* the pure mapping can be unit-tested without GLSP/Langium DI. The validator
|
|
18
|
+
* wires them to the live services.
|
|
19
|
+
*/
|
|
20
|
+
export interface DiagnosticMarkerLookups {
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a diagnostic's `element` AST-path (as produced by
|
|
23
|
+
* `AstNodeLocator.getAstNodePath`) to its node in the current source root,
|
|
24
|
+
* or `undefined` if it no longer resolves.
|
|
25
|
+
*/
|
|
26
|
+
resolveElement(elementPath: string): AstNode | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The GModel ids that currently render `node` on this diagram. Usually one,
|
|
29
|
+
* but a single AST element can be drawn as several nodes, and then every
|
|
30
|
+
* representing node is marked. Empty when `node` is not drawn here.
|
|
31
|
+
*/
|
|
32
|
+
renderedIdsFor(node: AstNode): readonly string[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Translate the current document's LSP diagnostics into GLSP {@link Marker}s
|
|
37
|
+
* for the diagram.
|
|
38
|
+
*
|
|
39
|
+
* Each diagnostic's `element` path is resolved to an AST node; if that node is
|
|
40
|
+
* not drawn on this diagram, the mapping walks up the `$container` chain to the
|
|
41
|
+
* nearest ancestor that is, and marks every GModel node representing it — so a
|
|
42
|
+
* deeply nested error still surfaces, on the innermost drawn container, at each
|
|
43
|
+
* of its occurrences. A diagnostic whose element — and every ancestor — is
|
|
44
|
+
* absent from this diagram is dropped: the model may span several diagrams, and
|
|
45
|
+
* the text editor / Problems view still report it.
|
|
46
|
+
*
|
|
47
|
+
* The full set is recomputed on every call; callers dispatch it under a single
|
|
48
|
+
* `MarkersReason` so a fresh `SetMarkersAction` replaces the previous markers
|
|
49
|
+
* (an empty result clears them when all errors are fixed).
|
|
50
|
+
*/
|
|
51
|
+
export function diagnosticsToMarkers(diagnostics: readonly TransferLspDiagnostic[], lookups: DiagnosticMarkerLookups): Marker[] {
|
|
52
|
+
const markers: Marker[] = [];
|
|
53
|
+
for (const diagnostic of diagnostics) {
|
|
54
|
+
const kind = markerKind(diagnostic.severity);
|
|
55
|
+
// LSP 3.18 allows a `MarkupContent` message; GLSP markers are plain text.
|
|
56
|
+
const message = Diagnostic.getMessageString(diagnostic);
|
|
57
|
+
for (const elementId of renderedElementIds(diagnostic.element, lookups)) {
|
|
58
|
+
markers.push({ elementId, kind, label: message, description: message });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return markers;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The ids of the elements drawn on this diagram for the diagnostic's target,
|
|
66
|
+
* starting at the node it points at and walking up its containers; empty when
|
|
67
|
+
* the path does not resolve or nothing on the chain is rendered.
|
|
68
|
+
*/
|
|
69
|
+
function renderedElementIds(elementPath: string, lookups: DiagnosticMarkerLookups): readonly string[] {
|
|
70
|
+
let node: AstNode | undefined = lookups.resolveElement(elementPath);
|
|
71
|
+
while (node !== undefined) {
|
|
72
|
+
const ids = lookups.renderedIdsFor(node);
|
|
73
|
+
if (ids.length > 0) {
|
|
74
|
+
return ids;
|
|
75
|
+
}
|
|
76
|
+
node = node.$container;
|
|
77
|
+
}
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Map an LSP {@link DiagnosticSeverity} to a GLSP {@link MarkerKind}; unset severity is treated as an error. */
|
|
82
|
+
function markerKind(severity: DiagnosticSeverity | undefined): string {
|
|
83
|
+
switch (severity) {
|
|
84
|
+
case DiagnosticSeverity.Warning:
|
|
85
|
+
return MarkerKind.WARNING;
|
|
86
|
+
case DiagnosticSeverity.Information:
|
|
87
|
+
case DiagnosticSeverity.Hint:
|
|
88
|
+
return MarkerKind.INFO;
|
|
89
|
+
case DiagnosticSeverity.Error:
|
|
90
|
+
default:
|
|
91
|
+
return MarkerKind.ERROR;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
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
|
+
import { type Marker } from '@eclipse-glsp/protocol';
|
|
11
|
+
import { type GModelElement, ModelState, type ModelValidator } from '@eclipse-glsp/server';
|
|
12
|
+
import { inject, injectable } from 'inversify';
|
|
13
|
+
import { type AstNode } from '@hydranium/langium';
|
|
14
|
+
import { URI } from '@hydranium/langium';
|
|
15
|
+
import { type ServerSharedServices, type TransferLspDiagnostic } from '@hydranium/core';
|
|
16
|
+
import { type AbstractHydraniumGlspState } from '../state/abstract-hydranium-glsp-state.js';
|
|
17
|
+
import { HydraniumTypes } from '../state/hydranium-shared-core-services.js';
|
|
18
|
+
import { type DiagnosticMarkerLookups, diagnosticsToMarkers } from './diagnostic-markers.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Framework {@link ModelValidator} that surfaces the model server's LSP
|
|
22
|
+
* diagnostics as GLSP diagram markers. Bound per diagram via
|
|
23
|
+
* `DiagramModule.bindModelValidator()`; the framework submission handler also
|
|
24
|
+
* pushes its output as a `SetMarkersAction` after every model submit so
|
|
25
|
+
* markers refresh live (the GLSP client otherwise only re-requests markers on
|
|
26
|
+
* the tool-palette validate command).
|
|
27
|
+
*
|
|
28
|
+
* The translation itself ({@link diagnosticsToMarkers}) is pure; this class
|
|
29
|
+
* supplies its model-shaped lookups from the live services: the per-language
|
|
30
|
+
* `AstNodeLocator` resolves a diagnostic's `element` path back to its AST node,
|
|
31
|
+
* and the GModel index assigns the node's diagram id and reports whether that
|
|
32
|
+
* id is currently drawn.
|
|
33
|
+
*
|
|
34
|
+
* **Cross-document.** A diagram routinely renders elements defined in *other*
|
|
35
|
+
* documents, and their validation errors are published on those documents, not
|
|
36
|
+
* on the diagram's own. The validator therefore scans the diagnostics of every
|
|
37
|
+
* document the index reports as contributing a rendered element (the index's
|
|
38
|
+
* `renderedDocumentUris`: the diagram's own document plus those reached via
|
|
39
|
+
* reference projections) and lets the index's rendered-check keep only those
|
|
40
|
+
* that map to an element drawn on this diagram; the rest fall away. The
|
|
41
|
+
* `elements` argument of {@link validate} is ignored — the diagnostic set is
|
|
42
|
+
* the source of truth, and the default `RequestMarkersAction` requests the
|
|
43
|
+
* whole diagram anyway.
|
|
44
|
+
*/
|
|
45
|
+
@injectable()
|
|
46
|
+
export class HydraniumGlspModelValidator<TRoot extends AstNode = AstNode> implements ModelValidator {
|
|
47
|
+
@inject(HydraniumTypes.SharedCoreServices) protected readonly sharedServices!: ServerSharedServices;
|
|
48
|
+
@inject(ModelState) protected readonly modelState!: AbstractHydraniumGlspState<TRoot>;
|
|
49
|
+
|
|
50
|
+
validate(_elements: GModelElement[], _reason?: string): Marker[] {
|
|
51
|
+
return this.markers();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Markers for everything drawn on this diagram, gathered from the
|
|
56
|
+
* diagnostics of every document the index reports as contributing a
|
|
57
|
+
* rendered element. Empty before the source model is loaded, and for any
|
|
58
|
+
* diagnostic whose element is not rendered here.
|
|
59
|
+
*/
|
|
60
|
+
markers(): Marker[] {
|
|
61
|
+
// `sourceUri` is a definite-assignment field — undefined until the
|
|
62
|
+
// storage load flow calls `setSourceRoot`. Guard so a marker request that
|
|
63
|
+
// races initial load returns empty rather than scanning an empty index.
|
|
64
|
+
if (!this.modelState.sourceUri) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const index = this.modelState.index;
|
|
68
|
+
const markers: Marker[] = [];
|
|
69
|
+
// Scan only the documents that contribute rendered elements, not every
|
|
70
|
+
// loaded document. The rendered-check below still keeps only what is
|
|
71
|
+
// drawn here.
|
|
72
|
+
for (const uri of index.renderedDocumentUris()) {
|
|
73
|
+
const document = this.sharedServices.workspace.LangiumDocuments.getDocument(URI.parse(uri));
|
|
74
|
+
if (!document) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// Diagnostics are produced by the framework's `HydraniumDocumentValidator`,
|
|
78
|
+
// which emits `TransferLspDiagnostic` (LSP `Diagnostic` + `element` path).
|
|
79
|
+
// Parser/lexer diagnostics carry no `element`; the lookup drops them.
|
|
80
|
+
const diagnostics = document.diagnostics as TransferLspDiagnostic[] | undefined;
|
|
81
|
+
if (!diagnostics || diagnostics.length === 0) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const root = document.parseResult.value;
|
|
85
|
+
const locator = this.sharedServices.ServiceRegistry.getServices(document.uri).workspace.AstNodeLocator;
|
|
86
|
+
const lookups: DiagnosticMarkerLookups = {
|
|
87
|
+
resolveElement: path => (path ? locator.getAstNode(root, path) : undefined),
|
|
88
|
+
renderedIdsFor: astNode => {
|
|
89
|
+
// A node renders as: every GModel element explicitly registered as
|
|
90
|
+
// representing it (reference projections, possibly several), plus its
|
|
91
|
+
// own stable id, for an element keyed directly by it. Keep only the
|
|
92
|
+
// ids actually drawn on this diagram.
|
|
93
|
+
const candidates = new Set(index.findElementIds(astNode));
|
|
94
|
+
const stableId = index.findId(astNode);
|
|
95
|
+
if (stableId !== undefined) {
|
|
96
|
+
candidates.add(stableId);
|
|
97
|
+
}
|
|
98
|
+
return [...candidates].filter(id => index.find(id) !== undefined);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
markers.push(...diagnosticsToMarkers(diagnostics, lookups));
|
|
102
|
+
}
|
|
103
|
+
return markers;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -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
|
+
|
|
10
|
+
export * from './diagnostic-markers.js';
|
|
11
|
+
export * from './hydranium-glsp-model-validator.js';
|