@fluidframework/sequence 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.3.1.0.125672
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 +9 -12
- package/.mocharc.js +2 -2
- package/.vscode/launch.json +15 -14
- package/README.md +186 -176
- package/api-extractor.json +2 -2
- package/dist/defaultMap.d.ts.map +1 -1
- package/dist/defaultMap.js +5 -4
- package/dist/defaultMap.js.map +1 -1
- 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 +7 -3
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +144 -79
- package/dist/intervalCollection.js.map +1 -1
- package/dist/intervalTree.d.ts.map +1 -1
- package/dist/intervalTree.js.map +1 -1
- package/dist/localValues.d.ts.map +1 -1
- package/dist/localValues.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/dist/sequence.d.ts +1 -1
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +24 -43
- package/dist/sequence.js.map +1 -1
- package/dist/sequenceDeltaEvent.d.ts.map +1 -1
- package/dist/sequenceDeltaEvent.js.map +1 -1
- package/dist/sequenceFactory.d.ts.map +1 -1
- package/dist/sequenceFactory.js.map +1 -1
- package/dist/sharedIntervalCollection.d.ts.map +1 -1
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedSequence.d.ts.map +1 -1
- package/dist/sharedSequence.js +3 -3
- package/dist/sharedSequence.js.map +1 -1
- package/dist/sharedString.d.ts.map +1 -1
- package/dist/sharedString.js +5 -4
- package/dist/sharedString.js.map +1 -1
- package/lib/defaultMap.d.ts.map +1 -1
- package/lib/defaultMap.js +6 -5
- package/lib/defaultMap.js.map +1 -1
- 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 +2 -2
- package/lib/index.js.map +1 -1
- package/lib/intervalCollection.d.ts +7 -3
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +144 -79
- package/lib/intervalCollection.js.map +1 -1
- package/lib/intervalTree.d.ts.map +1 -1
- package/lib/intervalTree.js.map +1 -1
- package/lib/localValues.d.ts.map +1 -1
- package/lib/localValues.js +1 -1
- package/lib/localValues.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/lib/sequence.d.ts +1 -1
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +26 -45
- package/lib/sequence.js.map +1 -1
- package/lib/sequenceDeltaEvent.d.ts.map +1 -1
- package/lib/sequenceDeltaEvent.js.map +1 -1
- package/lib/sequenceFactory.d.ts.map +1 -1
- package/lib/sequenceFactory.js +1 -1
- package/lib/sequenceFactory.js.map +1 -1
- package/lib/sharedIntervalCollection.d.ts.map +1 -1
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedSequence.d.ts.map +1 -1
- package/lib/sharedSequence.js +4 -4
- package/lib/sharedSequence.js.map +1 -1
- package/lib/sharedString.d.ts.map +1 -1
- package/lib/sharedString.js +5 -4
- package/lib/sharedString.js.map +1 -1
- package/package.json +25 -23
- package/prettier.config.cjs +1 -1
- package/src/defaultMap.ts +406 -405
- package/src/defaultMapInterfaces.ts +120 -115
- package/src/index.ts +27 -17
- package/src/intervalCollection.ts +2198 -1932
- package/src/intervalTree.ts +139 -139
- package/src/localValues.ts +64 -73
- package/src/packageVersion.ts +1 -1
- package/src/sequence.ts +752 -711
- package/src/sequenceDeltaEvent.ts +143 -137
- package/src/sequenceFactory.ts +48 -46
- package/src/sharedIntervalCollection.ts +150 -136
- package/src/sharedSequence.ts +165 -160
- package/src/sharedString.ts +385 -343
- package/tsconfig.esnext.json +6 -6
- package/tsconfig.json +8 -12
|
@@ -177,8 +177,7 @@ class Interval {
|
|
|
177
177
|
* {@inheritDoc IInterval.overlaps}
|
|
178
178
|
*/
|
|
179
179
|
overlaps(b) {
|
|
180
|
-
const result =
|
|
181
|
-
(this.end >= b.start);
|
|
180
|
+
const result = this.start <= b.end && this.end >= b.start;
|
|
182
181
|
return result;
|
|
183
182
|
}
|
|
184
183
|
/**
|
|
@@ -265,8 +264,8 @@ class SequenceInterval {
|
|
|
265
264
|
beforePositionChange,
|
|
266
265
|
afterPositionChange,
|
|
267
266
|
};
|
|
268
|
-
const startCbs = (_a = (_c = this.start).callbacks) !== null && _a !== void 0 ? _a : (_c.callbacks = {});
|
|
269
|
-
const endCbs = (_b = (_d = this.end).callbacks) !== null && _b !== void 0 ? _b : (_d.callbacks = {});
|
|
267
|
+
const startCbs = ((_a = (_c = this.start).callbacks) !== null && _a !== void 0 ? _a : (_c.callbacks = {}));
|
|
268
|
+
const endCbs = ((_b = (_d = this.end).callbacks) !== null && _b !== void 0 ? _b : (_d.callbacks = {}));
|
|
270
269
|
startCbs.beforeSlide = endCbs.beforeSlide = beforePositionChange;
|
|
271
270
|
startCbs.afterSlide = endCbs.afterSlide = afterPositionChange;
|
|
272
271
|
}
|
|
@@ -348,8 +347,8 @@ class SequenceInterval {
|
|
|
348
347
|
* {@inheritDoc IInterval.overlaps}
|
|
349
348
|
*/
|
|
350
349
|
overlaps(b) {
|
|
351
|
-
const result = (
|
|
352
|
-
(
|
|
350
|
+
const result = (0, merge_tree_1.compareReferencePositions)(this.start, b.end) <= 0 &&
|
|
351
|
+
(0, merge_tree_1.compareReferencePositions)(this.end, b.start) >= 0;
|
|
353
352
|
return result;
|
|
354
353
|
}
|
|
355
354
|
/**
|
|
@@ -383,7 +382,7 @@ class SequenceInterval {
|
|
|
383
382
|
overlapsPos(bstart, bend) {
|
|
384
383
|
const startPos = this.client.localReferencePositionToPosition(this.start);
|
|
385
384
|
const endPos = this.client.localReferencePositionToPosition(this.end);
|
|
386
|
-
return
|
|
385
|
+
return endPos > bstart && startPos < bend;
|
|
387
386
|
}
|
|
388
387
|
/**
|
|
389
388
|
* {@inheritDoc IInterval.modify}
|
|
@@ -428,13 +427,17 @@ class SequenceInterval {
|
|
|
428
427
|
}
|
|
429
428
|
}
|
|
430
429
|
exports.SequenceInterval = SequenceInterval;
|
|
431
|
-
function createPositionReferenceFromSegoff(client, segoff, refType, op) {
|
|
430
|
+
function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq) {
|
|
432
431
|
if (segoff.segment) {
|
|
433
432
|
const ref = client.createLocalReferencePosition(segoff.segment, segoff.offset, refType, undefined);
|
|
434
433
|
return ref;
|
|
435
434
|
}
|
|
436
|
-
|
|
437
|
-
|
|
435
|
+
// Creating references on detached segments is allowed for:
|
|
436
|
+
// - Transient segments
|
|
437
|
+
// - References coming from a remote client (location may have been concurrently removed)
|
|
438
|
+
// - References being rebased to a new sequence number
|
|
439
|
+
// (segment they originally referred to may have been removed with no suitable replacement)
|
|
440
|
+
if (!op && !localSeq && !(0, merge_tree_1.refTypeIncludesFlag)(refType, merge_tree_1.ReferenceType.Transient)) {
|
|
438
441
|
throw new container_utils_1.UsageError("Non-transient references need segment");
|
|
439
442
|
}
|
|
440
443
|
return (0, merge_tree_1.createDetachedLocalReferencePosition)(refType);
|
|
@@ -443,14 +446,17 @@ function createPositionReference(client, pos, refType, op, fromSnapshot, localSe
|
|
|
443
446
|
let segoff;
|
|
444
447
|
if (op) {
|
|
445
448
|
(0, common_utils_1.assert)((refType & merge_tree_1.ReferenceType.SlideOnRemove) !== 0, 0x2f5 /* op create references must be SlideOnRemove */);
|
|
446
|
-
segoff = client.getContainingSegment(pos,
|
|
449
|
+
segoff = client.getContainingSegment(pos, {
|
|
450
|
+
referenceSequenceNumber: op.referenceSequenceNumber,
|
|
451
|
+
clientId: op.clientId,
|
|
452
|
+
});
|
|
447
453
|
segoff = client.getSlideToSegment(segoff);
|
|
448
454
|
}
|
|
449
455
|
else {
|
|
450
456
|
(0, common_utils_1.assert)((refType & merge_tree_1.ReferenceType.SlideOnRemove) === 0 || !!fromSnapshot, 0x2f6 /* SlideOnRemove references must be op created */);
|
|
451
457
|
segoff = client.getContainingSegment(pos, undefined, localSeq);
|
|
452
458
|
}
|
|
453
|
-
return createPositionReferenceFromSegoff(client, segoff, refType, op);
|
|
459
|
+
return createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq);
|
|
454
460
|
}
|
|
455
461
|
function createSequenceInterval(label, start, end, client, intervalType, op, fromSnapshot) {
|
|
456
462
|
let beginRefType = merge_tree_1.ReferenceType.RangeBegin;
|
|
@@ -522,14 +528,13 @@ class LocalIntervalCollection {
|
|
|
522
528
|
}
|
|
523
529
|
addConflictResolver(conflictResolver) {
|
|
524
530
|
this.conflictResolver = conflictResolver;
|
|
525
|
-
this.endConflictResolver =
|
|
526
|
-
(key, currentKey)
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
key: ival,
|
|
531
|
-
};
|
|
531
|
+
this.endConflictResolver = (key, currentKey) => {
|
|
532
|
+
const ival = conflictResolver(key, currentKey);
|
|
533
|
+
return {
|
|
534
|
+
data: ival,
|
|
535
|
+
key: ival,
|
|
532
536
|
};
|
|
537
|
+
};
|
|
533
538
|
}
|
|
534
539
|
map(fn) {
|
|
535
540
|
this.intervalTree.map(fn);
|
|
@@ -609,11 +614,11 @@ class LocalIntervalCollection {
|
|
|
609
614
|
else {
|
|
610
615
|
// Start and (possibly) end provided. Walk the subtrees that may contain
|
|
611
616
|
// this start position.
|
|
612
|
-
const compareFn = end === undefined
|
|
613
|
-
(node) => {
|
|
617
|
+
const compareFn = end === undefined
|
|
618
|
+
? (node) => {
|
|
614
619
|
return transientInterval.compareStart(node.key);
|
|
615
|
-
}
|
|
616
|
-
(node) => {
|
|
620
|
+
}
|
|
621
|
+
: (node) => {
|
|
617
622
|
return transientInterval.compare(node.key);
|
|
618
623
|
};
|
|
619
624
|
const continueLeftFn = (cmpResult) => cmpResult <= 0;
|
|
@@ -748,18 +753,25 @@ class LocalIntervalCollection {
|
|
|
748
753
|
};
|
|
749
754
|
if (interval instanceof SequenceInterval) {
|
|
750
755
|
let previousInterval;
|
|
756
|
+
let pendingChanges = 0;
|
|
751
757
|
interval.addPositionChangeListeners(() => {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
758
|
+
pendingChanges++;
|
|
759
|
+
// Note: both start and end can change and invoke beforeSlide on each endpoint before afterSlide.
|
|
760
|
+
if (!previousInterval) {
|
|
761
|
+
previousInterval = interval.clone();
|
|
762
|
+
previousInterval.start = cloneRef(previousInterval.start);
|
|
763
|
+
previousInterval.end = cloneRef(previousInterval.end);
|
|
764
|
+
this.removeIntervalFromIndex(interval);
|
|
765
|
+
}
|
|
757
766
|
}, () => {
|
|
758
767
|
var _a;
|
|
759
768
|
(0, common_utils_1.assert)(previousInterval !== undefined, 0x3fa /* Invalid interleaving of before/after slide */);
|
|
760
|
-
|
|
761
|
-
(
|
|
762
|
-
|
|
769
|
+
pendingChanges--;
|
|
770
|
+
if (pendingChanges === 0) {
|
|
771
|
+
this.addIntervalToIndex(interval);
|
|
772
|
+
(_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval, previousInterval);
|
|
773
|
+
previousInterval = undefined;
|
|
774
|
+
}
|
|
763
775
|
});
|
|
764
776
|
}
|
|
765
777
|
}
|
|
@@ -844,17 +856,18 @@ function makeOpsMap() {
|
|
|
844
856
|
const rebasedOp = Object.assign(Object.assign({}, op), { value: rebasedValue });
|
|
845
857
|
return { rebasedOp, rebasedLocalOpMetadata: localOpMetadata };
|
|
846
858
|
};
|
|
847
|
-
return new Map([
|
|
859
|
+
return new Map([
|
|
860
|
+
[
|
|
848
861
|
"add",
|
|
849
862
|
{
|
|
850
|
-
process: (collection, params, local, op) => {
|
|
863
|
+
process: (collection, params, local, op, localOpMetadata) => {
|
|
851
864
|
// if params is undefined, the interval was deleted during
|
|
852
865
|
// rebasing
|
|
853
866
|
if (!params) {
|
|
854
867
|
return;
|
|
855
868
|
}
|
|
856
869
|
(0, common_utils_1.assert)(op !== undefined, 0x3fb /* op should exist here */);
|
|
857
|
-
collection.ackAdd(params, local, op);
|
|
870
|
+
collection.ackAdd(params, local, op, localOpMetadata);
|
|
858
871
|
},
|
|
859
872
|
rebase,
|
|
860
873
|
},
|
|
@@ -875,18 +888,19 @@ function makeOpsMap() {
|
|
|
875
888
|
[
|
|
876
889
|
"change",
|
|
877
890
|
{
|
|
878
|
-
process: (collection, params, local, op) => {
|
|
891
|
+
process: (collection, params, local, op, localOpMetadata) => {
|
|
879
892
|
// if params is undefined, the interval was deleted during
|
|
880
893
|
// rebasing
|
|
881
894
|
if (!params) {
|
|
882
895
|
return;
|
|
883
896
|
}
|
|
884
897
|
(0, common_utils_1.assert)(op !== undefined, 0x3fd /* op should exist here */);
|
|
885
|
-
collection.ackChange(params, local, op);
|
|
898
|
+
collection.ackChange(params, local, op, localOpMetadata);
|
|
886
899
|
},
|
|
887
900
|
rebase,
|
|
888
901
|
},
|
|
889
|
-
]
|
|
902
|
+
],
|
|
903
|
+
]);
|
|
890
904
|
}
|
|
891
905
|
exports.makeOpsMap = makeOpsMap;
|
|
892
906
|
class IntervalCollectionIterator {
|
|
@@ -923,6 +937,8 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
923
937
|
this.helpers = helpers;
|
|
924
938
|
this.requiresClient = requiresClient;
|
|
925
939
|
this.emitter = emitter;
|
|
940
|
+
this.localSeqToSerializedInterval = new Map();
|
|
941
|
+
this.localSeqToRebasedInterval = new Map();
|
|
926
942
|
this.pendingChangesStart = new Map();
|
|
927
943
|
this.pendingChangesEnd = new Map();
|
|
928
944
|
this.savedSerializedIntervals = Array.isArray(serializedIntervals)
|
|
@@ -932,16 +948,57 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
932
948
|
get attached() {
|
|
933
949
|
return !!this.localCollection;
|
|
934
950
|
}
|
|
951
|
+
rebasePositionWithSegmentSlide(pos, seqNumberFrom, localSeq) {
|
|
952
|
+
var _a;
|
|
953
|
+
if (!this.client) {
|
|
954
|
+
throw new telemetry_utils_1.LoggingError("mergeTree client must exist");
|
|
955
|
+
}
|
|
956
|
+
const { clientId } = this.client.getCollabWindow();
|
|
957
|
+
const { segment, offset } = this.client.getContainingSegment(pos, {
|
|
958
|
+
referenceSequenceNumber: seqNumberFrom,
|
|
959
|
+
clientId: this.client.getLongClientId(clientId),
|
|
960
|
+
}, localSeq);
|
|
961
|
+
// if segment is undefined, it slid off the string
|
|
962
|
+
(0, common_utils_1.assert)(segment !== undefined, 0x54e /* No segment found */);
|
|
963
|
+
const segoff = (_a = this.client.getSlideToSegment({ segment, offset })) !== null && _a !== void 0 ? _a : segment;
|
|
964
|
+
// case happens when rebasing op, but concurrently entire string has been deleted
|
|
965
|
+
if (segoff.segment === undefined || segoff.offset === undefined) {
|
|
966
|
+
return merge_tree_1.DetachedReferencePosition;
|
|
967
|
+
}
|
|
968
|
+
(0, common_utils_1.assert)(offset !== undefined && 0 <= offset && offset < segment.cachedLength, 0x54f /* Invalid offset */);
|
|
969
|
+
return this.client.findReconnectionPosition(segoff.segment, localSeq) + segoff.offset;
|
|
970
|
+
}
|
|
971
|
+
computeRebasedPositions(localSeq) {
|
|
972
|
+
(0, common_utils_1.assert)(this.client !== undefined, 0x550 /* Client should be defined when computing rebased position */);
|
|
973
|
+
const original = this.localSeqToSerializedInterval.get(localSeq);
|
|
974
|
+
(0, common_utils_1.assert)(original !== undefined, 0x551 /* Failed to store pending serialized interval info for this localSeq. */);
|
|
975
|
+
const rebased = Object.assign({}, original);
|
|
976
|
+
const { start, end, sequenceNumber } = original;
|
|
977
|
+
if (start !== undefined) {
|
|
978
|
+
rebased.start = this.rebasePositionWithSegmentSlide(start, sequenceNumber, localSeq);
|
|
979
|
+
}
|
|
980
|
+
if (end !== undefined) {
|
|
981
|
+
rebased.end = this.rebasePositionWithSegmentSlide(end, sequenceNumber, localSeq);
|
|
982
|
+
}
|
|
983
|
+
return rebased;
|
|
984
|
+
}
|
|
935
985
|
/** @internal */
|
|
936
986
|
attachGraph(client, label) {
|
|
937
987
|
if (this.attached) {
|
|
938
988
|
throw new telemetry_utils_1.LoggingError("Only supports one Sequence attach");
|
|
939
989
|
}
|
|
940
|
-
if (
|
|
990
|
+
if (client === undefined && this.requiresClient) {
|
|
941
991
|
throw new telemetry_utils_1.LoggingError("Client required for this collection");
|
|
942
992
|
}
|
|
943
993
|
// Instantiate the local interval collection based on the saved intervals
|
|
944
994
|
this.client = client;
|
|
995
|
+
if (client) {
|
|
996
|
+
client.on("normalize", () => {
|
|
997
|
+
for (const localSeq of this.localSeqToSerializedInterval.keys()) {
|
|
998
|
+
this.localSeqToRebasedInterval.set(localSeq, this.computeRebasedPositions(localSeq));
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
945
1002
|
this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval, previousInterval) => this.emitChange(interval, previousInterval, true));
|
|
946
1003
|
if (this.savedSerializedIntervals) {
|
|
947
1004
|
for (const serializedInterval of this.savedSerializedIntervals) {
|
|
@@ -1019,8 +1076,10 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1019
1076
|
sequenceNumber: (_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.getCurrentSeq()) !== null && _b !== void 0 ? _b : 0,
|
|
1020
1077
|
start,
|
|
1021
1078
|
};
|
|
1079
|
+
const localSeq = this.getNextLocalSeq();
|
|
1080
|
+
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
1022
1081
|
// Local ops get submitted to the server. Remote ops have the deserializer run.
|
|
1023
|
-
this.emitter.emit("add", undefined, serializedInterval, { localSeq
|
|
1082
|
+
this.emitter.emit("add", undefined, serializedInterval, { localSeq });
|
|
1024
1083
|
}
|
|
1025
1084
|
this.emit("addInterval", interval, true, undefined);
|
|
1026
1085
|
return interval;
|
|
@@ -1034,7 +1093,9 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1034
1093
|
if (interval) {
|
|
1035
1094
|
// Local ops get submitted to the server. Remote ops have the deserializer run.
|
|
1036
1095
|
if (local) {
|
|
1037
|
-
this.emitter.emit("delete", undefined, interval.serialize(), {
|
|
1096
|
+
this.emitter.emit("delete", undefined, interval.serialize(), {
|
|
1097
|
+
localSeq: this.getNextLocalSeq(),
|
|
1098
|
+
});
|
|
1038
1099
|
}
|
|
1039
1100
|
else {
|
|
1040
1101
|
if (this.onDeserialize) {
|
|
@@ -1069,7 +1130,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1069
1130
|
if (!this.attached) {
|
|
1070
1131
|
throw new telemetry_utils_1.LoggingError("Attach must be called before accessing intervals");
|
|
1071
1132
|
}
|
|
1072
|
-
if (typeof
|
|
1133
|
+
if (typeof id !== "string") {
|
|
1073
1134
|
throw new telemetry_utils_1.LoggingError("Change API requires an ID that is a string");
|
|
1074
1135
|
}
|
|
1075
1136
|
if (!props) {
|
|
@@ -1086,7 +1147,9 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1086
1147
|
serializedInterval.end = undefined;
|
|
1087
1148
|
serializedInterval.properties = props;
|
|
1088
1149
|
serializedInterval.properties[reservedIntervalIdKey] = interval.getIntervalId();
|
|
1089
|
-
|
|
1150
|
+
const localSeq = this.getNextLocalSeq();
|
|
1151
|
+
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
1152
|
+
this.emitter.emit("change", undefined, serializedInterval, { localSeq });
|
|
1090
1153
|
this.emit("propertyChanged", interval, deltaProps, true, undefined);
|
|
1091
1154
|
}
|
|
1092
1155
|
}
|
|
@@ -1102,7 +1165,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1102
1165
|
throw new telemetry_utils_1.LoggingError("Attach must be called before accessing intervals");
|
|
1103
1166
|
}
|
|
1104
1167
|
// Force id to be a string.
|
|
1105
|
-
if (typeof
|
|
1168
|
+
if (typeof id !== "string") {
|
|
1106
1169
|
throw new telemetry_utils_1.LoggingError("Change API requires an ID that is a string");
|
|
1107
1170
|
}
|
|
1108
1171
|
const interval = this.getIntervalById(id);
|
|
@@ -1115,11 +1178,12 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1115
1178
|
serializedInterval.start = start;
|
|
1116
1179
|
serializedInterval.end = end;
|
|
1117
1180
|
// Emit a property bag containing only the ID, as we don't intend for this op to change any properties.
|
|
1118
|
-
serializedInterval.properties =
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
this.
|
|
1181
|
+
serializedInterval.properties = {
|
|
1182
|
+
[reservedIntervalIdKey]: interval.getIntervalId(),
|
|
1183
|
+
};
|
|
1184
|
+
const localSeq = this.getNextLocalSeq();
|
|
1185
|
+
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
1186
|
+
this.emitter.emit("change", undefined, serializedInterval, { localSeq });
|
|
1123
1187
|
this.addPendingChange(id, serializedInterval);
|
|
1124
1188
|
this.emitChange(newInterval, interval, true);
|
|
1125
1189
|
return newInterval;
|
|
@@ -1176,12 +1240,14 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1176
1240
|
return entries && entries.length !== 0;
|
|
1177
1241
|
}
|
|
1178
1242
|
/** @internal */
|
|
1179
|
-
ackChange(serializedInterval, local, op) {
|
|
1243
|
+
ackChange(serializedInterval, local, op, localOpMetadata) {
|
|
1180
1244
|
var _a, _b, _c, _d;
|
|
1181
1245
|
if (!this.localCollection) {
|
|
1182
1246
|
throw new telemetry_utils_1.LoggingError("Attach must be called before accessing intervals");
|
|
1183
1247
|
}
|
|
1184
1248
|
if (local) {
|
|
1249
|
+
(0, common_utils_1.assert)(localOpMetadata !== undefined, 0x552 /* op metadata should be defined for local op */);
|
|
1250
|
+
this.localSeqToSerializedInterval.delete(localOpMetadata === null || localOpMetadata === void 0 ? void 0 : localOpMetadata.localSeq);
|
|
1185
1251
|
// This is an ack from the server. Remove the pending change.
|
|
1186
1252
|
this.removePendingChange(serializedInterval);
|
|
1187
1253
|
}
|
|
@@ -1219,7 +1285,8 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1219
1285
|
if (start !== undefined || end !== undefined) {
|
|
1220
1286
|
// If changeInterval gives us a new interval, work with that one. Otherwise keep working with
|
|
1221
1287
|
// the one we originally found in the tree.
|
|
1222
|
-
newInterval =
|
|
1288
|
+
newInterval =
|
|
1289
|
+
(_d = this.localCollection.changeInterval(interval, start, end, op)) !== null && _d !== void 0 ? _d : interval;
|
|
1223
1290
|
}
|
|
1224
1291
|
const deltaProps = newInterval.addProperties(newProps, true, op.sequenceNumber);
|
|
1225
1292
|
if (this.onDeserialize) {
|
|
@@ -1261,7 +1328,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1261
1328
|
* @internal
|
|
1262
1329
|
*/
|
|
1263
1330
|
rebaseLocalInterval(opName, serializedInterval, localSeq) {
|
|
1264
|
-
var _a, _b, _c, _d, _e, _f
|
|
1331
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1265
1332
|
if (!this.client) {
|
|
1266
1333
|
// If there's no associated mergeTree client, the originally submitted op is still correct.
|
|
1267
1334
|
return serializedInterval;
|
|
@@ -1269,44 +1336,36 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1269
1336
|
if (!this.attached) {
|
|
1270
1337
|
throw new telemetry_utils_1.LoggingError("attachSequence must be called");
|
|
1271
1338
|
}
|
|
1272
|
-
const {
|
|
1273
|
-
const startRebased =
|
|
1274
|
-
this.client.rebasePosition(start, sequenceNumber, localSeq);
|
|
1275
|
-
const endRebased = end === undefined ? undefined :
|
|
1276
|
-
this.client.rebasePosition(end, sequenceNumber, localSeq);
|
|
1339
|
+
const { intervalType, properties } = serializedInterval;
|
|
1340
|
+
const { start: startRebased, end: endRebased } = (_a = this.localSeqToRebasedInterval.get(localSeq)) !== null && _a !== void 0 ? _a : this.computeRebasedPositions(localSeq);
|
|
1277
1341
|
const intervalId = properties === null || properties === void 0 ? void 0 : properties[reservedIntervalIdKey];
|
|
1278
|
-
const localInterval = (
|
|
1342
|
+
const localInterval = (_b = this.localCollection) === null || _b === void 0 ? void 0 : _b.getIntervalById(intervalId);
|
|
1279
1343
|
const rebased = {
|
|
1280
1344
|
start: startRebased,
|
|
1281
1345
|
end: endRebased,
|
|
1282
1346
|
intervalType,
|
|
1283
|
-
sequenceNumber: (
|
|
1347
|
+
sequenceNumber: (_d = (_c = this.client) === null || _c === void 0 ? void 0 : _c.getCurrentSeq()) !== null && _d !== void 0 ? _d : 0,
|
|
1284
1348
|
properties,
|
|
1285
1349
|
};
|
|
1286
|
-
if (opName === "change" &&
|
|
1350
|
+
if (opName === "change" &&
|
|
1351
|
+
(this.hasPendingChangeStart(intervalId) || this.hasPendingChangeEnd(intervalId))) {
|
|
1287
1352
|
this.removePendingChange(serializedInterval);
|
|
1288
1353
|
this.addPendingChange(intervalId, rebased);
|
|
1289
1354
|
}
|
|
1290
|
-
// if the interval slid off the string, rebase the op to be a noop and
|
|
1291
|
-
|
|
1292
|
-
|
|
1355
|
+
// if the interval slid off the string, rebase the op to be a noop and delete the interval.
|
|
1356
|
+
if (startRebased === merge_tree_1.DetachedReferencePosition ||
|
|
1357
|
+
endRebased === merge_tree_1.DetachedReferencePosition) {
|
|
1293
1358
|
if (localInterval) {
|
|
1294
|
-
(
|
|
1359
|
+
(_e = this.localCollection) === null || _e === void 0 ? void 0 : _e.removeExistingInterval(localInterval);
|
|
1295
1360
|
}
|
|
1296
1361
|
return undefined;
|
|
1297
1362
|
}
|
|
1298
|
-
if (
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
const endSegment = this.getSlideToSegment(localInterval.end);
|
|
1305
|
-
// we need to slide because the reference has been removed
|
|
1306
|
-
if (startSegment || endSegment) {
|
|
1307
|
-
const newStart = startSegment && this.client.getPosition(startSegment.segment, localSeq) + ((_e = startSegment.offset) !== null && _e !== void 0 ? _e : 0);
|
|
1308
|
-
const newEnd = endSegment && this.client.getPosition(endSegment.segment, localSeq) + ((_f = endSegment.offset) !== null && _f !== void 0 ? _f : 0);
|
|
1309
|
-
(_g = this.localCollection) === null || _g === void 0 ? void 0 : _g.changeInterval(localInterval, newStart, newEnd, undefined, localSeq);
|
|
1363
|
+
if (localInterval !== undefined) {
|
|
1364
|
+
// we know we must be using `SequenceInterval` because `this.client` exists
|
|
1365
|
+
(0, common_utils_1.assert)(localInterval instanceof SequenceInterval, 0x3a0 /* localInterval must be `SequenceInterval` when used with client */);
|
|
1366
|
+
// The rebased op may place this interval's endpoints on different segments. Calling `changeInterval` here
|
|
1367
|
+
// updates the local client's state to be consistent with the emitted op.
|
|
1368
|
+
(_f = this.localCollection) === null || _f === void 0 ? void 0 : _f.changeInterval(localInterval, startRebased, endRebased, undefined, localSeq);
|
|
1310
1369
|
}
|
|
1311
1370
|
return rebased;
|
|
1312
1371
|
}
|
|
@@ -1320,7 +1379,9 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1320
1379
|
return undefined;
|
|
1321
1380
|
}
|
|
1322
1381
|
const newSegoff = this.client.getSlideToSegment(segoff);
|
|
1323
|
-
const value =
|
|
1382
|
+
const value = segoff.segment === newSegoff.segment && segoff.offset === newSegoff.offset
|
|
1383
|
+
? undefined
|
|
1384
|
+
: newSegoff;
|
|
1324
1385
|
return value;
|
|
1325
1386
|
}
|
|
1326
1387
|
setSlideOnRemove(lref) {
|
|
@@ -1394,9 +1455,11 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1394
1455
|
}
|
|
1395
1456
|
}
|
|
1396
1457
|
/** @internal */
|
|
1397
|
-
ackAdd(serializedInterval, local, op) {
|
|
1458
|
+
ackAdd(serializedInterval, local, op, localOpMetadata) {
|
|
1398
1459
|
var _a;
|
|
1399
1460
|
if (local) {
|
|
1461
|
+
(0, common_utils_1.assert)(localOpMetadata !== undefined, 0x553 /* op metadata should be defined for local op */);
|
|
1462
|
+
this.localSeqToSerializedInterval.delete(localOpMetadata.localSeq);
|
|
1400
1463
|
const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
1401
1464
|
const localInterval = this.getIntervalById(id);
|
|
1402
1465
|
if (localInterval) {
|
|
@@ -1533,8 +1596,10 @@ exports.IntervalCollection = IntervalCollection;
|
|
|
1533
1596
|
*/
|
|
1534
1597
|
function intervalLocatorFromEndpoint(potentialEndpoint) {
|
|
1535
1598
|
var _a;
|
|
1536
|
-
const { interval, [merge_tree_1.reservedRangeLabelsKey]: collectionNameArray
|
|
1537
|
-
return
|
|
1599
|
+
const { interval, [merge_tree_1.reservedRangeLabelsKey]: collectionNameArray } = (_a = potentialEndpoint.properties) !== null && _a !== void 0 ? _a : {};
|
|
1600
|
+
return interval && (collectionNameArray === null || collectionNameArray === void 0 ? void 0 : collectionNameArray.length) === 1
|
|
1601
|
+
? { label: collectionNameArray[0], interval }
|
|
1602
|
+
: undefined;
|
|
1538
1603
|
}
|
|
1539
1604
|
exports.intervalLocatorFromEndpoint = intervalLocatorFromEndpoint;
|
|
1540
1605
|
//# sourceMappingURL=intervalCollection.js.map
|