@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
|
@@ -15,7 +15,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
15
15
|
return t;
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.intervalLocatorFromEndpoint = exports.IntervalCollection = exports.IntervalCollectionIterator = exports.makeOpsMap = exports.IntervalCollectionValueType = exports.SequenceIntervalCollectionValueType = exports.compareSequenceIntervalEnds = exports.LocalIntervalCollection = exports.createIntervalIndex = exports.
|
|
18
|
+
exports.intervalLocatorFromEndpoint = exports.IntervalCollection = exports.IntervalCollectionIterator = exports.makeOpsMap = exports.IntervalCollectionValueType = exports.SequenceIntervalCollectionValueType = exports.compareSequenceIntervalEnds = exports.LocalIntervalCollection = exports.createIntervalIndex = exports.createSequenceInterval = exports.SequenceInterval = exports.Interval = exports.IntervalType = void 0;
|
|
19
19
|
/* eslint-disable no-bitwise */
|
|
20
20
|
const common_utils_1 = require("@fluidframework/common-utils");
|
|
21
21
|
const container_utils_1 = require("@fluidframework/container-utils");
|
|
@@ -87,9 +87,7 @@ class Interval {
|
|
|
87
87
|
getIntervalId() {
|
|
88
88
|
var _a;
|
|
89
89
|
const id = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
90
|
-
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
90
|
+
(0, common_utils_1.assert)(id !== undefined, 0x5e1 /* interval ID should not be undefined */);
|
|
93
91
|
return `${id}`;
|
|
94
92
|
}
|
|
95
93
|
/**
|
|
@@ -232,6 +230,22 @@ exports.Interval = Interval;
|
|
|
232
230
|
* Interval impelmentation whose ends are associated with positions in a mutatable sequence.
|
|
233
231
|
* As such, when content is inserted into the middle of the interval, the interval expands to
|
|
234
232
|
* include that content.
|
|
233
|
+
*
|
|
234
|
+
* @remarks - The endpoint's position should be treated exclusively to get reasonable behavior--i.e.
|
|
235
|
+
* an interval referring to "hello" in "hello world" should have a start position of 0 and an end
|
|
236
|
+
* position of 5.
|
|
237
|
+
*
|
|
238
|
+
* To see why, consider what happens if "llo wor" is removed from the string to make "held".
|
|
239
|
+
* The interval's startpoint remains on the "h" (it isn't altered), but the interval's endpoint
|
|
240
|
+
* slides forward to the next unremoved position, which is the "l" in "held".
|
|
241
|
+
* Users would generally expect the interval to now refer to "he" (as it is the subset of content
|
|
242
|
+
* remaining after the removal), hence the "l" should be excluded.
|
|
243
|
+
* If the interval endpoint was treated inclusively, the interval would now refer to "hel", which
|
|
244
|
+
* is undesirable.
|
|
245
|
+
*
|
|
246
|
+
* Since the end of an interval is treated exclusively but cannot be greater than or equal to the
|
|
247
|
+
* length of the associated sequence, application models which leverage interval collections should
|
|
248
|
+
* consider inserting a marker at the end of the sequence to represent the end of the content.
|
|
235
249
|
*/
|
|
236
250
|
class SequenceInterval {
|
|
237
251
|
constructor(client,
|
|
@@ -360,9 +374,7 @@ class SequenceInterval {
|
|
|
360
374
|
getIntervalId() {
|
|
361
375
|
var _a;
|
|
362
376
|
const id = (_a = this.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
363
|
-
|
|
364
|
-
return undefined;
|
|
365
|
-
}
|
|
377
|
+
(0, common_utils_1.assert)(id !== undefined, 0x5e2 /* interval ID should not be undefined */);
|
|
366
378
|
return `${id}`;
|
|
367
379
|
}
|
|
368
380
|
/**
|
|
@@ -382,7 +394,6 @@ class SequenceInterval {
|
|
|
382
394
|
}
|
|
383
395
|
/**
|
|
384
396
|
* @returns whether this interval overlaps two numerical positions.
|
|
385
|
-
* @remarks - this is currently strict overlap, which doesn't align with the endpoint treatment of`.overlaps()`
|
|
386
397
|
*/
|
|
387
398
|
overlapsPos(bstart, bend) {
|
|
388
399
|
const startPos = this.client.localReferencePositionToPosition(this.start);
|
|
@@ -433,7 +444,7 @@ class SequenceInterval {
|
|
|
433
444
|
}
|
|
434
445
|
}
|
|
435
446
|
exports.SequenceInterval = SequenceInterval;
|
|
436
|
-
function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq) {
|
|
447
|
+
function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq, fromSnapshot) {
|
|
437
448
|
if (segoff.segment) {
|
|
438
449
|
const ref = client.createLocalReferencePosition(segoff.segment, segoff.offset, refType, undefined);
|
|
439
450
|
return ref;
|
|
@@ -443,7 +454,10 @@ function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq
|
|
|
443
454
|
// - References coming from a remote client (location may have been concurrently removed)
|
|
444
455
|
// - References being rebased to a new sequence number
|
|
445
456
|
// (segment they originally referred to may have been removed with no suitable replacement)
|
|
446
|
-
if (!op &&
|
|
457
|
+
if (!op &&
|
|
458
|
+
!localSeq &&
|
|
459
|
+
!fromSnapshot &&
|
|
460
|
+
!(0, merge_tree_1.refTypeIncludesFlag)(refType, merge_tree_1.ReferenceType.Transient)) {
|
|
447
461
|
throw new container_utils_1.UsageError("Non-transient references need segment");
|
|
448
462
|
}
|
|
449
463
|
return (0, merge_tree_1.createDetachedLocalReferencePosition)(refType);
|
|
@@ -462,7 +476,7 @@ function createPositionReference(client, pos, refType, op, fromSnapshot, localSe
|
|
|
462
476
|
(0, common_utils_1.assert)((refType & merge_tree_1.ReferenceType.SlideOnRemove) === 0 || !!fromSnapshot, 0x2f6 /* SlideOnRemove references must be op created */);
|
|
463
477
|
segoff = client.getContainingSegment(pos, undefined, localSeq);
|
|
464
478
|
}
|
|
465
|
-
return createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq);
|
|
479
|
+
return createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq, fromSnapshot);
|
|
466
480
|
}
|
|
467
481
|
function createSequenceInterval(label, start, end, client, intervalType, op, fromSnapshot) {
|
|
468
482
|
let beginRefType = merge_tree_1.ReferenceType.RangeBegin;
|
|
@@ -499,84 +513,24 @@ function createSequenceInterval(label, start, end, client, intervalType, op, fro
|
|
|
499
513
|
return ival;
|
|
500
514
|
}
|
|
501
515
|
exports.createSequenceInterval = createSequenceInterval;
|
|
502
|
-
function
|
|
503
|
-
a.addPropertySet(b.properties);
|
|
504
|
-
return a;
|
|
505
|
-
}
|
|
506
|
-
exports.defaultIntervalConflictResolver = defaultIntervalConflictResolver;
|
|
507
|
-
function createIntervalIndex(conflict) {
|
|
516
|
+
function createIntervalIndex() {
|
|
508
517
|
const helpers = {
|
|
509
518
|
compareEnds: compareIntervalEnds,
|
|
510
519
|
create: createInterval,
|
|
511
520
|
};
|
|
512
521
|
const lc = new LocalIntervalCollection(undefined, "", helpers);
|
|
513
|
-
if (conflict) {
|
|
514
|
-
lc.addConflictResolver(conflict);
|
|
515
|
-
}
|
|
516
|
-
else {
|
|
517
|
-
lc.addConflictResolver(defaultIntervalConflictResolver);
|
|
518
|
-
}
|
|
519
522
|
return lc;
|
|
520
523
|
}
|
|
521
524
|
exports.createIntervalIndex = createIntervalIndex;
|
|
522
|
-
class
|
|
523
|
-
constructor(client,
|
|
524
|
-
/** Callback invoked each time one of the endpoints of an interval slides. */
|
|
525
|
-
onPositionChange) {
|
|
525
|
+
class OverlappingIntervalsIndex {
|
|
526
|
+
constructor(client, helpers) {
|
|
526
527
|
this.client = client;
|
|
527
|
-
this.label = label;
|
|
528
528
|
this.helpers = helpers;
|
|
529
|
-
this.onPositionChange = onPositionChange;
|
|
530
529
|
this.intervalTree = new intervalTree_1.IntervalTree();
|
|
531
|
-
this.intervalIdMap = new Map();
|
|
532
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
533
|
-
this.endIntervalTree = new merge_tree_1.RedBlackTree(helpers.compareEnds);
|
|
534
|
-
}
|
|
535
|
-
addConflictResolver(conflictResolver) {
|
|
536
|
-
this.conflictResolver = conflictResolver;
|
|
537
|
-
this.endConflictResolver = (key, currentKey) => {
|
|
538
|
-
const ival = conflictResolver(key, currentKey);
|
|
539
|
-
return {
|
|
540
|
-
data: ival,
|
|
541
|
-
key: ival,
|
|
542
|
-
};
|
|
543
|
-
};
|
|
544
530
|
}
|
|
545
531
|
map(fn) {
|
|
546
532
|
this.intervalTree.map(fn);
|
|
547
533
|
}
|
|
548
|
-
createLegacyId(start, end) {
|
|
549
|
-
// Create a non-unique ID based on start and end to be used on intervals that come from legacy clients
|
|
550
|
-
// without ID's.
|
|
551
|
-
return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Validates that a serialized interval has the ID property. Creates an ID
|
|
555
|
-
* if one does not already exist
|
|
556
|
-
*
|
|
557
|
-
* @param serializedInterval - The interval to be checked
|
|
558
|
-
* @returns The interval's existing or newly created id
|
|
559
|
-
*/
|
|
560
|
-
ensureSerializedId(serializedInterval) {
|
|
561
|
-
var _a;
|
|
562
|
-
let id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
563
|
-
if (id === undefined) {
|
|
564
|
-
// An interval came over the wire without an ID, so create a non-unique one based on start/end.
|
|
565
|
-
// This will allow all clients to refer to this interval consistently.
|
|
566
|
-
id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
|
|
567
|
-
const newProps = {
|
|
568
|
-
[reservedIntervalIdKey]: id,
|
|
569
|
-
};
|
|
570
|
-
serializedInterval.properties = (0, merge_tree_1.addProperties)(serializedInterval.properties, newProps);
|
|
571
|
-
}
|
|
572
|
-
// Make the ID immutable for safety's sake.
|
|
573
|
-
Object.defineProperty(serializedInterval.properties, reservedIntervalIdKey, {
|
|
574
|
-
configurable: false,
|
|
575
|
-
enumerable: true,
|
|
576
|
-
writable: false,
|
|
577
|
-
});
|
|
578
|
-
return id;
|
|
579
|
-
}
|
|
580
534
|
mapUntil(fn) {
|
|
581
535
|
this.intervalTree.mapUntil(fn);
|
|
582
536
|
}
|
|
@@ -643,7 +597,7 @@ class LocalIntervalCollection {
|
|
|
643
597
|
}
|
|
644
598
|
/**
|
|
645
599
|
* @returns an array of all intervals contained in this collection that overlap the range
|
|
646
|
-
* `[startPosition, endPosition
|
|
600
|
+
* `[startPosition, endPosition)`.
|
|
647
601
|
*/
|
|
648
602
|
findOverlappingIntervals(startPosition, endPosition) {
|
|
649
603
|
if (endPosition < startPosition || this.intervalTree.intervals.isEmpty()) {
|
|
@@ -653,6 +607,47 @@ class LocalIntervalCollection {
|
|
|
653
607
|
const overlappingIntervalNodes = this.intervalTree.match(transientInterval);
|
|
654
608
|
return overlappingIntervalNodes.map((node) => node.key);
|
|
655
609
|
}
|
|
610
|
+
remove(interval) {
|
|
611
|
+
this.intervalTree.removeExisting(interval);
|
|
612
|
+
}
|
|
613
|
+
add(interval) {
|
|
614
|
+
this.intervalTree.put(interval);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
class IdIntervalIndex {
|
|
618
|
+
constructor() {
|
|
619
|
+
this.intervalIdMap = new Map();
|
|
620
|
+
}
|
|
621
|
+
add(interval) {
|
|
622
|
+
const id = interval.getIntervalId();
|
|
623
|
+
(0, common_utils_1.assert)(id !== undefined, 0x2c0 /* "ID must be created before adding interval to collection" */);
|
|
624
|
+
// Make the ID immutable.
|
|
625
|
+
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
626
|
+
configurable: false,
|
|
627
|
+
enumerable: true,
|
|
628
|
+
writable: false,
|
|
629
|
+
});
|
|
630
|
+
this.intervalIdMap.set(id, interval);
|
|
631
|
+
}
|
|
632
|
+
remove(interval) {
|
|
633
|
+
const id = interval.getIntervalId();
|
|
634
|
+
(0, common_utils_1.assert)(id !== undefined, 0x311 /* expected id to exist on interval */);
|
|
635
|
+
this.intervalIdMap.delete(id);
|
|
636
|
+
}
|
|
637
|
+
getIntervalById(id) {
|
|
638
|
+
return this.intervalIdMap.get(id);
|
|
639
|
+
}
|
|
640
|
+
[Symbol.iterator]() {
|
|
641
|
+
return this.intervalIdMap.values();
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
class EndpointIndex {
|
|
645
|
+
constructor(client, helpers) {
|
|
646
|
+
this.client = client;
|
|
647
|
+
this.helpers = helpers;
|
|
648
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
649
|
+
this.endIntervalTree = new merge_tree_1.RedBlackTree(helpers.compareEnds);
|
|
650
|
+
}
|
|
656
651
|
previousInterval(pos) {
|
|
657
652
|
const transientInterval = this.helpers.create("transient", pos, pos, this.client, IntervalType.Transient);
|
|
658
653
|
const rbNode = this.endIntervalTree.floor(transientInterval);
|
|
@@ -667,21 +662,70 @@ class LocalIntervalCollection {
|
|
|
667
662
|
return rbNode.data;
|
|
668
663
|
}
|
|
669
664
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
this.intervalTree.remove(transientInterval);
|
|
673
|
-
this.endIntervalTree.remove(transientInterval);
|
|
674
|
-
return transientInterval;
|
|
665
|
+
add(interval) {
|
|
666
|
+
this.endIntervalTree.put(interval, interval);
|
|
675
667
|
}
|
|
676
|
-
|
|
677
|
-
this.intervalTree.removeExisting(interval);
|
|
668
|
+
remove(interval) {
|
|
678
669
|
this.endIntervalTree.remove(interval);
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
class LocalIntervalCollection {
|
|
673
|
+
constructor(client, label, helpers,
|
|
674
|
+
/** Callback invoked each time one of the endpoints of an interval slides. */
|
|
675
|
+
onPositionChange) {
|
|
676
|
+
this.client = client;
|
|
677
|
+
this.label = label;
|
|
678
|
+
this.helpers = helpers;
|
|
679
|
+
this.onPositionChange = onPositionChange;
|
|
680
|
+
this.overlappingIntervalsIndex = new OverlappingIntervalsIndex(client, helpers);
|
|
681
|
+
this.idIntervalIndex = new IdIntervalIndex();
|
|
682
|
+
this.endIntervalIndex = new EndpointIndex(client, helpers);
|
|
683
|
+
this.indexes = [
|
|
684
|
+
this.overlappingIntervalsIndex,
|
|
685
|
+
this.idIntervalIndex,
|
|
686
|
+
this.endIntervalIndex,
|
|
687
|
+
];
|
|
688
|
+
}
|
|
689
|
+
createLegacyId(start, end) {
|
|
690
|
+
// Create a non-unique ID based on start and end to be used on intervals that come from legacy clients
|
|
691
|
+
// without ID's.
|
|
692
|
+
return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Validates that a serialized interval has the ID property. Creates an ID
|
|
696
|
+
* if one does not already exist
|
|
697
|
+
*
|
|
698
|
+
* @param serializedInterval - The interval to be checked
|
|
699
|
+
* @returns The interval's existing or newly created id
|
|
700
|
+
*/
|
|
701
|
+
ensureSerializedId(serializedInterval) {
|
|
702
|
+
var _a;
|
|
703
|
+
let id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
704
|
+
if (id === undefined) {
|
|
705
|
+
// Back-compat: 0.39 and earlier did not have IDs on intervals. If an interval from such a client
|
|
706
|
+
// comes over the wire, create a non-unique one based on start/end.
|
|
707
|
+
// This will allow all clients to refer to this interval consistently.
|
|
708
|
+
id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
|
|
709
|
+
const newProps = {
|
|
710
|
+
[reservedIntervalIdKey]: id,
|
|
711
|
+
};
|
|
712
|
+
serializedInterval.properties = (0, merge_tree_1.addProperties)(serializedInterval.properties, newProps);
|
|
713
|
+
}
|
|
714
|
+
// Make the ID immutable for safety's sake.
|
|
715
|
+
Object.defineProperty(serializedInterval.properties, reservedIntervalIdKey, {
|
|
716
|
+
configurable: false,
|
|
717
|
+
enumerable: true,
|
|
718
|
+
writable: false,
|
|
719
|
+
});
|
|
720
|
+
return id;
|
|
721
|
+
}
|
|
722
|
+
removeIntervalFromIndexes(interval) {
|
|
723
|
+
for (const index of this.indexes) {
|
|
724
|
+
index.remove(interval);
|
|
725
|
+
}
|
|
682
726
|
}
|
|
683
727
|
removeExistingInterval(interval) {
|
|
684
|
-
this.
|
|
728
|
+
this.removeIntervalFromIndexes(interval);
|
|
685
729
|
this.removeIntervalListeners(interval);
|
|
686
730
|
}
|
|
687
731
|
createInterval(start, end, intervalType, op) {
|
|
@@ -709,27 +753,16 @@ class LocalIntervalCollection {
|
|
|
709
753
|
interval.end.addProperties({ interval });
|
|
710
754
|
}
|
|
711
755
|
}
|
|
712
|
-
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
717
|
-
configurable: false,
|
|
718
|
-
enumerable: true,
|
|
719
|
-
writable: false,
|
|
720
|
-
});
|
|
721
|
-
this.intervalTree.put(interval, this.conflictResolver);
|
|
722
|
-
this.endIntervalTree.put(interval, interval, this.endConflictResolver);
|
|
723
|
-
this.intervalIdMap.set(id, interval);
|
|
756
|
+
addIntervalToIndexes(interval) {
|
|
757
|
+
for (const index of this.indexes) {
|
|
758
|
+
index.add(interval);
|
|
759
|
+
}
|
|
724
760
|
}
|
|
725
761
|
add(interval) {
|
|
726
762
|
this.linkEndpointsToInterval(interval);
|
|
727
|
-
this.
|
|
763
|
+
this.addIntervalToIndexes(interval);
|
|
728
764
|
this.addIntervalListeners(interval);
|
|
729
765
|
}
|
|
730
|
-
getIntervalById(id) {
|
|
731
|
-
return this.intervalIdMap.get(id);
|
|
732
|
-
}
|
|
733
766
|
changeInterval(interval, start, end, op, localSeq) {
|
|
734
767
|
const newInterval = interval.modify(this.label, start, end, op, localSeq);
|
|
735
768
|
if (newInterval) {
|
|
@@ -739,10 +772,9 @@ class LocalIntervalCollection {
|
|
|
739
772
|
return newInterval;
|
|
740
773
|
}
|
|
741
774
|
serialize() {
|
|
742
|
-
const intervals = this.intervalTree.intervals.keys();
|
|
743
775
|
return {
|
|
744
776
|
label: this.label,
|
|
745
|
-
intervals:
|
|
777
|
+
intervals: Array.from(this.idIntervalIndex, (interval) => compressInterval(interval.serialize())),
|
|
746
778
|
version: 2,
|
|
747
779
|
};
|
|
748
780
|
}
|
|
@@ -767,14 +799,14 @@ class LocalIntervalCollection {
|
|
|
767
799
|
previousInterval = interval.clone();
|
|
768
800
|
previousInterval.start = cloneRef(previousInterval.start);
|
|
769
801
|
previousInterval.end = cloneRef(previousInterval.end);
|
|
770
|
-
this.
|
|
802
|
+
this.removeIntervalFromIndexes(interval);
|
|
771
803
|
}
|
|
772
804
|
}, () => {
|
|
773
805
|
var _a;
|
|
774
806
|
(0, common_utils_1.assert)(previousInterval !== undefined, 0x3fa /* Invalid interleaving of before/after slide */);
|
|
775
807
|
pendingChanges--;
|
|
776
808
|
if (pendingChanges === 0) {
|
|
777
|
-
this.
|
|
809
|
+
this.addIntervalToIndexes(interval);
|
|
778
810
|
(_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval, previousInterval);
|
|
779
811
|
previousInterval = undefined;
|
|
780
812
|
}
|
|
@@ -1055,15 +1087,17 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1055
1087
|
if (!this.localCollection) {
|
|
1056
1088
|
throw new telemetry_utils_1.LoggingError("attach must be called before accessing intervals");
|
|
1057
1089
|
}
|
|
1058
|
-
return this.localCollection.getIntervalById(id);
|
|
1090
|
+
return this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1059
1091
|
}
|
|
1060
1092
|
/**
|
|
1061
1093
|
* Creates a new interval and add it to the collection.
|
|
1062
|
-
* @param start - interval start position
|
|
1063
|
-
* @param end - interval end position
|
|
1094
|
+
* @param start - interval start position (inclusive)
|
|
1095
|
+
* @param end - interval end position (exclusive)
|
|
1064
1096
|
* @param intervalType - type of the interval. All intervals are SlideOnRemove. Intervals may not be Transient.
|
|
1065
1097
|
* @param props - properties of the interval
|
|
1066
1098
|
* @returns - the created interval
|
|
1099
|
+
* @remarks - See documentation on {@link SequenceInterval} for comments on interval endpoint semantics: there are subtleties
|
|
1100
|
+
* with how the current half-open behavior is represented.
|
|
1067
1101
|
*/
|
|
1068
1102
|
add(start, end, intervalType, props) {
|
|
1069
1103
|
var _a, _b;
|
|
@@ -1120,7 +1154,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1120
1154
|
if (!this.localCollection) {
|
|
1121
1155
|
throw new telemetry_utils_1.LoggingError("Attach must be called before accessing intervals");
|
|
1122
1156
|
}
|
|
1123
|
-
const interval = this.localCollection.getIntervalById(id);
|
|
1157
|
+
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1124
1158
|
if (interval) {
|
|
1125
1159
|
this.deleteExistingInterval(interval, true, undefined);
|
|
1126
1160
|
}
|
|
@@ -1307,14 +1341,19 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1307
1341
|
}
|
|
1308
1342
|
}
|
|
1309
1343
|
}
|
|
1310
|
-
|
|
1344
|
+
/**
|
|
1345
|
+
* @deprecated - This functionality was useful when adding two intervals at the same start/end positions resulted
|
|
1346
|
+
* in a conflict. This is no longer the case (as of PR#6407), as interval collections support multiple intervals
|
|
1347
|
+
* at the same location and gives each interval a unique id.
|
|
1348
|
+
*
|
|
1349
|
+
* As such, the conflict resolver is never invoked and unnecessary. This API will be removed in an upcoming release.
|
|
1350
|
+
*/
|
|
1351
|
+
addConflictResolver(_) {
|
|
1311
1352
|
if (!this.localCollection) {
|
|
1312
1353
|
throw new telemetry_utils_1.LoggingError("attachSequence must be called");
|
|
1313
1354
|
}
|
|
1314
|
-
this.localCollection.addConflictResolver(conflictResolver);
|
|
1315
1355
|
}
|
|
1316
1356
|
attachDeserializer(onDeserialize) {
|
|
1317
|
-
var _a;
|
|
1318
1357
|
// If no deserializer is specified can skip all processing work
|
|
1319
1358
|
if (!onDeserialize) {
|
|
1320
1359
|
return;
|
|
@@ -1322,9 +1361,9 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1322
1361
|
// Start by storing the callbacks so that any subsequent modifications make use of them
|
|
1323
1362
|
this.onDeserialize = onDeserialize;
|
|
1324
1363
|
// Trigger the async prepare work across all values in the collection
|
|
1325
|
-
(
|
|
1326
|
-
onDeserialize
|
|
1327
|
-
}
|
|
1364
|
+
if (this.attached) {
|
|
1365
|
+
this.map(onDeserialize);
|
|
1366
|
+
}
|
|
1328
1367
|
}
|
|
1329
1368
|
/**
|
|
1330
1369
|
* Returns new interval after rebasing. If undefined, the interval was
|
|
@@ -1345,7 +1384,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1345
1384
|
const { intervalType, properties } = serializedInterval;
|
|
1346
1385
|
const { start: startRebased, end: endRebased } = (_a = this.localSeqToRebasedInterval.get(localSeq)) !== null && _a !== void 0 ? _a : this.computeRebasedPositions(localSeq);
|
|
1347
1386
|
const intervalId = properties === null || properties === void 0 ? void 0 : properties[reservedIntervalIdKey];
|
|
1348
|
-
const localInterval = (_b = this.localCollection) === null || _b === void 0 ? void 0 : _b.getIntervalById(intervalId);
|
|
1387
|
+
const localInterval = (_b = this.localCollection) === null || _b === void 0 ? void 0 : _b.idIntervalIndex.getIntervalById(intervalId);
|
|
1349
1388
|
const rebased = {
|
|
1350
1389
|
start: startRebased,
|
|
1351
1390
|
end: endRebased,
|
|
@@ -1498,7 +1537,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1498
1537
|
throw new telemetry_utils_1.LoggingError("attach must be called prior to deleting intervals");
|
|
1499
1538
|
}
|
|
1500
1539
|
const id = this.localCollection.ensureSerializedId(serializedInterval);
|
|
1501
|
-
const interval = this.localCollection.getIntervalById(id);
|
|
1540
|
+
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1502
1541
|
if (interval) {
|
|
1503
1542
|
this.deleteExistingInterval(interval, local, op);
|
|
1504
1543
|
}
|
|
@@ -1559,7 +1598,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1559
1598
|
if (!this.localCollection) {
|
|
1560
1599
|
return;
|
|
1561
1600
|
}
|
|
1562
|
-
this.localCollection.gatherIterationResults(results, iteratesForward, start, end);
|
|
1601
|
+
this.localCollection.overlappingIntervalsIndex.gatherIterationResults(results, iteratesForward, start, end);
|
|
1563
1602
|
}
|
|
1564
1603
|
/**
|
|
1565
1604
|
* @returns an array of all intervals in this collection that overlap with the interval
|
|
@@ -1569,7 +1608,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1569
1608
|
if (!this.localCollection) {
|
|
1570
1609
|
throw new telemetry_utils_1.LoggingError("attachSequence must be called");
|
|
1571
1610
|
}
|
|
1572
|
-
return this.localCollection.findOverlappingIntervals(startPosition, endPosition);
|
|
1611
|
+
return this.localCollection.overlappingIntervalsIndex.findOverlappingIntervals(startPosition, endPosition);
|
|
1573
1612
|
}
|
|
1574
1613
|
/**
|
|
1575
1614
|
* Applies a function to each interval in this collection.
|
|
@@ -1578,19 +1617,21 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1578
1617
|
if (!this.localCollection) {
|
|
1579
1618
|
throw new telemetry_utils_1.LoggingError("attachSequence must be called");
|
|
1580
1619
|
}
|
|
1581
|
-
this.localCollection.
|
|
1620
|
+
for (const interval of this.localCollection.idIntervalIndex) {
|
|
1621
|
+
fn(interval);
|
|
1622
|
+
}
|
|
1582
1623
|
}
|
|
1583
1624
|
previousInterval(pos) {
|
|
1584
1625
|
if (!this.localCollection) {
|
|
1585
1626
|
throw new telemetry_utils_1.LoggingError("attachSequence must be called");
|
|
1586
1627
|
}
|
|
1587
|
-
return this.localCollection.previousInterval(pos);
|
|
1628
|
+
return this.localCollection.endIntervalIndex.previousInterval(pos);
|
|
1588
1629
|
}
|
|
1589
1630
|
nextInterval(pos) {
|
|
1590
1631
|
if (!this.localCollection) {
|
|
1591
1632
|
throw new telemetry_utils_1.LoggingError("attachSequence must be called");
|
|
1592
1633
|
}
|
|
1593
|
-
return this.localCollection.nextInterval(pos);
|
|
1634
|
+
return this.localCollection.endIntervalIndex.nextInterval(pos);
|
|
1594
1635
|
}
|
|
1595
1636
|
}
|
|
1596
1637
|
exports.IntervalCollection = IntervalCollection;
|