@hydranium/glsp-client-theia 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 (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/lib/browser/action-dispatcher.d.ts +85 -0
  4. package/lib/browser/action-dispatcher.d.ts.map +1 -0
  5. package/lib/browser/action-dispatcher.js +238 -0
  6. package/lib/browser/action-dispatcher.js.map +1 -0
  7. package/lib/browser/client-contribution.d.ts +53 -0
  8. package/lib/browser/client-contribution.d.ts.map +1 -0
  9. package/lib/browser/client-contribution.js +111 -0
  10. package/lib/browser/client-contribution.js.map +1 -0
  11. package/lib/browser/diagram-loader.d.ts +123 -0
  12. package/lib/browser/diagram-loader.d.ts.map +1 -0
  13. package/lib/browser/diagram-loader.js +153 -0
  14. package/lib/browser/diagram-loader.js.map +1 -0
  15. package/lib/browser/diagram-only-marker-manager.d.ts +28 -0
  16. package/lib/browser/diagram-only-marker-manager.d.ts.map +1 -0
  17. package/lib/browser/diagram-only-marker-manager.js +44 -0
  18. package/lib/browser/diagram-only-marker-manager.js.map +1 -0
  19. package/lib/browser/diagram-widget.d.ts +97 -0
  20. package/lib/browser/diagram-widget.d.ts.map +1 -0
  21. package/lib/browser/diagram-widget.js +172 -0
  22. package/lib/browser/diagram-widget.js.map +1 -0
  23. package/lib/browser/glsp-client-theia-module.d.ts +40 -0
  24. package/lib/browser/glsp-client-theia-module.d.ts.map +1 -0
  25. package/lib/browser/glsp-client-theia-module.js +46 -0
  26. package/lib/browser/glsp-client-theia-module.js.map +1 -0
  27. package/lib/browser/glsp-diagram-manager.d.ts +46 -0
  28. package/lib/browser/glsp-diagram-manager.d.ts.map +1 -0
  29. package/lib/browser/glsp-diagram-manager.js +66 -0
  30. package/lib/browser/glsp-diagram-manager.js.map +1 -0
  31. package/lib/browser/glsp-message-service.d.ts +59 -0
  32. package/lib/browser/glsp-message-service.d.ts.map +1 -0
  33. package/lib/browser/glsp-message-service.js +97 -0
  34. package/lib/browser/glsp-message-service.js.map +1 -0
  35. package/lib/browser/glsp-theia-frontend-module.d.ts +110 -0
  36. package/lib/browser/glsp-theia-frontend-module.d.ts.map +1 -0
  37. package/lib/browser/glsp-theia-frontend-module.js +133 -0
  38. package/lib/browser/glsp-theia-frontend-module.js.map +1 -0
  39. package/lib/browser/hidden-bounds-updater.d.ts +122 -0
  40. package/lib/browser/hidden-bounds-updater.d.ts.map +1 -0
  41. package/lib/browser/hidden-bounds-updater.js +207 -0
  42. package/lib/browser/hidden-bounds-updater.js.map +1 -0
  43. package/lib/browser/hydranium-glsp-diagram-configuration.d.ts +52 -0
  44. package/lib/browser/hydranium-glsp-diagram-configuration.d.ts.map +1 -0
  45. package/lib/browser/hydranium-glsp-diagram-configuration.js +72 -0
  46. package/lib/browser/hydranium-glsp-diagram-configuration.js.map +1 -0
  47. package/lib/browser/index.d.ts +20 -0
  48. package/lib/browser/index.d.ts.map +1 -0
  49. package/lib/browser/index.js +38 -0
  50. package/lib/browser/index.js.map +1 -0
  51. package/lib/index.d.ts +10 -0
  52. package/lib/index.d.ts.map +1 -0
  53. package/lib/index.js +39 -0
  54. package/lib/index.js.map +1 -0
  55. package/lib/node/connection-container-module.d.ts +22 -0
  56. package/lib/node/connection-container-module.d.ts.map +1 -0
  57. package/lib/node/connection-container-module.js +36 -0
  58. package/lib/node/connection-container-module.js.map +1 -0
  59. package/lib/node/glsp-server-connection-handler.d.ts +49 -0
  60. package/lib/node/glsp-server-connection-handler.d.ts.map +1 -0
  61. package/lib/node/glsp-server-connection-handler.js +64 -0
  62. package/lib/node/glsp-server-connection-handler.js.map +1 -0
  63. package/lib/node/index.d.ts +11 -0
  64. package/lib/node/index.d.ts.map +1 -0
  65. package/lib/node/index.js +28 -0
  66. package/lib/node/index.js.map +1 -0
  67. package/lib/testing/bind-recorder.d.ts +67 -0
  68. package/lib/testing/bind-recorder.d.ts.map +1 -0
  69. package/lib/testing/bind-recorder.js +72 -0
  70. package/lib/testing/bind-recorder.js.map +1 -0
  71. package/lib/testing/index.d.ts +10 -0
  72. package/lib/testing/index.d.ts.map +1 -0
  73. package/lib/testing/index.js +30 -0
  74. package/lib/testing/index.js.map +1 -0
  75. package/package.json +114 -0
  76. package/src/browser/action-dispatcher.ts +257 -0
  77. package/src/browser/client-contribution.ts +100 -0
  78. package/src/browser/diagram-loader.ts +173 -0
  79. package/src/browser/diagram-only-marker-manager.ts +33 -0
  80. package/src/browser/diagram-widget.ts +178 -0
  81. package/src/browser/glsp-client-theia-module.ts +54 -0
  82. package/src/browser/glsp-diagram-manager.ts +67 -0
  83. package/src/browser/glsp-message-service.ts +90 -0
  84. package/src/browser/glsp-theia-frontend-module.ts +157 -0
  85. package/src/browser/hidden-bounds-updater.ts +212 -0
  86. package/src/browser/hydranium-glsp-diagram-configuration.ts +63 -0
  87. package/src/browser/index.ts +22 -0
  88. package/src/index.ts +23 -0
  89. package/src/node/connection-container-module.ts +34 -0
  90. package/src/node/glsp-server-connection-handler.ts +69 -0
  91. package/src/node/index.ts +12 -0
  92. package/src/testing/bind-recorder.ts +126 -0
  93. package/src/testing/index.ts +15 -0
  94. package/style/diagram-loading.css +67 -0
@@ -0,0 +1,110 @@
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 ContainerContext, DiagramConfiguration, GLSPClientContribution, type GLSPDiagramManager, GLSPTheiaFrontendModule } from '@eclipse-glsp/theia-integration';
10
+ import { type GLSPDiagramLanguage } from '@eclipse-glsp/theia-integration/lib/common';
11
+ import type { interfaces } from '@theia/core/shared/inversify';
12
+ /**
13
+ * Sentinel returned from {@link AbstractHydraniumGlspTheiaFrontendModule.bindClientContribution}
14
+ * to mean "this module deliberately does not bind a GLSPClientContribution"
15
+ * — used for secondary diagram types that share a GLSP server with a
16
+ * primary diagram type whose module already bound the contribution. The
17
+ * override becomes a no-op rather than the framework default.
18
+ */
19
+ export declare const SkipClientContribution: unique symbol;
20
+ export type SkipClientContribution = typeof SkipClientContribution;
21
+ /**
22
+ * `GLSPTheiaFrontendModule` subclass that factors out the method overrides
23
+ * every adopter writes verbatim (`bindDiagramConfiguration` /
24
+ * `bindGLSPClientContribution` / `configureDiagramManager`) into hook methods
25
+ * reading from abstract fields.
26
+ *
27
+ * Adopters subclass and provide:
28
+ * - {@link diagramLanguage} (declared `abstract` on the base class but
29
+ * `readonly` on the base type — `GLSPTheiaFrontendModule` requires it)
30
+ * - {@link diagramConfiguration} — the adopter's `DiagramConfiguration`
31
+ * - {@link diagramManager} — the adopter's `GLSPDiagramManager` subclass
32
+ *
33
+ * Optional override hook:
34
+ * - {@link bindClientContribution} — return a `Newable<GLSPClientContribution>`
35
+ * to bind it (the common case), {@link SkipClientContribution} to
36
+ * bypass binding entirely (secondary diagrams), or `undefined` to
37
+ * defer to `super.bindGLSPClientContribution(context)`. Default
38
+ * returns `undefined` (framework default).
39
+ *
40
+ * Adopter-specific customisation that stays as `override` on the subclass:
41
+ * - `bindDiagramWidgetFactory` — custom `GLSPDiagramWidget` rebinds
42
+ * - `configure` — LibAvoid initialiser, color contribution, startup hooks
43
+ * - `enableLayoutCommands` / `enableMarkerNavigationCommands` — flags
44
+ *
45
+ * Abstract base class + adopter subclass with concrete fields, following the
46
+ * GLSP module convention. No `Default*` concrete sibling because the abstract
47
+ * fields have no sane defaults — every adopter must provide them.
48
+ */
49
+ export declare abstract class AbstractHydraniumGlspTheiaFrontendModule extends GLSPTheiaFrontendModule {
50
+ /** Wire-format identifiers + file routing — required by the base. */
51
+ abstract readonly diagramLanguage: GLSPDiagramLanguage;
52
+ /** Adopter's `DiagramConfiguration` class. Bound via `bindDiagramConfiguration`. */
53
+ protected abstract readonly diagramConfiguration: interfaces.Newable<DiagramConfiguration>;
54
+ /** Adopter's `GLSPDiagramManager` class. Bound + registered via `configureDiagramManager`. */
55
+ protected abstract readonly diagramManager: interfaces.Newable<GLSPDiagramManager>;
56
+ /**
57
+ * Theia preference id driving the framework log threshold, e.g.
58
+ * `'my-language.log.level'`. When set, {@link initialize} binds
59
+ * `LogLevelPreferenceContribution` so the level is applied at
60
+ * application start and kept in sync on change.
61
+ *
62
+ * It belongs here rather than beside the channel name in
63
+ * `createGlspClientTheiaModule`'s options because the two have different
64
+ * scopes: the channel is per diagram container, while the threshold is a
65
+ * process-global and must be applied once, from the frontend container.
66
+ */
67
+ protected readonly logLevelPreference?: string;
68
+ /**
69
+ * Hook returning the {@link GLSPClientContribution} class the framework
70
+ * should bind for this diagram module:
71
+ * - `undefined` (default) — invoke `super.bindGLSPClientContribution(context)`
72
+ * - a `Newable<GLSPClientContribution>` — bind it to-self singleton + bind
73
+ * `GLSPClientContribution` to the service
74
+ * - {@link SkipClientContribution} — no-op (secondary diagrams sharing
75
+ * a GLSP server with a primary diagram whose module already bound
76
+ * the contribution)
77
+ */
78
+ protected bindClientContribution(): interfaces.Newable<GLSPClientContribution> | SkipClientContribution | undefined;
79
+ /**
80
+ * Adds the framework's frontend-scoped bindings on top of the base wiring.
81
+ *
82
+ * Overrides `initialize` — the base's own orchestrator — rather than
83
+ * `configure`, which is documented as the *adopter's* hook: a subclass that
84
+ * overrides `configure` and forgets `super.configure(context)` would otherwise
85
+ * silently lose these bindings.
86
+ */
87
+ initialize(context: ContainerContext): void;
88
+ bindDiagramConfiguration(context: ContainerContext): void;
89
+ bindGLSPClientContribution(context: ContainerContext): void;
90
+ configureDiagramManager(context: ContainerContext): void;
91
+ /**
92
+ * Binds the framework diagram widget on top of the base factory wiring, so
93
+ * every hydranium head gets the loading overlay.
94
+ *
95
+ * `super` binds `GLSPDiagramWidget` to itself (via `lazyBind`, a no-op when
96
+ * already bound) plus the `DiagramWidgetFactory`; the rebind then points the
97
+ * same token at the subclass, leaving the factory untouched.
98
+ *
99
+ * Unconditional on purpose. {@link HydraniumGlspDiagramWidget} differs from
100
+ * GLSP's widget only by the overlay, so there is no flag here: an adopter that
101
+ * wants different behaviour overrides the widget (opt out of the overlay by
102
+ * no-op'ing `showLoadingOverlay`), and one that wants its own subclass rebinds
103
+ * this token again after calling `super`. A module-level flag gating the
104
+ * rebind would be worse than useless: it decides which CLASS to bind, so an
105
+ * adopter subclassing the framework widget and setting the flag to `false`
106
+ * still gets the overlay, and the flag's name lies.
107
+ */
108
+ bindDiagramWidgetFactory(context: ContainerContext): void;
109
+ }
110
+ //# sourceMappingURL=glsp-theia-frontend-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glsp-theia-frontend-module.d.ts","sourceRoot":"","sources":["../../src/browser/glsp-theia-frontend-module.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EACJ,KAAK,gBAAgB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,kBAAkB,EAEvB,uBAAuB,EAEzB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAEtF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAG/D;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,eAAoE,CAAC;AACxG,MAAM,MAAM,sBAAsB,GAAG,OAAO,sBAAsB,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,8BAAsB,wCAAyC,SAAQ,uBAAuB;IAC3F,qEAAqE;IACrE,kBAA2B,eAAe,EAAE,mBAAmB,CAAC;IAEhE,oFAAoF;IACpF,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,UAAU,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAE3F,8FAA8F;IAC9F,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAEnF;;;;;;;;;;OAUG;IACH,SAAS,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE/C;;;;;;;;;OASG;IACH,SAAS,CAAC,sBAAsB,IAAI,UAAU,CAAC,OAAO,CAAC,sBAAsB,CAAC,GAAG,sBAAsB,GAAG,SAAS;IAInH;;;;;;;OAOG;IACM,UAAU,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAO3C,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAIzD,0BAA0B,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAa3D,uBAAuB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAKjE;;;;;;;;;;;;;;;;OAgBG;IACM,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;CAIpE"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ /********************************************************************************
3
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
4
+ *
5
+ * This program and the accompanying materials are made available under the
6
+ * terms of the MIT License which is available in the project root.
7
+ *
8
+ * SPDX-License-Identifier: MIT
9
+ ********************************************************************************/
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.AbstractHydraniumGlspTheiaFrontendModule = exports.SkipClientContribution = void 0;
12
+ const theia_integration_1 = require("@eclipse-glsp/theia-integration");
13
+ const browser_1 = require("@hydranium/client-theia/lib/browser");
14
+ const diagram_widget_1 = require("./diagram-widget");
15
+ /**
16
+ * Sentinel returned from {@link AbstractHydraniumGlspTheiaFrontendModule.bindClientContribution}
17
+ * to mean "this module deliberately does not bind a GLSPClientContribution"
18
+ * — used for secondary diagram types that share a GLSP server with a
19
+ * primary diagram type whose module already bound the contribution. The
20
+ * override becomes a no-op rather than the framework default.
21
+ */
22
+ exports.SkipClientContribution = Symbol.for('@hydranium/glsp-client-theia#SkipClientContribution');
23
+ /**
24
+ * `GLSPTheiaFrontendModule` subclass that factors out the method overrides
25
+ * every adopter writes verbatim (`bindDiagramConfiguration` /
26
+ * `bindGLSPClientContribution` / `configureDiagramManager`) into hook methods
27
+ * reading from abstract fields.
28
+ *
29
+ * Adopters subclass and provide:
30
+ * - {@link diagramLanguage} (declared `abstract` on the base class but
31
+ * `readonly` on the base type — `GLSPTheiaFrontendModule` requires it)
32
+ * - {@link diagramConfiguration} — the adopter's `DiagramConfiguration`
33
+ * - {@link diagramManager} — the adopter's `GLSPDiagramManager` subclass
34
+ *
35
+ * Optional override hook:
36
+ * - {@link bindClientContribution} — return a `Newable<GLSPClientContribution>`
37
+ * to bind it (the common case), {@link SkipClientContribution} to
38
+ * bypass binding entirely (secondary diagrams), or `undefined` to
39
+ * defer to `super.bindGLSPClientContribution(context)`. Default
40
+ * returns `undefined` (framework default).
41
+ *
42
+ * Adopter-specific customisation that stays as `override` on the subclass:
43
+ * - `bindDiagramWidgetFactory` — custom `GLSPDiagramWidget` rebinds
44
+ * - `configure` — LibAvoid initialiser, color contribution, startup hooks
45
+ * - `enableLayoutCommands` / `enableMarkerNavigationCommands` — flags
46
+ *
47
+ * Abstract base class + adopter subclass with concrete fields, following the
48
+ * GLSP module convention. No `Default*` concrete sibling because the abstract
49
+ * fields have no sane defaults — every adopter must provide them.
50
+ */
51
+ class AbstractHydraniumGlspTheiaFrontendModule extends theia_integration_1.GLSPTheiaFrontendModule {
52
+ /**
53
+ * Theia preference id driving the framework log threshold, e.g.
54
+ * `'my-language.log.level'`. When set, {@link initialize} binds
55
+ * `LogLevelPreferenceContribution` so the level is applied at
56
+ * application start and kept in sync on change.
57
+ *
58
+ * It belongs here rather than beside the channel name in
59
+ * `createGlspClientTheiaModule`'s options because the two have different
60
+ * scopes: the channel is per diagram container, while the threshold is a
61
+ * process-global and must be applied once, from the frontend container.
62
+ */
63
+ logLevelPreference;
64
+ /**
65
+ * Hook returning the {@link GLSPClientContribution} class the framework
66
+ * should bind for this diagram module:
67
+ * - `undefined` (default) — invoke `super.bindGLSPClientContribution(context)`
68
+ * - a `Newable<GLSPClientContribution>` — bind it to-self singleton + bind
69
+ * `GLSPClientContribution` to the service
70
+ * - {@link SkipClientContribution} — no-op (secondary diagrams sharing
71
+ * a GLSP server with a primary diagram whose module already bound
72
+ * the contribution)
73
+ */
74
+ bindClientContribution() {
75
+ return undefined;
76
+ }
77
+ /**
78
+ * Adds the framework's frontend-scoped bindings on top of the base wiring.
79
+ *
80
+ * Overrides `initialize` — the base's own orchestrator — rather than
81
+ * `configure`, which is documented as the *adopter's* hook: a subclass that
82
+ * overrides `configure` and forgets `super.configure(context)` would otherwise
83
+ * silently lose these bindings.
84
+ */
85
+ initialize(context) {
86
+ super.initialize(context);
87
+ if (this.logLevelPreference) {
88
+ (0, browser_1.bindLogLevelPreference)(context.bind, this.logLevelPreference);
89
+ }
90
+ }
91
+ bindDiagramConfiguration(context) {
92
+ context.bind(theia_integration_1.DiagramConfiguration).to(this.diagramConfiguration);
93
+ }
94
+ bindGLSPClientContribution(context) {
95
+ const contribution = this.bindClientContribution();
96
+ if (contribution === exports.SkipClientContribution) {
97
+ return;
98
+ }
99
+ if (contribution === undefined) {
100
+ super.bindGLSPClientContribution(context);
101
+ return;
102
+ }
103
+ context.bind(contribution).toSelf().inSingletonScope();
104
+ context.bind(theia_integration_1.GLSPClientContribution).toService(contribution);
105
+ }
106
+ configureDiagramManager(context) {
107
+ context.bind(this.diagramManager).toSelf().inSingletonScope();
108
+ (0, theia_integration_1.registerDiagramManager)(context.bind, this.diagramManager, false);
109
+ }
110
+ /**
111
+ * Binds the framework diagram widget on top of the base factory wiring, so
112
+ * every hydranium head gets the loading overlay.
113
+ *
114
+ * `super` binds `GLSPDiagramWidget` to itself (via `lazyBind`, a no-op when
115
+ * already bound) plus the `DiagramWidgetFactory`; the rebind then points the
116
+ * same token at the subclass, leaving the factory untouched.
117
+ *
118
+ * Unconditional on purpose. {@link HydraniumGlspDiagramWidget} differs from
119
+ * GLSP's widget only by the overlay, so there is no flag here: an adopter that
120
+ * wants different behaviour overrides the widget (opt out of the overlay by
121
+ * no-op'ing `showLoadingOverlay`), and one that wants its own subclass rebinds
122
+ * this token again after calling `super`. A module-level flag gating the
123
+ * rebind would be worse than useless: it decides which CLASS to bind, so an
124
+ * adopter subclassing the framework widget and setting the flag to `false`
125
+ * still gets the overlay, and the flag's name lies.
126
+ */
127
+ bindDiagramWidgetFactory(context) {
128
+ super.bindDiagramWidgetFactory(context);
129
+ context.rebind(theia_integration_1.GLSPDiagramWidget).to(diagram_widget_1.HydraniumGlspDiagramWidget);
130
+ }
131
+ }
132
+ exports.AbstractHydraniumGlspTheiaFrontendModule = AbstractHydraniumGlspTheiaFrontendModule;
133
+ //# sourceMappingURL=glsp-theia-frontend-module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glsp-theia-frontend-module.js","sourceRoot":"","sources":["../../src/browser/glsp-theia-frontend-module.ts"],"names":[],"mappings":";AAAA;;;;;;;kFAOkF;;;AAElF,uEAQyC;AAEzC,iEAA6E;AAE7E,qDAA8D;AAE9D;;;;;;GAMG;AACU,QAAA,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;AAGxG;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAsB,wCAAyC,SAAQ,2CAAuB;IAU3F;;;;;;;;;;OAUG;IACgB,kBAAkB,CAAU;IAE/C;;;;;;;;;OASG;IACO,sBAAsB;QAC7B,OAAO,SAAS,CAAC;IACpB,CAAC;IAED;;;;;;;OAOG;IACM,UAAU,CAAC,OAAyB;QAC1C,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC3B,IAAA,gCAAsB,EAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACjE,CAAC;IACJ,CAAC;IAEQ,wBAAwB,CAAC,OAAyB;QACxD,OAAO,CAAC,IAAI,CAAC,wCAAoB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACpE,CAAC;IAEQ,0BAA0B,CAAC,OAAyB;QAC1D,MAAM,YAAY,GAAG,IAAI,CAAC,sBAAsB,EAAE,CAAC;QACnD,IAAI,YAAY,KAAK,8BAAsB,EAAE,CAAC;YAC3C,OAAO;QACV,CAAC;QACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC9B,KAAK,CAAC,0BAA0B,CAAC,OAAO,CAAC,CAAC;YAC1C,OAAO;QACV,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,0CAAsB,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAChE,CAAC;IAEQ,uBAAuB,CAAC,OAAyB;QACvD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;QAC9D,IAAA,0CAAsB,EAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACM,wBAAwB,CAAC,OAAyB;QACxD,KAAK,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC;QACxC,OAAO,CAAC,MAAM,CAAC,qCAAiB,CAAC,CAAC,EAAE,CAAC,2CAA0B,CAAC,CAAC;IACpE,CAAC;CACH;AA/FD,4FA+FC"}
@@ -0,0 +1,122 @@
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 Action, type ElementAndRoutingPoints, type GModelElement, type GRoutableElement, GLSPHiddenBoundsUpdater, RequestBoundsAction } from '@eclipse-glsp/client';
10
+ import { ChannelLogger } from '@hydranium/client-theia/lib/browser';
11
+ import { type Clock } from '@hydranium/protocol';
12
+ import { type VNode } from 'snabbdom';
13
+ /**
14
+ * Instruments sprotty's hidden-bounds pass and repairs degenerate routes before
15
+ * they go on the wire.
16
+ *
17
+ * **Why the framework owns this.** Every GLSP head runs the hidden-bounds pass on
18
+ * every model update, and it is the one client-side phase that scales with the
19
+ * *rendered element count* rather than the model size — labels, compartments and
20
+ * edge decorations expand a modest node count into orders of magnitude more DOM
21
+ * elements. Without a timing line there is no way to tell a slow measurement pass
22
+ * apart from slow edge routing or a slow server round trip; with one,
23
+ * `bounds-request` either exonerates the client in a sentence or names the
24
+ * dominant cost.
25
+ *
26
+ * Emits exactly one `trace` line per bounds request — `trace` because the
27
+ * frequency matches the per-action traffic `HydraniumGlspActionDispatcher` logs
28
+ * there (a bounds request is driven by those actions), so it belongs with them
29
+ * rather than above them. The line carries:
30
+ *
31
+ * - `server` / `local` — whether the request came from the server or from a
32
+ * client-local {@link LocalRequestBoundsAction}
33
+ * - `scope=<ids>` — the elements a scoped request named; absent when the request
34
+ * covers the whole diagram
35
+ * - `measured=N` — DOM elements whose bounds were read. Exceeds the scoped id
36
+ * count because the base class expands each requested element to its
37
+ * descendants
38
+ * - `getBBox=Nms` — {@link getBoundsFromDOM} **only**: the layout pass and the
39
+ * `ComputedBoundsAction` assembly stay outside it, so the number isolates raw
40
+ * measurement cost
41
+ *
42
+ * Composed from {@link Clock.measure} rather than `Tracer.time`, matching
43
+ * `HydraniumDocumentBuilder`'s phase instrumentation. `Tracer.time` is for "tell
44
+ * me when this is slow" and is deliberately silent on a fast success, which would
45
+ * drop the element count on every normal pass — and forcing it to emit costs a
46
+ * paired `[#N start]` line per request. This is a per-occurrence record, so it
47
+ * measures and composes its own line.
48
+ *
49
+ * Bound by `createGlspClientTheiaModule` via `rebind(GLSPHiddenBoundsUpdater)`.
50
+ */
51
+ export declare class HydraniumHiddenBoundsUpdater extends GLSPHiddenBoundsUpdater {
52
+ protected readonly channel: ChannelLogger;
53
+ /** Not injected: the browser container binds no {@link Clock}, and this only
54
+ * measures — no logic is gated on time, so there is nothing to fake in
55
+ * production. Overridden in tests for a deterministic elapsed value. */
56
+ protected readonly clock: Clock;
57
+ /**
58
+ * Scope description for the in-flight request, read from the `cause` in
59
+ * {@link postUpdate} and consumed by {@link getBoundsFromDOM} — which the base
60
+ * class calls with no arguments, so the cause cannot be threaded through.
61
+ */
62
+ protected currentScope?: string;
63
+ decorate(vnode: VNode, element: GModelElement): VNode;
64
+ /**
65
+ * Replace the routing entry the base class just pushed when it carries fewer
66
+ * than two points, which is not a valid route for any edge.
67
+ *
68
+ * `calcElementAndRoute` already guards the case where the registered router
69
+ * returns *nothing* — it falls back to source + own routing points + target.
70
+ * The hole is one step further in: `calcRoute` filters duplicate points at
71
+ * `Number.EPSILON`, so while obstacles still carry sprotty's unmeasured-bounds
72
+ * sentinel `(100, 100, -1, -1)` the source and target coincide and a valid
73
+ * two-point route collapses to a single point. That result is defined, so the
74
+ * upstream truthiness guard never fires and the single point ships.
75
+ *
76
+ * The substitute is deliberately upstream's own fallback shape rather than a
77
+ * new invention, so a repaired route is indistinguishable from a route the
78
+ * base class would have produced had it noticed. Only already-invalid payloads
79
+ * are touched, so a head with a working router is unaffected.
80
+ */
81
+ protected repairLastRoute(element: GRoutableElement): void;
82
+ /** A route needs at least a start and an end point to describe an edge. */
83
+ protected hasValidRoute(route: ElementAndRoutingPoints): boolean;
84
+ /** Upstream's `calcElementAndRoute` no-router fallback: the element's own
85
+ * bendpoints framed by its source and target anchor positions. */
86
+ protected toSourceTargetRoute(element: GRoutableElement): ElementAndRoutingPoints;
87
+ protected getBoundsFromDOM(): void;
88
+ /** Format the per-request line. Override to change the wording. */
89
+ protected formatBoundsRequest(scope: string, measured: number, elapsedMs: number): string;
90
+ postUpdate(cause?: Action): void;
91
+ /**
92
+ * Scope facts for the log line: where the request came from, and which
93
+ * elements it asked for.
94
+ *
95
+ * Origin is read from {@link ServerAction}, the `__receivedFromServer` marker
96
+ * `GLSPModelSource` stamps on inbound actions, rather than from
97
+ * `LocalRequestBoundsAction.is`. The latter would answer the same today, but
98
+ * only incidentally: its `elementIDs` check is declared optional, so it is
99
+ * really just "a bounds request that did not come from the server". Keying on
100
+ * the marker states that directly, and keeps an *unscoped* local request from
101
+ * being mislabelled `server` if GLSP ever tightens that guard.
102
+ */
103
+ protected formatCause(cause: Action): string;
104
+ /**
105
+ * Name the elements a scoped request asked for, or `undefined` when it covers
106
+ * the whole diagram.
107
+ *
108
+ * Deliberately the ids and not their count. A scoped request in practice names
109
+ * a single element, so a count is always `1` and says nothing, while the id
110
+ * says *which* element was re-measured — and it is the only part of the line
111
+ * that distinguishes one such request from the next. It also stops the line
112
+ * reading as a contradiction: `scope=node0, measured=6` is coherent (the base
113
+ * class expands a requested element to its descendants, so one id measures six
114
+ * DOM elements), where `scoped=1, measured=6` invites the reader to wonder
115
+ * which number is wrong.
116
+ *
117
+ * A request naming only the root is treated as unscoped: it measures
118
+ * everything, so the id adds nothing over the absence of a `scope` tag.
119
+ */
120
+ protected formatScope(cause: RequestBoundsAction): string | undefined;
121
+ }
122
+ //# sourceMappingURL=hidden-bounds-updater.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hidden-bounds-updater.d.ts","sourceRoot":"","sources":["../../src/browser/hidden-bounds-updater.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EACJ,KAAK,MAAM,EACX,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,uBAAuB,EAGvB,mBAAmB,EAGrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAOtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBACa,4BAA6B,SAAQ,uBAAuB;IAC/C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAG,aAAa,CAAC;IAElE;;6EAEyE;IACzE,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAqB;IAEpD;;;;OAIG;IACH,SAAS,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,GAAG,KAAK;IAQ9D;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAQ1D,2EAA2E;IAC3E,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO;IAIhE;uEACmE;IACnE,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,uBAAuB;cAO9D,gBAAgB,IAAI,IAAI;IAa3C,mEAAmE;IACnE,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAIhF,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAazC;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAM5C;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS;CAcvE"}
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ /********************************************************************************
3
+ * Copyright (c) 2026 CrossBreeze, EclipseSource and others.
4
+ *
5
+ * This program and the accompanying materials are made available under the
6
+ * terms of the MIT License which is available in the project root.
7
+ *
8
+ * SPDX-License-Identifier: MIT
9
+ ********************************************************************************/
10
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
11
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ var __metadata = (this && this.__metadata) || function (k, v) {
17
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.HydraniumHiddenBoundsUpdater = void 0;
21
+ const client_1 = require("@eclipse-glsp/client");
22
+ const browser_1 = require("@hydranium/client-theia/lib/browser");
23
+ const protocol_1 = require("@hydranium/protocol");
24
+ const inversify_1 = require("@theia/core/shared/inversify");
25
+ /** How many scoped element ids the log line names before summarising the rest.
26
+ * A scoped request names one element in practice; the cap only stops a
27
+ * pathological caller from writing a thousand ids into the channel. */
28
+ const SCOPE_ID_CAP = 3;
29
+ /**
30
+ * Instruments sprotty's hidden-bounds pass and repairs degenerate routes before
31
+ * they go on the wire.
32
+ *
33
+ * **Why the framework owns this.** Every GLSP head runs the hidden-bounds pass on
34
+ * every model update, and it is the one client-side phase that scales with the
35
+ * *rendered element count* rather than the model size — labels, compartments and
36
+ * edge decorations expand a modest node count into orders of magnitude more DOM
37
+ * elements. Without a timing line there is no way to tell a slow measurement pass
38
+ * apart from slow edge routing or a slow server round trip; with one,
39
+ * `bounds-request` either exonerates the client in a sentence or names the
40
+ * dominant cost.
41
+ *
42
+ * Emits exactly one `trace` line per bounds request — `trace` because the
43
+ * frequency matches the per-action traffic `HydraniumGlspActionDispatcher` logs
44
+ * there (a bounds request is driven by those actions), so it belongs with them
45
+ * rather than above them. The line carries:
46
+ *
47
+ * - `server` / `local` — whether the request came from the server or from a
48
+ * client-local {@link LocalRequestBoundsAction}
49
+ * - `scope=<ids>` — the elements a scoped request named; absent when the request
50
+ * covers the whole diagram
51
+ * - `measured=N` — DOM elements whose bounds were read. Exceeds the scoped id
52
+ * count because the base class expands each requested element to its
53
+ * descendants
54
+ * - `getBBox=Nms` — {@link getBoundsFromDOM} **only**: the layout pass and the
55
+ * `ComputedBoundsAction` assembly stay outside it, so the number isolates raw
56
+ * measurement cost
57
+ *
58
+ * Composed from {@link Clock.measure} rather than `Tracer.time`, matching
59
+ * `HydraniumDocumentBuilder`'s phase instrumentation. `Tracer.time` is for "tell
60
+ * me when this is slow" and is deliberately silent on a fast success, which would
61
+ * drop the element count on every normal pass — and forcing it to emit costs a
62
+ * paired `[#N start]` line per request. This is a per-occurrence record, so it
63
+ * measures and composes its own line.
64
+ *
65
+ * Bound by `createGlspClientTheiaModule` via `rebind(GLSPHiddenBoundsUpdater)`.
66
+ */
67
+ let HydraniumHiddenBoundsUpdater = class HydraniumHiddenBoundsUpdater extends client_1.GLSPHiddenBoundsUpdater {
68
+ channel;
69
+ /** Not injected: the browser container binds no {@link Clock}, and this only
70
+ * measures — no logic is gated on time, so there is nothing to fake in
71
+ * production. Overridden in tests for a deterministic elapsed value. */
72
+ clock = new protocol_1.SystemClock();
73
+ /**
74
+ * Scope description for the in-flight request, read from the `cause` in
75
+ * {@link postUpdate} and consumed by {@link getBoundsFromDOM} — which the base
76
+ * class calls with no arguments, so the cause cannot be threaded through.
77
+ */
78
+ currentScope;
79
+ decorate(vnode, element) {
80
+ super.decorate(vnode, element);
81
+ if ((0, client_1.isRoutable)(element)) {
82
+ this.repairLastRoute(element);
83
+ }
84
+ return vnode;
85
+ }
86
+ /**
87
+ * Replace the routing entry the base class just pushed when it carries fewer
88
+ * than two points, which is not a valid route for any edge.
89
+ *
90
+ * `calcElementAndRoute` already guards the case where the registered router
91
+ * returns *nothing* — it falls back to source + own routing points + target.
92
+ * The hole is one step further in: `calcRoute` filters duplicate points at
93
+ * `Number.EPSILON`, so while obstacles still carry sprotty's unmeasured-bounds
94
+ * sentinel `(100, 100, -1, -1)` the source and target coincide and a valid
95
+ * two-point route collapses to a single point. That result is defined, so the
96
+ * upstream truthiness guard never fires and the single point ships.
97
+ *
98
+ * The substitute is deliberately upstream's own fallback shape rather than a
99
+ * new invention, so a repaired route is indistinguishable from a route the
100
+ * base class would have produced had it noticed. Only already-invalid payloads
101
+ * are touched, so a head with a working router is unaffected.
102
+ */
103
+ repairLastRoute(element) {
104
+ const addedRoute = this.element2route.pop();
105
+ if (addedRoute === undefined) {
106
+ return;
107
+ }
108
+ this.element2route.push(this.hasValidRoute(addedRoute) ? addedRoute : this.toSourceTargetRoute(element));
109
+ }
110
+ /** A route needs at least a start and an end point to describe an edge. */
111
+ hasValidRoute(route) {
112
+ return route.newRoutingPoints !== undefined && route.newRoutingPoints.length >= 2;
113
+ }
114
+ /** Upstream's `calcElementAndRoute` no-router fallback: the element's own
115
+ * bendpoints framed by its source and target anchor positions. */
116
+ toSourceTargetRoute(element) {
117
+ return {
118
+ elementId: element.id,
119
+ newRoutingPoints: [element.source?.position ?? client_1.Point.ORIGIN, ...element.routingPoints, element.target?.position ?? client_1.Point.ORIGIN]
120
+ };
121
+ }
122
+ getBoundsFromDOM() {
123
+ if (this.currentScope === undefined) {
124
+ // Not inside an instrumented `postUpdate` (a subclass calling directly);
125
+ // with no cause there is nothing to attribute a measurement to.
126
+ super.getBoundsFromDOM();
127
+ return;
128
+ }
129
+ // Read before the pass: the base class clears the map on its way out.
130
+ const measured = this.getElement2BoundsData().size;
131
+ const { elapsedMs } = this.clock.measure(() => super.getBoundsFromDOM());
132
+ this.channel.trace(this.formatBoundsRequest(this.currentScope, measured, elapsedMs));
133
+ }
134
+ /** Format the per-request line. Override to change the wording. */
135
+ formatBoundsRequest(scope, measured, elapsedMs) {
136
+ return `bounds-request[${scope}] measured=${measured} getBBox=${elapsedMs.toFixed(0)}ms`;
137
+ }
138
+ postUpdate(cause) {
139
+ if (cause?.kind !== client_1.RequestBoundsAction.KIND) {
140
+ super.postUpdate(cause);
141
+ return;
142
+ }
143
+ this.currentScope = this.formatCause(cause);
144
+ try {
145
+ super.postUpdate(cause);
146
+ }
147
+ finally {
148
+ this.currentScope = undefined;
149
+ }
150
+ }
151
+ /**
152
+ * Scope facts for the log line: where the request came from, and which
153
+ * elements it asked for.
154
+ *
155
+ * Origin is read from {@link ServerAction}, the `__receivedFromServer` marker
156
+ * `GLSPModelSource` stamps on inbound actions, rather than from
157
+ * `LocalRequestBoundsAction.is`. The latter would answer the same today, but
158
+ * only incidentally: its `elementIDs` check is declared optional, so it is
159
+ * really just "a bounds request that did not come from the server". Keying on
160
+ * the marker states that directly, and keeps an *unscoped* local request from
161
+ * being mislabelled `server` if GLSP ever tightens that guard.
162
+ */
163
+ formatCause(cause) {
164
+ const origin = client_1.ServerAction.is(cause) ? 'server' : 'local';
165
+ const scope = this.formatScope(cause);
166
+ return scope ? `${origin} scope=${scope}` : origin;
167
+ }
168
+ /**
169
+ * Name the elements a scoped request asked for, or `undefined` when it covers
170
+ * the whole diagram.
171
+ *
172
+ * Deliberately the ids and not their count. A scoped request in practice names
173
+ * a single element, so a count is always `1` and says nothing, while the id
174
+ * says *which* element was re-measured — and it is the only part of the line
175
+ * that distinguishes one such request from the next. It also stops the line
176
+ * reading as a contradiction: `scope=node0, measured=6` is coherent (the base
177
+ * class expands a requested element to its descendants, so one id measures six
178
+ * DOM elements), where `scoped=1, measured=6` invites the reader to wonder
179
+ * which number is wrong.
180
+ *
181
+ * A request naming only the root is treated as unscoped: it measures
182
+ * everything, so the id adds nothing over the absence of a `scope` tag.
183
+ */
184
+ formatScope(cause) {
185
+ const scopedIds = cause.elementIDs;
186
+ if (!scopedIds || scopedIds.length === 0) {
187
+ return undefined;
188
+ }
189
+ const named = scopedIds.filter(id => id !== cause.newRoot?.id);
190
+ if (named.length === 0) {
191
+ return undefined;
192
+ }
193
+ if (named.length > SCOPE_ID_CAP) {
194
+ return `${named.slice(0, SCOPE_ID_CAP).join(',')},+${named.length - SCOPE_ID_CAP} more`;
195
+ }
196
+ return named.join(',');
197
+ }
198
+ };
199
+ exports.HydraniumHiddenBoundsUpdater = HydraniumHiddenBoundsUpdater;
200
+ __decorate([
201
+ (0, inversify_1.inject)(browser_1.ChannelLogger),
202
+ __metadata("design:type", browser_1.ChannelLogger)
203
+ ], HydraniumHiddenBoundsUpdater.prototype, "channel", void 0);
204
+ exports.HydraniumHiddenBoundsUpdater = HydraniumHiddenBoundsUpdater = __decorate([
205
+ (0, inversify_1.injectable)()
206
+ ], HydraniumHiddenBoundsUpdater);
207
+ //# sourceMappingURL=hidden-bounds-updater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hidden-bounds-updater.js","sourceRoot":"","sources":["../../src/browser/hidden-bounds-updater.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
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 { GLSPDiagramConfiguration } from '@eclipse-glsp/theia-integration';
10
+ import { type Container } from '@theia/core/shared/inversify';
11
+ /**
12
+ * `GLSPDiagramConfiguration` base for hydranium adopters. By default GLSP
13
+ * validation markers propagate into Theia's Problems view (the stock
14
+ * `@eclipse-glsp/theia-integration` behaviour); a head that already publishes
15
+ * the same diagnostics over LSP suppresses that propagation by setting
16
+ * {@link propagateMarkersToProblemsView} to `false`.
17
+ *
18
+ * **When to suppress.** A head with a co-resident LSP that publishes its
19
+ * diagnostics over standard LSP `publishDiagnostics` would otherwise list each
20
+ * error twice: GLSP's `TheiaMarkerManager` pushes the *same* errors again under
21
+ * a different marker owner, and Theia shows the union across owners. The GLSP
22
+ * path is also open-diagram-scoped (markers clear when the diagram closes), so
23
+ * for such a head it cannot reproduce the LSP head's persistent, cross-file
24
+ * Problems entries — it is only ever a flickering duplicate. A graphical-only
25
+ * head (no LSP diagnostics, or markers the LSP never produces) keeps the
26
+ * default so its markers reach the Problems view. The on-diagram decoration is
27
+ * a separate client feedback path (`ApplyMarkersCommand`), unaffected either
28
+ * way.
29
+ *
30
+ * **How.** {@link initializeContainer} hands {@link connectTheiaMarkerManager}
31
+ * the Theia marker-manager factory by default; when suppression is enabled it
32
+ * hands a no-op {@link ExternalMarkerManager} factory instead, so the
33
+ * per-diagram container binds a manager that renders-but-does-not-forward and
34
+ * the real `TheiaMarkerManager` (with its `@postConstruct`
35
+ * `ProblemManager`/shell subscriptions) is never constructed.
36
+ *
37
+ * NB: this overrides `GLSPDiagramConfiguration.initializeContainer` rather than
38
+ * calling `super`. It mirrors the base body (context-menu + marker-manager
39
+ * wiring); revisit if a future `@eclipse-glsp/theia-integration` adds further
40
+ * setup there.
41
+ */
42
+ export declare abstract class AbstractHydraniumGlspDiagramConfiguration extends GLSPDiagramConfiguration {
43
+ /**
44
+ * Whether GLSP markers propagate into Theia's Problems view. `true` (the
45
+ * framework default) keeps the stock Theia propagation; set `false` for a
46
+ * head with a co-resident LSP that already publishes the same diagnostics,
47
+ * to render markers on the diagram only and avoid double-listing.
48
+ */
49
+ protected propagateMarkersToProblemsView: boolean;
50
+ protected initializeContainer(container: Container): void;
51
+ }
52
+ //# sourceMappingURL=hydranium-glsp-diagram-configuration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydranium-glsp-diagram-configuration.d.ts","sourceRoot":"","sources":["../../src/browser/hydranium-glsp-diagram-configuration.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,EAAE,wBAAwB,EAA6D,MAAM,iCAAiC,CAAC;AACtI,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,8BAA8B,CAAC;AAG1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,8BACsB,yCAA0C,SAAQ,wBAAwB;IAC7F;;;;;OAKG;IACH,SAAS,CAAC,8BAA8B,UAAQ;cAE7B,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;CAOpE"}