prosemirror-changeset 2.1.1 → 2.2.0

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/dist/index.js CHANGED
@@ -1,612 +1,679 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
1
  // Convert the given range of a fragment to tokens, where node open
6
2
  // tokens are encoded as strings holding the node name, characters as
7
3
  // their character code, and node close tokens as -1.
8
4
  function tokens(frag, start, end, target) {
9
- for (var i = 0, off = 0; i < frag.childCount; i++) {
10
- var child = frag.child(i), endOff = off + child.nodeSize;
11
- var from = Math.max(off, start), to = Math.min(endOff, end);
12
- if (from < to) {
13
- if (child.isText) {
14
- for (var j = from; j < to; j++) { target.push(child.text.charCodeAt(j - off)); }
15
- } else if (child.isLeaf) {
16
- target.push(child.type.name);
17
- } else {
18
- if (from == off) { target.push(child.type.name); }
19
- tokens(child.content, Math.max(off + 1, from) - off - 1, Math.min(endOff - 1, to) - off - 1, target);
20
- if (to == endOff) { target.push(-1); }
21
- }
5
+ for (let i = 0, off = 0; i < frag.childCount; i++) {
6
+ let child = frag.child(i), endOff = off + child.nodeSize;
7
+ let from = Math.max(off, start), to = Math.min(endOff, end);
8
+ if (from < to) {
9
+ if (child.isText) {
10
+ for (let j = from; j < to; j++)
11
+ target.push(child.text.charCodeAt(j - off));
12
+ }
13
+ else if (child.isLeaf) {
14
+ target.push(child.type.name);
15
+ }
16
+ else {
17
+ if (from == off)
18
+ target.push(child.type.name);
19
+ tokens(child.content, Math.max(off + 1, from) - off - 1, Math.min(endOff - 1, to) - off - 1, target);
20
+ if (to == endOff)
21
+ target.push(-1);
22
+ }
23
+ }
24
+ off = endOff;
22
25
  }
23
- off = endOff;
24
- }
25
- return target
26
+ return target;
26
27
  }
27
-
28
28
  // The code below will refuse to compute a diff with more than 5000
29
29
  // insertions or deletions, which takes about 300ms to reach on my
30
30
  // machine. This is a safeguard against runaway computations.
31
- var MAX_DIFF_SIZE = 5000;
32
-
31
+ const MAX_DIFF_SIZE = 5000;
33
32
  // This obscure mess of constants computes the minimum length of an
34
33
  // unchanged range (not at the start/end of the compared content). The
35
34
  // idea is to make it higher in bigger replacements, so that you don't
36
35
  // get a diff soup of coincidentally identical letters when replacing
37
36
  // a paragraph.
38
37
  function minUnchanged(sizeA, sizeB) {
39
- return Math.min(15, Math.max(2, Math.floor(Math.max(sizeA, sizeB) / 10)))
38
+ return Math.min(15, Math.max(2, Math.floor(Math.max(sizeA, sizeB) / 10)));
40
39
  }
41
-
42
- // : (Fragment, Fragment, Change) → [Change]
43
40
  function computeDiff(fragA, fragB, range) {
44
- var tokA = tokens(fragA, range.fromA, range.toA, []);
45
- var tokB = tokens(fragB, range.fromB, range.toB, []);
46
-
47
- // Scan from both sides to cheaply eliminate work
48
- var start = 0, endA = tokA.length, endB = tokB.length;
49
- while (start < tokA.length && start < tokB.length && tokA[start] === tokB[start]) { start++; }
50
- if (start == tokA.length && start == tokB.length) { return [] }
51
- while (endA > start && endB > start && tokA[endA - 1] === tokB[endB - 1]) { endA--, endB--; }
52
- // If the result is simple _or_ too big to cheaply compute, return
53
- // the remaining region as the diff
54
- if (endA == start || endB == start || (endA == endB && endA == start + 1))
55
- { return [range.slice(start, endA, start, endB)] }
56
-
57
- // This is an implementation of Myers' diff algorithm
58
- // See https://neil.fraser.name/writing/diff/myers.pdf and
59
- // https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/
60
-
61
- var lenA = endA - start, lenB = endB - start;
62
- var max = Math.min(MAX_DIFF_SIZE, lenA + lenB), off = max + 1;
63
- var history = [];
64
- var frontier = [];
65
- for (var len = off * 2, i = 0; i < len; i++) { frontier[i] = -1; }
66
-
67
- for (var size = 0; size <= max; size++) {
68
- for (var diag = -size; diag <= size; diag += 2) {
69
- var next = frontier[diag + 1 + max], prev = frontier[diag - 1 + max];
70
- var x = next < prev ? prev : next + 1, y = x + diag;
71
- while (x < lenA && y < lenB && tokA[start + x] === tokB[start + y]) { x++, y++; }
72
- frontier[diag + max] = x;
73
- // Found a match
74
- if (x >= lenA && y >= lenB) {
75
- // Trace back through the history to build up a set of changed ranges.
76
- var diff = [], minSpan = minUnchanged(endA - start, endB - start);
77
- // Used to add steps to a diff one at a time, back to front, merging
78
- // ones that are less than minSpan tokens apart
79
- var fromA = -1, toA = -1, fromB = -1, toB = -1;
80
- var add = function (fA, tA, fB, tB) {
81
- if (fromA > -1 && fromA < tA + minSpan) {
82
- fromA = fA; fromB = fB;
83
- } else {
84
- if (fromA > -1)
85
- { diff.push(range.slice(fromA, toA, fromB, toB)); }
86
- fromA = fA; toA = tA;
87
- fromB = fB; toB = tB;
88
- }
89
- };
90
-
91
- for (var i$1 = size - 1; i$1 >= 0; i$1--) {
92
- var next$1 = frontier[diag + 1 + max], prev$1 = frontier[diag - 1 + max];
93
- if (next$1 < prev$1) { // Deletion
94
- diag--;
95
- x = prev$1 + start; y = x + diag;
96
- add(x, x, y, y + 1);
97
- } else { // Insertion
98
- diag++;
99
- x = next$1 + start; y = x + diag;
100
- add(x, x + 1, y, y);
101
- }
102
- frontier = history[i$1 >> 1];
41
+ let tokA = tokens(fragA, range.fromA, range.toA, []);
42
+ let tokB = tokens(fragB, range.fromB, range.toB, []);
43
+ // Scan from both sides to cheaply eliminate work
44
+ let start = 0, endA = tokA.length, endB = tokB.length;
45
+ while (start < tokA.length && start < tokB.length && tokA[start] === tokB[start])
46
+ start++;
47
+ if (start == tokA.length && start == tokB.length)
48
+ return [];
49
+ while (endA > start && endB > start && tokA[endA - 1] === tokB[endB - 1])
50
+ endA--, endB--;
51
+ // If the result is simple _or_ too big to cheaply compute, return
52
+ // the remaining region as the diff
53
+ if (endA == start || endB == start || (endA == endB && endA == start + 1))
54
+ return [range.slice(start, endA, start, endB)];
55
+ // This is an implementation of Myers' diff algorithm
56
+ // See https://neil.fraser.name/writing/diff/myers.pdf and
57
+ // https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/
58
+ let lenA = endA - start, lenB = endB - start;
59
+ let max = Math.min(MAX_DIFF_SIZE, lenA + lenB), off = max + 1;
60
+ let history = [];
61
+ let frontier = [];
62
+ for (let len = off * 2, i = 0; i < len; i++)
63
+ frontier[i] = -1;
64
+ for (let size = 0; size <= max; size++) {
65
+ for (let diag = -size; diag <= size; diag += 2) {
66
+ let next = frontier[diag + 1 + max], prev = frontier[diag - 1 + max];
67
+ let x = next < prev ? prev : next + 1, y = x + diag;
68
+ while (x < lenA && y < lenB && tokA[start + x] === tokB[start + y])
69
+ x++, y++;
70
+ frontier[diag + max] = x;
71
+ // Found a match
72
+ if (x >= lenA && y >= lenB) {
73
+ // Trace back through the history to build up a set of changed ranges.
74
+ let diff = [], minSpan = minUnchanged(endA - start, endB - start);
75
+ // Used to add steps to a diff one at a time, back to front, merging
76
+ // ones that are less than minSpan tokens apart
77
+ let fromA = -1, toA = -1, fromB = -1, toB = -1;
78
+ let add = (fA, tA, fB, tB) => {
79
+ if (fromA > -1 && fromA < tA + minSpan) {
80
+ fromA = fA;
81
+ fromB = fB;
82
+ }
83
+ else {
84
+ if (fromA > -1)
85
+ diff.push(range.slice(fromA, toA, fromB, toB));
86
+ fromA = fA;
87
+ toA = tA;
88
+ fromB = fB;
89
+ toB = tB;
90
+ }
91
+ };
92
+ for (let i = size - 1; i >= 0; i--) {
93
+ let next = frontier[diag + 1 + max], prev = frontier[diag - 1 + max];
94
+ if (next < prev) { // Deletion
95
+ diag--;
96
+ x = prev + start;
97
+ y = x + diag;
98
+ add(x, x, y, y + 1);
99
+ }
100
+ else { // Insertion
101
+ diag++;
102
+ x = next + start;
103
+ y = x + diag;
104
+ add(x, x + 1, y, y);
105
+ }
106
+ frontier = history[i >> 1];
107
+ }
108
+ if (fromA > -1)
109
+ diff.push(range.slice(fromA, toA, fromB, toB));
110
+ return diff.reverse();
111
+ }
103
112
  }
104
- if (fromA > -1) { diff.push(range.slice(fromA, toA, fromB, toB)); }
105
- return diff.reverse()
106
- }
113
+ // Since only either odd or even diagonals are read from each
114
+ // frontier, we only copy them every other iteration.
115
+ if (size % 2 == 0)
116
+ history.push(frontier.slice());
107
117
  }
108
- // Since only either odd or even diagonals are read from each
109
- // frontier, we only copy them every other iteration.
110
- if (size % 2 == 0) { history.push(frontier.slice()); }
111
- }
112
- // The loop exited, meaning the maximum amount of work was done.
113
- // Just return a change spanning the entire range.
114
- return [range.slice(start, endA, start, endB)]
118
+ // The loop exited, meaning the maximum amount of work was done.
119
+ // Just return a change spanning the entire range.
120
+ return [range.slice(start, endA, start, endB)];
115
121
  }
116
122
 
117
- // ::- Stores metadata for a part of a change.
118
- var Span = function Span(length, data) {
119
- // :: number
120
- this.length = length;
121
- // :: any
122
- this.data = data;
123
- };
124
-
125
- Span.prototype.cut = function cut (length) {
126
- return length == this.length ? this : new Span(length, this.data)
127
- };
128
-
129
- Span.slice = function slice (spans, from, to) {
130
- if (from == to) { return Span.none }
131
- if (from == 0 && to == Span.len(spans)) { return spans }
132
- var result = [];
133
- for (var i = 0, off = 0; off < to; i++) {
134
- var span = spans[i], end = off + span.length;
135
- var overlap = Math.min(to, end) - Math.max(from, off);
136
- if (overlap > 0) { result.push(span.cut(overlap)); }
137
- off = end;
138
- }
139
- return result
140
- };
141
-
142
- Span.join = function join (a, b, combine) {
143
- if (a.length == 0) { return b }
144
- if (b.length == 0) { return a }
145
- var combined = combine(a[a.length - 1].data, b[0].data);
146
- if (combined == null) { return a.concat(b) }
147
- var result = a.slice(0, a.length - 1);
148
- result.push(new Span(a[a.length - 1].length + b[0].length, combined));
149
- for (var i = 1; i < b.length; i++) { result.push(b[i]); }
150
- return result
151
- };
152
-
153
- Span.len = function len (spans) {
154
- var len = 0;
155
- for (var i = 0; i < spans.length; i++) { len += spans[i].length; }
156
- return len
157
- };
158
-
159
- Span.none = [];
160
-
161
- // ::- A replaced range with metadata associated with it.
162
- var Change = function Change(fromA, toA, fromB, toB, deleted, inserted) {
163
- // :: number The start of the range deleted/replaced in the old
164
- // document.
165
- this.fromA = fromA;
166
- // :: number The end of the range in the old document.
167
- this.toA = toA;
168
- // :: number The start of the range inserted in the new document.
169
- this.fromB = fromB;
170
- // :: number The end of the range in the new document.
171
- this.toB = toB;
172
- // :: [Span] Data associated with the deleted content. The length
173
- // of these spans adds up to `this.toA - this.fromA`.
174
- this.deleted = deleted;
175
- // :: [Span] Data associated with the inserted content. Length
176
- // adds up to `this.toB - this.toA`.
177
- this.inserted = inserted;
178
- };
179
-
180
- var prototypeAccessors = { lenA: { configurable: true },lenB: { configurable: true } };
181
-
182
- prototypeAccessors.lenA.get = function () { return this.toA - this.fromA };
183
- prototypeAccessors.lenB.get = function () { return this.toB - this.fromB };
184
-
185
- Change.prototype.slice = function slice (startA, endA, startB, endB) {
186
- if (startA == 0 && startB == 0 && endA == this.toA - this.fromA &&
187
- endB == this.toB - this.fromB) { return this }
188
- return new Change(this.fromA + startA, this.fromA + endA,
189
- this.fromB + startB, this.fromB + endB,
190
- Span.slice(this.deleted, startA, endA),
191
- Span.slice(this.inserted, startB, endB))
192
- };
193
-
194
- // : ([Change], [Change], (any, any) → any) → [Change]
195
- // This merges two changesets (the end document of x should be the
196
- // start document of y) into a single one spanning the start of x to
197
- // the end of y.
198
- Change.merge = function merge (x, y, combine) {
199
- if (x.length == 0) { return y }
200
- if (y.length == 0) { return x }
201
-
202
- var result = [];
203
- // Iterate over both sets in parallel, using the middle coordinate
204
- // system (B in x, A in y) to synchronize.
205
- for (var iX = 0, iY = 0, curX = x[0], curY = y[0];;) {
206
- if (!curX && !curY) {
207
- return result
208
- } else if (curX && (!curY || curX.toB < curY.fromA)) { // curX entirely in front of curY
209
- var off = iY ? y[iY - 1].toB - y[iY - 1].toA : 0;
210
- result.push(off == 0 ? curX :
211
- new Change(curX.fromA, curX.toA, curX.fromB + off, curX.toB + off,
212
- curX.deleted, curX.inserted));
213
- curX = iX++ == x.length ? null : x[iX];
214
- } else if (curY && (!curX || curY.toA < curX.fromB)) { // curY entirely in front of curX
215
- var off$1 = iX ? x[iX - 1].toB - x[iX - 1].toA : 0;
216
- result.push(off$1 == 0 ? curY :
217
- new Change(curY.fromA - off$1, curY.toA - off$1, curY.fromB, curY.toB,
218
- curY.deleted, curY.inserted));
219
- curY = iY++ == y.length ? null : y[iY];
220
- } else { // Touch, need to merge
221
- // The rules for merging ranges are that deletions from the
222
- // old set and insertions from the new are kept. Areas of the
223
- // middle document covered by a but not by b are insertions
224
- // from a that need to be added, and areas covered by b but
225
- // not a are deletions from b that need to be added.
226
- var pos = Math.min(curX.fromB, curY.fromA);
227
- var fromA = Math.min(curX.fromA, curY.fromA - (iX ? x[iX - 1].toB - x[iX - 1].toA : 0)), toA = fromA;
228
- var fromB = Math.min(curY.fromB, curX.fromB + (iY ? y[iY - 1].toB - y[iY - 1].toA : 0)), toB = fromB;
229
- var deleted = Span.none, inserted = Span.none;
230
-
231
- // Used to prevent appending ins/del range for the same Change twice
232
- var enteredX = false, enteredY = false;
233
-
234
- // Need to have an inner loop since any number of further
235
- // ranges might be touching this group
236
- for (;;) {
237
- var nextX = !curX ? 2e8 : pos >= curX.fromB ? curX.toB : curX.fromB;
238
- var nextY = !curY ? 2e8 : pos >= curY.fromA ? curY.toA : curY.fromA;
239
- var next = Math.min(nextX, nextY);
240
- var inX = curX && pos >= curX.fromB, inY = curY && pos >= curY.fromA;
241
- if (!inX && !inY) { break }
242
- if (inX && pos == curX.fromB && !enteredX) {
243
- deleted = Span.join(deleted, curX.deleted, combine);
244
- toA += curX.lenA;
245
- enteredX = true;
246
- }
247
- if (inX && !inY) {
248
- inserted = Span.join(inserted, Span.slice(curX.inserted, pos - curX.fromB, next - curX.fromB), combine);
249
- toB += next - pos;
250
- }
251
- if (inY && pos == curY.fromA && !enteredY) {
252
- inserted = Span.join(inserted, curY.inserted, combine);
253
- toB += curY.lenB;
254
- enteredY = true;
255
- }
256
- if (inY && !inX) {
257
- deleted = Span.join(deleted, Span.slice(curY.deleted, pos - curY.fromA, next - curY.fromA), combine);
258
- toA += next - pos;
259
- }
260
-
261
- if (inX && next == curX.toB) {
262
- curX = iX++ == x.length ? null : x[iX];
263
- enteredX = false;
123
+ /**
124
+ Stores metadata for a part of a change.
125
+ */
126
+ class Span {
127
+ /**
128
+ @internal
129
+ */
130
+ constructor(
131
+ /**
132
+ The length of this span.
133
+ */
134
+ length,
135
+ /**
136
+ The data associated with this span.
137
+ */
138
+ data) {
139
+ this.length = length;
140
+ this.data = data;
141
+ }
142
+ /**
143
+ @internal
144
+ */
145
+ cut(length) {
146
+ return length == this.length ? this : new Span(length, this.data);
147
+ }
148
+ /**
149
+ @internal
150
+ */
151
+ static slice(spans, from, to) {
152
+ if (from == to)
153
+ return Span.none;
154
+ if (from == 0 && to == Span.len(spans))
155
+ return spans;
156
+ let result = [];
157
+ for (let i = 0, off = 0; off < to; i++) {
158
+ let span = spans[i], end = off + span.length;
159
+ let overlap = Math.min(to, end) - Math.max(from, off);
160
+ if (overlap > 0)
161
+ result.push(span.cut(overlap));
162
+ off = end;
264
163
  }
265
- if (inY && next == curY.toA) {
266
- curY = iY++ == y.length ? null : y[iY];
267
- enteredY = false;
164
+ return result;
165
+ }
166
+ /**
167
+ @internal
168
+ */
169
+ static join(a, b, combine) {
170
+ if (a.length == 0)
171
+ return b;
172
+ if (b.length == 0)
173
+ return a;
174
+ let combined = combine(a[a.length - 1].data, b[0].data);
175
+ if (combined == null)
176
+ return a.concat(b);
177
+ let result = a.slice(0, a.length - 1);
178
+ result.push(new Span(a[a.length - 1].length + b[0].length, combined));
179
+ for (let i = 1; i < b.length; i++)
180
+ result.push(b[i]);
181
+ return result;
182
+ }
183
+ /**
184
+ @internal
185
+ */
186
+ static len(spans) {
187
+ let len = 0;
188
+ for (let i = 0; i < spans.length; i++)
189
+ len += spans[i].length;
190
+ return len;
191
+ }
192
+ }
193
+ /**
194
+ @internal
195
+ */
196
+ Span.none = [];
197
+ /**
198
+ A replaced range with metadata associated with it.
199
+ */
200
+ class Change {
201
+ /**
202
+ @internal
203
+ */
204
+ constructor(
205
+ /**
206
+ The start of the range deleted/replaced in the old document.
207
+ */
208
+ fromA,
209
+ /**
210
+ The end of the range in the old document.
211
+ */
212
+ toA,
213
+ /**
214
+ The start of the range inserted in the new document.
215
+ */
216
+ fromB,
217
+ /**
218
+ The end of the range in the new document.
219
+ */
220
+ toB,
221
+ /**
222
+ Data associated with the deleted content. The length of these
223
+ spans adds up to `this.toA - this.fromA`.
224
+ */
225
+ deleted,
226
+ /**
227
+ Data associated with the inserted content. Length adds up to
228
+ `this.toB - this.toA`.
229
+ */
230
+ inserted) {
231
+ this.fromA = fromA;
232
+ this.toA = toA;
233
+ this.fromB = fromB;
234
+ this.toB = toB;
235
+ this.deleted = deleted;
236
+ this.inserted = inserted;
237
+ }
238
+ /**
239
+ @internal
240
+ */
241
+ get lenA() { return this.toA - this.fromA; }
242
+ /**
243
+ @internal
244
+ */
245
+ get lenB() { return this.toB - this.fromB; }
246
+ /**
247
+ @internal
248
+ */
249
+ slice(startA, endA, startB, endB) {
250
+ if (startA == 0 && startB == 0 && endA == this.toA - this.fromA &&
251
+ endB == this.toB - this.fromB)
252
+ return this;
253
+ return new Change(this.fromA + startA, this.fromA + endA, this.fromB + startB, this.fromB + endB, Span.slice(this.deleted, startA, endA), Span.slice(this.inserted, startB, endB));
254
+ }
255
+ /**
256
+ This merges two changesets (the end document of x should be the
257
+ start document of y) into a single one spanning the start of x to
258
+ the end of y.
259
+ */
260
+ static merge(x, y, combine) {
261
+ if (x.length == 0)
262
+ return y;
263
+ if (y.length == 0)
264
+ return x;
265
+ let result = [];
266
+ // Iterate over both sets in parallel, using the middle coordinate
267
+ // system (B in x, A in y) to synchronize.
268
+ for (let iX = 0, iY = 0, curX = x[0], curY = y[0];;) {
269
+ if (!curX && !curY) {
270
+ return result;
271
+ }
272
+ else if (curX && (!curY || curX.toB < curY.fromA)) { // curX entirely in front of curY
273
+ let off = iY ? y[iY - 1].toB - y[iY - 1].toA : 0;
274
+ result.push(off == 0 ? curX :
275
+ new Change(curX.fromA, curX.toA, curX.fromB + off, curX.toB + off, curX.deleted, curX.inserted));
276
+ curX = iX++ == x.length ? null : x[iX];
277
+ }
278
+ else if (curY && (!curX || curY.toA < curX.fromB)) { // curY entirely in front of curX
279
+ let off = iX ? x[iX - 1].toB - x[iX - 1].toA : 0;
280
+ result.push(off == 0 ? curY :
281
+ new Change(curY.fromA - off, curY.toA - off, curY.fromB, curY.toB, curY.deleted, curY.inserted));
282
+ curY = iY++ == y.length ? null : y[iY];
283
+ }
284
+ else { // Touch, need to merge
285
+ // The rules for merging ranges are that deletions from the
286
+ // old set and insertions from the new are kept. Areas of the
287
+ // middle document covered by a but not by b are insertions
288
+ // from a that need to be added, and areas covered by b but
289
+ // not a are deletions from b that need to be added.
290
+ let pos = Math.min(curX.fromB, curY.fromA);
291
+ let fromA = Math.min(curX.fromA, curY.fromA - (iX ? x[iX - 1].toB - x[iX - 1].toA : 0)), toA = fromA;
292
+ let fromB = Math.min(curY.fromB, curX.fromB + (iY ? y[iY - 1].toB - y[iY - 1].toA : 0)), toB = fromB;
293
+ let deleted = Span.none, inserted = Span.none;
294
+ // Used to prevent appending ins/del range for the same Change twice
295
+ let enteredX = false, enteredY = false;
296
+ // Need to have an inner loop since any number of further
297
+ // ranges might be touching this group
298
+ for (;;) {
299
+ let nextX = !curX ? 2e8 : pos >= curX.fromB ? curX.toB : curX.fromB;
300
+ let nextY = !curY ? 2e8 : pos >= curY.fromA ? curY.toA : curY.fromA;
301
+ let next = Math.min(nextX, nextY);
302
+ let inX = curX && pos >= curX.fromB, inY = curY && pos >= curY.fromA;
303
+ if (!inX && !inY)
304
+ break;
305
+ if (inX && pos == curX.fromB && !enteredX) {
306
+ deleted = Span.join(deleted, curX.deleted, combine);
307
+ toA += curX.lenA;
308
+ enteredX = true;
309
+ }
310
+ if (inX && !inY) {
311
+ inserted = Span.join(inserted, Span.slice(curX.inserted, pos - curX.fromB, next - curX.fromB), combine);
312
+ toB += next - pos;
313
+ }
314
+ if (inY && pos == curY.fromA && !enteredY) {
315
+ inserted = Span.join(inserted, curY.inserted, combine);
316
+ toB += curY.lenB;
317
+ enteredY = true;
318
+ }
319
+ if (inY && !inX) {
320
+ deleted = Span.join(deleted, Span.slice(curY.deleted, pos - curY.fromA, next - curY.fromA), combine);
321
+ toA += next - pos;
322
+ }
323
+ if (inX && next == curX.toB) {
324
+ curX = iX++ == x.length ? null : x[iX];
325
+ enteredX = false;
326
+ }
327
+ if (inY && next == curY.toA) {
328
+ curY = iY++ == y.length ? null : y[iY];
329
+ enteredY = false;
330
+ }
331
+ pos = next;
332
+ }
333
+ if (fromA < toA || fromB < toB)
334
+ result.push(new Change(fromA, toA, fromB, toB, deleted, inserted));
335
+ }
268
336
  }
269
- pos = next;
270
- }
271
- if (fromA < toA || fromB < toB)
272
- { result.push(new Change(fromA, toA, fromB, toB, deleted, inserted)); }
273
337
  }
274
- }
275
- };
276
-
277
- Object.defineProperties( Change.prototype, prototypeAccessors );
338
+ }
278
339
 
279
- var letter;
340
+ let letter;
280
341
  // If the runtime support unicode properties in regexps, that's a good
281
342
  // source of info on whether something is a letter.
282
- try { letter = new RegExp("[\\p{Alphabetic}_]", "u"); } catch(_) {}
283
-
343
+ try {
344
+ letter = new RegExp("[\\p{Alphabetic}_]", "u");
345
+ }
346
+ catch (_) { }
284
347
  // Otherwise, we see if the character changes when upper/lowercased,
285
348
  // or if it is part of these common single-case scripts.
286
- var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
287
-
349
+ const nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
288
350
  function isLetter(code) {
289
- if (code < 128)
290
- { return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 79 && code <= 122 }
291
- var ch = String.fromCharCode(code);
292
- if (letter) { return letter.test(ch) }
293
- return ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)
351
+ if (code < 128)
352
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 79 && code <= 122;
353
+ let ch = String.fromCharCode(code);
354
+ if (letter)
355
+ return letter.test(ch);
356
+ return ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch);
294
357
  }
295
-
296
358
  // Convert a range of document into a string, so that we can easily
297
359
  // access characters at a given position. Treat non-text tokens as
298
360
  // spaces so that they aren't considered part of a word.
299
361
  function getText(frag, start, end) {
300
- var out = "";
301
- function convert(frag, start, end) {
302
- for (var i = 0, off = 0; i < frag.childCount; i++) {
303
- var child = frag.child(i), endOff = off + child.nodeSize;
304
- var from = Math.max(off, start), to = Math.min(endOff, end);
305
- if (from < to) {
306
- if (child.isText) {
307
- out += child.text.slice(Math.max(0, start - off), Math.min(child.text.length, end - off));
308
- } else if (child.isLeaf) {
309
- out += " ";
310
- } else {
311
- if (from == off) { out += " "; }
312
- convert(child.content, Math.max(0, from - off - 1), Math.min(child.content.size, end - off));
313
- if (to == endOff) { out += " "; }
362
+ let out = "";
363
+ function convert(frag, start, end) {
364
+ for (let i = 0, off = 0; i < frag.childCount; i++) {
365
+ let child = frag.child(i), endOff = off + child.nodeSize;
366
+ let from = Math.max(off, start), to = Math.min(endOff, end);
367
+ if (from < to) {
368
+ if (child.isText) {
369
+ out += child.text.slice(Math.max(0, start - off), Math.min(child.text.length, end - off));
370
+ }
371
+ else if (child.isLeaf) {
372
+ out += " ";
373
+ }
374
+ else {
375
+ if (from == off)
376
+ out += " ";
377
+ convert(child.content, Math.max(0, from - off - 1), Math.min(child.content.size, end - off));
378
+ if (to == endOff)
379
+ out += " ";
380
+ }
381
+ }
382
+ off = endOff;
314
383
  }
315
- }
316
- off = endOff;
317
384
  }
318
- }
319
- convert(frag, start, end);
320
- return out
385
+ convert(frag, start, end);
386
+ return out;
321
387
  }
322
-
323
388
  // The distance changes have to be apart for us to not consider them
324
389
  // candidates for merging.
325
- var MAX_SIMPLIFY_DISTANCE = 30;
326
-
327
- // :: ([Change], Node) → [Change]
328
- // Simplifies a set of changes for presentation. This makes the
329
- // assumption that having both insertions and deletions within a word
330
- // is confusing, and, when such changes occur without a word boundary
331
- // between them, they should be expanded to cover the entire set of
332
- // words (in the new document) they touch. An exception is made for
333
- // single-character replacements.
390
+ const MAX_SIMPLIFY_DISTANCE = 30;
391
+ /**
392
+ Simplifies a set of changes for presentation. This makes the
393
+ assumption that having both insertions and deletions within a word
394
+ is confusing, and, when such changes occur without a word boundary
395
+ between them, they should be expanded to cover the entire set of
396
+ words (in the new document) they touch. An exception is made for
397
+ single-character replacements.
398
+ */
334
399
  function simplifyChanges(changes, doc) {
335
- var result = [];
336
- for (var i = 0; i < changes.length; i++) {
337
- var end = changes[i].toB, start = i;
338
- while (i < changes.length - 1 && changes[i + 1].fromB <= end + MAX_SIMPLIFY_DISTANCE)
339
- { end = changes[++i].toB; }
340
- simplifyAdjacentChanges(changes, start, i + 1, doc, result);
341
- }
342
- return result
400
+ let result = [];
401
+ for (let i = 0; i < changes.length; i++) {
402
+ let end = changes[i].toB, start = i;
403
+ while (i < changes.length - 1 && changes[i + 1].fromB <= end + MAX_SIMPLIFY_DISTANCE)
404
+ end = changes[++i].toB;
405
+ simplifyAdjacentChanges(changes, start, i + 1, doc, result);
406
+ }
407
+ return result;
343
408
  }
344
-
345
409
  function simplifyAdjacentChanges(changes, from, to, doc, target) {
346
- var start = Math.max(0, changes[from].fromB - MAX_SIMPLIFY_DISTANCE);
347
- var end = Math.min(doc.content.size, changes[to - 1].toB + MAX_SIMPLIFY_DISTANCE);
348
- var text = getText(doc.content, start, end);
349
-
350
- for (var i = from; i < to; i++) {
351
- var startI = i, last = changes[i], deleted = last.lenA, inserted = last.lenB;
352
- while (i < to - 1) {
353
- var next = changes[i + 1], boundary = false;
354
- var prevLetter = last.toB == end ? false : isLetter(text.charCodeAt(last.toB - 1 - start));
355
- for (var pos = last.toB; !boundary && pos < next.fromB; pos++) {
356
- var nextLetter = pos == end ? false : isLetter(text.charCodeAt(pos - start));
357
- if ((!prevLetter || !nextLetter) && pos != changes[startI].fromB) { boundary = true; }
358
- prevLetter = nextLetter;
359
- }
360
- if (boundary) { break }
361
- deleted += next.lenA; inserted += next.lenB;
362
- last = next;
363
- i++;
364
- }
365
-
366
- if (inserted > 0 && deleted > 0 && !(inserted == 1 && deleted == 1)) {
367
- var from$1 = changes[startI].fromB, to$1 = changes[i].toB;
368
- if (from$1 < end && isLetter(text.charCodeAt(from$1 - start)))
369
- { while (from$1 > start && isLetter(text.charCodeAt(from$1 - 1 - start))) { from$1--; } }
370
- if (to$1 > start && isLetter(text.charCodeAt(to$1 - 1 - start)))
371
- { while (to$1 < end && isLetter(text.charCodeAt(to$1 - start))) { to$1++; } }
372
- var joined = fillChange(changes.slice(startI, i + 1), from$1, to$1);
373
- var last$1 = target.length ? target[target.length - 1] : null;
374
- if (last$1 && last$1.toA == joined.fromA)
375
- { target[target.length - 1] = new Change(last$1.fromA, joined.toA, last$1.fromB, joined.toB,
376
- last$1.deleted.concat(joined.deleted), last$1.inserted.concat(joined.inserted)); }
377
- else
378
- { target.push(joined); }
379
- } else {
380
- for (var j = startI; j <= i; j++) { target.push(changes[j]); }
410
+ let start = Math.max(0, changes[from].fromB - MAX_SIMPLIFY_DISTANCE);
411
+ let end = Math.min(doc.content.size, changes[to - 1].toB + MAX_SIMPLIFY_DISTANCE);
412
+ let text = getText(doc.content, start, end);
413
+ for (let i = from; i < to; i++) {
414
+ let startI = i, last = changes[i], deleted = last.lenA, inserted = last.lenB;
415
+ while (i < to - 1) {
416
+ let next = changes[i + 1], boundary = false;
417
+ let prevLetter = last.toB == end ? false : isLetter(text.charCodeAt(last.toB - 1 - start));
418
+ for (let pos = last.toB; !boundary && pos < next.fromB; pos++) {
419
+ let nextLetter = pos == end ? false : isLetter(text.charCodeAt(pos - start));
420
+ if ((!prevLetter || !nextLetter) && pos != changes[startI].fromB)
421
+ boundary = true;
422
+ prevLetter = nextLetter;
423
+ }
424
+ if (boundary)
425
+ break;
426
+ deleted += next.lenA;
427
+ inserted += next.lenB;
428
+ last = next;
429
+ i++;
430
+ }
431
+ if (inserted > 0 && deleted > 0 && !(inserted == 1 && deleted == 1)) {
432
+ let from = changes[startI].fromB, to = changes[i].toB;
433
+ if (from < end && isLetter(text.charCodeAt(from - start)))
434
+ while (from > start && isLetter(text.charCodeAt(from - 1 - start)))
435
+ from--;
436
+ if (to > start && isLetter(text.charCodeAt(to - 1 - start)))
437
+ while (to < end && isLetter(text.charCodeAt(to - start)))
438
+ to++;
439
+ let joined = fillChange(changes.slice(startI, i + 1), from, to);
440
+ let last = target.length ? target[target.length - 1] : null;
441
+ if (last && last.toA == joined.fromA)
442
+ target[target.length - 1] = new Change(last.fromA, joined.toA, last.fromB, joined.toB, last.deleted.concat(joined.deleted), last.inserted.concat(joined.inserted));
443
+ else
444
+ target.push(joined);
445
+ }
446
+ else {
447
+ for (let j = startI; j <= i; j++)
448
+ target.push(changes[j]);
449
+ }
381
450
  }
382
- }
383
- return changes
451
+ return changes;
384
452
  }
385
-
386
- function combine(a, b) { return a === b ? a : null }
387
-
453
+ function combine(a, b) { return a === b ? a : null; }
388
454
  function fillChange(changes, fromB, toB) {
389
- var fromA = changes[0].fromA - (changes[0].fromB - fromB);
390
- var last = changes[changes.length - 1];
391
- var toA = last.toA + (toB - last.toB);
392
- var deleted = Span.none, inserted = Span.none;
393
- var delData = (changes[0].deleted.length ? changes[0].deleted : changes[0].inserted)[0].data;
394
- var insData = (changes[0].inserted.length ? changes[0].inserted : changes[0].deleted)[0].data;
395
- for (var posA = fromA, posB = fromB, i = 0;; i++) {
396
- var next = i == changes.length ? null : changes[i];
397
- var endA = next ? next.fromA : toA, endB = next ? next.fromB : toB;
398
- if (endA > posA) { deleted = Span.join(deleted, [new Span(endA - posA, delData)], combine); }
399
- if (endB > posB) { inserted = Span.join(inserted, [new Span(endB - posB, insData)], combine); }
400
- if (!next) { break }
401
- deleted = Span.join(deleted, next.deleted, combine);
402
- inserted = Span.join(inserted, next.inserted, combine);
403
- if (deleted.length) { delData = deleted[deleted.length - 1].data; }
404
- if (inserted.length) { insData = inserted[inserted.length - 1].data; }
405
- posA = next.toA; posB = next.toB;
406
- }
407
- return new Change(fromA, toA, fromB, toB, deleted, inserted)
455
+ let fromA = changes[0].fromA - (changes[0].fromB - fromB);
456
+ let last = changes[changes.length - 1];
457
+ let toA = last.toA + (toB - last.toB);
458
+ let deleted = Span.none, inserted = Span.none;
459
+ let delData = (changes[0].deleted.length ? changes[0].deleted : changes[0].inserted)[0].data;
460
+ let insData = (changes[0].inserted.length ? changes[0].inserted : changes[0].deleted)[0].data;
461
+ for (let posA = fromA, posB = fromB, i = 0;; i++) {
462
+ let next = i == changes.length ? null : changes[i];
463
+ let endA = next ? next.fromA : toA, endB = next ? next.fromB : toB;
464
+ if (endA > posA)
465
+ deleted = Span.join(deleted, [new Span(endA - posA, delData)], combine);
466
+ if (endB > posB)
467
+ inserted = Span.join(inserted, [new Span(endB - posB, insData)], combine);
468
+ if (!next)
469
+ break;
470
+ deleted = Span.join(deleted, next.deleted, combine);
471
+ inserted = Span.join(inserted, next.inserted, combine);
472
+ if (deleted.length)
473
+ delData = deleted[deleted.length - 1].data;
474
+ if (inserted.length)
475
+ insData = inserted[inserted.length - 1].data;
476
+ posA = next.toA;
477
+ posB = next.toB;
478
+ }
479
+ return new Change(fromA, toA, fromB, toB, deleted, inserted);
408
480
  }
409
481
 
410
- // ::- A change set tracks the changes to a document from a given
411
- // point in the past. It condenses a number of step maps down to a
412
- // flat sequence of replacements, and simplifies replacments that
413
- // partially undo themselves by comparing their content.
414
- var ChangeSet = function ChangeSet(config, changes) {
415
- this.config = config;
416
- // :: [Change] Replaced regions.
417
- this.changes = changes;
418
- };
419
-
420
- var prototypeAccessors$1 = { startDoc: { configurable: true } };
421
-
422
- // :: (Node, [StepMap], union<[any], any>) → ChangeSet
423
- // Computes a new changeset by adding the given step maps and
424
- // metadata (either as an array, per-map, or as a single value to be
425
- // associated with all maps) to the current set. Will not mutate the
426
- // old set.
427
- //
428
- // Note that due to simplification that happens after each add,
429
- // incrementally adding steps might create a different final set
430
- // than adding all those changes at once, since different document
431
- // tokens might be matched during simplification depending on the
432
- // boundaries of the current changed ranges.
433
- ChangeSet.prototype.addSteps = function addSteps (newDoc, maps, data) {
434
- var this$1 = this;
435
-
436
- // This works by inspecting the position maps for the changes,
437
- // which indicate what parts of the document were replaced by new
438
- // content, and the size of that new content. It uses these to
439
- // build up Change objects.
440
- //
441
- // These change objects are put in sets and merged together using
442
- // Change.merge, giving us the changes created by the new steps.
443
- // Those changes can then be merged with the existing set of
444
- // changes.
445
- //
446
- // For each change that was touched by the new steps, we recompute
447
- // a diff to try to minimize the change by dropping matching
448
- // pieces of the old and new document from the change.
449
-
450
- var stepChanges = [];
451
- // Add spans for new steps.
452
- var loop = function ( i ) {
453
- var d = Array.isArray(data) ? data[i] : data;
454
- var off = 0;
455
- maps[i].forEach(function (fromA, toA, fromB, toB) {
456
-
457
- stepChanges.push(new Change(fromA + off, toA + off, fromB, toB,
458
- fromA == toA ? Span.none : [new Span(toA - fromA, d)],
459
- fromB == toB ? Span.none : [new Span(toB - fromB, d)]));
460
-
461
- off = (toB - fromB) - (toA - fromA);
462
- });
463
- };
464
-
465
- for (var i = 0; i < maps.length; i++) loop( i );
466
- if (stepChanges.length == 0) { return this }
467
-
468
- var newChanges = mergeAll(stepChanges, this.config.combine);
469
- var changes = Change.merge(this.changes, newChanges, this.config.combine);
470
-
471
- // Minimize changes when possible
472
- var loop$1 = function ( i$2 ) {
473
- var change = changes[i$2];
474
- if (change.fromA == change.toA || change.fromB == change.toB ||
475
- // Only look at changes that touch newly added changed ranges
476
- !newChanges.some(function (r) { return r.toB > change.fromB && r.fromB < change.toB; })) { return }
477
- var diff = computeDiff(this$1.config.doc.content, newDoc.content, change);
478
-
479
- // Fast path: If they are completely different, don't do anything
480
- if (diff.length == 1 && diff[0].fromB == 0 && diff[0].toB == change.toB - change.fromB)
481
- { return }
482
-
483
- if (diff.length == 1) {
484
- changes[i$2] = diff[0];
485
- } else {
486
- changes.splice.apply(changes, [ i$2, 1 ].concat( diff ));
487
- i$2 += diff.length - 1;
482
+ /**
483
+ A change set tracks the changes to a document from a given point
484
+ in the past. It condenses a number of step maps down to a flat
485
+ sequence of replacements, and simplifies replacments that
486
+ partially undo themselves by comparing their content.
487
+ */
488
+ class ChangeSet {
489
+ /**
490
+ @internal
491
+ */
492
+ constructor(
493
+ /**
494
+ @internal
495
+ */
496
+ config,
497
+ /**
498
+ Replaced regions.
499
+ */
500
+ changes) {
501
+ this.config = config;
502
+ this.changes = changes;
488
503
  }
489
-
490
- i$1 = i$2;
491
- };
492
-
493
- for (var i$1 = 0; i$1 < changes.length; i$1++) loop$1( i$1 );
494
-
495
- return new ChangeSet(this.config, changes)
496
- };
497
-
498
- // :: Node
499
- // The starting document of the change set.
500
- prototypeAccessors$1.startDoc.get = function () { return this.config.doc };
501
-
502
- // :: (f: (range: Change) → any) → ChangeSet
503
- // Map the span's data values in the given set through a function
504
- // and construct a new set with the resulting data.
505
- ChangeSet.prototype.map = function map (f) {
506
- return new ChangeSet(this.config, this.changes.map(function (change) {
507
- var data = f(change);
508
- return data === change.data ? change :
509
- new Change(change.fromA, change.toA, change.fromB, change.toB, data)
510
- }))
511
- };
512
-
513
- // :: (ChangeSet, ?[StepMap]) → ?{from: number, to: number}
514
- // Compare two changesets and return the range in which they are
515
- // changed, if any. If the document changed between the maps, pass
516
- // the maps for the steps that changed it as second argument, and
517
- // make sure the method is called on the old set and passed the new
518
- // set. The returned positions will be in new document coordinates.
519
- ChangeSet.prototype.changedRange = function changedRange (b, maps) {
520
- if (b == this) { return null }
521
- var touched = maps && touchedRange(maps);
522
- var moved = touched ? (touched.toB - touched.fromB) - (touched.toA - touched.fromA) : 0;
523
- function map(p) {
524
- return !touched || p <= touched.fromA ? p : p + moved
525
- }
526
-
527
- var from = touched ? touched.fromB : 2e8, to = touched ? touched.toB : -2e8;
528
- function add(start, end) {
529
- if ( end === void 0 ) end = start;
530
-
531
- from = Math.min(start, from); to = Math.max(end, to);
532
- }
533
-
534
- var rA = this.changes, rB = b.changes;
535
- for (var iA = 0, iB = 0; iA < rA.length && iB < rB.length;) {
536
- var rangeA = rA[iA], rangeB = rB[iB];
537
- if (rangeA && rangeB && sameRanges(rangeA, rangeB, map)) { iA++; iB++; }
538
- else if (rangeB && (!rangeA || map(rangeA.fromB) >= rangeB.fromB)) { add(rangeB.fromB, rangeB.toB); iB++; }
539
- else { add(map(rangeA.fromB), map(rangeA.toB)); iA++; }
540
- }
541
-
542
- return from <= to ? {from: from, to: to} : null
543
- };
544
-
545
- // :: (Node, ?(a: any, b: any) → any) → ChangeSet
546
- // Create a changeset with the given base object and configuration.
547
- // The `combine` function is used to compare and combine metadata—it
548
- // should return null when metadata isn't compatible, and a combined
549
- // version for a merged range when it is.
550
- ChangeSet.create = function create (doc, combine) {
551
- if ( combine === void 0 ) combine = function (a, b) { return a === b ? a : null; };
552
-
553
- return new ChangeSet({combine: combine, doc: doc}, [], [])
554
- };
555
-
556
- Object.defineProperties( ChangeSet.prototype, prototypeAccessors$1 );
557
-
558
- // Exported for testing
504
+ /**
505
+ Computes a new changeset by adding the given step maps and
506
+ metadata (either as an array, per-map, or as a single value to be
507
+ associated with all maps) to the current set. Will not mutate the
508
+ old set.
509
+
510
+ Note that due to simplification that happens after each add,
511
+ incrementally adding steps might create a different final set
512
+ than adding all those changes at once, since different document
513
+ tokens might be matched during simplification depending on the
514
+ boundaries of the current changed ranges.
515
+ */
516
+ addSteps(newDoc, maps, data) {
517
+ // This works by inspecting the position maps for the changes,
518
+ // which indicate what parts of the document were replaced by new
519
+ // content, and the size of that new content. It uses these to
520
+ // build up Change objects.
521
+ //
522
+ // These change objects are put in sets and merged together using
523
+ // Change.merge, giving us the changes created by the new steps.
524
+ // Those changes can then be merged with the existing set of
525
+ // changes.
526
+ //
527
+ // For each change that was touched by the new steps, we recompute
528
+ // a diff to try to minimize the change by dropping matching
529
+ // pieces of the old and new document from the change.
530
+ let stepChanges = [];
531
+ // Add spans for new steps.
532
+ for (let i = 0; i < maps.length; i++) {
533
+ let d = Array.isArray(data) ? data[i] : data;
534
+ let off = 0;
535
+ maps[i].forEach((fromA, toA, fromB, toB) => {
536
+ stepChanges.push(new Change(fromA + off, toA + off, fromB, toB, fromA == toA ? Span.none : [new Span(toA - fromA, d)], fromB == toB ? Span.none : [new Span(toB - fromB, d)]));
537
+ off = (toB - fromB) - (toA - fromA);
538
+ });
539
+ }
540
+ if (stepChanges.length == 0)
541
+ return this;
542
+ let newChanges = mergeAll(stepChanges, this.config.combine);
543
+ let changes = Change.merge(this.changes, newChanges, this.config.combine);
544
+ let updated = changes;
545
+ // Minimize changes when possible
546
+ for (let i = 0; i < updated.length; i++) {
547
+ let change = updated[i];
548
+ if (change.fromA == change.toA || change.fromB == change.toB ||
549
+ // Only look at changes that touch newly added changed ranges
550
+ !newChanges.some(r => r.toB > change.fromB && r.fromB < change.toB))
551
+ continue;
552
+ let diff = computeDiff(this.config.doc.content, newDoc.content, change);
553
+ // Fast path: If they are completely different, don't do anything
554
+ if (diff.length == 1 && diff[0].fromB == 0 && diff[0].toB == change.toB - change.fromB)
555
+ continue;
556
+ if (updated == changes)
557
+ updated = changes.slice();
558
+ if (diff.length == 1) {
559
+ updated[i] = diff[0];
560
+ }
561
+ else {
562
+ updated.splice(i, 1, ...diff);
563
+ i += diff.length - 1;
564
+ }
565
+ }
566
+ return new ChangeSet(this.config, updated);
567
+ }
568
+ /**
569
+ The starting document of the change set.
570
+ */
571
+ get startDoc() { return this.config.doc; }
572
+ /**
573
+ Map the span's data values in the given set through a function
574
+ and construct a new set with the resulting data.
575
+ */
576
+ map(f) {
577
+ let mapSpan = (span) => {
578
+ let newData = f(span);
579
+ return newData === span.data ? span : new Span(span.length, newData);
580
+ };
581
+ return new ChangeSet(this.config, this.changes.map((ch) => {
582
+ return new Change(ch.fromA, ch.toA, ch.fromB, ch.toB, ch.deleted.map(mapSpan), ch.inserted.map(mapSpan));
583
+ }));
584
+ }
585
+ /**
586
+ Compare two changesets and return the range in which they are
587
+ changed, if any. If the document changed between the maps, pass
588
+ the maps for the steps that changed it as second argument, and
589
+ make sure the method is called on the old set and passed the new
590
+ set. The returned positions will be in new document coordinates.
591
+ */
592
+ changedRange(b, maps) {
593
+ if (b == this)
594
+ return null;
595
+ let touched = maps && touchedRange(maps);
596
+ let moved = touched ? (touched.toB - touched.fromB) - (touched.toA - touched.fromA) : 0;
597
+ function map(p) {
598
+ return !touched || p <= touched.fromA ? p : p + moved;
599
+ }
600
+ let from = touched ? touched.fromB : 2e8, to = touched ? touched.toB : -2e8;
601
+ function add(start, end = start) {
602
+ from = Math.min(start, from);
603
+ to = Math.max(end, to);
604
+ }
605
+ let rA = this.changes, rB = b.changes;
606
+ for (let iA = 0, iB = 0; iA < rA.length && iB < rB.length;) {
607
+ let rangeA = rA[iA], rangeB = rB[iB];
608
+ if (rangeA && rangeB && sameRanges(rangeA, rangeB, map)) {
609
+ iA++;
610
+ iB++;
611
+ }
612
+ else if (rangeB && (!rangeA || map(rangeA.fromB) >= rangeB.fromB)) {
613
+ add(rangeB.fromB, rangeB.toB);
614
+ iB++;
615
+ }
616
+ else {
617
+ add(map(rangeA.fromB), map(rangeA.toB));
618
+ iA++;
619
+ }
620
+ }
621
+ return from <= to ? { from, to } : null;
622
+ }
623
+ /**
624
+ Create a changeset with the given base object and configuration.
625
+ The `combine` function is used to compare and combine metadata—it
626
+ should return null when metadata isn't compatible, and a combined
627
+ version for a merged range when it is.
628
+ */
629
+ static create(doc, combine = (a, b) => a === b ? a : null) {
630
+ return new ChangeSet({ combine, doc }, []);
631
+ }
632
+ }
633
+ /**
634
+ Exported for testing @internal
635
+ */
559
636
  ChangeSet.computeDiff = computeDiff;
560
-
561
- // : ([[Change]], (any, any) → any, number, number) → [Change]
562
637
  // Divide-and-conquer approach to merging a series of ranges.
563
- function mergeAll(ranges, combine, start, end) {
564
- if ( start === void 0 ) start = 0;
565
- if ( end === void 0 ) end = ranges.length;
566
-
567
- if (end == start + 1) { return [ranges[start]] }
568
- var mid = (start + end) >> 1;
569
- return Change.merge(mergeAll(ranges, combine, start, mid),
570
- mergeAll(ranges, combine, mid, end), combine)
638
+ function mergeAll(ranges, combine, start = 0, end = ranges.length) {
639
+ if (end == start + 1)
640
+ return [ranges[start]];
641
+ let mid = (start + end) >> 1;
642
+ return Change.merge(mergeAll(ranges, combine, start, mid), mergeAll(ranges, combine, mid, end), combine);
571
643
  }
572
-
573
644
  function endRange(maps) {
574
- var from = 2e8, to = -2e8;
575
- for (var i = 0; i < maps.length; i++) {
576
- var map = maps[i];
577
- if (from != 2e8) {
578
- from = map.map(from, -1);
579
- to = map.map(to, 1);
645
+ let from = 2e8, to = -2e8;
646
+ for (let i = 0; i < maps.length; i++) {
647
+ let map = maps[i];
648
+ if (from != 2e8) {
649
+ from = map.map(from, -1);
650
+ to = map.map(to, 1);
651
+ }
652
+ map.forEach((_s, _e, start, end) => {
653
+ from = Math.min(from, start);
654
+ to = Math.max(to, end);
655
+ });
580
656
  }
581
- map.forEach(function (_s, _e, start, end) {
582
- from = Math.min(from, start);
583
- to = Math.max(to, end);
584
- });
585
- }
586
- return from == 2e8 ? null : {from: from, to: to}
657
+ return from == 2e8 ? null : { from, to };
587
658
  }
588
-
589
659
  function touchedRange(maps) {
590
- var b = endRange(maps);
591
- if (!b) { return null }
592
- var a = endRange(maps.map(function (m) { return m.invert(); }).reverse());
593
- return {fromA: a.from, toA: a.to, fromB: b.from, toB: b.to}
660
+ let b = endRange(maps);
661
+ if (!b)
662
+ return null;
663
+ let a = endRange(maps.map(m => m.invert()).reverse());
664
+ return { fromA: a.from, toA: a.to, fromB: b.from, toB: b.to };
594
665
  }
595
-
596
666
  function sameRanges(a, b, map) {
597
- return map(a.fromB) == b.fromB && map(a.toB) == b.toB &&
598
- sameSpans(a.deleted, b.deleted) && sameSpans(a.inserted, b.inserted)
667
+ return map(a.fromB) == b.fromB && map(a.toB) == b.toB &&
668
+ sameSpans(a.deleted, b.deleted) && sameSpans(a.inserted, b.inserted);
599
669
  }
600
-
601
670
  function sameSpans(a, b) {
602
- if (a.length != b.length) { return false }
603
- for (var i = 0; i < a.length; i++)
604
- { if (a[i].length != b[i].length || a[i].data !== b[i].data) { return false } }
605
- return true
671
+ if (a.length != b.length)
672
+ return false;
673
+ for (let i = 0; i < a.length; i++)
674
+ if (a[i].length != b[i].length || a[i].data !== b[i].data)
675
+ return false;
676
+ return true;
606
677
  }
607
678
 
608
- exports.Change = Change;
609
- exports.ChangeSet = ChangeSet;
610
- exports.Span = Span;
611
- exports.simplifyChanges = simplifyChanges;
612
- //# sourceMappingURL=index.js.map
679
+ export { Change, ChangeSet, Span, simplifyChanges };