@fluidframework/sequence 0.59.4002 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -1
- package/dist/intervalCollection.d.ts +33 -1
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +130 -41
- 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 +2 -2
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +6 -6
- package/dist/sequence.js.map +1 -1
- package/dist/sharedIntervalCollection.js +1 -1
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/lib/intervalCollection.d.ts +33 -1
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +131 -42
- 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 +2 -2
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +7 -7
- package/lib/sequence.js.map +1 -1
- package/lib/sharedIntervalCollection.js +1 -1
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/package.json +40 -38
- package/src/intervalCollection.ts +182 -56
- package/src/packageVersion.ts +1 -1
- package/src/sequence.ts +19 -17
- package/src/sharedIntervalCollection.ts +1 -1
|
@@ -15,14 +15,25 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
15
15
|
};
|
|
16
16
|
/* eslint-disable no-bitwise */
|
|
17
17
|
import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
18
|
-
import {
|
|
18
|
+
import { UsageError } from "@fluidframework/container-utils";
|
|
19
|
+
import { addProperties, createMap, IntervalTree, LocalReference, MergeTreeDeltaType, PropertiesManager, RedBlackTree, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, } from "@fluidframework/merge-tree";
|
|
19
20
|
import { v4 as uuid } from "uuid";
|
|
20
21
|
const reservedIntervalIdKey = "intervalId";
|
|
21
22
|
export var IntervalType;
|
|
22
23
|
(function (IntervalType) {
|
|
23
24
|
IntervalType[IntervalType["Simple"] = 0] = "Simple";
|
|
24
25
|
IntervalType[IntervalType["Nest"] = 1] = "Nest";
|
|
26
|
+
/**
|
|
27
|
+
* SlideOnRemove indicates that the ends of the interval will slide if the segment
|
|
28
|
+
* they reference is removed and acked.
|
|
29
|
+
* See `packages\dds\merge-tree\REFERENCEPOSITIONS.md` for details
|
|
30
|
+
* SlideOnRemove is the default interval behavior and does not need to be specified.
|
|
31
|
+
*/
|
|
25
32
|
IntervalType[IntervalType["SlideOnRemove"] = 2] = "SlideOnRemove";
|
|
33
|
+
/**
|
|
34
|
+
* @internal
|
|
35
|
+
* A temporary interval, used internally
|
|
36
|
+
*/
|
|
26
37
|
IntervalType[IntervalType["Transient"] = 4] = "Transient";
|
|
27
38
|
})(IntervalType || (IntervalType = {}));
|
|
28
39
|
export class Interval {
|
|
@@ -229,46 +240,66 @@ export class SequenceInterval {
|
|
|
229
240
|
return newInterval;
|
|
230
241
|
}
|
|
231
242
|
}
|
|
232
|
-
function
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
243
|
+
function createPositionReferenceFromSegoff(client, segoff, refType, op) {
|
|
244
|
+
if (segoff.segment) {
|
|
245
|
+
const ref = client.createLocalReferencePosition(segoff.segment, segoff.offset, refType, undefined);
|
|
246
|
+
return ref;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
if (!op && !refTypeIncludesFlag(refType, ReferenceType.Transient)) {
|
|
250
|
+
throw new UsageError("Non-transient references need segment");
|
|
238
251
|
}
|
|
239
|
-
return
|
|
252
|
+
return new LocalReference(client, undefined, 0, refType);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function createPositionReference(client, pos, refType, op, fromSnapshot) {
|
|
256
|
+
let segoff;
|
|
257
|
+
if (op) {
|
|
258
|
+
assert((refType & ReferenceType.SlideOnRemove) !== 0, 0x2f5 /* op create references must be SlideOnRemove */);
|
|
259
|
+
segoff = client.getContainingSegment(pos, op);
|
|
260
|
+
segoff = client.getSlideToSegment(segoff);
|
|
240
261
|
}
|
|
241
|
-
|
|
262
|
+
else {
|
|
263
|
+
assert((refType & ReferenceType.SlideOnRemove) === 0 || fromSnapshot, 0x2f6 /* SlideOnRemove references must be op created */);
|
|
264
|
+
segoff = client.getContainingSegment(pos);
|
|
265
|
+
}
|
|
266
|
+
return createPositionReferenceFromSegoff(client, segoff, refType, op);
|
|
242
267
|
}
|
|
243
|
-
function createSequenceInterval(label, start, end, client, intervalType, op) {
|
|
268
|
+
function createSequenceInterval(label, start, end, client, intervalType, op, fromSnapshot) {
|
|
244
269
|
let beginRefType = ReferenceType.RangeBegin;
|
|
245
270
|
let endRefType = ReferenceType.RangeEnd;
|
|
246
|
-
if (intervalType === IntervalType.
|
|
247
|
-
beginRefType = ReferenceType.NestBegin;
|
|
248
|
-
endRefType = ReferenceType.NestEnd;
|
|
249
|
-
}
|
|
250
|
-
else if (intervalType === IntervalType.Transient) {
|
|
271
|
+
if (intervalType === IntervalType.Transient) {
|
|
251
272
|
beginRefType = ReferenceType.Transient;
|
|
252
273
|
endRefType = ReferenceType.Transient;
|
|
253
274
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return ival;
|
|
275
|
+
else {
|
|
276
|
+
if (intervalType === IntervalType.Nest) {
|
|
277
|
+
beginRefType = ReferenceType.NestBegin;
|
|
278
|
+
endRefType = ReferenceType.NestEnd;
|
|
279
|
+
}
|
|
280
|
+
// All non-transient interval references must eventually be SlideOnRemove
|
|
281
|
+
// To ensure eventual consistency, they must start as StayOnRemove when
|
|
282
|
+
// pending (created locally and creation op is not acked)
|
|
283
|
+
if (op || fromSnapshot) {
|
|
284
|
+
beginRefType |= ReferenceType.SlideOnRemove;
|
|
285
|
+
endRefType |= ReferenceType.SlideOnRemove;
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
beginRefType |= ReferenceType.StayOnRemove;
|
|
289
|
+
endRefType |= ReferenceType.StayOnRemove;
|
|
290
|
+
}
|
|
271
291
|
}
|
|
292
|
+
const startLref = createPositionReference(client, start, beginRefType, op, fromSnapshot);
|
|
293
|
+
const endLref = createPositionReference(client, end, endRefType, op, fromSnapshot);
|
|
294
|
+
startLref.pairedRef = endLref;
|
|
295
|
+
endLref.pairedRef = startLref;
|
|
296
|
+
const rangeProp = {
|
|
297
|
+
[reservedRangeLabelsKey]: [label],
|
|
298
|
+
};
|
|
299
|
+
startLref.addProperties(rangeProp);
|
|
300
|
+
endLref.addProperties(rangeProp);
|
|
301
|
+
const ival = new SequenceInterval(startLref, endLref, intervalType, rangeProp);
|
|
302
|
+
return ival;
|
|
272
303
|
}
|
|
273
304
|
export function defaultIntervalConflictResolver(a, b) {
|
|
274
305
|
a.addPropertySet(b.properties);
|
|
@@ -398,14 +429,12 @@ export class LocalIntervalCollection {
|
|
|
398
429
|
}
|
|
399
430
|
}
|
|
400
431
|
findOverlappingIntervals(startPosition, endPosition) {
|
|
401
|
-
if (
|
|
402
|
-
const transientInterval = this.helpers.create("transient", startPosition, endPosition, this.client, IntervalType.Transient);
|
|
403
|
-
const overlappingIntervalNodes = this.intervalTree.match(transientInterval);
|
|
404
|
-
return overlappingIntervalNodes.map((node) => node.key);
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
432
|
+
if (endPosition < startPosition || this.intervalTree.intervals.isEmpty()) {
|
|
407
433
|
return [];
|
|
408
434
|
}
|
|
435
|
+
const transientInterval = this.helpers.create("transient", startPosition, endPosition, this.client, IntervalType.Transient);
|
|
436
|
+
const overlappingIntervalNodes = this.intervalTree.match(transientInterval);
|
|
437
|
+
return overlappingIntervalNodes.map((node) => node.key);
|
|
409
438
|
}
|
|
410
439
|
previousInterval(pos) {
|
|
411
440
|
const transientInterval = this.helpers.create("transient", pos, pos, this.client, IntervalType.Transient);
|
|
@@ -642,7 +671,10 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
642
671
|
if (this.savedSerializedIntervals) {
|
|
643
672
|
for (const serializedInterval of this.savedSerializedIntervals) {
|
|
644
673
|
this.localCollection.ensureSerializedId(serializedInterval);
|
|
645
|
-
|
|
674
|
+
const { start, end, intervalType, properties } = serializedInterval;
|
|
675
|
+
const interval = this.helpers.create(label, start, end, client, intervalType, undefined, true);
|
|
676
|
+
interval.addProperties(properties);
|
|
677
|
+
this.localCollection.add(interval);
|
|
646
678
|
}
|
|
647
679
|
}
|
|
648
680
|
this.savedSerializedIntervals = undefined;
|
|
@@ -653,11 +685,22 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
653
685
|
}
|
|
654
686
|
return this.localCollection.getIntervalById(id);
|
|
655
687
|
}
|
|
688
|
+
/**
|
|
689
|
+
* Create a new interval and add it to the collection
|
|
690
|
+
* @param start - interval start position
|
|
691
|
+
* @param end - interval end position
|
|
692
|
+
* @param intervalType - type of the interval. All intervals are SlideOnRemove. Intervals may not be Transient.
|
|
693
|
+
* @param props - properties of the interval
|
|
694
|
+
* @returns - the created interval
|
|
695
|
+
*/
|
|
656
696
|
add(start, end, intervalType, props) {
|
|
657
697
|
var _a, _b;
|
|
658
698
|
if (!this.attached) {
|
|
659
699
|
throw new Error("attach must be called prior to adding intervals");
|
|
660
700
|
}
|
|
701
|
+
if (intervalType & IntervalType.Transient) {
|
|
702
|
+
throw new Error("Can not add transient intervals");
|
|
703
|
+
}
|
|
661
704
|
const interval = this.localCollection.addInterval(start, end, intervalType, props);
|
|
662
705
|
if (interval) {
|
|
663
706
|
const serializedInterval = {
|
|
@@ -816,13 +859,15 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
816
859
|
// This is an ack from the server. Remove the pending change.
|
|
817
860
|
this.removePendingChange(serializedInterval);
|
|
818
861
|
const id = serializedInterval.properties[reservedIntervalIdKey];
|
|
862
|
+
// Could store the interval in the localOpMetadata to avoid the getIntervalById call
|
|
819
863
|
interval = this.getIntervalById(id);
|
|
820
864
|
if (interval) {
|
|
821
865
|
// Let the propertyManager prune its pending change-properties set.
|
|
822
866
|
(_a = interval.propertyManager) === null || _a === void 0 ? void 0 : _a.ackPendingProperties({
|
|
823
|
-
type:
|
|
867
|
+
type: MergeTreeDeltaType.ANNOTATE,
|
|
824
868
|
props: serializedInterval.properties,
|
|
825
869
|
});
|
|
870
|
+
this.ackInterval(interval, op);
|
|
826
871
|
}
|
|
827
872
|
}
|
|
828
873
|
else {
|
|
@@ -877,6 +922,46 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
877
922
|
this.onDeserialize(interval);
|
|
878
923
|
});
|
|
879
924
|
}
|
|
925
|
+
getSlideToSegment(lref) {
|
|
926
|
+
const segoff = { segment: lref.segment, offset: lref.offset };
|
|
927
|
+
const newSegoff = this.client.getSlideToSegment(segoff);
|
|
928
|
+
const value = (segoff === newSegoff) ? undefined : newSegoff;
|
|
929
|
+
return value;
|
|
930
|
+
}
|
|
931
|
+
setSlideOnRemove(lref) {
|
|
932
|
+
let refType = lref.refType;
|
|
933
|
+
refType = refType & ~ReferenceType.StayOnRemove;
|
|
934
|
+
refType = refType | ReferenceType.SlideOnRemove;
|
|
935
|
+
lref.refType = refType;
|
|
936
|
+
}
|
|
937
|
+
ackInterval(interval, op) {
|
|
938
|
+
// in current usage, interval is always a SequenceInterval
|
|
939
|
+
if (!(interval instanceof SequenceInterval)) {
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
if (!refTypeIncludesFlag(interval.start, ReferenceType.StayOnRemove)) {
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
assert(refTypeIncludesFlag(interval.end, ReferenceType.StayOnRemove), 0x2f7 /* start and end must both be StayOnRemove */);
|
|
946
|
+
const newStart = this.getSlideToSegment(interval.start);
|
|
947
|
+
const newEnd = this.getSlideToSegment(interval.end);
|
|
948
|
+
this.setSlideOnRemove(interval.start);
|
|
949
|
+
this.setSlideOnRemove(interval.end);
|
|
950
|
+
if (newStart || newEnd) {
|
|
951
|
+
this.localCollection.removeExistingInterval(interval);
|
|
952
|
+
if (newStart) {
|
|
953
|
+
const props = interval.start.properties;
|
|
954
|
+
interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op);
|
|
955
|
+
interval.start.addProperties(props);
|
|
956
|
+
}
|
|
957
|
+
if (newEnd) {
|
|
958
|
+
const props = interval.end.properties;
|
|
959
|
+
interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op);
|
|
960
|
+
interval.end.addProperties(props);
|
|
961
|
+
}
|
|
962
|
+
this.localCollection.add(interval);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
880
965
|
/** @deprecated - use ackAdd */
|
|
881
966
|
addInternal(serializedInterval, local, op) {
|
|
882
967
|
return this.ackAdd(serializedInterval, local, op);
|
|
@@ -884,8 +969,12 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
884
969
|
/** @internal */
|
|
885
970
|
ackAdd(serializedInterval, local, op) {
|
|
886
971
|
if (local) {
|
|
887
|
-
|
|
888
|
-
//
|
|
972
|
+
const id = serializedInterval.properties[reservedIntervalIdKey];
|
|
973
|
+
// Could store the interval in the localOpMetadata to avoid the getIntervalById call
|
|
974
|
+
const localInterval = this.getIntervalById(id);
|
|
975
|
+
if (localInterval) {
|
|
976
|
+
this.ackInterval(localInterval, op);
|
|
977
|
+
}
|
|
889
978
|
return;
|
|
890
979
|
}
|
|
891
980
|
if (!this.attached) {
|