@1agh/maude 1.5.0 → 1.5.2

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.
@@ -21,6 +21,7 @@
21
21
  import { anchorPoint, facingAnchor } from './elements/arrow.model.ts';
22
22
  import { compareOrder, keyBetween } from './fractional-index.ts';
23
23
  import { type ApplyResult, applyOps, type Op } from './ops.ts';
24
+ import './ops-merge.ts';
24
25
  import { defOf, REGISTRY, specOf } from './registry.ts';
25
26
  import { Scene } from './scene.ts';
26
27
  import type { AnnotationElement, Box } from './types.ts';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @file annotations/ops-merge.ts — wire the 3-way text merge into ops.ts
3
+ * @scope apps/studio/annotations/ops-merge.ts
4
+ * @purpose Side-effect import for SERVER entry points only (api, collab,
5
+ * codec, ai-write, the hub's accepted lane). `sync/source-merge.ts`
6
+ * needs the `diff` package, which the canvas iframe cannot resolve,
7
+ * so ops.ts takes the merge by injection instead of importing it.
8
+ * Never import this from anything in the canvas-lib graph —
9
+ * `test/canvas-lib-graph.test.ts` fails if `diff` gets back in.
10
+ */
11
+
12
+ import { mergeSource } from '../sync/source-merge.ts';
13
+ import { setTextMerge } from './ops.ts';
14
+
15
+ setTextMerge(mergeSource);
@@ -13,8 +13,9 @@
13
13
  * • the same scalar field follows acceptance order (last wins —
14
14
  * DDR-241 §5);
15
15
  * • the same TEXT field is merged 3-way at character level
16
- * against the patch's `expect` (sync/source-merge.ts), so two
17
- * people typing in one sticky both keep their words;
16
+ * against the patch's `expect` (sync/source-merge.ts, wired in
17
+ * by `ops-merge.ts` — see `setTextMerge`), so two people
18
+ * typing in one sticky both keep their words;
18
19
  * • a patch on a missing element is rejected `gone` (the client
19
20
  * offers to restore — it never silently re-creates).
20
21
  * A `strict` patch (undo) only touches fields that still hold the
@@ -26,7 +27,6 @@
26
27
  * are not deleted with it (coordinates converted — they don't jump).
27
28
  */
28
29
 
29
- import { mergeSource } from '../sync/source-merge.ts';
30
30
  import { MAX_NESTING_DEPTH } from './constants.ts';
31
31
  import { DANGEROUS_KEYS, jsonEq } from './fields.ts';
32
32
  import { defOf, validateElement } from './registry.ts';
@@ -83,15 +83,40 @@ interface MergeBudget {
83
83
  left: number;
84
84
  }
85
85
 
86
+ /** A 3-way text merge: `ok:false` means the edits touch (ours wins). */
87
+ export type TextMerge = (
88
+ base: string,
89
+ ours: string,
90
+ theirs: string
91
+ ) => { ok: true; merged: string } | { ok: false };
92
+
93
+ /**
94
+ * The character-level merge, injected rather than imported: it needs the
95
+ * `diff` package, and this module is in the canvas iframe's graph
96
+ * (`annotations-layer.tsx`), where only the prebuilt `/_canvas-runtime/`
97
+ * externals resolve — a static import broke every canvas build in v1.5.0.
98
+ * Server entry points import `ops-merge.ts`, which registers `mergeSource`;
99
+ * without it a same-field text race resolves by acceptance order (ours).
100
+ */
101
+ let textMerge: TextMerge | null = null;
102
+
103
+ export function setTextMerge(merge: TextMerge | null): void {
104
+ textMerge = merge;
105
+ }
106
+
107
+ export function hasTextMerge(): boolean {
108
+ return textMerge !== null;
109
+ }
110
+
86
111
  /** Merge a text value: ours vs theirs against base. Overlap → ours (acceptance order). */
87
112
  function mergeText(base: unknown, ours: unknown, theirs: unknown, budget: MergeBudget): unknown {
88
113
  if (typeof base !== 'string' || typeof ours !== 'string' || typeof theirs !== 'string')
89
114
  return ours;
90
115
  if (theirs === base) return ours;
91
116
  if (ours === base) return theirs;
92
- if (budget.left <= 0) return ours;
117
+ if (!textMerge || budget.left <= 0) return ours;
93
118
  budget.left--;
94
- const m = mergeSource(base, ours, theirs);
119
+ const m = textMerge(base, ours, theirs);
95
120
  return m.ok ? m.merged : ours;
96
121
  }
97
122
 
@@ -21,6 +21,7 @@ import {
21
21
  applyOps as applyAnnotationOpsPure,
22
22
  diffToOps,
23
23
  } from './annotations/ops.ts';
24
+ import './annotations/ops-merge.ts';
24
25
  import { parseBoard, serializeBoard } from './annotations/schema.ts';
25
26
  import type { AnnotationElement } from './annotations/types.ts';
26
27
  import { createAssetMirror, s3ConfigFromEnv } from './assets-s3.ts';
@@ -11,6 +11,7 @@ import type * as Y from 'yjs';
11
11
 
12
12
  import { canonicalAnnotations } from '../annotations/board-text.ts';
13
13
  import { type ApplyResult, applyOps, type Op } from '../annotations/ops.ts';
14
+ import '../annotations/ops-merge.ts';
14
15
  import { readReplica, validActionId, writeReplica } from '../annotations/replica.ts';
15
16
  import { parseBoard, serializeBoard } from '../annotations/schema.ts';
16
17
  import { applyCommentsToDoc, stampAnnotationsEdit } from '../sync/codec.ts';