@hydranium/glsp-server 1.0.0-next.12 → 1.0.0-next.123

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +13 -2
  2. package/lib/command/hydranium-glsp-recording-command.d.ts +22 -22
  3. package/lib/command/hydranium-glsp-recording-command.d.ts.map +1 -1
  4. package/lib/command/hydranium-glsp-recording-command.js +25 -26
  5. package/lib/command/hydranium-glsp-recording-command.js.map +1 -1
  6. package/lib/launcher/hydranium-glsp-server.d.ts +4 -3
  7. package/lib/launcher/hydranium-glsp-server.d.ts.map +1 -1
  8. package/lib/launcher/hydranium-glsp-server.js +4 -3
  9. package/lib/launcher/hydranium-glsp-server.js.map +1 -1
  10. package/lib/messages/index.d.ts +24 -0
  11. package/lib/messages/index.d.ts.map +1 -0
  12. package/lib/messages/index.js +24 -0
  13. package/lib/messages/index.js.map +1 -0
  14. package/lib/node/start-glsp-server.js +1 -1
  15. package/lib/node/start-glsp-server.js.map +1 -1
  16. package/lib/state/abstract-hydranium-glsp-state.d.ts +110 -43
  17. package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -1
  18. package/lib/state/abstract-hydranium-glsp-state.js +130 -41
  19. package/lib/state/abstract-hydranium-glsp-state.js.map +1 -1
  20. package/lib/state/full-text-hydranium-glsp-state.d.ts +6 -6
  21. package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -1
  22. package/lib/state/full-text-hydranium-glsp-state.js +6 -10
  23. package/lib/state/full-text-hydranium-glsp-state.js.map +1 -1
  24. package/lib/state/reconcile-source-model-write.d.ts +9 -8
  25. package/lib/state/reconcile-source-model-write.d.ts.map +1 -1
  26. package/lib/state/reconcile-source-model-write.js +8 -8
  27. package/lib/state/reconcile-source-model-write.js.map +1 -1
  28. package/lib/state/reconciling-multi-document-glsp-state.d.ts +59 -59
  29. package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -1
  30. package/lib/state/reconciling-multi-document-glsp-state.js +84 -82
  31. package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -1
  32. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +19 -18
  33. package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -1
  34. package/lib/state/reconciling-transfer-hydranium-glsp-state.js +26 -30
  35. package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -1
  36. package/lib/storage/hydranium-glsp-storage.d.ts +271 -76
  37. package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -1
  38. package/lib/storage/hydranium-glsp-storage.js +383 -87
  39. package/lib/storage/hydranium-glsp-storage.js.map +1 -1
  40. package/lib/storage/index.d.ts +1 -1
  41. package/lib/storage/index.js +1 -1
  42. package/lib/storage/save-delivery-policy.d.ts +46 -0
  43. package/lib/storage/save-delivery-policy.d.ts.map +1 -0
  44. package/lib/storage/{save-conflict-policy.js → save-delivery-policy.js} +7 -8
  45. package/lib/storage/save-delivery-policy.js.map +1 -0
  46. package/lib/validation/diagnostic-markers.d.ts +2 -2
  47. package/lib/validation/diagnostic-markers.d.ts.map +1 -1
  48. package/lib/validation/diagnostic-markers.js +7 -0
  49. package/lib/validation/diagnostic-markers.js.map +1 -1
  50. package/lib/validation/hydranium-glsp-model-validator.d.ts.map +1 -1
  51. package/lib/validation/hydranium-glsp-model-validator.js +1 -1
  52. package/lib/validation/hydranium-glsp-model-validator.js.map +1 -1
  53. package/package.json +17 -8
  54. package/src/command/hydranium-glsp-recording-command.ts +26 -26
  55. package/src/launcher/hydranium-glsp-server.ts +4 -3
  56. package/src/messages/index.ts +30 -0
  57. package/src/node/start-glsp-server.ts +1 -1
  58. package/src/state/abstract-hydranium-glsp-state.ts +162 -51
  59. package/src/state/full-text-hydranium-glsp-state.ts +7 -11
  60. package/src/state/reconcile-source-model-write.ts +18 -15
  61. package/src/state/reconciling-multi-document-glsp-state.ts +86 -83
  62. package/src/state/reconciling-transfer-hydranium-glsp-state.ts +27 -31
  63. package/src/storage/hydranium-glsp-storage.ts +445 -97
  64. package/src/storage/index.ts +1 -1
  65. package/src/storage/save-delivery-policy.ts +44 -0
  66. package/src/validation/diagnostic-markers.ts +10 -3
  67. package/src/validation/hydranium-glsp-model-validator.ts +3 -3
  68. package/lib/storage/save-conflict-policy.d.ts +0 -56
  69. package/lib/storage/save-conflict-policy.d.ts.map +0 -1
  70. package/lib/storage/save-conflict-policy.js.map +0 -1
  71. package/src/storage/save-conflict-policy.ts +0 -52
@@ -8,7 +8,8 @@
8
8
  ********************************************************************************/
9
9
  import { type JsonModelState } from '@eclipse-glsp/server';
10
10
  import { type AstNode } from '@hydranium/langium';
11
- import { type TransferElement } from '@hydranium/protocol';
11
+ import { type ClientSession } from '@hydranium/core';
12
+ import { type BasedOn, type TransferElement } from '@hydranium/protocol';
12
13
  import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
13
14
  /**
14
15
  * Source model spanning more than one document: the primary document's
@@ -39,43 +40,30 @@ export interface MultiDocumentSourceModel<TPrimary extends TransferElement = Tra
39
40
  * defines them over the primary plus the secondary write set registered through
40
41
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}.
41
42
  *
42
- * **Writes are NOT atomic, deliberately, and the window is real.** Each document
43
- * goes through its own `ModelService.update`, so a failure after the first write
44
- * has landed leaves the set inconsistent on disk. There is no multi-document
45
- * transaction to lean on: `WorkspaceLock` serialises builds but does not roll
46
- * back, and the document store commits per URI. An adopter that cannot accept the
47
- * window should not span documents in one operation.
43
+ * **The write set is written all or none.** {@link persist} hands every
44
+ * changed document to one `ClientSession.updateAll` on the diagram's session,
45
+ * so a conflict on any document leaves every document of the set as it was,
46
+ * and write order carries no meaning.
48
47
  *
49
- * **What makes the window tolerable is write ORDER, and the rule is
50
- * referenced-before-referencing** — not "secondaries first" as such. Write the
51
- * document whose content the others point AT before the documents that point at
52
- * it, so a partial write leaves an unreferenced element (inert, and the direction
53
- * an integrity rule can repair) rather than a reference to something that does
54
- * not exist (a linking error). {@link persist} implements that as
55
- * secondaries-then-primary, which is correct for the common shape where the
56
- * primary is the DIAGRAM and the semantics it references are secondaries: the
57
- * user opened the diagram, so it is also the document the conflict gate should
58
- * guard. **An adopter whose primary is the referenced document — a semantic file
59
- * as the diagram source, with layout in a secondary — has the ordering backwards
60
- * and must override {@link persist} to write the primary first.** Overriding it
61
- * is the supported route; the base order is a default for the common case, not an
62
- * invariant of the class.
48
+ * **Every document of the set is gated.** The primary on the caller's
49
+ * `basedOn`, each secondary on {@link secondaryBasedOn}, by default the version
50
+ * it had when the source root was last read. A conflict on any of them is
51
+ * reconciled against the whole write set. A write based on `'anything'` — a
52
+ * merged retry, an undo or redo replaying a patch — forces every document of
53
+ * the set.
63
54
  *
64
- * **The conflict gate covers the primary only.** Secondaries are written without
65
- * a based-on version, so a concurrent foreign edit to one is overwritten rather
66
- * than reconciled. Gating them too would need a per-document reconcile whose
67
- * outcomes can disagree (merge one, conflict another) with no way to un-write the
68
- * merged one — the atomicity problem again, one layer up. The captured versions
69
- * ARE available via {@link AbstractHydraniumGlspState.capturedVersionOf}, so an
70
- * adopter that wants a coarser check can compare before writing.
55
+ * A secondary is written only while the diagram's session has it open. The
56
+ * storage opens it as it joins the write set, and {@link openForWrite} opens it
57
+ * again before each write; an adopter whose write set can name a document that
58
+ * does not exist yet overrides {@link openForWrite} to create it.
71
59
  */
72
60
  export declare class ReconcilingMultiDocumentGlspState<TRoot extends AstNode, TPrimary extends TransferElement = TransferElement> extends AbstractHydraniumGlspState<TRoot, MultiDocumentSourceModel<TPrimary>> implements JsonModelState<MultiDocumentSourceModel<TPrimary>> {
73
61
  /**
74
62
  * Last in-sync projection across the whole write set, captured on every
75
- * {@link setSourceRoot}. Same role as the single-document baseline: the state a
63
+ * {@link setSourceRoot}. Same role as the single-document base: the state a
76
64
  * forward-write conflict reconciles the user's intent against.
77
65
  */
78
- protected baseline?: MultiDocumentSourceModel<TPrimary>;
66
+ protected base?: MultiDocumentSourceModel<TPrimary>;
79
67
  /**
80
68
  * Projection of the primary plus every registered secondary, in the framework
81
69
  * encoder's `'grammar'` mode (authored state only — cross-references as
@@ -93,14 +81,14 @@ export declare class ReconcilingMultiDocumentGlspState<TRoot extends AstNode, TP
93
81
  * Register the secondary documents that belong to the primary at `uri`, via
94
82
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}. Called on every
95
83
  * {@link setSourceRoot}, after the primary is captured (so `sourceUri` is
96
- * current) and BEFORE the baseline is taken (so the baseline includes them).
84
+ * current) and BEFORE the base is taken (so the base includes them).
97
85
  * Default: no secondaries.
98
86
  *
99
87
  * This hook exists because that ordering is a trap an adopter would otherwise
100
88
  * hit silently. Registering from an overridden `setSourceRoot` *after*
101
- * `super.setSourceRoot(...)` runs too late — the baseline has already been
89
+ * `super.setSourceRoot(...)` runs too late — the base has already been
102
90
  * captured without the secondaries, so the first conflict reconcile measures
103
- * the user's intent against a baseline missing half the write set and the
91
+ * the user's intent against a base missing half the write set and the
104
92
  * secondary edits look like foreign changes. Registering *before* the super
105
93
  * call is too early for a URI derived from the new primary. Overriding this
106
94
  * instead removes the choice.
@@ -108,49 +96,61 @@ export declare class ReconcilingMultiDocumentGlspState<TRoot extends AstNode, TP
108
96
  protected trackWriteSet(_uri: string): void;
109
97
  /**
110
98
  * Persist the whole write set, then capture the resulting primary root. On a
111
- * `ConflictError` from the primary, reconcile via the injected policy exactly
112
- * as the single-document state does — the orchestration is shared.
99
+ * `ConflictError` from any document of the set, reconcile via the injected
100
+ * policy exactly as the single-document state does — the orchestration is
101
+ * shared.
113
102
  */
114
- updateSourceModel(model: MultiDocumentSourceModel<TPrimary>, version?: number): Promise<void>;
103
+ updateSourceModel(model: MultiDocumentSourceModel<TPrimary>, basedOn?: BasedOn): Promise<void>;
115
104
  /**
116
- * Write hook — secondaries first (ungated), primary last (gated on
117
- * `baseVersion`). The order is the failure-mode choice documented on the
118
- * class, not incidental: override this when the primary is the document the
119
- * others REFERENCE, since then this order writes the references first.
105
+ * Write hook — every document of `model` that changed, opened first through
106
+ * {@link openForWrite}, in one `updateAll` on the diagram's session: the
107
+ * primary gated on `basedOn`, each secondary on {@link secondaryBasedOn}, or
108
+ * every document on `'anything'` when `basedOn` is `'anything'`. Resolves to
109
+ * the primary's root, the one already captured when the primary did not
110
+ * change. A write that bypasses `updateAll` gives up the all-or-none
111
+ * guarantee the class describes. Throws without a session
112
+ * ({@link requireModelSession}).
120
113
  */
121
- protected persist(model: MultiDocumentSourceModel<TPrimary>, baseVersion?: number): Promise<{
114
+ protected persist(model: MultiDocumentSourceModel<TPrimary>, basedOn: BasedOn): Promise<{
122
115
  root: TRoot;
123
116
  }>;
124
117
  /**
125
- * Whether `candidate` differs from the baseline projection of the same
118
+ * Whether `candidate` differs from the base projection of the same
126
119
  * document, and therefore needs writing.
127
120
  *
128
121
  * **Skipping unchanged documents is correctness, not an optimisation.** A
129
- * write goes through `ModelService.update`, which re-serializes from the AST —
130
- * so writing a document that did not change still rewrites its text, and a
131
- * serializer is free to normalise formatting and cannot preserve comments.
132
- * Persisting the whole write set unconditionally therefore means a pure layout
133
- * drag reflows the semantic file and strips its comments, which is a data
134
- * loss the user never asked for and would struggle to attribute.
122
+ * write re-serializes from the AST, so writing a document that did not
123
+ * change still rewrites its text in the serializer's own layout. Persisting
124
+ * the whole write set unconditionally therefore means a pure layout drag
125
+ * reflows the semantic file, a change the user never asked for and would
126
+ * struggle to attribute. Comments survive that rewrite, but the
127
+ * hand-formatting around them does not.
135
128
  *
136
129
  * Compared by serialised form. Both sides come from the same encoder walking
137
130
  * the same shape, so key order is stable and a string compare is sound here;
138
131
  * it is also cheap enough to run per document per write.
139
132
  */
140
- protected hasChanged(baseline: object | undefined, candidate: object): boolean;
141
- /** Write the primary document, opting into the conflict gate when `baseVersion` is given. */
142
- protected persistPrimary(model: TPrimary, baseVersion?: number): Promise<{
143
- root: TRoot;
144
- }>;
133
+ protected hasChanged(base: object | undefined, candidate: object): boolean;
134
+ /**
135
+ * Make sure the diagram's session has `uri` open before the write set is
136
+ * written. Default: open it, a no-op for a document the session already
137
+ * has open. Override to create a document the write set names before it
138
+ * exists, through `session.create`: `updateAll` opens nothing.
139
+ */
140
+ protected openForWrite(session: ClientSession<AstNode>, uri: string): Promise<void>;
145
141
  /**
146
- * Write one secondary document. Ungated by design (see the class doc); override
147
- * alongside {@link persistPrimary} when the round-trip differs per document
148
- * role — a layout file and a semantic file need not share a serializer.
142
+ * What a secondary write declares it was based on. Default: the version the
143
+ * secondary had when the source root was last read
144
+ * ({@link AbstractHydraniumGlspState.snapshotVersionOf}), so a foreign edit
145
+ * to it since is reported as a conflict and reconciled rather than
146
+ * overwritten; `'anything'` for a secondary with no recorded version.
147
+ * Return `'anything'` to force secondary writes.
149
148
  */
150
- protected persistSecondary(uri: string, model: TransferElement): Promise<void>;
149
+ protected secondaryBasedOn(uri: string): BasedOn;
151
150
  /**
152
- * Refetch hook — the current settled projection across the write set, used by
153
- * the conflict resolver to replay the user's intent against fresh state.
151
+ * Refetch hook — the current projection across the write set, each document
152
+ * read through {@link AbstractHydraniumGlspState.readCurrentRoot}: theirs,
153
+ * which the conflict resolver replays the user's intent onto.
154
154
  * Returns `undefined` when the PRIMARY cannot be read, since a reconcile
155
155
  * without it has nothing to merge into; an unreadable secondary is omitted the
156
156
  * same way {@link sourceModel} omits one.
@@ -1 +1 @@
1
- {"version":3,"file":"reconciling-multi-document-glsp-state.d.ts","sourceRoot":"","sources":["../../src/state/reconciling-multi-document-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;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB,CAAC,QAAQ,SAAS,eAAe,GAAG,eAAe;IACzF,gFAAgF;IAChF,OAAO,EAAE,QAAQ,CAAC;IAClB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBACa,iCAAiC,CAAC,KAAK,SAAS,OAAO,EAAE,QAAQ,SAAS,eAAe,GAAG,eAAe,CACrH,SAAQ,0BAA0B,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAC5E,YAAW,cAAc,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAE7D;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAExD;;;;;;;;;;OAUG;IACH,IAAI,WAAW,IAAI,wBAAwB,CAAC,QAAQ,CAAC,CASpD;IAEQ,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI;IAMtD;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3C;;;;OAIG;IACG,iBAAiB,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcnG;;;;;OAKG;cACa,OAAO,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAclH;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAI9E,6FAA6F;cAC7E,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAU/F;;;;OAIG;cACa,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpF;;;;;;OAMG;cACa,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAelF,wFAAwF;IACxF,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAKnE,oFAAoF;IACpF,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;CAGtF"}
1
+ {"version":3,"file":"reconciling-multi-document-glsp-state.d.ts","sourceRoot":"","sources":["../../src/state/reconciling-multi-document-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,aAAa,EAA+B,MAAM,iBAAiB,CAAC;AAClF,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB,CAAC,QAAQ,SAAS,eAAe,GAAG,eAAe;IACzF,gFAAgF;IAChF,OAAO,EAAE,QAAQ,CAAC;IAClB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC/C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBACa,iCAAiC,CAAC,KAAK,SAAS,OAAO,EAAE,QAAQ,SAAS,eAAe,GAAG,eAAe,CACrH,SAAQ,0BAA0B,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAC5E,YAAW,cAAc,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAE7D;;;;OAIG;IACH,SAAS,CAAC,IAAI,CAAC,EAAE,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IAEpD;;;;;;;;;;OAUG;IACH,IAAI,WAAW,IAAI,wBAAwB,CAAC,QAAQ,CAAC,CASpD;IAEQ,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG,IAAI;IAMtD;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3C;;;;;OAKG;IACG,iBAAiB,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAE,OAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAclH;;;;;;;;;OASG;cACa,OAAO,CAAC,KAAK,EAAE,wBAAwB,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAqB9G;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAI1E;;;;;OAKG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInF;;;;;;;OAOG;IACH,SAAS,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIhD;;;;;;;OAOG;cACa,OAAO,IAAI,OAAO,CAAC,wBAAwB,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IAelF,wFAAwF;IACxF,SAAS,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAKnE,oFAAoF;IACpF,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,eAAe,GAAG,eAAe,EAAE,IAAI,EAAE,OAAO,GAAG,CAAC;CAGtF"}
@@ -28,43 +28,30 @@ import { reconcileSourceModelWrite } from './reconcile-source-model-write.js';
28
28
  * defines them over the primary plus the secondary write set registered through
29
29
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}.
30
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.
31
+ * **The write set is written all or none.** {@link persist} hands every
32
+ * changed document to one `ClientSession.updateAll` on the diagram's session,
33
+ * so a conflict on any document leaves every document of the set as it was,
34
+ * and write order carries no meaning.
37
35
  *
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.
36
+ * **Every document of the set is gated.** The primary on the caller's
37
+ * `basedOn`, each secondary on {@link secondaryBasedOn}, by default the version
38
+ * it had when the source root was last read. A conflict on any of them is
39
+ * reconciled against the whole write set. A write based on `'anything'` — a
40
+ * merged retry, an undo or redo replaying a patch — forces every document of
41
+ * the set.
52
42
  *
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.
43
+ * A secondary is written only while the diagram's session has it open. The
44
+ * storage opens it as it joins the write set, and {@link openForWrite} opens it
45
+ * again before each write; an adopter whose write set can name a document that
46
+ * does not exist yet overrides {@link openForWrite} to create it.
60
47
  */
61
48
  let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState extends AbstractHydraniumGlspState {
62
49
  /**
63
50
  * 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
51
+ * {@link setSourceRoot}. Same role as the single-document base: the state a
65
52
  * forward-write conflict reconciles the user's intent against.
66
53
  */
67
- baseline;
54
+ base;
68
55
  /**
69
56
  * Projection of the primary plus every registered secondary, in the framework
70
57
  * encoder's `'grammar'` mode (authored state only — cross-references as
@@ -89,20 +76,20 @@ let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState
89
76
  setSourceRoot(uri, root) {
90
77
  super.setSourceRoot(uri, root);
91
78
  this.trackWriteSet(uri);
92
- this.baseline = this.sourceModel;
79
+ this.base = this.sourceModel;
93
80
  }
94
81
  /**
95
82
  * Register the secondary documents that belong to the primary at `uri`, via
96
83
  * {@link AbstractHydraniumGlspState.trackSecondaryDocument}. Called on every
97
84
  * {@link setSourceRoot}, after the primary is captured (so `sourceUri` is
98
- * current) and BEFORE the baseline is taken (so the baseline includes them).
85
+ * current) and BEFORE the base is taken (so the base includes them).
99
86
  * Default: no secondaries.
100
87
  *
101
88
  * This hook exists because that ordering is a trap an adopter would otherwise
102
89
  * hit silently. Registering from an overridden `setSourceRoot` *after*
103
- * `super.setSourceRoot(...)` runs too late — the baseline has already been
90
+ * `super.setSourceRoot(...)` runs too late — the base has already been
104
91
  * 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
92
+ * the user's intent against a base missing half the write set and the
106
93
  * secondary edits look like foreign changes. Registering *before* the super
107
94
  * call is too early for a URI derived from the new primary. Overriding this
108
95
  * instead removes the choice.
@@ -112,98 +99,113 @@ let ReconcilingMultiDocumentGlspState = class ReconcilingMultiDocumentGlspState
112
99
  }
113
100
  /**
114
101
  * 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.
102
+ * `ConflictError` from any document of the set, reconcile via the injected
103
+ * policy exactly as the single-document state does — the orchestration is
104
+ * shared.
117
105
  */
118
- async updateSourceModel(model, version) {
119
- return reconcileSourceModelWrite(model, version, {
120
- persist: async (candidate, baseVersion) => {
121
- const { root } = await this.persist(candidate, baseVersion);
106
+ async updateSourceModel(model, basedOn = this.basedOn) {
107
+ return reconcileSourceModelWrite(model, basedOn, {
108
+ persist: async (candidate, candidateBasedOn) => {
109
+ const { root } = await this.persist(candidate, candidateBasedOn);
122
110
  this.setSourceRoot(this._sourceUri, root);
123
111
  },
124
112
  refetch: () => this.refetch(),
125
- baseline: this.baseline,
113
+ base: this.base,
126
114
  conflictResolver: this.conflictResolver,
127
115
  logger: this.logger,
128
116
  onConflictDropped: () => this.refreshSourceRoot()
129
117
  });
130
118
  }
131
119
  /**
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.
120
+ * Write hook — every document of `model` that changed, opened first through
121
+ * {@link openForWrite}, in one `updateAll` on the diagram's session: the
122
+ * primary gated on `basedOn`, each secondary on {@link secondaryBasedOn}, or
123
+ * every document on `'anything'` when `basedOn` is `'anything'`. Resolves to
124
+ * the primary's root, the one already captured when the primary did not
125
+ * change. A write that bypasses `updateAll` gives up the all-or-none
126
+ * guarantee the class describes. Throws without a session
127
+ * ({@link requireModelSession}).
136
128
  */
137
- async persist(model, baseVersion) {
129
+ async persist(model, basedOn) {
130
+ const primaryChanged = this.hasChanged(this.base?.primary, model.primary);
131
+ const updates = primaryChanged
132
+ ? [{ uri: this._sourceUri, model: model.primary, basedOn }]
133
+ : [];
138
134
  for (const [uri, secondary] of Object.entries(model.secondaries)) {
139
- if (this.hasChanged(this.baseline?.secondaries[uri], secondary)) {
140
- await this.persistSecondary(uri, secondary);
135
+ if (this.hasChanged(this.base?.secondaries[uri], secondary)) {
136
+ updates.push({ uri, model: secondary, basedOn: basedOn === 'anything' ? 'anything' : this.secondaryBasedOn(uri) });
141
137
  }
142
138
  }
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.
139
+ if (updates.length === 0) {
146
140
  return { root: this._sourceRoot };
147
141
  }
148
- return this.persistPrimary(model.primary, baseVersion);
142
+ const session = this.requireModelSession();
143
+ for (const update of updates) {
144
+ await this.openForWrite(session, update.uri);
145
+ }
146
+ const documents = await session.updateAll({ updates });
147
+ return { root: primaryChanged ? documents[0].root : this._sourceRoot };
149
148
  }
150
149
  /**
151
- * Whether `candidate` differs from the baseline projection of the same
150
+ * Whether `candidate` differs from the base projection of the same
152
151
  * document, and therefore needs writing.
153
152
  *
154
153
  * **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.
154
+ * write re-serializes from the AST, so writing a document that did not
155
+ * change still rewrites its text in the serializer's own layout. Persisting
156
+ * the whole write set unconditionally therefore means a pure layout drag
157
+ * reflows the semantic file, a change the user never asked for and would
158
+ * struggle to attribute. Comments survive that rewrite, but the
159
+ * hand-formatting around them does not.
161
160
  *
162
161
  * Compared by serialised form. Both sides come from the same encoder walking
163
162
  * the same shape, so key order is stable and a string compare is sound here;
164
163
  * it is also cheap enough to run per document per write.
165
164
  */
166
- hasChanged(baseline, candidate) {
167
- return baseline === undefined || JSON.stringify(baseline) !== JSON.stringify(candidate);
165
+ hasChanged(base, candidate) {
166
+ return base === undefined || JSON.stringify(base) !== JSON.stringify(candidate);
168
167
  }
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;
168
+ /**
169
+ * Make sure the diagram's session has `uri` open before the write set is
170
+ * written. Default: open it, a no-op for a document the session already
171
+ * has open. Override to create a document the write set names before it
172
+ * exists, through `session.create`: `updateAll` opens nothing.
173
+ */
174
+ openForWrite(session, uri) {
175
+ return session.open(uri);
178
176
  }
179
177
  /**
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.
178
+ * What a secondary write declares it was based on. Default: the version the
179
+ * secondary had when the source root was last read
180
+ * ({@link AbstractHydraniumGlspState.snapshotVersionOf}), so a foreign edit
181
+ * to it since is reported as a conflict and reconciled rather than
182
+ * overwritten; `'anything'` for a secondary with no recorded version.
183
+ * Return `'anything'` to force secondary writes.
183
184
  */
184
- async persistSecondary(uri, model) {
185
- await this.sharedServices.model.ModelService.update({ uri, model, clientId: this.clientId });
185
+ secondaryBasedOn(uri) {
186
+ return this.snapshotVersionOf(uri) ?? 'anything';
186
187
  }
187
188
  /**
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.
189
+ * Refetch hook — the current projection across the write set, each document
190
+ * read through {@link AbstractHydraniumGlspState.readCurrentRoot}: theirs,
191
+ * which the conflict resolver replays the user's intent onto.
190
192
  * Returns `undefined` when the PRIMARY cannot be read, since a reconcile
191
193
  * without it has nothing to merge into; an unreadable secondary is omitted the
192
194
  * same way {@link sourceModel} omits one.
193
195
  */
194
196
  async refetch() {
195
- const fresh = await this.sharedServices.model.ModelService.validated(this._sourceUri).catch(() => undefined);
196
- if (!fresh) {
197
+ const theirs = await this.readCurrentRoot(this._sourceUri);
198
+ if (!theirs) {
197
199
  return undefined;
198
200
  }
199
201
  const secondaries = {};
200
202
  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);
203
+ const root = await this.readCurrentRoot(uri);
204
+ if (root) {
205
+ secondaries[uri] = this.projectRoot(root);
204
206
  }
205
207
  }
206
- return { primary: this.projectRoot(fresh.root), secondaries };
208
+ return { primary: this.projectRoot(theirs), secondaries };
207
209
  }
208
210
  /** Project a currently-loaded document's root, or `undefined` when it is not loaded. */
209
211
  projectDocument(uri) {
@@ -1 +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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"}
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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"}
@@ -8,7 +8,7 @@
8
8
  ********************************************************************************/
9
9
  import { type JsonModelState } from '@eclipse-glsp/server';
10
10
  import { type AstNode } from '@hydranium/langium';
11
- import { type TransferElement } from '@hydranium/protocol';
11
+ import { type BasedOn, type TransferElement } from '@hydranium/protocol';
12
12
  import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
13
13
  /**
14
14
  * Editable GLSP state for adopters whose source model is a **structured
@@ -23,16 +23,16 @@ import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
23
23
  * field-level shape is what lets `fast-json-patch` diff per field, so undo /
24
24
  * redo and forward-write reconcile act per field instead of clobbering the
25
25
  * whole document.
26
- * - {@link baseline} — the last in-sync projection, captured on every
26
+ * - {@link base} — the last in-sync projection, captured on every
27
27
  * {@link setSourceRoot}. A forward-write conflict reconciles the user's
28
- * intent (baseline → attempted) against the fresh server root.
28
+ * intent (base → ours) against the server's current root (theirs).
29
29
  * - {@link updateSourceModel} — the concrete reconcile template: persist,
30
30
  * and on a `ConflictError` consult the injected `conflictResolver` and act
31
31
  * on the merged / no-op / conflict / unavailable outcome.
32
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.
33
+ * through the diagram session's `update` and `ModelService.validated`;
34
+ * adopters whose document round-trip differs override these without
35
+ * touching the orchestration.
36
36
  *
37
37
  * Adopters whose source model is whole-document text (a bare `{ text }`
38
38
  * source model) or that are read-only do NOT extend this class — they extend
@@ -44,12 +44,12 @@ import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
44
44
  export declare class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode, TSourceModel extends TransferElement> extends AbstractHydraniumGlspState<TRoot, TSourceModel> implements JsonModelState<TSourceModel> {
45
45
  /**
46
46
  * Last in-sync source-model projection, captured on every
47
- * {@link setSourceRoot} (initial load + post-update). The baseline a
47
+ * {@link setSourceRoot} (initial load + post-update). The base a
48
48
  * forward-write conflict reconciles against: it stays the pre-command
49
49
  * state because operation handlers mutate `_sourceRoot` in place during
50
50
  * `execute` while `setSourceRoot` only re-runs once the write commits.
51
51
  */
52
- protected baseline?: TSourceModel;
52
+ protected base?: TSourceModel;
53
53
  /**
54
54
  * Persisted-shape projection of the current source root, consumed by GLSP's
55
55
  * {@link JsonModelState} read side and recorded for field-level undo / redo.
@@ -63,28 +63,29 @@ export declare class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode
63
63
  /**
64
64
  * Persist `model` back to the document store, then capture the resulting
65
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
66
+ * reconcile the user's intent against the server's current root via the bound
67
67
  * `conflictResolver` and act on the outcome — one declarative policy
68
68
  * (force = last-writer-wins, reconciling = field-level merge) shared with
69
69
  * undo / redo.
70
70
  */
71
- updateSourceModel(model: TSourceModel, version?: number): Promise<void>;
71
+ updateSourceModel(model: TSourceModel, basedOn?: BasedOn): Promise<void>;
72
72
  /**
73
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
74
+ * model through the diagram session's `update` (serialize → reparse),
75
+ * opting into the `ConflictError` gate unless `basedOn` is `'anything'`,
76
+ * and throws without a session. Adopters whose document
76
77
  * round-trip differs override this; the orchestration in
77
78
  * {@link updateSourceModel} is unchanged.
78
79
  */
79
- protected persist(model: TSourceModel, baseVersion?: number): Promise<{
80
+ protected persist(model: TSourceModel, basedOn: BasedOn): Promise<{
80
81
  root: TRoot;
81
82
  }>;
82
83
  /**
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}.
84
+ * Refetch hook — the stored text parsed afresh, as a persisted-shape
85
+ * projection (or `undefined` when unavailable): theirs, which the
86
+ * `conflictResolver` replays the user's intent onto. Default uses
87
+ * {@link AbstractHydraniumGlspState.readCurrentRoot} + the framework
88
+ * encoder's `'grammar'` mode; adopters override alongside {@link persist}.
88
89
  */
89
90
  protected refetch(): Promise<TSourceModel | undefined>;
90
91
  }
@@ -1 +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"}
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,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,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,IAAI,CAAC,EAAE,YAAY,CAAC;IAE9B;;;;;;;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,GAAE,OAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB5F;;;;;;;OAOG;cACa,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE,CAAC;IAKxF;;;;;;OAMG;cACa,OAAO,IAAI,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;CAI9D"}