@fluidframework/sequence 2.0.0-dev.4.1.0.148229 → 2.0.0-dev.4.3.0.157531
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/CHANGELOG.md +12 -0
- package/README.md +28 -6
- package/dist/intervalCollection.d.ts +96 -30
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +164 -123
- package/dist/intervalCollection.js.map +1 -1
- package/dist/intervalTree.d.ts +8 -1
- package/dist/intervalTree.d.ts.map +1 -1
- package/dist/intervalTree.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/lib/intervalCollection.d.ts +96 -30
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +163 -121
- package/lib/intervalCollection.js.map +1 -1
- package/lib/intervalTree.d.ts +8 -1
- package/lib/intervalTree.d.ts.map +1 -1
- package/lib/intervalTree.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +21 -31
- package/src/intervalCollection.ts +230 -145
- package/src/intervalTree.ts +8 -1
- package/src/packageVersion.ts +1 -1
|
@@ -84,9 +84,7 @@ export class Interval {
|
|
|
84
84
|
getIntervalId() {
|
|
85
85
|
var _a;
|
|
86
86
|
const id = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
87
|
-
|
|
88
|
-
return undefined;
|
|
89
|
-
}
|
|
87
|
+
assert(id !== undefined, 0x5e1 /* interval ID should not be undefined */);
|
|
90
88
|
return `${id}`;
|
|
91
89
|
}
|
|
92
90
|
/**
|
|
@@ -228,6 +226,22 @@ export class Interval {
|
|
|
228
226
|
* Interval impelmentation whose ends are associated with positions in a mutatable sequence.
|
|
229
227
|
* As such, when content is inserted into the middle of the interval, the interval expands to
|
|
230
228
|
* include that content.
|
|
229
|
+
*
|
|
230
|
+
* @remarks - The endpoint's position should be treated exclusively to get reasonable behavior--i.e.
|
|
231
|
+
* an interval referring to "hello" in "hello world" should have a start position of 0 and an end
|
|
232
|
+
* position of 5.
|
|
233
|
+
*
|
|
234
|
+
* To see why, consider what happens if "llo wor" is removed from the string to make "held".
|
|
235
|
+
* The interval's startpoint remains on the "h" (it isn't altered), but the interval's endpoint
|
|
236
|
+
* slides forward to the next unremoved position, which is the "l" in "held".
|
|
237
|
+
* Users would generally expect the interval to now refer to "he" (as it is the subset of content
|
|
238
|
+
* remaining after the removal), hence the "l" should be excluded.
|
|
239
|
+
* If the interval endpoint was treated inclusively, the interval would now refer to "hel", which
|
|
240
|
+
* is undesirable.
|
|
241
|
+
*
|
|
242
|
+
* Since the end of an interval is treated exclusively but cannot be greater than or equal to the
|
|
243
|
+
* length of the associated sequence, application models which leverage interval collections should
|
|
244
|
+
* consider inserting a marker at the end of the sequence to represent the end of the content.
|
|
231
245
|
*/
|
|
232
246
|
export class SequenceInterval {
|
|
233
247
|
constructor(client,
|
|
@@ -356,9 +370,7 @@ export class SequenceInterval {
|
|
|
356
370
|
getIntervalId() {
|
|
357
371
|
var _a;
|
|
358
372
|
const id = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
359
|
-
|
|
360
|
-
return undefined;
|
|
361
|
-
}
|
|
373
|
+
assert(id !== undefined, 0x5e2 /* interval ID should not be undefined */);
|
|
362
374
|
return `${id}`;
|
|
363
375
|
}
|
|
364
376
|
/**
|
|
@@ -378,7 +390,6 @@ export class SequenceInterval {
|
|
|
378
390
|
}
|
|
379
391
|
/**
|
|
380
392
|
* @returns whether this interval overlaps two numerical positions.
|
|
381
|
-
* @remarks - this is currently strict overlap, which doesn't align with the endpoint treatment of`.overlaps()`
|
|
382
393
|
*/
|
|
383
394
|
overlapsPos(bstart, bend) {
|
|
384
395
|
const startPos = this.client.localReferencePositionToPosition(this.start);
|
|
@@ -428,7 +439,7 @@ export class SequenceInterval {
|
|
|
428
439
|
}
|
|
429
440
|
}
|
|
430
441
|
}
|
|
431
|
-
function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq) {
|
|
442
|
+
function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq, fromSnapshot) {
|
|
432
443
|
if (segoff.segment) {
|
|
433
444
|
const ref = client.createLocalReferencePosition(segoff.segment, segoff.offset, refType, undefined);
|
|
434
445
|
return ref;
|
|
@@ -438,7 +449,10 @@ function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq
|
|
|
438
449
|
// - References coming from a remote client (location may have been concurrently removed)
|
|
439
450
|
// - References being rebased to a new sequence number
|
|
440
451
|
// (segment they originally referred to may have been removed with no suitable replacement)
|
|
441
|
-
if (!op &&
|
|
452
|
+
if (!op &&
|
|
453
|
+
!localSeq &&
|
|
454
|
+
!fromSnapshot &&
|
|
455
|
+
!refTypeIncludesFlag(refType, ReferenceType.Transient)) {
|
|
442
456
|
throw new UsageError("Non-transient references need segment");
|
|
443
457
|
}
|
|
444
458
|
return createDetachedLocalReferencePosition(refType);
|
|
@@ -457,7 +471,7 @@ function createPositionReference(client, pos, refType, op, fromSnapshot, localSe
|
|
|
457
471
|
assert((refType & ReferenceType.SlideOnRemove) === 0 || !!fromSnapshot, 0x2f6 /* SlideOnRemove references must be op created */);
|
|
458
472
|
segoff = client.getContainingSegment(pos, undefined, localSeq);
|
|
459
473
|
}
|
|
460
|
-
return createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq);
|
|
474
|
+
return createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq, fromSnapshot);
|
|
461
475
|
}
|
|
462
476
|
export function createSequenceInterval(label, start, end, client, intervalType, op, fromSnapshot) {
|
|
463
477
|
let beginRefType = ReferenceType.RangeBegin;
|
|
@@ -493,82 +507,23 @@ export function createSequenceInterval(label, start, end, client, intervalType,
|
|
|
493
507
|
const ival = new SequenceInterval(client, startLref, endLref, intervalType, rangeProp);
|
|
494
508
|
return ival;
|
|
495
509
|
}
|
|
496
|
-
export function
|
|
497
|
-
a.addPropertySet(b.properties);
|
|
498
|
-
return a;
|
|
499
|
-
}
|
|
500
|
-
export function createIntervalIndex(conflict) {
|
|
510
|
+
export function createIntervalIndex() {
|
|
501
511
|
const helpers = {
|
|
502
512
|
compareEnds: compareIntervalEnds,
|
|
503
513
|
create: createInterval,
|
|
504
514
|
};
|
|
505
515
|
const lc = new LocalIntervalCollection(undefined, "", helpers);
|
|
506
|
-
if (conflict) {
|
|
507
|
-
lc.addConflictResolver(conflict);
|
|
508
|
-
}
|
|
509
|
-
else {
|
|
510
|
-
lc.addConflictResolver(defaultIntervalConflictResolver);
|
|
511
|
-
}
|
|
512
516
|
return lc;
|
|
513
517
|
}
|
|
514
|
-
|
|
515
|
-
constructor(client,
|
|
516
|
-
/** Callback invoked each time one of the endpoints of an interval slides. */
|
|
517
|
-
onPositionChange) {
|
|
518
|
+
class OverlappingIntervalsIndex {
|
|
519
|
+
constructor(client, helpers) {
|
|
518
520
|
this.client = client;
|
|
519
|
-
this.label = label;
|
|
520
521
|
this.helpers = helpers;
|
|
521
|
-
this.onPositionChange = onPositionChange;
|
|
522
522
|
this.intervalTree = new IntervalTree();
|
|
523
|
-
this.intervalIdMap = new Map();
|
|
524
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
525
|
-
this.endIntervalTree = new RedBlackTree(helpers.compareEnds);
|
|
526
|
-
}
|
|
527
|
-
addConflictResolver(conflictResolver) {
|
|
528
|
-
this.conflictResolver = conflictResolver;
|
|
529
|
-
this.endConflictResolver = (key, currentKey) => {
|
|
530
|
-
const ival = conflictResolver(key, currentKey);
|
|
531
|
-
return {
|
|
532
|
-
data: ival,
|
|
533
|
-
key: ival,
|
|
534
|
-
};
|
|
535
|
-
};
|
|
536
523
|
}
|
|
537
524
|
map(fn) {
|
|
538
525
|
this.intervalTree.map(fn);
|
|
539
526
|
}
|
|
540
|
-
createLegacyId(start, end) {
|
|
541
|
-
// Create a non-unique ID based on start and end to be used on intervals that come from legacy clients
|
|
542
|
-
// without ID's.
|
|
543
|
-
return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* Validates that a serialized interval has the ID property. Creates an ID
|
|
547
|
-
* if one does not already exist
|
|
548
|
-
*
|
|
549
|
-
* @param serializedInterval - The interval to be checked
|
|
550
|
-
* @returns The interval's existing or newly created id
|
|
551
|
-
*/
|
|
552
|
-
ensureSerializedId(serializedInterval) {
|
|
553
|
-
var _a;
|
|
554
|
-
let id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
555
|
-
if (id === undefined) {
|
|
556
|
-
// An interval came over the wire without an ID, so create a non-unique one based on start/end.
|
|
557
|
-
// This will allow all clients to refer to this interval consistently.
|
|
558
|
-
id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
|
|
559
|
-
const newProps = {
|
|
560
|
-
[reservedIntervalIdKey]: id,
|
|
561
|
-
};
|
|
562
|
-
serializedInterval.properties = addProperties(serializedInterval.properties, newProps);
|
|
563
|
-
}
|
|
564
|
-
// Make the ID immutable for safety's sake.
|
|
565
|
-
Object.defineProperty(serializedInterval.properties, reservedIntervalIdKey, {
|
|
566
|
-
configurable: false,
|
|
567
|
-
enumerable: true,
|
|
568
|
-
writable: false,
|
|
569
|
-
});
|
|
570
|
-
return id;
|
|
571
|
-
}
|
|
572
527
|
mapUntil(fn) {
|
|
573
528
|
this.intervalTree.mapUntil(fn);
|
|
574
529
|
}
|
|
@@ -635,7 +590,7 @@ export class LocalIntervalCollection {
|
|
|
635
590
|
}
|
|
636
591
|
/**
|
|
637
592
|
* @returns an array of all intervals contained in this collection that overlap the range
|
|
638
|
-
* `[startPosition, endPosition
|
|
593
|
+
* `[startPosition, endPosition)`.
|
|
639
594
|
*/
|
|
640
595
|
findOverlappingIntervals(startPosition, endPosition) {
|
|
641
596
|
if (endPosition < startPosition || this.intervalTree.intervals.isEmpty()) {
|
|
@@ -645,6 +600,47 @@ export class LocalIntervalCollection {
|
|
|
645
600
|
const overlappingIntervalNodes = this.intervalTree.match(transientInterval);
|
|
646
601
|
return overlappingIntervalNodes.map((node) => node.key);
|
|
647
602
|
}
|
|
603
|
+
remove(interval) {
|
|
604
|
+
this.intervalTree.removeExisting(interval);
|
|
605
|
+
}
|
|
606
|
+
add(interval) {
|
|
607
|
+
this.intervalTree.put(interval);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
class IdIntervalIndex {
|
|
611
|
+
constructor() {
|
|
612
|
+
this.intervalIdMap = new Map();
|
|
613
|
+
}
|
|
614
|
+
add(interval) {
|
|
615
|
+
const id = interval.getIntervalId();
|
|
616
|
+
assert(id !== undefined, 0x2c0 /* "ID must be created before adding interval to collection" */);
|
|
617
|
+
// Make the ID immutable.
|
|
618
|
+
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
619
|
+
configurable: false,
|
|
620
|
+
enumerable: true,
|
|
621
|
+
writable: false,
|
|
622
|
+
});
|
|
623
|
+
this.intervalIdMap.set(id, interval);
|
|
624
|
+
}
|
|
625
|
+
remove(interval) {
|
|
626
|
+
const id = interval.getIntervalId();
|
|
627
|
+
assert(id !== undefined, 0x311 /* expected id to exist on interval */);
|
|
628
|
+
this.intervalIdMap.delete(id);
|
|
629
|
+
}
|
|
630
|
+
getIntervalById(id) {
|
|
631
|
+
return this.intervalIdMap.get(id);
|
|
632
|
+
}
|
|
633
|
+
[Symbol.iterator]() {
|
|
634
|
+
return this.intervalIdMap.values();
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
class EndpointIndex {
|
|
638
|
+
constructor(client, helpers) {
|
|
639
|
+
this.client = client;
|
|
640
|
+
this.helpers = helpers;
|
|
641
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
642
|
+
this.endIntervalTree = new RedBlackTree(helpers.compareEnds);
|
|
643
|
+
}
|
|
648
644
|
previousInterval(pos) {
|
|
649
645
|
const transientInterval = this.helpers.create("transient", pos, pos, this.client, IntervalType.Transient);
|
|
650
646
|
const rbNode = this.endIntervalTree.floor(transientInterval);
|
|
@@ -659,21 +655,70 @@ export class LocalIntervalCollection {
|
|
|
659
655
|
return rbNode.data;
|
|
660
656
|
}
|
|
661
657
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
this.intervalTree.remove(transientInterval);
|
|
665
|
-
this.endIntervalTree.remove(transientInterval);
|
|
666
|
-
return transientInterval;
|
|
658
|
+
add(interval) {
|
|
659
|
+
this.endIntervalTree.put(interval, interval);
|
|
667
660
|
}
|
|
668
|
-
|
|
669
|
-
this.intervalTree.removeExisting(interval);
|
|
661
|
+
remove(interval) {
|
|
670
662
|
this.endIntervalTree.remove(interval);
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
export class LocalIntervalCollection {
|
|
666
|
+
constructor(client, label, helpers,
|
|
667
|
+
/** Callback invoked each time one of the endpoints of an interval slides. */
|
|
668
|
+
onPositionChange) {
|
|
669
|
+
this.client = client;
|
|
670
|
+
this.label = label;
|
|
671
|
+
this.helpers = helpers;
|
|
672
|
+
this.onPositionChange = onPositionChange;
|
|
673
|
+
this.overlappingIntervalsIndex = new OverlappingIntervalsIndex(client, helpers);
|
|
674
|
+
this.idIntervalIndex = new IdIntervalIndex();
|
|
675
|
+
this.endIntervalIndex = new EndpointIndex(client, helpers);
|
|
676
|
+
this.indexes = [
|
|
677
|
+
this.overlappingIntervalsIndex,
|
|
678
|
+
this.idIntervalIndex,
|
|
679
|
+
this.endIntervalIndex,
|
|
680
|
+
];
|
|
681
|
+
}
|
|
682
|
+
createLegacyId(start, end) {
|
|
683
|
+
// Create a non-unique ID based on start and end to be used on intervals that come from legacy clients
|
|
684
|
+
// without ID's.
|
|
685
|
+
return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Validates that a serialized interval has the ID property. Creates an ID
|
|
689
|
+
* if one does not already exist
|
|
690
|
+
*
|
|
691
|
+
* @param serializedInterval - The interval to be checked
|
|
692
|
+
* @returns The interval's existing or newly created id
|
|
693
|
+
*/
|
|
694
|
+
ensureSerializedId(serializedInterval) {
|
|
695
|
+
var _a;
|
|
696
|
+
let id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
697
|
+
if (id === undefined) {
|
|
698
|
+
// Back-compat: 0.39 and earlier did not have IDs on intervals. If an interval from such a client
|
|
699
|
+
// comes over the wire, create a non-unique one based on start/end.
|
|
700
|
+
// This will allow all clients to refer to this interval consistently.
|
|
701
|
+
id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
|
|
702
|
+
const newProps = {
|
|
703
|
+
[reservedIntervalIdKey]: id,
|
|
704
|
+
};
|
|
705
|
+
serializedInterval.properties = addProperties(serializedInterval.properties, newProps);
|
|
706
|
+
}
|
|
707
|
+
// Make the ID immutable for safety's sake.
|
|
708
|
+
Object.defineProperty(serializedInterval.properties, reservedIntervalIdKey, {
|
|
709
|
+
configurable: false,
|
|
710
|
+
enumerable: true,
|
|
711
|
+
writable: false,
|
|
712
|
+
});
|
|
713
|
+
return id;
|
|
714
|
+
}
|
|
715
|
+
removeIntervalFromIndexes(interval) {
|
|
716
|
+
for (const index of this.indexes) {
|
|
717
|
+
index.remove(interval);
|
|
718
|
+
}
|
|
674
719
|
}
|
|
675
720
|
removeExistingInterval(interval) {
|
|
676
|
-
this.
|
|
721
|
+
this.removeIntervalFromIndexes(interval);
|
|
677
722
|
this.removeIntervalListeners(interval);
|
|
678
723
|
}
|
|
679
724
|
createInterval(start, end, intervalType, op) {
|
|
@@ -701,27 +746,16 @@ export class LocalIntervalCollection {
|
|
|
701
746
|
interval.end.addProperties({ interval });
|
|
702
747
|
}
|
|
703
748
|
}
|
|
704
|
-
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
709
|
-
configurable: false,
|
|
710
|
-
enumerable: true,
|
|
711
|
-
writable: false,
|
|
712
|
-
});
|
|
713
|
-
this.intervalTree.put(interval, this.conflictResolver);
|
|
714
|
-
this.endIntervalTree.put(interval, interval, this.endConflictResolver);
|
|
715
|
-
this.intervalIdMap.set(id, interval);
|
|
749
|
+
addIntervalToIndexes(interval) {
|
|
750
|
+
for (const index of this.indexes) {
|
|
751
|
+
index.add(interval);
|
|
752
|
+
}
|
|
716
753
|
}
|
|
717
754
|
add(interval) {
|
|
718
755
|
this.linkEndpointsToInterval(interval);
|
|
719
|
-
this.
|
|
756
|
+
this.addIntervalToIndexes(interval);
|
|
720
757
|
this.addIntervalListeners(interval);
|
|
721
758
|
}
|
|
722
|
-
getIntervalById(id) {
|
|
723
|
-
return this.intervalIdMap.get(id);
|
|
724
|
-
}
|
|
725
759
|
changeInterval(interval, start, end, op, localSeq) {
|
|
726
760
|
const newInterval = interval.modify(this.label, start, end, op, localSeq);
|
|
727
761
|
if (newInterval) {
|
|
@@ -731,10 +765,9 @@ export class LocalIntervalCollection {
|
|
|
731
765
|
return newInterval;
|
|
732
766
|
}
|
|
733
767
|
serialize() {
|
|
734
|
-
const intervals = this.intervalTree.intervals.keys();
|
|
735
768
|
return {
|
|
736
769
|
label: this.label,
|
|
737
|
-
intervals:
|
|
770
|
+
intervals: Array.from(this.idIntervalIndex, (interval) => compressInterval(interval.serialize())),
|
|
738
771
|
version: 2,
|
|
739
772
|
};
|
|
740
773
|
}
|
|
@@ -759,14 +792,14 @@ export class LocalIntervalCollection {
|
|
|
759
792
|
previousInterval = interval.clone();
|
|
760
793
|
previousInterval.start = cloneRef(previousInterval.start);
|
|
761
794
|
previousInterval.end = cloneRef(previousInterval.end);
|
|
762
|
-
this.
|
|
795
|
+
this.removeIntervalFromIndexes(interval);
|
|
763
796
|
}
|
|
764
797
|
}, () => {
|
|
765
798
|
var _a;
|
|
766
799
|
assert(previousInterval !== undefined, 0x3fa /* Invalid interleaving of before/after slide */);
|
|
767
800
|
pendingChanges--;
|
|
768
801
|
if (pendingChanges === 0) {
|
|
769
|
-
this.
|
|
802
|
+
this.addIntervalToIndexes(interval);
|
|
770
803
|
(_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval, previousInterval);
|
|
771
804
|
previousInterval = undefined;
|
|
772
805
|
}
|
|
@@ -1041,15 +1074,17 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1041
1074
|
if (!this.localCollection) {
|
|
1042
1075
|
throw new LoggingError("attach must be called before accessing intervals");
|
|
1043
1076
|
}
|
|
1044
|
-
return this.localCollection.getIntervalById(id);
|
|
1077
|
+
return this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1045
1078
|
}
|
|
1046
1079
|
/**
|
|
1047
1080
|
* Creates a new interval and add it to the collection.
|
|
1048
|
-
* @param start - interval start position
|
|
1049
|
-
* @param end - interval end position
|
|
1081
|
+
* @param start - interval start position (inclusive)
|
|
1082
|
+
* @param end - interval end position (exclusive)
|
|
1050
1083
|
* @param intervalType - type of the interval. All intervals are SlideOnRemove. Intervals may not be Transient.
|
|
1051
1084
|
* @param props - properties of the interval
|
|
1052
1085
|
* @returns - the created interval
|
|
1086
|
+
* @remarks - See documentation on {@link SequenceInterval} for comments on interval endpoint semantics: there are subtleties
|
|
1087
|
+
* with how the current half-open behavior is represented.
|
|
1053
1088
|
*/
|
|
1054
1089
|
add(start, end, intervalType, props) {
|
|
1055
1090
|
var _a, _b;
|
|
@@ -1106,7 +1141,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1106
1141
|
if (!this.localCollection) {
|
|
1107
1142
|
throw new LoggingError("Attach must be called before accessing intervals");
|
|
1108
1143
|
}
|
|
1109
|
-
const interval = this.localCollection.getIntervalById(id);
|
|
1144
|
+
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1110
1145
|
if (interval) {
|
|
1111
1146
|
this.deleteExistingInterval(interval, true, undefined);
|
|
1112
1147
|
}
|
|
@@ -1293,14 +1328,19 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1293
1328
|
}
|
|
1294
1329
|
}
|
|
1295
1330
|
}
|
|
1296
|
-
|
|
1331
|
+
/**
|
|
1332
|
+
* @deprecated - This functionality was useful when adding two intervals at the same start/end positions resulted
|
|
1333
|
+
* in a conflict. This is no longer the case (as of PR#6407), as interval collections support multiple intervals
|
|
1334
|
+
* at the same location and gives each interval a unique id.
|
|
1335
|
+
*
|
|
1336
|
+
* As such, the conflict resolver is never invoked and unnecessary. This API will be removed in an upcoming release.
|
|
1337
|
+
*/
|
|
1338
|
+
addConflictResolver(_) {
|
|
1297
1339
|
if (!this.localCollection) {
|
|
1298
1340
|
throw new LoggingError("attachSequence must be called");
|
|
1299
1341
|
}
|
|
1300
|
-
this.localCollection.addConflictResolver(conflictResolver);
|
|
1301
1342
|
}
|
|
1302
1343
|
attachDeserializer(onDeserialize) {
|
|
1303
|
-
var _a;
|
|
1304
1344
|
// If no deserializer is specified can skip all processing work
|
|
1305
1345
|
if (!onDeserialize) {
|
|
1306
1346
|
return;
|
|
@@ -1308,9 +1348,9 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1308
1348
|
// Start by storing the callbacks so that any subsequent modifications make use of them
|
|
1309
1349
|
this.onDeserialize = onDeserialize;
|
|
1310
1350
|
// Trigger the async prepare work across all values in the collection
|
|
1311
|
-
(
|
|
1312
|
-
onDeserialize
|
|
1313
|
-
}
|
|
1351
|
+
if (this.attached) {
|
|
1352
|
+
this.map(onDeserialize);
|
|
1353
|
+
}
|
|
1314
1354
|
}
|
|
1315
1355
|
/**
|
|
1316
1356
|
* Returns new interval after rebasing. If undefined, the interval was
|
|
@@ -1331,7 +1371,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1331
1371
|
const { intervalType, properties } = serializedInterval;
|
|
1332
1372
|
const { start: startRebased, end: endRebased } = (_a = this.localSeqToRebasedInterval.get(localSeq)) !== null && _a !== void 0 ? _a : this.computeRebasedPositions(localSeq);
|
|
1333
1373
|
const intervalId = properties === null || properties === void 0 ? void 0 : properties[reservedIntervalIdKey];
|
|
1334
|
-
const localInterval = (_b = this.localCollection) === null || _b === void 0 ? void 0 : _b.getIntervalById(intervalId);
|
|
1374
|
+
const localInterval = (_b = this.localCollection) === null || _b === void 0 ? void 0 : _b.idIntervalIndex.getIntervalById(intervalId);
|
|
1335
1375
|
const rebased = {
|
|
1336
1376
|
start: startRebased,
|
|
1337
1377
|
end: endRebased,
|
|
@@ -1484,7 +1524,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1484
1524
|
throw new LoggingError("attach must be called prior to deleting intervals");
|
|
1485
1525
|
}
|
|
1486
1526
|
const id = this.localCollection.ensureSerializedId(serializedInterval);
|
|
1487
|
-
const interval = this.localCollection.getIntervalById(id);
|
|
1527
|
+
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1488
1528
|
if (interval) {
|
|
1489
1529
|
this.deleteExistingInterval(interval, local, op);
|
|
1490
1530
|
}
|
|
@@ -1545,7 +1585,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1545
1585
|
if (!this.localCollection) {
|
|
1546
1586
|
return;
|
|
1547
1587
|
}
|
|
1548
|
-
this.localCollection.gatherIterationResults(results, iteratesForward, start, end);
|
|
1588
|
+
this.localCollection.overlappingIntervalsIndex.gatherIterationResults(results, iteratesForward, start, end);
|
|
1549
1589
|
}
|
|
1550
1590
|
/**
|
|
1551
1591
|
* @returns an array of all intervals in this collection that overlap with the interval
|
|
@@ -1555,7 +1595,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1555
1595
|
if (!this.localCollection) {
|
|
1556
1596
|
throw new LoggingError("attachSequence must be called");
|
|
1557
1597
|
}
|
|
1558
|
-
return this.localCollection.findOverlappingIntervals(startPosition, endPosition);
|
|
1598
|
+
return this.localCollection.overlappingIntervalsIndex.findOverlappingIntervals(startPosition, endPosition);
|
|
1559
1599
|
}
|
|
1560
1600
|
/**
|
|
1561
1601
|
* Applies a function to each interval in this collection.
|
|
@@ -1564,19 +1604,21 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1564
1604
|
if (!this.localCollection) {
|
|
1565
1605
|
throw new LoggingError("attachSequence must be called");
|
|
1566
1606
|
}
|
|
1567
|
-
this.localCollection.
|
|
1607
|
+
for (const interval of this.localCollection.idIntervalIndex) {
|
|
1608
|
+
fn(interval);
|
|
1609
|
+
}
|
|
1568
1610
|
}
|
|
1569
1611
|
previousInterval(pos) {
|
|
1570
1612
|
if (!this.localCollection) {
|
|
1571
1613
|
throw new LoggingError("attachSequence must be called");
|
|
1572
1614
|
}
|
|
1573
|
-
return this.localCollection.previousInterval(pos);
|
|
1615
|
+
return this.localCollection.endIntervalIndex.previousInterval(pos);
|
|
1574
1616
|
}
|
|
1575
1617
|
nextInterval(pos) {
|
|
1576
1618
|
if (!this.localCollection) {
|
|
1577
1619
|
throw new LoggingError("attachSequence must be called");
|
|
1578
1620
|
}
|
|
1579
|
-
return this.localCollection.nextInterval(pos);
|
|
1621
|
+
return this.localCollection.endIntervalIndex.nextInterval(pos);
|
|
1580
1622
|
}
|
|
1581
1623
|
}
|
|
1582
1624
|
/**
|