@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,222 @@
|
|
|
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
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
10
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
12
|
+
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;
|
|
13
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
14
|
+
};
|
|
15
|
+
import { injectable } from 'inversify';
|
|
16
|
+
import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
|
|
17
|
+
import { reconcileSourceModelWrite } from './reconcile-source-model-write.js';
|
|
18
|
+
/**
|
|
19
|
+
* Editable GLSP state for a diagram whose edits span SEVERAL Langium documents —
|
|
20
|
+
* a diagram file plus the semantic file it references, say, where creating a node
|
|
21
|
+
* on the canvas writes both.
|
|
22
|
+
*
|
|
23
|
+
* The single-document `ReconcilingTransferHydraniumGlspState` cannot express
|
|
24
|
+
* that: its `sourceModel`, `persist` and `refetch` are all defined over
|
|
25
|
+
* `sourceUri` alone, so an adopter needing a second document had to override all
|
|
26
|
+
* three — i.e. the entire class. This subclass keeps the same three seams and the
|
|
27
|
+
* same conflict handling (both share {@link reconcileSourceModelWrite}) but
|
|
28
|
+
* defines them over the primary plus the secondary write set registered through
|
|
29
|
+
* {@link AbstractHydraniumGlspState.trackSecondaryDocument}.
|
|
30
|
+
*
|
|
31
|
+
* **Writes are NOT atomic, deliberately, and the window is real.** Each document
|
|
32
|
+
* goes through its own `ModelService.update`, so a failure after the first write
|
|
33
|
+
* has landed leaves the set inconsistent on disk. There is no multi-document
|
|
34
|
+
* transaction to lean on: `WorkspaceLock` serialises builds but does not roll
|
|
35
|
+
* back, and the document store commits per URI. An adopter that cannot accept the
|
|
36
|
+
* window should not span documents in one operation.
|
|
37
|
+
*
|
|
38
|
+
* **What makes the window tolerable is write ORDER, and the rule is
|
|
39
|
+
* referenced-before-referencing** — not "secondaries first" as such. Write the
|
|
40
|
+
* document whose content the others point AT before the documents that point at
|
|
41
|
+
* it, so a partial write leaves an unreferenced element (inert, and the direction
|
|
42
|
+
* an integrity rule can repair) rather than a reference to something that does
|
|
43
|
+
* not exist (a linking error). {@link persist} implements that as
|
|
44
|
+
* secondaries-then-primary, which is correct for the common shape where the
|
|
45
|
+
* primary is the DIAGRAM and the semantics it references are secondaries: the
|
|
46
|
+
* user opened the diagram, so it is also the document the conflict gate should
|
|
47
|
+
* guard. **An adopter whose primary is the referenced document — a semantic file
|
|
48
|
+
* as the diagram source, with layout in a secondary — has the ordering backwards
|
|
49
|
+
* and must override {@link persist} to write the primary first.** Overriding it
|
|
50
|
+
* is the supported route; the base order is a default for the common case, not an
|
|
51
|
+
* invariant of the class.
|
|
52
|
+
*
|
|
53
|
+
* **The conflict gate covers the primary only.** Secondaries are written without
|
|
54
|
+
* a based-on version, so a concurrent foreign edit to one is overwritten rather
|
|
55
|
+
* than reconciled. Gating them too would need a per-document reconcile whose
|
|
56
|
+
* outcomes can disagree (merge one, conflict another) with no way to un-write the
|
|
57
|
+
* merged one — the atomicity problem again, one layer up. The captured versions
|
|
58
|
+
* ARE available via {@link AbstractHydraniumGlspState.capturedVersionOf}, so an
|
|
59
|
+
* adopter that wants a coarser check can compare before writing.
|
|
60
|
+
*/
|
|
61
|
+
let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState extends AbstractHydraniumGlspState {
|
|
62
|
+
/**
|
|
63
|
+
* Last in-sync projection across the whole write set, captured on every
|
|
64
|
+
* {@link setSourceRoot}. Same role as the single-document baseline: the state a
|
|
65
|
+
* forward-write conflict reconciles the user's intent against.
|
|
66
|
+
*/
|
|
67
|
+
baseline;
|
|
68
|
+
/**
|
|
69
|
+
* Projection of the primary plus every registered secondary, in the framework
|
|
70
|
+
* encoder's `'grammar'` mode (authored state only — cross-references as
|
|
71
|
+
* `$refText`, computed / synthetic properties excluded), so `fast-json-patch`
|
|
72
|
+
* diffs per field across all of them at once.
|
|
73
|
+
*
|
|
74
|
+
* A secondary that is not currently loaded is OMITTED rather than represented
|
|
75
|
+
* as `undefined`: an absent key produces no patch operations for that
|
|
76
|
+
* document, whereas an explicit `undefined` would diff as a removal and
|
|
77
|
+
* persist as a deletion of content the state simply could not see.
|
|
78
|
+
*/
|
|
79
|
+
get sourceModel() {
|
|
80
|
+
const secondaries = {};
|
|
81
|
+
for (const uri of this.secondaryUris) {
|
|
82
|
+
const projection = this.projectDocument(uri);
|
|
83
|
+
if (projection) {
|
|
84
|
+
secondaries[uri] = projection;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { primary: this.projectRoot(this._sourceRoot), secondaries };
|
|
88
|
+
}
|
|
89
|
+
setSourceRoot(uri, root) {
|
|
90
|
+
super.setSourceRoot(uri, root);
|
|
91
|
+
this.trackWriteSet(uri);
|
|
92
|
+
this.baseline = this.sourceModel;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Register the secondary documents that belong to the primary at `uri`, via
|
|
96
|
+
* {@link AbstractHydraniumGlspState.trackSecondaryDocument}. Called on every
|
|
97
|
+
* {@link setSourceRoot}, after the primary is captured (so `sourceUri` is
|
|
98
|
+
* current) and BEFORE the baseline is taken (so the baseline includes them).
|
|
99
|
+
* Default: no secondaries.
|
|
100
|
+
*
|
|
101
|
+
* This hook exists because that ordering is a trap an adopter would otherwise
|
|
102
|
+
* hit silently. Registering from an overridden `setSourceRoot` *after*
|
|
103
|
+
* `super.setSourceRoot(...)` runs too late — the baseline has already been
|
|
104
|
+
* captured without the secondaries, so the first conflict reconcile measures
|
|
105
|
+
* the user's intent against a baseline missing half the write set and the
|
|
106
|
+
* secondary edits look like foreign changes. Registering *before* the super
|
|
107
|
+
* call is too early for a URI derived from the new primary. Overriding this
|
|
108
|
+
* instead removes the choice.
|
|
109
|
+
*/
|
|
110
|
+
trackWriteSet(_uri) {
|
|
111
|
+
// No-op by default; adopters with secondaries override.
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Persist the whole write set, then capture the resulting primary root. On a
|
|
115
|
+
* `ConflictError` from the primary, reconcile via the injected policy exactly
|
|
116
|
+
* as the single-document state does — the orchestration is shared.
|
|
117
|
+
*/
|
|
118
|
+
async updateSourceModel(model, version) {
|
|
119
|
+
return reconcileSourceModelWrite(model, version, {
|
|
120
|
+
persist: async (candidate, baseVersion) => {
|
|
121
|
+
const { root } = await this.persist(candidate, baseVersion);
|
|
122
|
+
this.setSourceRoot(this._sourceUri, root);
|
|
123
|
+
},
|
|
124
|
+
refetch: () => this.refetch(),
|
|
125
|
+
baseline: this.baseline,
|
|
126
|
+
conflictResolver: this.conflictResolver,
|
|
127
|
+
logger: this.logger,
|
|
128
|
+
onConflictDropped: () => this.refreshSourceRoot()
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Write hook — secondaries first (ungated), primary last (gated on
|
|
133
|
+
* `baseVersion`). The order is the failure-mode choice documented on the
|
|
134
|
+
* class, not incidental: override this when the primary is the document the
|
|
135
|
+
* others REFERENCE, since then this order writes the references first.
|
|
136
|
+
*/
|
|
137
|
+
async persist(model, baseVersion) {
|
|
138
|
+
for (const [uri, secondary] of Object.entries(model.secondaries)) {
|
|
139
|
+
if (this.hasChanged(this.baseline?.secondaries[uri], secondary)) {
|
|
140
|
+
await this.persistSecondary(uri, secondary);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (!this.hasChanged(this.baseline?.primary, model.primary)) {
|
|
144
|
+
// Nothing to write, so nothing to gate either — return the root already
|
|
145
|
+
// captured rather than round-tripping the document for no reason.
|
|
146
|
+
return { root: this._sourceRoot };
|
|
147
|
+
}
|
|
148
|
+
return this.persistPrimary(model.primary, baseVersion);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Whether `candidate` differs from the baseline projection of the same
|
|
152
|
+
* document, and therefore needs writing.
|
|
153
|
+
*
|
|
154
|
+
* **Skipping unchanged documents is correctness, not an optimisation.** A
|
|
155
|
+
* write goes through `ModelService.update`, which re-serializes from the AST —
|
|
156
|
+
* so writing a document that did not change still rewrites its text, and a
|
|
157
|
+
* serializer is free to normalise formatting and cannot preserve comments.
|
|
158
|
+
* Persisting the whole write set unconditionally therefore means a pure layout
|
|
159
|
+
* drag reflows the semantic file and strips its comments, which is a data
|
|
160
|
+
* loss the user never asked for and would struggle to attribute.
|
|
161
|
+
*
|
|
162
|
+
* Compared by serialised form. Both sides come from the same encoder walking
|
|
163
|
+
* the same shape, so key order is stable and a string compare is sound here;
|
|
164
|
+
* it is also cheap enough to run per document per write.
|
|
165
|
+
*/
|
|
166
|
+
hasChanged(baseline, candidate) {
|
|
167
|
+
return baseline === undefined || JSON.stringify(baseline) !== JSON.stringify(candidate);
|
|
168
|
+
}
|
|
169
|
+
/** Write the primary document, opting into the conflict gate when `baseVersion` is given. */
|
|
170
|
+
async persistPrimary(model, baseVersion) {
|
|
171
|
+
const document = await this.sharedServices.model.ModelService.update({
|
|
172
|
+
uri: this._sourceUri,
|
|
173
|
+
model,
|
|
174
|
+
clientId: this.clientId,
|
|
175
|
+
baseVersion
|
|
176
|
+
});
|
|
177
|
+
return document;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Write one secondary document. Ungated by design (see the class doc); override
|
|
181
|
+
* alongside {@link persistPrimary} when the round-trip differs per document
|
|
182
|
+
* role — a layout file and a semantic file need not share a serializer.
|
|
183
|
+
*/
|
|
184
|
+
async persistSecondary(uri, model) {
|
|
185
|
+
await this.sharedServices.model.ModelService.update({ uri, model, clientId: this.clientId });
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Refetch hook — the current settled projection across the write set, used by
|
|
189
|
+
* the conflict resolver to replay the user's intent against fresh state.
|
|
190
|
+
* Returns `undefined` when the PRIMARY cannot be read, since a reconcile
|
|
191
|
+
* without it has nothing to merge into; an unreadable secondary is omitted the
|
|
192
|
+
* same way {@link sourceModel} omits one.
|
|
193
|
+
*/
|
|
194
|
+
async refetch() {
|
|
195
|
+
const fresh = await this.sharedServices.model.ModelService.validated(this._sourceUri).catch(() => undefined);
|
|
196
|
+
if (!fresh) {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
const secondaries = {};
|
|
200
|
+
for (const uri of this.secondaryUris) {
|
|
201
|
+
const settled = await this.sharedServices.model.ModelService.validated(uri).catch(() => undefined);
|
|
202
|
+
if (settled) {
|
|
203
|
+
secondaries[uri] = this.projectRoot(settled.root);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { primary: this.projectRoot(fresh.root), secondaries };
|
|
207
|
+
}
|
|
208
|
+
/** Project a currently-loaded document's root, or `undefined` when it is not loaded. */
|
|
209
|
+
projectDocument(uri) {
|
|
210
|
+
const root = this.sharedServices.model.ModelService.getDocument(uri)?.parseResult?.value;
|
|
211
|
+
return root ? this.projectRoot(root) : undefined;
|
|
212
|
+
}
|
|
213
|
+
/** Grammar-mode transfer projection of one AST root. The single projection seam. */
|
|
214
|
+
projectRoot(root) {
|
|
215
|
+
return this.sharedServices.model.TransferEncoder.toTransfer(root, 'grammar');
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
ReconcilingMultiDocumentGlspState = __decorate([
|
|
219
|
+
injectable()
|
|
220
|
+
], ReconcilingMultiDocumentGlspState);
|
|
221
|
+
export { ReconcilingMultiDocumentGlspState };
|
|
222
|
+
//# sourceMappingURL=reconciling-multi-document-glsp-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciling-multi-document-glsp-state.js","sourceRoot":"","sources":["../../src/state/reconciling-multi-document-glsp-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
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 JsonModelState } from '@eclipse-glsp/server';
|
|
10
|
+
import { type AstNode } from '@hydranium/langium';
|
|
11
|
+
import { type TransferElement } from '@hydranium/protocol';
|
|
12
|
+
import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
|
|
13
|
+
/**
|
|
14
|
+
* Editable GLSP state for adopters whose source model is a **structured
|
|
15
|
+
* transfer-model projection** round-tripped through the language
|
|
16
|
+
* `ModelService`. Adds the forward-write
|
|
17
|
+
* reconcile machinery on top of the slim {@link AbstractHydraniumGlspState} base:
|
|
18
|
+
*
|
|
19
|
+
* - {@link sourceModel} — the persisted-shape projection of the current
|
|
20
|
+
* source root, produced by the framework
|
|
21
|
+
* `TransferEncoder` in `'grammar'` mode
|
|
22
|
+
* (grammar-declared properties only; computed / synthetic excluded). The
|
|
23
|
+
* field-level shape is what lets `fast-json-patch` diff per field, so undo /
|
|
24
|
+
* redo and forward-write reconcile act per field instead of clobbering the
|
|
25
|
+
* whole document.
|
|
26
|
+
* - {@link baseline} — the last in-sync projection, captured on every
|
|
27
|
+
* {@link setSourceRoot}. A forward-write conflict reconciles the user's
|
|
28
|
+
* intent (baseline → attempted) against the fresh server root.
|
|
29
|
+
* - {@link updateSourceModel} — the concrete reconcile template: persist,
|
|
30
|
+
* and on a `ConflictError` consult the injected `conflictResolver` and act
|
|
31
|
+
* on the merged / no-op / conflict / unavailable outcome.
|
|
32
|
+
* - {@link persist} / {@link refetch} — the only I/O seams. Defaults route
|
|
33
|
+
* through `ModelService.update` / `.validated` (reachable from the base via
|
|
34
|
+
* `sharedServices.model`); adopters whose document round-trip differs
|
|
35
|
+
* override these without touching the orchestration.
|
|
36
|
+
*
|
|
37
|
+
* Adopters whose source model is whole-document text (a bare `{ text }`
|
|
38
|
+
* source model) or that are read-only do NOT extend this class — they extend
|
|
39
|
+
* {@link AbstractHydraniumGlspState} directly and supply their own `updateSourceModel`
|
|
40
|
+
* (or throw). The conflict-resolution *policy* (reconcile vs force) is still
|
|
41
|
+
* the base's injected `conflictResolver`; this class owns the forward-write
|
|
42
|
+
* *orchestration* that consults it.
|
|
43
|
+
*/
|
|
44
|
+
export declare class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode, TSourceModel extends TransferElement> extends AbstractHydraniumGlspState<TRoot, TSourceModel> implements JsonModelState<TSourceModel> {
|
|
45
|
+
/**
|
|
46
|
+
* Last in-sync source-model projection, captured on every
|
|
47
|
+
* {@link setSourceRoot} (initial load + post-update). The baseline a
|
|
48
|
+
* forward-write conflict reconciles against: it stays the pre-command
|
|
49
|
+
* state because operation handlers mutate `_sourceRoot` in place during
|
|
50
|
+
* `execute` while `setSourceRoot` only re-runs once the write commits.
|
|
51
|
+
*/
|
|
52
|
+
protected baseline?: TSourceModel;
|
|
53
|
+
/**
|
|
54
|
+
* Persisted-shape projection of the current source root, consumed by GLSP's
|
|
55
|
+
* {@link JsonModelState} read side and recorded for field-level undo / redo.
|
|
56
|
+
* Produced by the framework `TransferEncoder` in `'grammar'` mode
|
|
57
|
+
* (cross-references → `$refText`, Langium internals + computed / synthetic
|
|
58
|
+
* properties excluded), so the diff reflects only authored state.
|
|
59
|
+
* Synchronous — the encoder walks the in-memory AST without serialising.
|
|
60
|
+
*/
|
|
61
|
+
get sourceModel(): TSourceModel;
|
|
62
|
+
setSourceRoot(uri: string, root: TRoot): void;
|
|
63
|
+
/**
|
|
64
|
+
* Persist `model` back to the document store, then capture the resulting
|
|
65
|
+
* AST root. On a `ConflictError` (the based-on version was superseded),
|
|
66
|
+
* reconcile the user's intent against the fresh server root via the bound
|
|
67
|
+
* `conflictResolver` and act on the outcome — one declarative policy
|
|
68
|
+
* (force = last-writer-wins, reconciling = field-level merge) shared with
|
|
69
|
+
* undo / redo.
|
|
70
|
+
*/
|
|
71
|
+
updateSourceModel(model: TSourceModel, version?: number): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Persist hook — the only write-side I/O. Default routes the structured
|
|
74
|
+
* model through `ModelService.update` (serialize → reparse), opting into
|
|
75
|
+
* the `ConflictError` gate when `version` is given. Adopters whose document
|
|
76
|
+
* round-trip differs override this; the orchestration in
|
|
77
|
+
* {@link updateSourceModel} is unchanged.
|
|
78
|
+
*/
|
|
79
|
+
protected persist(model: TSourceModel, baseVersion?: number): Promise<{
|
|
80
|
+
root: TRoot;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Refetch hook — reads the current settled server root as a persisted-shape
|
|
84
|
+
* projection (or `undefined` when unavailable). The `conflictResolver`
|
|
85
|
+
* replays the user's intent against this fresh state. Default uses
|
|
86
|
+
* `ModelService.validated` + the framework encoder's `'grammar'` mode;
|
|
87
|
+
* adopters override alongside {@link persist}.
|
|
88
|
+
*/
|
|
89
|
+
protected refetch(): Promise<TSourceModel | undefined>;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=reconciling-transfer-hydranium-glsp-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciling-transfer-hydranium-glsp-state.d.ts","sourceRoot":"","sources":["../../src/state/reconciling-transfer-hydranium-glsp-state.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBACa,qCAAqC,CAAC,KAAK,SAAS,OAAO,EAAE,YAAY,SAAS,eAAe,CAC3G,SAAQ,0BAA0B,CAAC,KAAK,EAAE,YAAY,CACtD,YAAW,cAAc,CAAC,YAAY,CAAC;IAEvC;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IAElC;;;;;;;OAOG;IACH,IAAI,WAAW,IAAI,YAAY,CAE9B;IAEQ,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI;IAKtD;;;;;;;OAOG;IACG,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB7E;;;;;;OAMG;cACa,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAU5F;;;;;;OAMG;cACa,OAAO,IAAI,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;CAI9D"}
|
|
@@ -0,0 +1,129 @@
|
|
|
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
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
10
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
12
|
+
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;
|
|
13
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
14
|
+
};
|
|
15
|
+
import { injectable } from 'inversify';
|
|
16
|
+
import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
|
|
17
|
+
import { reconcileSourceModelWrite } from './reconcile-source-model-write.js';
|
|
18
|
+
/**
|
|
19
|
+
* Editable GLSP state for adopters whose source model is a **structured
|
|
20
|
+
* transfer-model projection** round-tripped through the language
|
|
21
|
+
* `ModelService`. Adds the forward-write
|
|
22
|
+
* reconcile machinery on top of the slim {@link AbstractHydraniumGlspState} base:
|
|
23
|
+
*
|
|
24
|
+
* - {@link sourceModel} — the persisted-shape projection of the current
|
|
25
|
+
* source root, produced by the framework
|
|
26
|
+
* `TransferEncoder` in `'grammar'` mode
|
|
27
|
+
* (grammar-declared properties only; computed / synthetic excluded). The
|
|
28
|
+
* field-level shape is what lets `fast-json-patch` diff per field, so undo /
|
|
29
|
+
* redo and forward-write reconcile act per field instead of clobbering the
|
|
30
|
+
* whole document.
|
|
31
|
+
* - {@link baseline} — the last in-sync projection, captured on every
|
|
32
|
+
* {@link setSourceRoot}. A forward-write conflict reconciles the user's
|
|
33
|
+
* intent (baseline → attempted) against the fresh server root.
|
|
34
|
+
* - {@link updateSourceModel} — the concrete reconcile template: persist,
|
|
35
|
+
* and on a `ConflictError` consult the injected `conflictResolver` and act
|
|
36
|
+
* on the merged / no-op / conflict / unavailable outcome.
|
|
37
|
+
* - {@link persist} / {@link refetch} — the only I/O seams. Defaults route
|
|
38
|
+
* through `ModelService.update` / `.validated` (reachable from the base via
|
|
39
|
+
* `sharedServices.model`); adopters whose document round-trip differs
|
|
40
|
+
* override these without touching the orchestration.
|
|
41
|
+
*
|
|
42
|
+
* Adopters whose source model is whole-document text (a bare `{ text }`
|
|
43
|
+
* source model) or that are read-only do NOT extend this class — they extend
|
|
44
|
+
* {@link AbstractHydraniumGlspState} directly and supply their own `updateSourceModel`
|
|
45
|
+
* (or throw). The conflict-resolution *policy* (reconcile vs force) is still
|
|
46
|
+
* the base's injected `conflictResolver`; this class owns the forward-write
|
|
47
|
+
* *orchestration* that consults it.
|
|
48
|
+
*/
|
|
49
|
+
let ReconcilingTransferHydraniumGlspState = class ReconcilingTransferHydraniumGlspState extends AbstractHydraniumGlspState {
|
|
50
|
+
/**
|
|
51
|
+
* Last in-sync source-model projection, captured on every
|
|
52
|
+
* {@link setSourceRoot} (initial load + post-update). The baseline a
|
|
53
|
+
* forward-write conflict reconciles against: it stays the pre-command
|
|
54
|
+
* state because operation handlers mutate `_sourceRoot` in place during
|
|
55
|
+
* `execute` while `setSourceRoot` only re-runs once the write commits.
|
|
56
|
+
*/
|
|
57
|
+
baseline;
|
|
58
|
+
/**
|
|
59
|
+
* Persisted-shape projection of the current source root, consumed by GLSP's
|
|
60
|
+
* {@link JsonModelState} read side and recorded for field-level undo / redo.
|
|
61
|
+
* Produced by the framework `TransferEncoder` in `'grammar'` mode
|
|
62
|
+
* (cross-references → `$refText`, Langium internals + computed / synthetic
|
|
63
|
+
* properties excluded), so the diff reflects only authored state.
|
|
64
|
+
* Synchronous — the encoder walks the in-memory AST without serialising.
|
|
65
|
+
*/
|
|
66
|
+
get sourceModel() {
|
|
67
|
+
return this.sharedServices.model.TransferEncoder.toTransfer(this._sourceRoot, 'grammar');
|
|
68
|
+
}
|
|
69
|
+
setSourceRoot(uri, root) {
|
|
70
|
+
super.setSourceRoot(uri, root);
|
|
71
|
+
this.baseline = this.sourceModel;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Persist `model` back to the document store, then capture the resulting
|
|
75
|
+
* AST root. On a `ConflictError` (the based-on version was superseded),
|
|
76
|
+
* reconcile the user's intent against the fresh server root via the bound
|
|
77
|
+
* `conflictResolver` and act on the outcome — one declarative policy
|
|
78
|
+
* (force = last-writer-wins, reconciling = field-level merge) shared with
|
|
79
|
+
* undo / redo.
|
|
80
|
+
*/
|
|
81
|
+
async updateSourceModel(model, version) {
|
|
82
|
+
// Orchestration lives in `reconcileSourceModelWrite` so the multi-document
|
|
83
|
+
// state gets the identical conflict handling; this method supplies only
|
|
84
|
+
// the single-document meaning of persist / project.
|
|
85
|
+
return reconcileSourceModelWrite(model, version, {
|
|
86
|
+
persist: async (candidate, baseVersion) => {
|
|
87
|
+
const { root } = await this.persist(candidate, baseVersion);
|
|
88
|
+
this.setSourceRoot(this._sourceUri, root);
|
|
89
|
+
},
|
|
90
|
+
refetch: () => this.refetch(),
|
|
91
|
+
baseline: this.baseline,
|
|
92
|
+
conflictResolver: this.conflictResolver,
|
|
93
|
+
logger: this.logger,
|
|
94
|
+
onConflictDropped: () => this.refreshSourceRoot()
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Persist hook — the only write-side I/O. Default routes the structured
|
|
99
|
+
* model through `ModelService.update` (serialize → reparse), opting into
|
|
100
|
+
* the `ConflictError` gate when `version` is given. Adopters whose document
|
|
101
|
+
* round-trip differs override this; the orchestration in
|
|
102
|
+
* {@link updateSourceModel} is unchanged.
|
|
103
|
+
*/
|
|
104
|
+
async persist(model, baseVersion) {
|
|
105
|
+
const document = await this.sharedServices.model.ModelService.update({
|
|
106
|
+
uri: this._sourceUri,
|
|
107
|
+
model,
|
|
108
|
+
clientId: this.clientId,
|
|
109
|
+
baseVersion
|
|
110
|
+
});
|
|
111
|
+
return document;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Refetch hook — reads the current settled server root as a persisted-shape
|
|
115
|
+
* projection (or `undefined` when unavailable). The `conflictResolver`
|
|
116
|
+
* replays the user's intent against this fresh state. Default uses
|
|
117
|
+
* `ModelService.validated` + the framework encoder's `'grammar'` mode;
|
|
118
|
+
* adopters override alongside {@link persist}.
|
|
119
|
+
*/
|
|
120
|
+
async refetch() {
|
|
121
|
+
const fresh = await this.sharedServices.model.ModelService.validated(this._sourceUri).catch(() => undefined);
|
|
122
|
+
return fresh ? this.sharedServices.model.TransferEncoder.toTransfer(fresh.root, 'grammar') : undefined;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
ReconcilingTransferHydraniumGlspState = __decorate([
|
|
126
|
+
injectable()
|
|
127
|
+
], ReconcilingTransferHydraniumGlspState);
|
|
128
|
+
export { ReconcilingTransferHydraniumGlspState };
|
|
129
|
+
//# sourceMappingURL=reconciling-transfer-hydranium-glsp-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconciling-transfer-hydranium-glsp-state.js","sourceRoot":"","sources":["../../src/state/reconciling-transfer-hydranium-glsp-state.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;;;;;;;AAGlF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEI,IAAM,qCAAqC,GAA3C,MAAM,qCACV,SAAQ,0BAA+C;IAGvD;;;;;;OAMG;IACO,QAAQ,CAAgB;IAElC;;;;;;;OAOG;IACH,IAAI,WAAW;QACZ,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAA4B,CAAC;IACvH,CAAC;IAEQ,aAAa,CAAC,GAAW,EAAE,IAAW;QAC5C,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;IACpC,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,iBAAiB,CAAC,KAAmB,EAAE,OAAgB;QAC1D,2EAA2E;QAC3E,wEAAwE;QACxE,oDAAoD;QACpD,OAAO,yBAAyB,CAAe,KAAK,EAAE,OAAO,EAAE;YAC5D,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE;gBACvC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;gBAC5D,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;YAC7B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE;SACnD,CAAC,CAAC;IACN,CAAC;IAED;;;;;;OAMG;IACO,KAAK,CAAC,OAAO,CAAC,KAAmB,EAAE,WAAoB;QAC9D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC;YAClE,GAAG,EAAE,IAAI,CAAC,UAAU;YACpB,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,WAAW;SACb,CAAC,CAAC;QACH,OAAO,QAAsC,CAAC;IACjD,CAAC;IAED;;;;;;OAMG;IACO,KAAK,CAAC,OAAO;QACpB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7G,OAAO,KAAK,CAAC,CAAC,CAAE,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAA6B,CAAC,CAAC,CAAC,SAAS,CAAC;IACvI,CAAC;CACH,CAAA;AAnFY,qCAAqC;IADjD,UAAU,EAAE;GACA,qCAAqC,CAmFjD"}
|