@fluidframework/sequence 2.0.0-dev.2.3.0.115467 → 2.0.0-dev.4.1.0.148229
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 +204 -177
- 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 +15 -3
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +150 -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 +16 -42
- 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 +15 -3
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +150 -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 +17 -43
- 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 +79 -67
- 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 +2206 -1932
- package/src/intervalTree.ts +139 -139
- package/src/localValues.ts +64 -73
- package/src/packageVersion.ts +1 -1
- package/src/sequence.ts +738 -710
- 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
- package/.editorconfig +0 -7
|
@@ -177,12 +177,12 @@ 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
|
/**
|
|
185
184
|
* {@inheritDoc IInterval.union}
|
|
185
|
+
* @deprecated - This API was never intended to be public and will be marked internal in a future release.
|
|
186
186
|
*/
|
|
187
187
|
union(b) {
|
|
188
188
|
return new Interval(Math.min(this.start, b.start), Math.max(this.end, b.end), this.properties);
|
|
@@ -192,6 +192,7 @@ class Interval {
|
|
|
192
192
|
}
|
|
193
193
|
/**
|
|
194
194
|
* {@inheritDoc ISerializableInterval.addProperties}
|
|
195
|
+
* @deprecated - This API was never intended to be public and will be marked internal in a future release.
|
|
195
196
|
*/
|
|
196
197
|
addProperties(newProps, collaborating = false, seq, op) {
|
|
197
198
|
if (newProps) {
|
|
@@ -201,6 +202,7 @@ class Interval {
|
|
|
201
202
|
}
|
|
202
203
|
/**
|
|
203
204
|
* {@inheritDoc IInterval.modify}
|
|
205
|
+
* @deprecated - This API was never intended to be public and will be marked internal in a future release.
|
|
204
206
|
*/
|
|
205
207
|
modify(label, start, end, op) {
|
|
206
208
|
const startPos = start !== null && start !== void 0 ? start : this.start;
|
|
@@ -265,8 +267,8 @@ class SequenceInterval {
|
|
|
265
267
|
beforePositionChange,
|
|
266
268
|
afterPositionChange,
|
|
267
269
|
};
|
|
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 = {});
|
|
270
|
+
const startCbs = ((_a = (_c = this.start).callbacks) !== null && _a !== void 0 ? _a : (_c.callbacks = {}));
|
|
271
|
+
const endCbs = ((_b = (_d = this.end).callbacks) !== null && _b !== void 0 ? _b : (_d.callbacks = {}));
|
|
270
272
|
startCbs.beforeSlide = endCbs.beforeSlide = beforePositionChange;
|
|
271
273
|
startCbs.afterSlide = endCbs.afterSlide = afterPositionChange;
|
|
272
274
|
}
|
|
@@ -348,8 +350,8 @@ class SequenceInterval {
|
|
|
348
350
|
* {@inheritDoc IInterval.overlaps}
|
|
349
351
|
*/
|
|
350
352
|
overlaps(b) {
|
|
351
|
-
const result = (
|
|
352
|
-
(
|
|
353
|
+
const result = (0, merge_tree_1.compareReferencePositions)(this.start, b.end) <= 0 &&
|
|
354
|
+
(0, merge_tree_1.compareReferencePositions)(this.end, b.start) >= 0;
|
|
353
355
|
return result;
|
|
354
356
|
}
|
|
355
357
|
/**
|
|
@@ -365,12 +367,14 @@ class SequenceInterval {
|
|
|
365
367
|
}
|
|
366
368
|
/**
|
|
367
369
|
* {@inheritDoc IInterval.union}
|
|
370
|
+
* @deprecated - This API was never intended to be public and will be marked internal in a future release.
|
|
368
371
|
*/
|
|
369
372
|
union(b) {
|
|
370
373
|
return new SequenceInterval(this.client, (0, merge_tree_1.minReferencePosition)(this.start, b.start), (0, merge_tree_1.maxReferencePosition)(this.end, b.end), this.intervalType);
|
|
371
374
|
}
|
|
372
375
|
/**
|
|
373
376
|
* {@inheritDoc ISerializableInterval.addProperties}
|
|
377
|
+
* @deprecated - This API was never intended to be public and will be marked internal in a future release.
|
|
374
378
|
*/
|
|
375
379
|
addProperties(newProps, collab = false, seq, op) {
|
|
376
380
|
this.initializeProperties();
|
|
@@ -383,10 +387,11 @@ class SequenceInterval {
|
|
|
383
387
|
overlapsPos(bstart, bend) {
|
|
384
388
|
const startPos = this.client.localReferencePositionToPosition(this.start);
|
|
385
389
|
const endPos = this.client.localReferencePositionToPosition(this.end);
|
|
386
|
-
return
|
|
390
|
+
return endPos > bstart && startPos < bend;
|
|
387
391
|
}
|
|
388
392
|
/**
|
|
389
393
|
* {@inheritDoc IInterval.modify}
|
|
394
|
+
* @deprecated - This API was never intended to be public and will be marked internal in a future release.
|
|
390
395
|
*/
|
|
391
396
|
modify(label, start, end, op, localSeq) {
|
|
392
397
|
const getRefType = (baseType) => {
|
|
@@ -428,13 +433,17 @@ class SequenceInterval {
|
|
|
428
433
|
}
|
|
429
434
|
}
|
|
430
435
|
exports.SequenceInterval = SequenceInterval;
|
|
431
|
-
function createPositionReferenceFromSegoff(client, segoff, refType, op) {
|
|
436
|
+
function createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq) {
|
|
432
437
|
if (segoff.segment) {
|
|
433
438
|
const ref = client.createLocalReferencePosition(segoff.segment, segoff.offset, refType, undefined);
|
|
434
439
|
return ref;
|
|
435
440
|
}
|
|
436
|
-
|
|
437
|
-
|
|
441
|
+
// Creating references on detached segments is allowed for:
|
|
442
|
+
// - Transient segments
|
|
443
|
+
// - References coming from a remote client (location may have been concurrently removed)
|
|
444
|
+
// - References being rebased to a new sequence number
|
|
445
|
+
// (segment they originally referred to may have been removed with no suitable replacement)
|
|
446
|
+
if (!op && !localSeq && !(0, merge_tree_1.refTypeIncludesFlag)(refType, merge_tree_1.ReferenceType.Transient)) {
|
|
438
447
|
throw new container_utils_1.UsageError("Non-transient references need segment");
|
|
439
448
|
}
|
|
440
449
|
return (0, merge_tree_1.createDetachedLocalReferencePosition)(refType);
|
|
@@ -443,14 +452,17 @@ function createPositionReference(client, pos, refType, op, fromSnapshot, localSe
|
|
|
443
452
|
let segoff;
|
|
444
453
|
if (op) {
|
|
445
454
|
(0, common_utils_1.assert)((refType & merge_tree_1.ReferenceType.SlideOnRemove) !== 0, 0x2f5 /* op create references must be SlideOnRemove */);
|
|
446
|
-
segoff = client.getContainingSegment(pos,
|
|
455
|
+
segoff = client.getContainingSegment(pos, {
|
|
456
|
+
referenceSequenceNumber: op.referenceSequenceNumber,
|
|
457
|
+
clientId: op.clientId,
|
|
458
|
+
});
|
|
447
459
|
segoff = client.getSlideToSegment(segoff);
|
|
448
460
|
}
|
|
449
461
|
else {
|
|
450
462
|
(0, common_utils_1.assert)((refType & merge_tree_1.ReferenceType.SlideOnRemove) === 0 || !!fromSnapshot, 0x2f6 /* SlideOnRemove references must be op created */);
|
|
451
463
|
segoff = client.getContainingSegment(pos, undefined, localSeq);
|
|
452
464
|
}
|
|
453
|
-
return createPositionReferenceFromSegoff(client, segoff, refType, op);
|
|
465
|
+
return createPositionReferenceFromSegoff(client, segoff, refType, op, localSeq);
|
|
454
466
|
}
|
|
455
467
|
function createSequenceInterval(label, start, end, client, intervalType, op, fromSnapshot) {
|
|
456
468
|
let beginRefType = merge_tree_1.ReferenceType.RangeBegin;
|
|
@@ -522,14 +534,13 @@ class LocalIntervalCollection {
|
|
|
522
534
|
}
|
|
523
535
|
addConflictResolver(conflictResolver) {
|
|
524
536
|
this.conflictResolver = conflictResolver;
|
|
525
|
-
this.endConflictResolver =
|
|
526
|
-
(key, currentKey)
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
key: ival,
|
|
531
|
-
};
|
|
537
|
+
this.endConflictResolver = (key, currentKey) => {
|
|
538
|
+
const ival = conflictResolver(key, currentKey);
|
|
539
|
+
return {
|
|
540
|
+
data: ival,
|
|
541
|
+
key: ival,
|
|
532
542
|
};
|
|
543
|
+
};
|
|
533
544
|
}
|
|
534
545
|
map(fn) {
|
|
535
546
|
this.intervalTree.map(fn);
|
|
@@ -609,11 +620,11 @@ class LocalIntervalCollection {
|
|
|
609
620
|
else {
|
|
610
621
|
// Start and (possibly) end provided. Walk the subtrees that may contain
|
|
611
622
|
// this start position.
|
|
612
|
-
const compareFn = end === undefined
|
|
613
|
-
(node) => {
|
|
623
|
+
const compareFn = end === undefined
|
|
624
|
+
? (node) => {
|
|
614
625
|
return transientInterval.compareStart(node.key);
|
|
615
|
-
}
|
|
616
|
-
(node) => {
|
|
626
|
+
}
|
|
627
|
+
: (node) => {
|
|
617
628
|
return transientInterval.compare(node.key);
|
|
618
629
|
};
|
|
619
630
|
const continueLeftFn = (cmpResult) => cmpResult <= 0;
|
|
@@ -748,18 +759,25 @@ class LocalIntervalCollection {
|
|
|
748
759
|
};
|
|
749
760
|
if (interval instanceof SequenceInterval) {
|
|
750
761
|
let previousInterval;
|
|
762
|
+
let pendingChanges = 0;
|
|
751
763
|
interval.addPositionChangeListeners(() => {
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
764
|
+
pendingChanges++;
|
|
765
|
+
// Note: both start and end can change and invoke beforeSlide on each endpoint before afterSlide.
|
|
766
|
+
if (!previousInterval) {
|
|
767
|
+
previousInterval = interval.clone();
|
|
768
|
+
previousInterval.start = cloneRef(previousInterval.start);
|
|
769
|
+
previousInterval.end = cloneRef(previousInterval.end);
|
|
770
|
+
this.removeIntervalFromIndex(interval);
|
|
771
|
+
}
|
|
757
772
|
}, () => {
|
|
758
773
|
var _a;
|
|
759
774
|
(0, common_utils_1.assert)(previousInterval !== undefined, 0x3fa /* Invalid interleaving of before/after slide */);
|
|
760
|
-
|
|
761
|
-
(
|
|
762
|
-
|
|
775
|
+
pendingChanges--;
|
|
776
|
+
if (pendingChanges === 0) {
|
|
777
|
+
this.addIntervalToIndex(interval);
|
|
778
|
+
(_a = this.onPositionChange) === null || _a === void 0 ? void 0 : _a.call(this, interval, previousInterval);
|
|
779
|
+
previousInterval = undefined;
|
|
780
|
+
}
|
|
763
781
|
});
|
|
764
782
|
}
|
|
765
783
|
}
|
|
@@ -844,17 +862,18 @@ function makeOpsMap() {
|
|
|
844
862
|
const rebasedOp = Object.assign(Object.assign({}, op), { value: rebasedValue });
|
|
845
863
|
return { rebasedOp, rebasedLocalOpMetadata: localOpMetadata };
|
|
846
864
|
};
|
|
847
|
-
return new Map([
|
|
865
|
+
return new Map([
|
|
866
|
+
[
|
|
848
867
|
"add",
|
|
849
868
|
{
|
|
850
|
-
process: (collection, params, local, op) => {
|
|
869
|
+
process: (collection, params, local, op, localOpMetadata) => {
|
|
851
870
|
// if params is undefined, the interval was deleted during
|
|
852
871
|
// rebasing
|
|
853
872
|
if (!params) {
|
|
854
873
|
return;
|
|
855
874
|
}
|
|
856
875
|
(0, common_utils_1.assert)(op !== undefined, 0x3fb /* op should exist here */);
|
|
857
|
-
collection.ackAdd(params, local, op);
|
|
876
|
+
collection.ackAdd(params, local, op, localOpMetadata);
|
|
858
877
|
},
|
|
859
878
|
rebase,
|
|
860
879
|
},
|
|
@@ -875,18 +894,19 @@ function makeOpsMap() {
|
|
|
875
894
|
[
|
|
876
895
|
"change",
|
|
877
896
|
{
|
|
878
|
-
process: (collection, params, local, op) => {
|
|
897
|
+
process: (collection, params, local, op, localOpMetadata) => {
|
|
879
898
|
// if params is undefined, the interval was deleted during
|
|
880
899
|
// rebasing
|
|
881
900
|
if (!params) {
|
|
882
901
|
return;
|
|
883
902
|
}
|
|
884
903
|
(0, common_utils_1.assert)(op !== undefined, 0x3fd /* op should exist here */);
|
|
885
|
-
collection.ackChange(params, local, op);
|
|
904
|
+
collection.ackChange(params, local, op, localOpMetadata);
|
|
886
905
|
},
|
|
887
906
|
rebase,
|
|
888
907
|
},
|
|
889
|
-
]
|
|
908
|
+
],
|
|
909
|
+
]);
|
|
890
910
|
}
|
|
891
911
|
exports.makeOpsMap = makeOpsMap;
|
|
892
912
|
class IntervalCollectionIterator {
|
|
@@ -923,6 +943,8 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
923
943
|
this.helpers = helpers;
|
|
924
944
|
this.requiresClient = requiresClient;
|
|
925
945
|
this.emitter = emitter;
|
|
946
|
+
this.localSeqToSerializedInterval = new Map();
|
|
947
|
+
this.localSeqToRebasedInterval = new Map();
|
|
926
948
|
this.pendingChangesStart = new Map();
|
|
927
949
|
this.pendingChangesEnd = new Map();
|
|
928
950
|
this.savedSerializedIntervals = Array.isArray(serializedIntervals)
|
|
@@ -932,16 +954,57 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
932
954
|
get attached() {
|
|
933
955
|
return !!this.localCollection;
|
|
934
956
|
}
|
|
957
|
+
rebasePositionWithSegmentSlide(pos, seqNumberFrom, localSeq) {
|
|
958
|
+
var _a;
|
|
959
|
+
if (!this.client) {
|
|
960
|
+
throw new telemetry_utils_1.LoggingError("mergeTree client must exist");
|
|
961
|
+
}
|
|
962
|
+
const { clientId } = this.client.getCollabWindow();
|
|
963
|
+
const { segment, offset } = this.client.getContainingSegment(pos, {
|
|
964
|
+
referenceSequenceNumber: seqNumberFrom,
|
|
965
|
+
clientId: this.client.getLongClientId(clientId),
|
|
966
|
+
}, localSeq);
|
|
967
|
+
// if segment is undefined, it slid off the string
|
|
968
|
+
(0, common_utils_1.assert)(segment !== undefined, 0x54e /* No segment found */);
|
|
969
|
+
const segoff = (_a = this.client.getSlideToSegment({ segment, offset })) !== null && _a !== void 0 ? _a : segment;
|
|
970
|
+
// case happens when rebasing op, but concurrently entire string has been deleted
|
|
971
|
+
if (segoff.segment === undefined || segoff.offset === undefined) {
|
|
972
|
+
return merge_tree_1.DetachedReferencePosition;
|
|
973
|
+
}
|
|
974
|
+
(0, common_utils_1.assert)(offset !== undefined && 0 <= offset && offset < segment.cachedLength, 0x54f /* Invalid offset */);
|
|
975
|
+
return this.client.findReconnectionPosition(segoff.segment, localSeq) + segoff.offset;
|
|
976
|
+
}
|
|
977
|
+
computeRebasedPositions(localSeq) {
|
|
978
|
+
(0, common_utils_1.assert)(this.client !== undefined, 0x550 /* Client should be defined when computing rebased position */);
|
|
979
|
+
const original = this.localSeqToSerializedInterval.get(localSeq);
|
|
980
|
+
(0, common_utils_1.assert)(original !== undefined, 0x551 /* Failed to store pending serialized interval info for this localSeq. */);
|
|
981
|
+
const rebased = Object.assign({}, original);
|
|
982
|
+
const { start, end, sequenceNumber } = original;
|
|
983
|
+
if (start !== undefined) {
|
|
984
|
+
rebased.start = this.rebasePositionWithSegmentSlide(start, sequenceNumber, localSeq);
|
|
985
|
+
}
|
|
986
|
+
if (end !== undefined) {
|
|
987
|
+
rebased.end = this.rebasePositionWithSegmentSlide(end, sequenceNumber, localSeq);
|
|
988
|
+
}
|
|
989
|
+
return rebased;
|
|
990
|
+
}
|
|
935
991
|
/** @internal */
|
|
936
992
|
attachGraph(client, label) {
|
|
937
993
|
if (this.attached) {
|
|
938
994
|
throw new telemetry_utils_1.LoggingError("Only supports one Sequence attach");
|
|
939
995
|
}
|
|
940
|
-
if (
|
|
996
|
+
if (client === undefined && this.requiresClient) {
|
|
941
997
|
throw new telemetry_utils_1.LoggingError("Client required for this collection");
|
|
942
998
|
}
|
|
943
999
|
// Instantiate the local interval collection based on the saved intervals
|
|
944
1000
|
this.client = client;
|
|
1001
|
+
if (client) {
|
|
1002
|
+
client.on("normalize", () => {
|
|
1003
|
+
for (const localSeq of this.localSeqToSerializedInterval.keys()) {
|
|
1004
|
+
this.localSeqToRebasedInterval.set(localSeq, this.computeRebasedPositions(localSeq));
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
945
1008
|
this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval, previousInterval) => this.emitChange(interval, previousInterval, true));
|
|
946
1009
|
if (this.savedSerializedIntervals) {
|
|
947
1010
|
for (const serializedInterval of this.savedSerializedIntervals) {
|
|
@@ -1019,8 +1082,10 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1019
1082
|
sequenceNumber: (_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.getCurrentSeq()) !== null && _b !== void 0 ? _b : 0,
|
|
1020
1083
|
start,
|
|
1021
1084
|
};
|
|
1085
|
+
const localSeq = this.getNextLocalSeq();
|
|
1086
|
+
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
1022
1087
|
// Local ops get submitted to the server. Remote ops have the deserializer run.
|
|
1023
|
-
this.emitter.emit("add", undefined, serializedInterval, { localSeq
|
|
1088
|
+
this.emitter.emit("add", undefined, serializedInterval, { localSeq });
|
|
1024
1089
|
}
|
|
1025
1090
|
this.emit("addInterval", interval, true, undefined);
|
|
1026
1091
|
return interval;
|
|
@@ -1034,7 +1099,9 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1034
1099
|
if (interval) {
|
|
1035
1100
|
// Local ops get submitted to the server. Remote ops have the deserializer run.
|
|
1036
1101
|
if (local) {
|
|
1037
|
-
this.emitter.emit("delete", undefined, interval.serialize(), {
|
|
1102
|
+
this.emitter.emit("delete", undefined, interval.serialize(), {
|
|
1103
|
+
localSeq: this.getNextLocalSeq(),
|
|
1104
|
+
});
|
|
1038
1105
|
}
|
|
1039
1106
|
else {
|
|
1040
1107
|
if (this.onDeserialize) {
|
|
@@ -1069,7 +1136,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1069
1136
|
if (!this.attached) {
|
|
1070
1137
|
throw new telemetry_utils_1.LoggingError("Attach must be called before accessing intervals");
|
|
1071
1138
|
}
|
|
1072
|
-
if (typeof
|
|
1139
|
+
if (typeof id !== "string") {
|
|
1073
1140
|
throw new telemetry_utils_1.LoggingError("Change API requires an ID that is a string");
|
|
1074
1141
|
}
|
|
1075
1142
|
if (!props) {
|
|
@@ -1086,7 +1153,9 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1086
1153
|
serializedInterval.end = undefined;
|
|
1087
1154
|
serializedInterval.properties = props;
|
|
1088
1155
|
serializedInterval.properties[reservedIntervalIdKey] = interval.getIntervalId();
|
|
1089
|
-
|
|
1156
|
+
const localSeq = this.getNextLocalSeq();
|
|
1157
|
+
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
1158
|
+
this.emitter.emit("change", undefined, serializedInterval, { localSeq });
|
|
1090
1159
|
this.emit("propertyChanged", interval, deltaProps, true, undefined);
|
|
1091
1160
|
}
|
|
1092
1161
|
}
|
|
@@ -1102,7 +1171,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1102
1171
|
throw new telemetry_utils_1.LoggingError("Attach must be called before accessing intervals");
|
|
1103
1172
|
}
|
|
1104
1173
|
// Force id to be a string.
|
|
1105
|
-
if (typeof
|
|
1174
|
+
if (typeof id !== "string") {
|
|
1106
1175
|
throw new telemetry_utils_1.LoggingError("Change API requires an ID that is a string");
|
|
1107
1176
|
}
|
|
1108
1177
|
const interval = this.getIntervalById(id);
|
|
@@ -1115,11 +1184,12 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1115
1184
|
serializedInterval.start = start;
|
|
1116
1185
|
serializedInterval.end = end;
|
|
1117
1186
|
// 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.
|
|
1187
|
+
serializedInterval.properties = {
|
|
1188
|
+
[reservedIntervalIdKey]: interval.getIntervalId(),
|
|
1189
|
+
};
|
|
1190
|
+
const localSeq = this.getNextLocalSeq();
|
|
1191
|
+
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
1192
|
+
this.emitter.emit("change", undefined, serializedInterval, { localSeq });
|
|
1123
1193
|
this.addPendingChange(id, serializedInterval);
|
|
1124
1194
|
this.emitChange(newInterval, interval, true);
|
|
1125
1195
|
return newInterval;
|
|
@@ -1176,12 +1246,14 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1176
1246
|
return entries && entries.length !== 0;
|
|
1177
1247
|
}
|
|
1178
1248
|
/** @internal */
|
|
1179
|
-
ackChange(serializedInterval, local, op) {
|
|
1249
|
+
ackChange(serializedInterval, local, op, localOpMetadata) {
|
|
1180
1250
|
var _a, _b, _c, _d;
|
|
1181
1251
|
if (!this.localCollection) {
|
|
1182
1252
|
throw new telemetry_utils_1.LoggingError("Attach must be called before accessing intervals");
|
|
1183
1253
|
}
|
|
1184
1254
|
if (local) {
|
|
1255
|
+
(0, common_utils_1.assert)(localOpMetadata !== undefined, 0x552 /* op metadata should be defined for local op */);
|
|
1256
|
+
this.localSeqToSerializedInterval.delete(localOpMetadata === null || localOpMetadata === void 0 ? void 0 : localOpMetadata.localSeq);
|
|
1185
1257
|
// This is an ack from the server. Remove the pending change.
|
|
1186
1258
|
this.removePendingChange(serializedInterval);
|
|
1187
1259
|
}
|
|
@@ -1219,7 +1291,8 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1219
1291
|
if (start !== undefined || end !== undefined) {
|
|
1220
1292
|
// If changeInterval gives us a new interval, work with that one. Otherwise keep working with
|
|
1221
1293
|
// the one we originally found in the tree.
|
|
1222
|
-
newInterval =
|
|
1294
|
+
newInterval =
|
|
1295
|
+
(_d = this.localCollection.changeInterval(interval, start, end, op)) !== null && _d !== void 0 ? _d : interval;
|
|
1223
1296
|
}
|
|
1224
1297
|
const deltaProps = newInterval.addProperties(newProps, true, op.sequenceNumber);
|
|
1225
1298
|
if (this.onDeserialize) {
|
|
@@ -1261,7 +1334,7 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1261
1334
|
* @internal
|
|
1262
1335
|
*/
|
|
1263
1336
|
rebaseLocalInterval(opName, serializedInterval, localSeq) {
|
|
1264
|
-
var _a, _b, _c, _d, _e, _f
|
|
1337
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1265
1338
|
if (!this.client) {
|
|
1266
1339
|
// If there's no associated mergeTree client, the originally submitted op is still correct.
|
|
1267
1340
|
return serializedInterval;
|
|
@@ -1269,44 +1342,36 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1269
1342
|
if (!this.attached) {
|
|
1270
1343
|
throw new telemetry_utils_1.LoggingError("attachSequence must be called");
|
|
1271
1344
|
}
|
|
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);
|
|
1345
|
+
const { intervalType, properties } = serializedInterval;
|
|
1346
|
+
const { start: startRebased, end: endRebased } = (_a = this.localSeqToRebasedInterval.get(localSeq)) !== null && _a !== void 0 ? _a : this.computeRebasedPositions(localSeq);
|
|
1277
1347
|
const intervalId = properties === null || properties === void 0 ? void 0 : properties[reservedIntervalIdKey];
|
|
1278
|
-
const localInterval = (
|
|
1348
|
+
const localInterval = (_b = this.localCollection) === null || _b === void 0 ? void 0 : _b.getIntervalById(intervalId);
|
|
1279
1349
|
const rebased = {
|
|
1280
1350
|
start: startRebased,
|
|
1281
1351
|
end: endRebased,
|
|
1282
1352
|
intervalType,
|
|
1283
|
-
sequenceNumber: (
|
|
1353
|
+
sequenceNumber: (_d = (_c = this.client) === null || _c === void 0 ? void 0 : _c.getCurrentSeq()) !== null && _d !== void 0 ? _d : 0,
|
|
1284
1354
|
properties,
|
|
1285
1355
|
};
|
|
1286
|
-
if (opName === "change" &&
|
|
1356
|
+
if (opName === "change" &&
|
|
1357
|
+
(this.hasPendingChangeStart(intervalId) || this.hasPendingChangeEnd(intervalId))) {
|
|
1287
1358
|
this.removePendingChange(serializedInterval);
|
|
1288
1359
|
this.addPendingChange(intervalId, rebased);
|
|
1289
1360
|
}
|
|
1290
|
-
// if the interval slid off the string, rebase the op to be a noop and
|
|
1291
|
-
|
|
1292
|
-
|
|
1361
|
+
// if the interval slid off the string, rebase the op to be a noop and delete the interval.
|
|
1362
|
+
if (startRebased === merge_tree_1.DetachedReferencePosition ||
|
|
1363
|
+
endRebased === merge_tree_1.DetachedReferencePosition) {
|
|
1293
1364
|
if (localInterval) {
|
|
1294
|
-
(
|
|
1365
|
+
(_e = this.localCollection) === null || _e === void 0 ? void 0 : _e.removeExistingInterval(localInterval);
|
|
1295
1366
|
}
|
|
1296
1367
|
return undefined;
|
|
1297
1368
|
}
|
|
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);
|
|
1369
|
+
if (localInterval !== undefined) {
|
|
1370
|
+
// we know we must be using `SequenceInterval` because `this.client` exists
|
|
1371
|
+
(0, common_utils_1.assert)(localInterval instanceof SequenceInterval, 0x3a0 /* localInterval must be `SequenceInterval` when used with client */);
|
|
1372
|
+
// The rebased op may place this interval's endpoints on different segments. Calling `changeInterval` here
|
|
1373
|
+
// updates the local client's state to be consistent with the emitted op.
|
|
1374
|
+
(_f = this.localCollection) === null || _f === void 0 ? void 0 : _f.changeInterval(localInterval, startRebased, endRebased, undefined, localSeq);
|
|
1310
1375
|
}
|
|
1311
1376
|
return rebased;
|
|
1312
1377
|
}
|
|
@@ -1320,7 +1385,9 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1320
1385
|
return undefined;
|
|
1321
1386
|
}
|
|
1322
1387
|
const newSegoff = this.client.getSlideToSegment(segoff);
|
|
1323
|
-
const value =
|
|
1388
|
+
const value = segoff.segment === newSegoff.segment && segoff.offset === newSegoff.offset
|
|
1389
|
+
? undefined
|
|
1390
|
+
: newSegoff;
|
|
1324
1391
|
return value;
|
|
1325
1392
|
}
|
|
1326
1393
|
setSlideOnRemove(lref) {
|
|
@@ -1394,9 +1461,11 @@ class IntervalCollection extends common_utils_1.TypedEventEmitter {
|
|
|
1394
1461
|
}
|
|
1395
1462
|
}
|
|
1396
1463
|
/** @internal */
|
|
1397
|
-
ackAdd(serializedInterval, local, op) {
|
|
1464
|
+
ackAdd(serializedInterval, local, op, localOpMetadata) {
|
|
1398
1465
|
var _a;
|
|
1399
1466
|
if (local) {
|
|
1467
|
+
(0, common_utils_1.assert)(localOpMetadata !== undefined, 0x553 /* op metadata should be defined for local op */);
|
|
1468
|
+
this.localSeqToSerializedInterval.delete(localOpMetadata.localSeq);
|
|
1400
1469
|
const id = (_a = serializedInterval.properties) === null || _a === void 0 ? void 0 : _a[reservedIntervalIdKey];
|
|
1401
1470
|
const localInterval = this.getIntervalById(id);
|
|
1402
1471
|
if (localInterval) {
|
|
@@ -1533,8 +1602,10 @@ exports.IntervalCollection = IntervalCollection;
|
|
|
1533
1602
|
*/
|
|
1534
1603
|
function intervalLocatorFromEndpoint(potentialEndpoint) {
|
|
1535
1604
|
var _a;
|
|
1536
|
-
const { interval, [merge_tree_1.reservedRangeLabelsKey]: collectionNameArray
|
|
1537
|
-
return
|
|
1605
|
+
const { interval, [merge_tree_1.reservedRangeLabelsKey]: collectionNameArray } = (_a = potentialEndpoint.properties) !== null && _a !== void 0 ? _a : {};
|
|
1606
|
+
return interval && (collectionNameArray === null || collectionNameArray === void 0 ? void 0 : collectionNameArray.length) === 1
|
|
1607
|
+
? { label: collectionNameArray[0], interval }
|
|
1608
|
+
: undefined;
|
|
1538
1609
|
}
|
|
1539
1610
|
exports.intervalLocatorFromEndpoint = intervalLocatorFromEndpoint;
|
|
1540
1611
|
//# sourceMappingURL=intervalCollection.js.map
|