@fluidframework/sequence 1.0.0 → 1.1.0-76254
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/README.md +18 -6
- package/dist/defaultMap.d.ts +2 -6
- package/dist/defaultMap.d.ts.map +1 -1
- package/dist/defaultMap.js +27 -37
- package/dist/defaultMap.js.map +1 -1
- package/dist/defaultMapInterfaces.d.ts +24 -3
- package/dist/defaultMapInterfaces.d.ts.map +1 -1
- package/dist/defaultMapInterfaces.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/intervalCollection.d.ts +72 -8
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +325 -155
- package/dist/intervalCollection.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/sequence.d.ts +4 -5
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +11 -15
- package/dist/sequence.js.map +1 -1
- package/dist/sharedIntervalCollection.d.ts.map +1 -1
- package/dist/sharedIntervalCollection.js +1 -1
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedSequence.js.map +1 -1
- package/dist/sparsematrix.js +2 -2
- package/dist/sparsematrix.js.map +1 -1
- package/lib/defaultMap.d.ts +2 -6
- package/lib/defaultMap.d.ts.map +1 -1
- package/lib/defaultMap.js +27 -37
- package/lib/defaultMap.js.map +1 -1
- package/lib/defaultMapInterfaces.d.ts +24 -3
- package/lib/defaultMapInterfaces.d.ts.map +1 -1
- package/lib/defaultMapInterfaces.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/intervalCollection.d.ts +72 -8
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +325 -155
- package/lib/intervalCollection.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/sequence.d.ts +4 -5
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +11 -15
- package/lib/sequence.js.map +1 -1
- package/lib/sharedIntervalCollection.d.ts.map +1 -1
- package/lib/sharedIntervalCollection.js +1 -1
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedSequence.js.map +1 -1
- package/lib/sparsematrix.js +2 -2
- package/lib/sparsematrix.js.map +1 -1
- package/package.json +20 -44
- package/src/defaultMap.ts +39 -41
- package/src/defaultMapInterfaces.ts +28 -3
- package/src/index.ts +3 -0
- package/src/intervalCollection.ts +447 -181
- package/src/packageVersion.ts +1 -1
- package/src/sequence.ts +17 -21
- package/src/sharedIntervalCollection.ts +3 -2
- package/src/sharedSequence.ts +1 -1
- package/src/sparsematrix.ts +2 -2
|
@@ -17,6 +17,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
17
17
|
import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
18
18
|
import { UsageError } from "@fluidframework/container-utils";
|
|
19
19
|
import { addProperties, createMap, IntervalTree, LocalReference, MergeTreeDeltaType, PropertiesManager, RedBlackTree, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, } from "@fluidframework/merge-tree";
|
|
20
|
+
import { LoggingError } from "@fluidframework/telemetry-utils";
|
|
20
21
|
import { v4 as uuid } from "uuid";
|
|
21
22
|
const reservedIntervalIdKey = "intervalId";
|
|
22
23
|
export var IntervalType;
|
|
@@ -36,10 +37,39 @@ export var IntervalType;
|
|
|
36
37
|
*/
|
|
37
38
|
IntervalType[IntervalType["Transient"] = 4] = "Transient";
|
|
38
39
|
})(IntervalType || (IntervalType = {}));
|
|
40
|
+
/**
|
|
41
|
+
* Decompress an interval after loading a summary from JSON. The exact format
|
|
42
|
+
* of this compression is unspecified and subject to change
|
|
43
|
+
*/
|
|
44
|
+
function decompressInterval(interval, label) {
|
|
45
|
+
return {
|
|
46
|
+
start: interval[0],
|
|
47
|
+
end: interval[1],
|
|
48
|
+
sequenceNumber: interval[2],
|
|
49
|
+
intervalType: interval[3],
|
|
50
|
+
properties: Object.assign(Object.assign({}, interval[4]), { [reservedRangeLabelsKey]: label }),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Compress an interval prior to serialization as JSON. The exact format of this
|
|
55
|
+
* compression is unspecified and subject to change
|
|
56
|
+
*/
|
|
57
|
+
function compressInterval(interval) {
|
|
58
|
+
const { start, end, sequenceNumber, intervalType, properties } = interval;
|
|
59
|
+
return [
|
|
60
|
+
start,
|
|
61
|
+
end,
|
|
62
|
+
sequenceNumber,
|
|
63
|
+
intervalType,
|
|
64
|
+
Object.assign(Object.assign({}, properties), { [reservedRangeLabelsKey]: undefined }),
|
|
65
|
+
];
|
|
66
|
+
}
|
|
39
67
|
export class Interval {
|
|
40
68
|
constructor(start, end, props) {
|
|
41
69
|
this.start = start;
|
|
42
70
|
this.end = end;
|
|
71
|
+
this.propertyManager = new PropertiesManager();
|
|
72
|
+
this.properties = {};
|
|
43
73
|
if (props) {
|
|
44
74
|
this.addProperties(props);
|
|
45
75
|
}
|
|
@@ -122,12 +152,7 @@ export class Interval {
|
|
|
122
152
|
}
|
|
123
153
|
addProperties(newProps, collaborating = false, seq, op) {
|
|
124
154
|
if (newProps) {
|
|
125
|
-
|
|
126
|
-
this.propertyManager = new PropertiesManager();
|
|
127
|
-
}
|
|
128
|
-
if (!this.properties) {
|
|
129
|
-
this.properties = createMap();
|
|
130
|
-
}
|
|
155
|
+
this.initializeProperties();
|
|
131
156
|
return this.propertyManager.addProperties(this.properties, newProps, op, seq, collaborating);
|
|
132
157
|
}
|
|
133
158
|
}
|
|
@@ -138,7 +163,20 @@ export class Interval {
|
|
|
138
163
|
// Return undefined to indicate that no change is necessary.
|
|
139
164
|
return;
|
|
140
165
|
}
|
|
141
|
-
|
|
166
|
+
const newInterval = new Interval(startPos, endPos);
|
|
167
|
+
if (this.properties) {
|
|
168
|
+
newInterval.initializeProperties();
|
|
169
|
+
this.propertyManager.copyTo(this.properties, newInterval.properties, newInterval.propertyManager);
|
|
170
|
+
}
|
|
171
|
+
return newInterval;
|
|
172
|
+
}
|
|
173
|
+
initializeProperties() {
|
|
174
|
+
if (!this.propertyManager) {
|
|
175
|
+
this.propertyManager = new PropertiesManager();
|
|
176
|
+
}
|
|
177
|
+
if (!this.properties) {
|
|
178
|
+
this.properties = createMap();
|
|
179
|
+
}
|
|
142
180
|
}
|
|
143
181
|
}
|
|
144
182
|
export class SequenceInterval {
|
|
@@ -146,10 +184,41 @@ export class SequenceInterval {
|
|
|
146
184
|
this.start = start;
|
|
147
185
|
this.end = end;
|
|
148
186
|
this.intervalType = intervalType;
|
|
187
|
+
this.propertyManager = new PropertiesManager();
|
|
188
|
+
this.properties = {};
|
|
149
189
|
if (props) {
|
|
150
190
|
this.addProperties(props);
|
|
151
191
|
}
|
|
152
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* @internal
|
|
195
|
+
* Subscribes to position change events on this interval if there are no current listeners.
|
|
196
|
+
*/
|
|
197
|
+
addPositionChangeListeners(beforePositionChange, afterPositionChange) {
|
|
198
|
+
var _a, _b;
|
|
199
|
+
var _c, _d;
|
|
200
|
+
if (this.callbacks === undefined) {
|
|
201
|
+
this.callbacks = {
|
|
202
|
+
beforePositionChange,
|
|
203
|
+
afterPositionChange,
|
|
204
|
+
};
|
|
205
|
+
const startCbs = (_a = (_c = this.start).callbacks) !== null && _a !== void 0 ? _a : (_c.callbacks = {});
|
|
206
|
+
const endCbs = (_b = (_d = this.end).callbacks) !== null && _b !== void 0 ? _b : (_d.callbacks = {});
|
|
207
|
+
startCbs.beforeSlide = endCbs.beforeSlide = beforePositionChange;
|
|
208
|
+
startCbs.afterSlide = endCbs.afterSlide = afterPositionChange;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* @internal
|
|
213
|
+
* Removes the currently subscribed position change listeners.
|
|
214
|
+
*/
|
|
215
|
+
removePositionChangeListeners() {
|
|
216
|
+
if (this.callbacks) {
|
|
217
|
+
this.callbacks = undefined;
|
|
218
|
+
this.start.callbacks = undefined;
|
|
219
|
+
this.end.callbacks = undefined;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
153
222
|
serialize(client) {
|
|
154
223
|
const startPosition = this.start.toPosition();
|
|
155
224
|
const endPosition = this.end.toPosition();
|
|
@@ -213,12 +282,7 @@ export class SequenceInterval {
|
|
|
213
282
|
return new SequenceInterval(this.start.min(b.start), this.end.max(b.end), this.intervalType);
|
|
214
283
|
}
|
|
215
284
|
addProperties(newProps, collab = false, seq, op) {
|
|
216
|
-
|
|
217
|
-
this.propertyManager = new PropertiesManager();
|
|
218
|
-
}
|
|
219
|
-
if (!this.properties) {
|
|
220
|
-
this.properties = createMap();
|
|
221
|
-
}
|
|
285
|
+
this.initializeProperties();
|
|
222
286
|
return this.propertyManager.addProperties(this.properties, newProps, op, seq, collab);
|
|
223
287
|
}
|
|
224
288
|
overlapsPos(bstart, bend) {
|
|
@@ -227,18 +291,41 @@ export class SequenceInterval {
|
|
|
227
291
|
return (endPos > bstart) && (startPos < bend);
|
|
228
292
|
}
|
|
229
293
|
modify(label, start, end, op) {
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
294
|
+
const getRefType = (baseType) => {
|
|
295
|
+
let refType = baseType;
|
|
296
|
+
if (op === undefined) {
|
|
297
|
+
refType &= ~ReferenceType.SlideOnRemove;
|
|
298
|
+
refType |= ReferenceType.StayOnRemove;
|
|
299
|
+
}
|
|
300
|
+
return refType;
|
|
301
|
+
};
|
|
302
|
+
let startRef = this.start;
|
|
303
|
+
if (start !== undefined) {
|
|
304
|
+
startRef = createPositionReference(this.start.getClient(), start, getRefType(this.start.refType), op);
|
|
305
|
+
startRef.addProperties(this.start.properties);
|
|
306
|
+
}
|
|
307
|
+
let endRef = this.end;
|
|
308
|
+
if (end !== undefined) {
|
|
309
|
+
endRef = createPositionReference(this.end.getClient(), end, getRefType(this.end.refType), op);
|
|
310
|
+
endRef.addProperties(this.end.properties);
|
|
311
|
+
}
|
|
312
|
+
startRef.pairedRef = endRef;
|
|
313
|
+
endRef.pairedRef = startRef;
|
|
314
|
+
const newInterval = new SequenceInterval(startRef, endRef, this.intervalType);
|
|
237
315
|
if (this.properties) {
|
|
238
|
-
newInterval.
|
|
316
|
+
newInterval.initializeProperties();
|
|
317
|
+
this.propertyManager.copyTo(this.properties, newInterval.properties, newInterval.propertyManager);
|
|
239
318
|
}
|
|
240
319
|
return newInterval;
|
|
241
320
|
}
|
|
321
|
+
initializeProperties() {
|
|
322
|
+
if (!this.propertyManager) {
|
|
323
|
+
this.propertyManager = new PropertiesManager();
|
|
324
|
+
}
|
|
325
|
+
if (!this.properties) {
|
|
326
|
+
this.properties = createMap();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
242
329
|
}
|
|
243
330
|
function createPositionReferenceFromSegoff(client, segoff, refType, op) {
|
|
244
331
|
if (segoff.segment) {
|
|
@@ -320,11 +407,15 @@ export function createIntervalIndex(conflict) {
|
|
|
320
407
|
return lc;
|
|
321
408
|
}
|
|
322
409
|
export class LocalIntervalCollection {
|
|
323
|
-
constructor(client, label, helpers
|
|
410
|
+
constructor(client, label, helpers,
|
|
411
|
+
/** Callback invoked each time one of the endpoints of an interval slides. */
|
|
412
|
+
onPositionChange) {
|
|
324
413
|
this.client = client;
|
|
325
414
|
this.label = label;
|
|
326
415
|
this.helpers = helpers;
|
|
416
|
+
this.onPositionChange = onPositionChange;
|
|
327
417
|
this.intervalTree = new IntervalTree();
|
|
418
|
+
this.intervalIdMap = new Map();
|
|
328
419
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
329
420
|
this.endIntervalTree = new RedBlackTree(helpers.compareEnds);
|
|
330
421
|
}
|
|
@@ -332,7 +423,7 @@ export class LocalIntervalCollection {
|
|
|
332
423
|
this.conflictResolver = conflictResolver;
|
|
333
424
|
this.endConflictResolver =
|
|
334
425
|
(key, currentKey) => {
|
|
335
|
-
const ival =
|
|
426
|
+
const ival = conflictResolver(key, currentKey);
|
|
336
427
|
return {
|
|
337
428
|
data: ival,
|
|
338
429
|
key: ival,
|
|
@@ -347,13 +438,22 @@ export class LocalIntervalCollection {
|
|
|
347
438
|
// without ID's.
|
|
348
439
|
return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
|
|
349
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Validates that a serialized interval has the ID property. Creates an ID
|
|
443
|
+
* if one does not already exist
|
|
444
|
+
*
|
|
445
|
+
* @param serializedInterval - The interval to be checked
|
|
446
|
+
* @returns The interval's existing or newly created id
|
|
447
|
+
*/
|
|
350
448
|
ensureSerializedId(serializedInterval) {
|
|
351
449
|
var _a;
|
|
352
|
-
|
|
450
|
+
let id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
451
|
+
if (id === undefined) {
|
|
353
452
|
// An interval came over the wire without an ID, so create a non-unique one based on start/end.
|
|
354
453
|
// This will allow all clients to refer to this interval consistently.
|
|
454
|
+
id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
|
|
355
455
|
const newProps = {
|
|
356
|
-
[reservedIntervalIdKey]:
|
|
456
|
+
[reservedIntervalIdKey]: id,
|
|
357
457
|
};
|
|
358
458
|
serializedInterval.properties = addProperties(serializedInterval.properties, newProps);
|
|
359
459
|
}
|
|
@@ -363,6 +463,7 @@ export class LocalIntervalCollection {
|
|
|
363
463
|
enumerable: true,
|
|
364
464
|
writable: false,
|
|
365
465
|
});
|
|
466
|
+
return id;
|
|
366
467
|
}
|
|
367
468
|
mapUntil(fn) {
|
|
368
469
|
this.intervalTree.mapUntil(fn);
|
|
@@ -456,9 +557,16 @@ export class LocalIntervalCollection {
|
|
|
456
557
|
this.endIntervalTree.remove(transientInterval);
|
|
457
558
|
return transientInterval;
|
|
458
559
|
}
|
|
459
|
-
|
|
560
|
+
removeIntervalFromIndex(interval) {
|
|
460
561
|
this.intervalTree.removeExisting(interval);
|
|
461
562
|
this.endIntervalTree.remove(interval);
|
|
563
|
+
const id = interval.getIntervalId();
|
|
564
|
+
assert(id !== undefined, 0x311 /* expected id to exist on interval */);
|
|
565
|
+
this.intervalIdMap.delete(id);
|
|
566
|
+
}
|
|
567
|
+
removeExistingInterval(interval) {
|
|
568
|
+
this.removeIntervalFromIndex(interval);
|
|
569
|
+
this.removeIntervalListeners(interval);
|
|
462
570
|
}
|
|
463
571
|
createInterval(start, end, intervalType, op) {
|
|
464
572
|
return this.helpers.create(this.label, start, end, this.client, intervalType, op);
|
|
@@ -480,8 +588,9 @@ export class LocalIntervalCollection {
|
|
|
480
588
|
}
|
|
481
589
|
return interval;
|
|
482
590
|
}
|
|
483
|
-
|
|
484
|
-
|
|
591
|
+
addIntervalToIndex(interval) {
|
|
592
|
+
const id = interval.getIntervalId();
|
|
593
|
+
assert(id !== undefined, 0x2c0 /* "ID must be created before adding interval to collection" */);
|
|
485
594
|
// Make the ID immutable.
|
|
486
595
|
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
487
596
|
configurable: false,
|
|
@@ -490,17 +599,14 @@ export class LocalIntervalCollection {
|
|
|
490
599
|
});
|
|
491
600
|
this.intervalTree.put(interval, this.conflictResolver);
|
|
492
601
|
this.endIntervalTree.put(interval, interval, this.endConflictResolver);
|
|
602
|
+
this.intervalIdMap.set(id, interval);
|
|
603
|
+
}
|
|
604
|
+
add(interval) {
|
|
605
|
+
this.addIntervalToIndex(interval);
|
|
606
|
+
this.addIntervalListeners(interval);
|
|
493
607
|
}
|
|
494
608
|
getIntervalById(id) {
|
|
495
|
-
|
|
496
|
-
this.mapUntil((interval) => {
|
|
497
|
-
if (interval.getIntervalId() === id) {
|
|
498
|
-
result = interval;
|
|
499
|
-
return false;
|
|
500
|
-
}
|
|
501
|
-
return true;
|
|
502
|
-
});
|
|
503
|
-
return result;
|
|
609
|
+
return this.intervalIdMap.get(id);
|
|
504
610
|
}
|
|
505
611
|
changeInterval(interval, start, end, op) {
|
|
506
612
|
const newInterval = interval.modify(this.label, start, end, op);
|
|
@@ -513,7 +619,25 @@ export class LocalIntervalCollection {
|
|
|
513
619
|
serialize() {
|
|
514
620
|
const client = this.client;
|
|
515
621
|
const intervals = this.intervalTree.intervals.keys();
|
|
516
|
-
return
|
|
622
|
+
return {
|
|
623
|
+
label: this.label,
|
|
624
|
+
intervals: intervals.map((interval) => compressInterval(interval.serialize(client))),
|
|
625
|
+
version: 2,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
addIntervalListeners(interval) {
|
|
629
|
+
if (interval instanceof SequenceInterval) {
|
|
630
|
+
interval.addPositionChangeListeners(() => this.removeIntervalFromIndex(interval), () => {
|
|
631
|
+
var _a;
|
|
632
|
+
this.addIntervalToIndex(interval);
|
|
633
|
+
(_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval);
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
removeIntervalListeners(interval) {
|
|
638
|
+
if (interval instanceof SequenceInterval) {
|
|
639
|
+
interval.removePositionChangeListeners();
|
|
640
|
+
}
|
|
517
641
|
}
|
|
518
642
|
}
|
|
519
643
|
LocalIntervalCollection.legacyIdPrefix = "legacy";
|
|
@@ -543,37 +667,12 @@ export class SequenceIntervalCollectionValueType {
|
|
|
543
667
|
}
|
|
544
668
|
SequenceIntervalCollectionValueType.Name = "sharedStringIntervalCollection";
|
|
545
669
|
SequenceIntervalCollectionValueType._factory = new SequenceIntervalCollectionFactory();
|
|
546
|
-
SequenceIntervalCollectionValueType._ops =
|
|
547
|
-
"add",
|
|
548
|
-
{
|
|
549
|
-
process: (value, params, local, op) => {
|
|
550
|
-
value.ackAdd(params, local, op);
|
|
551
|
-
},
|
|
552
|
-
},
|
|
553
|
-
],
|
|
554
|
-
[
|
|
555
|
-
"delete",
|
|
556
|
-
{
|
|
557
|
-
process: (value, params, local, op) => {
|
|
558
|
-
value.ackDelete(params, local, op);
|
|
559
|
-
},
|
|
560
|
-
},
|
|
561
|
-
],
|
|
562
|
-
[
|
|
563
|
-
"change",
|
|
564
|
-
{
|
|
565
|
-
process: (value, params, local, op) => {
|
|
566
|
-
value.ackChange(params, local, op);
|
|
567
|
-
},
|
|
568
|
-
},
|
|
569
|
-
]]);
|
|
670
|
+
SequenceIntervalCollectionValueType._ops = makeOpsMap();
|
|
570
671
|
const compareIntervalEnds = (a, b) => a.end - b.end;
|
|
571
672
|
function createInterval(label, start, end, client) {
|
|
572
|
-
|
|
573
|
-
if (label &&
|
|
574
|
-
rangeProp =
|
|
575
|
-
[reservedRangeLabelsKey]: [label],
|
|
576
|
-
};
|
|
673
|
+
const rangeProp = {};
|
|
674
|
+
if (label && label.length > 0) {
|
|
675
|
+
rangeProp[reservedRangeLabelsKey] = [label];
|
|
577
676
|
}
|
|
578
677
|
return new Interval(start, end, rangeProp);
|
|
579
678
|
}
|
|
@@ -604,30 +703,45 @@ export class IntervalCollectionValueType {
|
|
|
604
703
|
}
|
|
605
704
|
IntervalCollectionValueType.Name = "sharedIntervalCollection";
|
|
606
705
|
IntervalCollectionValueType._factory = new IntervalCollectionFactory();
|
|
607
|
-
IntervalCollectionValueType._ops =
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
706
|
+
IntervalCollectionValueType._ops = makeOpsMap();
|
|
707
|
+
function makeOpsMap() {
|
|
708
|
+
const rebase = (collection, op, localOpMetadata) => {
|
|
709
|
+
const { localSeq } = localOpMetadata;
|
|
710
|
+
const rebasedValue = collection.rebaseLocalInterval(op.opName, op.value, localSeq);
|
|
711
|
+
const rebasedOp = Object.assign(Object.assign({}, op), { value: rebasedValue });
|
|
712
|
+
return { rebasedOp, rebasedLocalOpMetadata: localOpMetadata };
|
|
713
|
+
};
|
|
714
|
+
return new Map([[
|
|
715
|
+
"add",
|
|
716
|
+
{
|
|
717
|
+
process: (collection, params, local, op) => {
|
|
718
|
+
collection.ackAdd(params, local, op);
|
|
719
|
+
},
|
|
720
|
+
rebase,
|
|
612
721
|
},
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
722
|
+
],
|
|
723
|
+
[
|
|
724
|
+
"delete",
|
|
725
|
+
{
|
|
726
|
+
process: (collection, params, local, op) => {
|
|
727
|
+
collection.ackDelete(params, local, op);
|
|
728
|
+
},
|
|
729
|
+
rebase: (collection, op, localOpMetadata) => {
|
|
730
|
+
// Deletion of intervals is based on id, so requires no rebasing.
|
|
731
|
+
return { rebasedOp: op, rebasedLocalOpMetadata: localOpMetadata };
|
|
732
|
+
},
|
|
620
733
|
},
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
734
|
+
],
|
|
735
|
+
[
|
|
736
|
+
"change",
|
|
737
|
+
{
|
|
738
|
+
process: (collection, params, local, op) => {
|
|
739
|
+
collection.ackChange(params, local, op);
|
|
740
|
+
},
|
|
741
|
+
rebase,
|
|
628
742
|
},
|
|
629
|
-
|
|
630
|
-
|
|
743
|
+
]]);
|
|
744
|
+
}
|
|
631
745
|
export class IntervalCollectionIterator {
|
|
632
746
|
constructor(collection, iteratesForward = true, start, end) {
|
|
633
747
|
this.results = [];
|
|
@@ -648,26 +762,35 @@ export class IntervalCollectionIterator {
|
|
|
648
762
|
}
|
|
649
763
|
}
|
|
650
764
|
export class IntervalCollection extends TypedEventEmitter {
|
|
765
|
+
/** @internal */
|
|
651
766
|
constructor(helpers, requiresClient, emitter, serializedIntervals) {
|
|
652
767
|
super();
|
|
653
768
|
this.helpers = helpers;
|
|
654
769
|
this.requiresClient = requiresClient;
|
|
655
770
|
this.emitter = emitter;
|
|
656
|
-
this.
|
|
771
|
+
this.pendingChangesStart = new Map();
|
|
772
|
+
this.pendingChangesEnd = new Map();
|
|
773
|
+
if (Array.isArray(serializedIntervals)) {
|
|
774
|
+
this.savedSerializedIntervals = serializedIntervals;
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
this.savedSerializedIntervals =
|
|
778
|
+
serializedIntervals.intervals.map((i) => decompressInterval(i, serializedIntervals.label));
|
|
779
|
+
}
|
|
657
780
|
}
|
|
658
781
|
get attached() {
|
|
659
782
|
return !!this.localCollection;
|
|
660
783
|
}
|
|
661
784
|
attachGraph(client, label) {
|
|
662
785
|
if (this.attached) {
|
|
663
|
-
throw new
|
|
786
|
+
throw new LoggingError("Only supports one Sequence attach");
|
|
664
787
|
}
|
|
665
788
|
if ((client === undefined) && (this.requiresClient)) {
|
|
666
|
-
throw new
|
|
789
|
+
throw new LoggingError("Client required for this collection");
|
|
667
790
|
}
|
|
668
791
|
// Instantiate the local interval collection based on the saved intervals
|
|
669
792
|
this.client = client;
|
|
670
|
-
this.localCollection = new LocalIntervalCollection(client, label, this.helpers);
|
|
793
|
+
this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval) => this.emit("changeInterval", interval, true, undefined));
|
|
671
794
|
if (this.savedSerializedIntervals) {
|
|
672
795
|
for (const serializedInterval of this.savedSerializedIntervals) {
|
|
673
796
|
this.localCollection.ensureSerializedId(serializedInterval);
|
|
@@ -676,9 +799,15 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
676
799
|
}
|
|
677
800
|
this.savedSerializedIntervals = undefined;
|
|
678
801
|
}
|
|
802
|
+
/**
|
|
803
|
+
* Gets the next local sequence number, modifying this client's collab window in doing so.
|
|
804
|
+
*/
|
|
805
|
+
getNextLocalSeq() {
|
|
806
|
+
return ++this.client.getCollabWindow().localSeq;
|
|
807
|
+
}
|
|
679
808
|
getIntervalById(id) {
|
|
680
809
|
if (!this.attached) {
|
|
681
|
-
throw new
|
|
810
|
+
throw new LoggingError("attach must be called before accessing intervals");
|
|
682
811
|
}
|
|
683
812
|
return this.localCollection.getIntervalById(id);
|
|
684
813
|
}
|
|
@@ -693,10 +822,10 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
693
822
|
add(start, end, intervalType, props) {
|
|
694
823
|
var _a, _b;
|
|
695
824
|
if (!this.attached) {
|
|
696
|
-
throw new
|
|
825
|
+
throw new LoggingError("attach must be called prior to adding intervals");
|
|
697
826
|
}
|
|
698
827
|
if (intervalType & IntervalType.Transient) {
|
|
699
|
-
throw new
|
|
828
|
+
throw new LoggingError("Can not add transient intervals");
|
|
700
829
|
}
|
|
701
830
|
const interval = this.localCollection.addInterval(start, end, intervalType, props);
|
|
702
831
|
if (interval) {
|
|
@@ -708,7 +837,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
708
837
|
start,
|
|
709
838
|
};
|
|
710
839
|
// Local ops get submitted to the server. Remote ops have the deserializer run.
|
|
711
|
-
this.emitter.emit("add", undefined, serializedInterval);
|
|
840
|
+
this.emitter.emit("add", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
|
|
712
841
|
}
|
|
713
842
|
this.emit("addInterval", interval, true, undefined);
|
|
714
843
|
return interval;
|
|
@@ -719,7 +848,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
719
848
|
if (interval) {
|
|
720
849
|
// Local ops get submitted to the server. Remote ops have the deserializer run.
|
|
721
850
|
if (local) {
|
|
722
|
-
this.emitter.emit("delete", undefined, interval.serialize(this.client));
|
|
851
|
+
this.emitter.emit("delete", undefined, interval.serialize(this.client), { localSeq: this.getNextLocalSeq() });
|
|
723
852
|
}
|
|
724
853
|
else {
|
|
725
854
|
if (this.onDeserialize) {
|
|
@@ -738,40 +867,41 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
738
867
|
}
|
|
739
868
|
changeProperties(id, props) {
|
|
740
869
|
if (!this.attached) {
|
|
741
|
-
throw new
|
|
870
|
+
throw new LoggingError("Attach must be called before accessing intervals");
|
|
742
871
|
}
|
|
743
872
|
if (typeof (id) !== "string") {
|
|
744
|
-
throw new
|
|
873
|
+
throw new LoggingError("Change API requires an ID that is a string");
|
|
745
874
|
}
|
|
746
875
|
if (!props) {
|
|
747
|
-
throw new
|
|
876
|
+
throw new LoggingError("changeProperties should be called with a property set");
|
|
748
877
|
}
|
|
749
878
|
const interval = this.getIntervalById(id);
|
|
750
879
|
if (interval) {
|
|
751
880
|
// Pass Unassigned as the sequence number to indicate that this is a local op that is waiting for an ack.
|
|
752
881
|
const deltaProps = interval.addProperties(props, true, UnassignedSequenceNumber);
|
|
753
882
|
const serializedInterval = interval.serialize(this.client);
|
|
754
|
-
// Emit a change op that will only change properties. Add the ID to
|
|
883
|
+
// Emit a change op that will only change properties. Add the ID to
|
|
884
|
+
// the property bag provided by the caller.
|
|
755
885
|
serializedInterval.start = undefined;
|
|
756
886
|
serializedInterval.end = undefined;
|
|
757
887
|
serializedInterval.properties = props;
|
|
758
888
|
serializedInterval.properties[reservedIntervalIdKey] = interval.getIntervalId();
|
|
759
|
-
this.emitter.emit("change", undefined, serializedInterval);
|
|
889
|
+
this.emitter.emit("change", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
|
|
760
890
|
this.emit("propertyChanged", interval, deltaProps);
|
|
761
891
|
}
|
|
762
892
|
this.emit("changeInterval", interval, true, undefined);
|
|
763
893
|
}
|
|
764
894
|
change(id, start, end) {
|
|
765
895
|
if (!this.attached) {
|
|
766
|
-
throw new
|
|
896
|
+
throw new LoggingError("Attach must be called before accessing intervals");
|
|
767
897
|
}
|
|
898
|
+
// Force id to be a string.
|
|
768
899
|
if (typeof (id) !== "string") {
|
|
769
|
-
throw new
|
|
900
|
+
throw new LoggingError("Change API requires an ID that is a string");
|
|
770
901
|
}
|
|
771
|
-
// Force id to be a string.
|
|
772
902
|
const interval = this.getIntervalById(id);
|
|
773
903
|
if (interval) {
|
|
774
|
-
this.localCollection.changeInterval(interval, start, end);
|
|
904
|
+
const newInterval = this.localCollection.changeInterval(interval, start, end);
|
|
775
905
|
const serializedInterval = interval.serialize(this.client);
|
|
776
906
|
serializedInterval.start = start;
|
|
777
907
|
serializedInterval.end = end;
|
|
@@ -780,23 +910,19 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
780
910
|
{
|
|
781
911
|
[reservedIntervalIdKey]: interval.getIntervalId(),
|
|
782
912
|
};
|
|
783
|
-
this.emitter.emit("change", undefined, serializedInterval);
|
|
913
|
+
this.emitter.emit("change", undefined, serializedInterval, { localSeq: this.getNextLocalSeq() });
|
|
784
914
|
this.addPendingChange(id, serializedInterval);
|
|
915
|
+
this.emit("changeInterval", newInterval, true, undefined);
|
|
916
|
+
return newInterval;
|
|
785
917
|
}
|
|
786
|
-
|
|
787
|
-
return
|
|
918
|
+
// No interval to change
|
|
919
|
+
return undefined;
|
|
788
920
|
}
|
|
789
921
|
addPendingChange(id, serializedInterval) {
|
|
790
922
|
if (serializedInterval.start !== undefined) {
|
|
791
|
-
if (!this.pendingChangesStart) {
|
|
792
|
-
this.pendingChangesStart = new Map();
|
|
793
|
-
}
|
|
794
923
|
this.addPendingChangeHelper(id, this.pendingChangesStart, serializedInterval);
|
|
795
924
|
}
|
|
796
925
|
if (serializedInterval.end !== undefined) {
|
|
797
|
-
if (!this.pendingChangesEnd) {
|
|
798
|
-
this.pendingChangesEnd = new Map();
|
|
799
|
-
}
|
|
800
926
|
this.addPendingChangeHelper(id, this.pendingChangesEnd, serializedInterval);
|
|
801
927
|
}
|
|
802
928
|
}
|
|
@@ -809,8 +935,9 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
809
935
|
entries.push(serializedInterval);
|
|
810
936
|
}
|
|
811
937
|
removePendingChange(serializedInterval) {
|
|
938
|
+
var _a;
|
|
812
939
|
// Change ops always have an ID.
|
|
813
|
-
const id = serializedInterval.properties[reservedIntervalIdKey];
|
|
940
|
+
const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
814
941
|
if (serializedInterval.start !== undefined) {
|
|
815
942
|
this.removePendingChangeHelper(id, this.pendingChangesStart, serializedInterval);
|
|
816
943
|
}
|
|
@@ -819,26 +946,24 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
819
946
|
}
|
|
820
947
|
}
|
|
821
948
|
removePendingChangeHelper(id, pendingChanges, serializedInterval) {
|
|
822
|
-
const entries = pendingChanges
|
|
949
|
+
const entries = pendingChanges.get(id);
|
|
823
950
|
if (entries) {
|
|
824
951
|
const pendingChange = entries.shift();
|
|
825
952
|
if (entries.length === 0) {
|
|
826
953
|
pendingChanges.delete(id);
|
|
827
954
|
}
|
|
828
|
-
if (pendingChange.start !== serializedInterval.start ||
|
|
829
|
-
pendingChange.end !== serializedInterval.end) {
|
|
830
|
-
throw new
|
|
955
|
+
if ((pendingChange === null || pendingChange === void 0 ? void 0 : pendingChange.start) !== serializedInterval.start ||
|
|
956
|
+
(pendingChange === null || pendingChange === void 0 ? void 0 : pendingChange.end) !== serializedInterval.end) {
|
|
957
|
+
throw new LoggingError("Mismatch in pending changes");
|
|
831
958
|
}
|
|
832
959
|
}
|
|
833
960
|
}
|
|
834
961
|
hasPendingChangeStart(id) {
|
|
835
|
-
|
|
836
|
-
const entries = (_a = this.pendingChangesStart) === null || _a === void 0 ? void 0 : _a.get(id);
|
|
962
|
+
const entries = this.pendingChangesStart.get(id);
|
|
837
963
|
return entries && entries.length !== 0;
|
|
838
964
|
}
|
|
839
965
|
hasPendingChangeEnd(id) {
|
|
840
|
-
|
|
841
|
-
const entries = (_a = this.pendingChangesEnd) === null || _a === void 0 ? void 0 : _a.get(id);
|
|
966
|
+
const entries = this.pendingChangesEnd.get(id);
|
|
842
967
|
return entries && entries.length !== 0;
|
|
843
968
|
}
|
|
844
969
|
/** @deprecated - use ackChange */
|
|
@@ -847,22 +972,21 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
847
972
|
}
|
|
848
973
|
/** @internal */
|
|
849
974
|
ackChange(serializedInterval, local, op) {
|
|
850
|
-
var _a, _b;
|
|
975
|
+
var _a, _b, _c, _d;
|
|
851
976
|
if (!this.attached) {
|
|
852
|
-
throw new
|
|
977
|
+
throw new LoggingError("Attach must be called before accessing intervals");
|
|
853
978
|
}
|
|
854
979
|
let interval;
|
|
855
980
|
if (local) {
|
|
856
981
|
// This is an ack from the server. Remove the pending change.
|
|
857
982
|
this.removePendingChange(serializedInterval);
|
|
858
|
-
const id = serializedInterval.properties[reservedIntervalIdKey];
|
|
859
|
-
// Could store the interval in the localOpMetadata to avoid the getIntervalById call
|
|
983
|
+
const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
860
984
|
interval = this.getIntervalById(id);
|
|
861
985
|
if (interval) {
|
|
862
986
|
// Let the propertyManager prune its pending change-properties set.
|
|
863
|
-
(
|
|
987
|
+
(_b = interval.propertyManager) === null || _b === void 0 ? void 0 : _b.ackPendingProperties({
|
|
864
988
|
type: MergeTreeDeltaType.ANNOTATE,
|
|
865
|
-
props: serializedInterval.properties,
|
|
989
|
+
props: (_c = serializedInterval.properties) !== null && _c !== void 0 ? _c : {},
|
|
866
990
|
});
|
|
867
991
|
this.ackInterval(interval, op);
|
|
868
992
|
}
|
|
@@ -873,7 +997,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
873
997
|
// Note that the ID is in the property bag only to allow us to find the interval.
|
|
874
998
|
// This API cannot change the ID, and writing to the ID property will result in an exception. So we
|
|
875
999
|
// strip it out of the properties here.
|
|
876
|
-
const
|
|
1000
|
+
const _e = serializedInterval.properties, _f = reservedIntervalIdKey, id = _e[_f], newProps = __rest(_e, [typeof _f === "symbol" ? _f : _f + ""]);
|
|
877
1001
|
interval = this.getIntervalById(id);
|
|
878
1002
|
if (interval) {
|
|
879
1003
|
let start;
|
|
@@ -888,7 +1012,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
888
1012
|
if (start !== undefined || end !== undefined) {
|
|
889
1013
|
// If changeInterval gives us a new interval, work with that one. Otherwise keep working with
|
|
890
1014
|
// the one we originally found in the tree.
|
|
891
|
-
interval = (
|
|
1015
|
+
interval = (_d = this.localCollection.changeInterval(interval, start, end, op)) !== null && _d !== void 0 ? _d : interval;
|
|
892
1016
|
}
|
|
893
1017
|
const deltaProps = interval.addProperties(newProps, true, op.sequenceNumber);
|
|
894
1018
|
if (this.onDeserialize) {
|
|
@@ -903,7 +1027,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
903
1027
|
}
|
|
904
1028
|
addConflictResolver(conflictResolver) {
|
|
905
1029
|
if (!this.attached) {
|
|
906
|
-
throw new
|
|
1030
|
+
throw new LoggingError("attachSequence must be called");
|
|
907
1031
|
}
|
|
908
1032
|
this.localCollection.addConflictResolver(conflictResolver);
|
|
909
1033
|
}
|
|
@@ -916,13 +1040,38 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
916
1040
|
this.onDeserialize = onDeserialize;
|
|
917
1041
|
// Trigger the async prepare work across all values in the collection
|
|
918
1042
|
this.localCollection.map((interval) => {
|
|
919
|
-
|
|
1043
|
+
onDeserialize(interval);
|
|
920
1044
|
});
|
|
921
1045
|
}
|
|
1046
|
+
/** @internal */
|
|
1047
|
+
rebaseLocalInterval(opName, serializedInterval, localSeq) {
|
|
1048
|
+
var _a, _b;
|
|
1049
|
+
if (!this.attached) {
|
|
1050
|
+
throw new LoggingError("attachSequence must be called");
|
|
1051
|
+
}
|
|
1052
|
+
const { start, end, intervalType, properties, sequenceNumber } = serializedInterval;
|
|
1053
|
+
const startRebased = start === undefined ? undefined :
|
|
1054
|
+
this.client.rebasePosition(start, sequenceNumber, localSeq);
|
|
1055
|
+
const endRebased = end === undefined ? undefined :
|
|
1056
|
+
this.client.rebasePosition(end, sequenceNumber, localSeq);
|
|
1057
|
+
const intervalId = properties === null || properties === void 0 ? void 0 : properties[reservedIntervalIdKey];
|
|
1058
|
+
const rebased = {
|
|
1059
|
+
start: startRebased,
|
|
1060
|
+
end: endRebased,
|
|
1061
|
+
intervalType,
|
|
1062
|
+
sequenceNumber: (_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.getCurrentSeq()) !== null && _b !== void 0 ? _b : 0,
|
|
1063
|
+
properties,
|
|
1064
|
+
};
|
|
1065
|
+
if (opName === "change" && (this.hasPendingChangeStart(intervalId) || this.hasPendingChangeEnd(intervalId))) {
|
|
1066
|
+
this.removePendingChange(serializedInterval);
|
|
1067
|
+
this.addPendingChange(intervalId, rebased);
|
|
1068
|
+
}
|
|
1069
|
+
return rebased;
|
|
1070
|
+
}
|
|
922
1071
|
getSlideToSegment(lref) {
|
|
923
1072
|
const segoff = { segment: lref.segment, offset: lref.offset };
|
|
924
1073
|
const newSegoff = this.client.getSlideToSegment(segoff);
|
|
925
|
-
const value = (segoff === newSegoff) ? undefined : newSegoff;
|
|
1074
|
+
const value = (segoff.segment === newSegoff.segment && segoff.offset === newSegoff.offset) ? undefined : newSegoff;
|
|
926
1075
|
return value;
|
|
927
1076
|
}
|
|
928
1077
|
setSlideOnRemove(lref) {
|
|
@@ -936,25 +1085,43 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
936
1085
|
if (!(interval instanceof SequenceInterval)) {
|
|
937
1086
|
return;
|
|
938
1087
|
}
|
|
939
|
-
if (!refTypeIncludesFlag(interval.start, ReferenceType.StayOnRemove)
|
|
1088
|
+
if (!refTypeIncludesFlag(interval.start, ReferenceType.StayOnRemove) &&
|
|
1089
|
+
!refTypeIncludesFlag(interval.end, ReferenceType.StayOnRemove)) {
|
|
940
1090
|
return;
|
|
941
1091
|
}
|
|
942
|
-
assert(refTypeIncludesFlag(interval.end, ReferenceType.StayOnRemove), 0x2f7 /* start and end must both be StayOnRemove */);
|
|
943
1092
|
const newStart = this.getSlideToSegment(interval.start);
|
|
944
1093
|
const newEnd = this.getSlideToSegment(interval.end);
|
|
945
|
-
|
|
946
|
-
this.
|
|
947
|
-
|
|
1094
|
+
const id = interval.properties[reservedIntervalIdKey];
|
|
1095
|
+
const hasPendingStartChange = this.hasPendingChangeStart(id);
|
|
1096
|
+
const hasPendingEndChange = this.hasPendingChangeEnd(id);
|
|
1097
|
+
if (!hasPendingStartChange) {
|
|
1098
|
+
this.setSlideOnRemove(interval.start);
|
|
1099
|
+
}
|
|
1100
|
+
if (!hasPendingEndChange) {
|
|
1101
|
+
this.setSlideOnRemove(interval.end);
|
|
1102
|
+
}
|
|
1103
|
+
const needsStartUpdate = newStart !== undefined && !hasPendingStartChange;
|
|
1104
|
+
const needsEndUpdate = newEnd !== undefined && !hasPendingEndChange;
|
|
1105
|
+
if (needsStartUpdate || needsEndUpdate) {
|
|
1106
|
+
// In this case, where we change the start or end of an interval,
|
|
1107
|
+
// it is necessary to remove and re-add the interval listeners.
|
|
1108
|
+
// This ensures that the correct listeners are added to the ReferencePosition.
|
|
948
1109
|
this.localCollection.removeExistingInterval(interval);
|
|
949
|
-
if (
|
|
1110
|
+
if (needsStartUpdate) {
|
|
950
1111
|
const props = interval.start.properties;
|
|
1112
|
+
this.client.removeLocalReferencePosition(interval.start);
|
|
951
1113
|
interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op);
|
|
952
|
-
|
|
1114
|
+
if (props) {
|
|
1115
|
+
interval.start.addProperties(props);
|
|
1116
|
+
}
|
|
953
1117
|
}
|
|
954
|
-
if (
|
|
1118
|
+
if (needsEndUpdate) {
|
|
955
1119
|
const props = interval.end.properties;
|
|
1120
|
+
this.client.removeLocalReferencePosition(interval.end);
|
|
956
1121
|
interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op);
|
|
957
|
-
|
|
1122
|
+
if (props) {
|
|
1123
|
+
interval.end.addProperties(props);
|
|
1124
|
+
}
|
|
958
1125
|
}
|
|
959
1126
|
this.localCollection.add(interval);
|
|
960
1127
|
}
|
|
@@ -965,9 +1132,9 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
965
1132
|
}
|
|
966
1133
|
/** @internal */
|
|
967
1134
|
ackAdd(serializedInterval, local, op) {
|
|
1135
|
+
var _a;
|
|
968
1136
|
if (local) {
|
|
969
|
-
const id = serializedInterval.properties[reservedIntervalIdKey];
|
|
970
|
-
// Could store the interval in the localOpMetadata to avoid the getIntervalById call
|
|
1137
|
+
const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
971
1138
|
const localInterval = this.getIntervalById(id);
|
|
972
1139
|
if (localInterval) {
|
|
973
1140
|
this.ackInterval(localInterval, op);
|
|
@@ -975,7 +1142,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
975
1142
|
return;
|
|
976
1143
|
}
|
|
977
1144
|
if (!this.attached) {
|
|
978
|
-
throw new
|
|
1145
|
+
throw new LoggingError("attachSequence must be called");
|
|
979
1146
|
}
|
|
980
1147
|
this.localCollection.ensureSerializedId(serializedInterval);
|
|
981
1148
|
const interval = this.localCollection.addInterval(serializedInterval.start, serializedInterval.end, serializedInterval.intervalType, serializedInterval.properties, op);
|
|
@@ -1000,17 +1167,20 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1000
1167
|
return;
|
|
1001
1168
|
}
|
|
1002
1169
|
if (!this.attached) {
|
|
1003
|
-
throw new
|
|
1170
|
+
throw new LoggingError("attach must be called prior to deleting intervals");
|
|
1004
1171
|
}
|
|
1005
|
-
this.localCollection.ensureSerializedId(serializedInterval);
|
|
1006
|
-
const interval = this.localCollection.getIntervalById(
|
|
1172
|
+
const id = this.localCollection.ensureSerializedId(serializedInterval);
|
|
1173
|
+
const interval = this.localCollection.getIntervalById(id);
|
|
1007
1174
|
if (interval) {
|
|
1008
1175
|
this.deleteExistingInterval(interval, local, op);
|
|
1009
1176
|
}
|
|
1010
1177
|
}
|
|
1178
|
+
/**
|
|
1179
|
+
* @internal
|
|
1180
|
+
*/
|
|
1011
1181
|
serializeInternal() {
|
|
1012
1182
|
if (!this.attached) {
|
|
1013
|
-
throw new
|
|
1183
|
+
throw new LoggingError("attachSequence must be called");
|
|
1014
1184
|
}
|
|
1015
1185
|
return this.localCollection.serialize();
|
|
1016
1186
|
}
|
|
@@ -1042,25 +1212,25 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1042
1212
|
}
|
|
1043
1213
|
findOverlappingIntervals(startPosition, endPosition) {
|
|
1044
1214
|
if (!this.attached) {
|
|
1045
|
-
throw new
|
|
1215
|
+
throw new LoggingError("attachSequence must be called");
|
|
1046
1216
|
}
|
|
1047
1217
|
return this.localCollection.findOverlappingIntervals(startPosition, endPosition);
|
|
1048
1218
|
}
|
|
1049
1219
|
map(fn) {
|
|
1050
1220
|
if (!this.attached) {
|
|
1051
|
-
throw new
|
|
1221
|
+
throw new LoggingError("attachSequence must be called");
|
|
1052
1222
|
}
|
|
1053
1223
|
this.localCollection.map(fn);
|
|
1054
1224
|
}
|
|
1055
1225
|
previousInterval(pos) {
|
|
1056
1226
|
if (!this.attached) {
|
|
1057
|
-
throw new
|
|
1227
|
+
throw new LoggingError("attachSequence must be called");
|
|
1058
1228
|
}
|
|
1059
1229
|
return this.localCollection.previousInterval(pos);
|
|
1060
1230
|
}
|
|
1061
1231
|
nextInterval(pos) {
|
|
1062
1232
|
if (!this.attached) {
|
|
1063
|
-
throw new
|
|
1233
|
+
throw new LoggingError("attachSequence must be called");
|
|
1064
1234
|
}
|
|
1065
1235
|
return this.localCollection.nextInterval(pos);
|
|
1066
1236
|
}
|