@fluidframework/sequence 2.0.0-internal.6.3.3 → 2.0.0-internal.7.0.0
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 +64 -0
- package/README.md +130 -0
- package/dist/defaultMap.d.ts +1 -1
- package/dist/defaultMap.d.ts.map +1 -1
- package/dist/defaultMap.js +6 -6
- package/dist/defaultMap.js.map +1 -1
- package/dist/defaultMapInterfaces.d.ts +21 -2
- 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 +2 -1
- package/dist/index.js.map +1 -1
- package/dist/intervalCollection.d.ts +140 -22
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +146 -49
- package/dist/intervalCollection.js.map +1 -1
- package/dist/intervalIndex/endpointInRangeIndex.d.ts +13 -3
- package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
- package/dist/intervalIndex/endpointInRangeIndex.js +9 -6
- package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -1
- package/dist/intervalIndex/endpointIndex.d.ts +13 -2
- package/dist/intervalIndex/endpointIndex.d.ts.map +1 -1
- package/dist/intervalIndex/endpointIndex.js +7 -5
- package/dist/intervalIndex/endpointIndex.js.map +1 -1
- package/dist/intervalIndex/idIntervalIndex.js.map +1 -1
- package/dist/intervalIndex/index.d.ts +4 -4
- package/dist/intervalIndex/index.d.ts.map +1 -1
- package/dist/intervalIndex/index.js +5 -1
- package/dist/intervalIndex/index.js.map +1 -1
- package/dist/intervalIndex/intervalIndex.d.ts +2 -2
- package/dist/intervalIndex/intervalIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +8 -6
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.js +11 -4
- package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.d.ts +2 -2
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +3 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/dist/intervalIndex/startpointInRangeIndex.d.ts +13 -3
- package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
- package/dist/intervalIndex/startpointInRangeIndex.js +9 -8
- package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -1
- package/dist/intervalTree.d.ts +1 -1
- package/dist/intervalTree.d.ts.map +1 -1
- package/dist/intervals/interval.d.ts +4 -3
- package/dist/intervals/interval.d.ts.map +1 -1
- package/dist/intervals/interval.js +14 -6
- package/dist/intervals/interval.js.map +1 -1
- package/dist/intervals/intervalUtils.d.ts +42 -20
- package/dist/intervals/intervalUtils.d.ts.map +1 -1
- package/dist/intervals/intervalUtils.js +12 -10
- package/dist/intervals/intervalUtils.js.map +1 -1
- package/dist/intervals/sequenceInterval.d.ts +30 -17
- package/dist/intervals/sequenceInterval.d.ts.map +1 -1
- package/dist/intervals/sequenceInterval.js +124 -45
- package/dist/intervals/sequenceInterval.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/revertibles.d.ts +3 -15
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +6 -17
- package/dist/revertibles.js.map +1 -1
- package/dist/sequence.d.ts +3 -2
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +46 -45
- package/dist/sequence.js.map +1 -1
- package/dist/sequenceDeltaEvent.d.ts +8 -3
- package/dist/sequenceDeltaEvent.d.ts.map +1 -1
- package/dist/sequenceDeltaEvent.js.map +1 -1
- package/dist/sequenceFactory.js +1 -1
- package/dist/sequenceFactory.js.map +1 -1
- package/dist/sharedIntervalCollection.js +9 -9
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedSequence.js +6 -6
- package/dist/sharedSequence.js.map +1 -1
- package/dist/sharedString.d.ts +1 -1
- package/dist/sharedString.d.ts.map +1 -1
- package/dist/sharedString.js +7 -6
- package/dist/sharedString.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/defaultMap.d.ts +1 -1
- package/lib/defaultMap.d.ts.map +1 -1
- package/lib/defaultMap.js +6 -6
- package/lib/defaultMap.js.map +1 -1
- package/lib/defaultMapInterfaces.d.ts +21 -2
- 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 +1 -1
- package/lib/index.js.map +1 -1
- package/lib/intervalCollection.d.ts +140 -22
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +144 -50
- package/lib/intervalCollection.js.map +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.d.ts +13 -3
- package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.js +9 -7
- package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -1
- package/lib/intervalIndex/endpointIndex.d.ts +13 -2
- package/lib/intervalIndex/endpointIndex.d.ts.map +1 -1
- package/lib/intervalIndex/endpointIndex.js +7 -6
- package/lib/intervalIndex/endpointIndex.js.map +1 -1
- package/lib/intervalIndex/idIntervalIndex.js.map +1 -1
- package/lib/intervalIndex/index.d.ts +4 -4
- package/lib/intervalIndex/index.d.ts.map +1 -1
- package/lib/intervalIndex/index.js +4 -4
- package/lib/intervalIndex/index.js.map +1 -1
- package/lib/intervalIndex/intervalIndex.d.ts +2 -2
- package/lib/intervalIndex/intervalIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +8 -6
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js +12 -5
- package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.d.ts +2 -2
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +3 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.d.ts +13 -3
- package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.js +9 -9
- package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -1
- package/lib/intervalTree.d.ts +1 -1
- package/lib/intervalTree.d.ts.map +1 -1
- package/lib/intervals/interval.d.ts +4 -3
- package/lib/intervals/interval.d.ts.map +1 -1
- package/lib/intervals/interval.js +14 -6
- package/lib/intervals/interval.js.map +1 -1
- package/lib/intervals/intervalUtils.d.ts +42 -20
- package/lib/intervals/intervalUtils.d.ts.map +1 -1
- package/lib/intervals/intervalUtils.js +8 -6
- package/lib/intervals/intervalUtils.js.map +1 -1
- package/lib/intervals/sequenceInterval.d.ts +30 -17
- package/lib/intervals/sequenceInterval.d.ts.map +1 -1
- package/lib/intervals/sequenceInterval.js +125 -44
- package/lib/intervals/sequenceInterval.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/revertibles.d.ts +3 -15
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +6 -17
- package/lib/revertibles.js.map +1 -1
- package/lib/sequence.d.ts +3 -2
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +46 -45
- package/lib/sequence.js.map +1 -1
- package/lib/sequenceDeltaEvent.d.ts +8 -3
- package/lib/sequenceDeltaEvent.d.ts.map +1 -1
- package/lib/sequenceDeltaEvent.js.map +1 -1
- package/lib/sequenceFactory.js +1 -1
- package/lib/sequenceFactory.js.map +1 -1
- package/lib/sharedIntervalCollection.js +9 -9
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedSequence.js +6 -6
- package/lib/sharedSequence.js.map +1 -1
- package/lib/sharedString.d.ts +1 -1
- package/lib/sharedString.d.ts.map +1 -1
- package/lib/sharedString.js +7 -6
- package/lib/sharedString.js.map +1 -1
- package/package.json +49 -23
- package/src/defaultMapInterfaces.ts +21 -2
- package/src/index.ts +4 -1
- package/src/intervalCollection.ts +347 -84
- package/src/intervalIndex/endpointInRangeIndex.ts +19 -11
- package/src/intervalIndex/endpointIndex.ts +16 -9
- package/src/intervalIndex/idIntervalIndex.ts +1 -1
- package/src/intervalIndex/index.ts +12 -3
- package/src/intervalIndex/intervalIndex.ts +2 -2
- package/src/intervalIndex/overlappingIntervalsIndex.ts +31 -15
- package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +4 -1
- package/src/intervalIndex/sequenceIntervalIndexes.ts +1 -1
- package/src/intervalIndex/startpointInRangeIndex.ts +19 -17
- package/src/intervals/interval.ts +30 -8
- package/src/intervals/intervalUtils.ts +51 -28
- package/src/intervals/sequenceInterval.ts +197 -49
- package/src/packageVersion.ts +1 -1
- package/src/revertibles.ts +8 -33
- package/src/sequence.ts +5 -2
- package/src/sequenceDeltaEvent.ts +11 -3
- package/src/sequenceFactory.ts +1 -1
- package/src/sharedString.ts +2 -1
|
@@ -3,26 +3,46 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
/* eslint-disable no-bitwise */
|
|
6
|
+
/* eslint-disable import/no-deprecated */
|
|
6
7
|
import { TypedEventEmitter } from "@fluid-internal/client-utils";
|
|
7
8
|
import { assert } from "@fluidframework/core-utils";
|
|
8
|
-
import { addProperties, createMap, getSlideToSegoff, MergeTreeDeltaType, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, DetachedReferencePosition, } from "@fluidframework/merge-tree";
|
|
9
|
+
import { addProperties, createMap, getSlideToSegoff, MergeTreeDeltaType, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, DetachedReferencePosition, UniversalSequenceNumber, SlidingPreference, } from "@fluidframework/merge-tree";
|
|
9
10
|
import { LoggingError, UsageError } from "@fluidframework/telemetry-utils";
|
|
10
11
|
import { v4 as uuid } from "uuid";
|
|
11
12
|
import { IntervalOpType, IntervalStickiness, IntervalType, SequenceInterval, createPositionReferenceFromSegoff, endReferenceSlidingPreference, startReferenceSlidingPreference, sequenceIntervalHelpers, createInterval, } from "./intervals";
|
|
12
|
-
import {
|
|
13
|
+
import { EndpointIndex, OverlappingIntervalsIndex, createIdIntervalIndex, } from "./intervalIndex";
|
|
14
|
+
/**
|
|
15
|
+
* Defines a side relative to a character in a sequence.
|
|
16
|
+
*
|
|
17
|
+
* @remarks See {@link SequencePlace} for additional context on usage.
|
|
18
|
+
*/
|
|
19
|
+
export var Side;
|
|
20
|
+
(function (Side) {
|
|
21
|
+
Side[Side["Before"] = 0] = "Before";
|
|
22
|
+
Side[Side["After"] = 1] = "After";
|
|
23
|
+
})(Side || (Side = {}));
|
|
13
24
|
const reservedIntervalIdKey = "intervalId";
|
|
25
|
+
export function sidesFromStickiness(stickiness) {
|
|
26
|
+
const startSide = (stickiness & IntervalStickiness.START) !== 0 ? Side.After : Side.Before;
|
|
27
|
+
const endSide = (stickiness & IntervalStickiness.END) !== 0 ? Side.Before : Side.After;
|
|
28
|
+
return { startSide, endSide };
|
|
29
|
+
}
|
|
14
30
|
/**
|
|
15
31
|
* Decompress an interval after loading a summary from JSON. The exact format
|
|
16
32
|
* of this compression is unspecified and subject to change
|
|
17
33
|
*/
|
|
18
34
|
function decompressInterval(interval, label) {
|
|
35
|
+
const stickiness = interval[5] ?? IntervalStickiness.END;
|
|
36
|
+
const { startSide, endSide } = sidesFromStickiness(stickiness);
|
|
19
37
|
return {
|
|
20
38
|
start: interval[0],
|
|
21
39
|
end: interval[1],
|
|
22
40
|
sequenceNumber: interval[2],
|
|
23
41
|
intervalType: interval[3],
|
|
24
42
|
properties: { ...interval[4], [reservedRangeLabelsKey]: [label] },
|
|
25
|
-
stickiness
|
|
43
|
+
stickiness,
|
|
44
|
+
startSide,
|
|
45
|
+
endSide,
|
|
26
46
|
};
|
|
27
47
|
}
|
|
28
48
|
/**
|
|
@@ -31,7 +51,7 @@ function decompressInterval(interval, label) {
|
|
|
31
51
|
*/
|
|
32
52
|
function compressInterval(interval) {
|
|
33
53
|
const { start, end, sequenceNumber, intervalType, properties } = interval;
|
|
34
|
-
|
|
54
|
+
let base = [
|
|
35
55
|
start,
|
|
36
56
|
end,
|
|
37
57
|
sequenceNumber,
|
|
@@ -41,29 +61,60 @@ function compressInterval(interval) {
|
|
|
41
61
|
{ ...properties, [reservedRangeLabelsKey]: undefined },
|
|
42
62
|
];
|
|
43
63
|
if (interval.stickiness !== undefined && interval.stickiness !== IntervalStickiness.END) {
|
|
44
|
-
|
|
64
|
+
// reassignment to make it easier for typescript to reason about types
|
|
65
|
+
base = [...base, interval.stickiness];
|
|
45
66
|
}
|
|
46
67
|
return base;
|
|
47
68
|
}
|
|
69
|
+
export function endpointPosAndSide(start, end) {
|
|
70
|
+
const startIsPlainEndpoint = typeof start === "number" || start === "start" || start === "end";
|
|
71
|
+
const endIsPlainEndpoint = typeof end === "number" || end === "start" || end === "end";
|
|
72
|
+
const startSide = startIsPlainEndpoint ? Side.Before : start?.side;
|
|
73
|
+
const endSide = endIsPlainEndpoint ? Side.Before : end?.side;
|
|
74
|
+
const startPos = startIsPlainEndpoint ? start : start?.pos;
|
|
75
|
+
const endPos = endIsPlainEndpoint ? end : end?.pos;
|
|
76
|
+
return {
|
|
77
|
+
startSide,
|
|
78
|
+
endSide,
|
|
79
|
+
startPos,
|
|
80
|
+
endPos,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function toSequencePlace(pos, side) {
|
|
84
|
+
return typeof pos === "number" ? { pos, side } : pos;
|
|
85
|
+
}
|
|
86
|
+
function toOptionalSequencePlace(pos, side = Side.Before) {
|
|
87
|
+
return typeof pos === "number" ? { pos, side } : pos;
|
|
88
|
+
}
|
|
89
|
+
export function computeStickinessFromSide(startPos = -1, startSide = Side.Before, endPos = -1, endSide = Side.Before) {
|
|
90
|
+
let stickiness = IntervalStickiness.NONE;
|
|
91
|
+
if (startSide === Side.After || startPos === "start") {
|
|
92
|
+
stickiness |= IntervalStickiness.START;
|
|
93
|
+
}
|
|
94
|
+
if (endSide === Side.Before || endPos === "end") {
|
|
95
|
+
stickiness |= IntervalStickiness.END;
|
|
96
|
+
}
|
|
97
|
+
return stickiness;
|
|
98
|
+
}
|
|
48
99
|
export function createIntervalIndex() {
|
|
49
100
|
const helpers = {
|
|
50
|
-
compareEnds: (a, b) => a.end - b.end,
|
|
51
101
|
create: createInterval,
|
|
52
102
|
};
|
|
53
|
-
const lc = new LocalIntervalCollection(undefined, "", helpers);
|
|
103
|
+
const lc = new LocalIntervalCollection(undefined, "", helpers, {});
|
|
54
104
|
return lc;
|
|
55
105
|
}
|
|
56
106
|
export class LocalIntervalCollection {
|
|
57
|
-
constructor(client, label, helpers,
|
|
107
|
+
constructor(client, label, helpers, options,
|
|
58
108
|
/** Callback invoked each time one of the endpoints of an interval slides. */
|
|
59
109
|
onPositionChange) {
|
|
60
110
|
this.client = client;
|
|
61
111
|
this.label = label;
|
|
62
112
|
this.helpers = helpers;
|
|
113
|
+
this.options = options;
|
|
63
114
|
this.onPositionChange = onPositionChange;
|
|
64
|
-
this.overlappingIntervalsIndex =
|
|
115
|
+
this.overlappingIntervalsIndex = new OverlappingIntervalsIndex(client, helpers);
|
|
65
116
|
this.idIntervalIndex = createIdIntervalIndex();
|
|
66
|
-
this.endIntervalIndex =
|
|
117
|
+
this.endIntervalIndex = new EndpointIndex(client, helpers);
|
|
67
118
|
this.indexes = new Set([
|
|
68
119
|
this.overlappingIntervalsIndex,
|
|
69
120
|
this.idIntervalIndex,
|
|
@@ -117,12 +168,12 @@ export class LocalIntervalCollection {
|
|
|
117
168
|
this.removeIntervalFromIndexes(interval);
|
|
118
169
|
this.removeIntervalListeners(interval);
|
|
119
170
|
}
|
|
120
|
-
createInterval(start, end, intervalType, op
|
|
121
|
-
return this.helpers.create(this.label, start, end, this.client, intervalType, op, undefined,
|
|
171
|
+
createInterval(start, end, intervalType, op) {
|
|
172
|
+
return this.helpers.create(this.label, start, end, this.client, intervalType, op, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint);
|
|
122
173
|
}
|
|
123
|
-
addInterval(start, end, intervalType, props, op
|
|
174
|
+
addInterval(start, end, intervalType, props, op) {
|
|
124
175
|
var _a;
|
|
125
|
-
const interval = this.createInterval(start, end, intervalType, op
|
|
176
|
+
const interval = this.createInterval(start, end, intervalType, op);
|
|
126
177
|
if (interval) {
|
|
127
178
|
if (!interval.properties) {
|
|
128
179
|
interval.properties = createMap();
|
|
@@ -159,7 +210,7 @@ export class LocalIntervalCollection {
|
|
|
159
210
|
this.addIntervalListeners(interval);
|
|
160
211
|
}
|
|
161
212
|
changeInterval(interval, start, end, op, localSeq) {
|
|
162
|
-
const newInterval = interval.modify(this.label, start, end, op, localSeq);
|
|
213
|
+
const newInterval = interval.modify(this.label, start, end, op, localSeq, this.options.mergeTreeReferencesCanSlideToEndpoint);
|
|
163
214
|
if (newInterval) {
|
|
164
215
|
this.removeExistingInterval(interval);
|
|
165
216
|
this.add(newInterval);
|
|
@@ -182,7 +233,7 @@ export class LocalIntervalCollection {
|
|
|
182
233
|
// either, so this must be special-cased.
|
|
183
234
|
return ref;
|
|
184
235
|
}
|
|
185
|
-
return this.client.createLocalReferencePosition(segment, ref.getOffset(), ReferenceType.Transient, ref.properties, ref.slidingPreference);
|
|
236
|
+
return this.client.createLocalReferencePosition(segment, ref.getOffset(), ReferenceType.Transient, ref.properties, ref.slidingPreference, ref.canSlideToEndpoint);
|
|
186
237
|
};
|
|
187
238
|
if (interval instanceof SequenceInterval) {
|
|
188
239
|
let previousInterval;
|
|
@@ -239,7 +290,6 @@ SequenceIntervalCollectionValueType._ops = makeOpsMap();
|
|
|
239
290
|
class IntervalCollectionFactory {
|
|
240
291
|
load(emitter, raw = [], options) {
|
|
241
292
|
const helpers = {
|
|
242
|
-
compareEnds: (a, b) => a.end - b.end,
|
|
243
293
|
create: createInterval,
|
|
244
294
|
};
|
|
245
295
|
const collection = new IntervalCollection(helpers, false, emitter, raw, options);
|
|
@@ -340,6 +390,9 @@ class IntervalCollectionIterator {
|
|
|
340
390
|
* {@inheritdoc IIntervalCollection}
|
|
341
391
|
*/
|
|
342
392
|
export class IntervalCollection extends TypedEventEmitter {
|
|
393
|
+
get attached() {
|
|
394
|
+
return !!this.localCollection;
|
|
395
|
+
}
|
|
343
396
|
/** @internal */
|
|
344
397
|
constructor(helpers, requiresClient, emitter, serializedIntervals, options = {}) {
|
|
345
398
|
super();
|
|
@@ -355,9 +408,6 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
355
408
|
? serializedIntervals
|
|
356
409
|
: serializedIntervals.intervals.map((i) => decompressInterval(i, serializedIntervals.label));
|
|
357
410
|
}
|
|
358
|
-
get attached() {
|
|
359
|
-
return !!this.localCollection;
|
|
360
|
-
}
|
|
361
411
|
/**
|
|
362
412
|
* {@inheritdoc IIntervalCollection.attachIndex}
|
|
363
413
|
*/
|
|
@@ -390,6 +440,9 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
390
440
|
if (!this.client) {
|
|
391
441
|
throw new LoggingError("mergeTree client must exist");
|
|
392
442
|
}
|
|
443
|
+
if (pos === "start" || pos === "end") {
|
|
444
|
+
return pos;
|
|
445
|
+
}
|
|
393
446
|
const { clientId } = this.client.getCollabWindow();
|
|
394
447
|
const { segment, offset } = this.client.getContainingSegment(pos, {
|
|
395
448
|
referenceSequenceNumber: seqNumberFrom,
|
|
@@ -397,7 +450,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
397
450
|
}, localSeq);
|
|
398
451
|
// if segment is undefined, it slid off the string
|
|
399
452
|
assert(segment !== undefined, 0x54e /* No segment found */);
|
|
400
|
-
const segoff = getSlideToSegoff({ segment, offset }) ?? segment;
|
|
453
|
+
const segoff = getSlideToSegoff({ segment, offset }, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint) ?? segment;
|
|
401
454
|
// case happens when rebasing op, but concurrently entire string has been deleted
|
|
402
455
|
if (segoff.segment === undefined || segoff.offset === undefined) {
|
|
403
456
|
return DetachedReferencePosition;
|
|
@@ -436,12 +489,18 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
436
489
|
}
|
|
437
490
|
});
|
|
438
491
|
}
|
|
439
|
-
this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval, previousInterval) => this.emitChange(interval, previousInterval, true, true));
|
|
492
|
+
this.localCollection = new LocalIntervalCollection(client, label, this.helpers, this.options, (interval, previousInterval) => this.emitChange(interval, previousInterval, true, true));
|
|
440
493
|
if (this.savedSerializedIntervals) {
|
|
441
494
|
for (const serializedInterval of this.savedSerializedIntervals) {
|
|
442
495
|
this.localCollection.ensureSerializedId(serializedInterval);
|
|
443
|
-
const { start, end, intervalType, properties,
|
|
444
|
-
const
|
|
496
|
+
const { start: startPos, end: endPos, intervalType, properties, startSide, endSide, } = serializedInterval;
|
|
497
|
+
const start = typeof startPos === "number" && startSide !== undefined
|
|
498
|
+
? { pos: startPos, side: startSide }
|
|
499
|
+
: startPos;
|
|
500
|
+
const end = typeof endPos === "number" && endSide !== undefined
|
|
501
|
+
? { pos: endPos, side: endSide }
|
|
502
|
+
: endPos;
|
|
503
|
+
const interval = this.helpers.create(label, start, end, client, intervalType, undefined, true, this.options.mergeTreeReferencesCanSlideToEndpoint);
|
|
445
504
|
if (properties) {
|
|
446
505
|
interval.addProperties(properties);
|
|
447
506
|
}
|
|
@@ -487,28 +546,44 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
487
546
|
}
|
|
488
547
|
return this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
489
548
|
}
|
|
549
|
+
assertStickinessEnabled(start, end) {
|
|
550
|
+
if (!(typeof start === "number" && typeof end === "number") &&
|
|
551
|
+
!this.options.intervalStickinessEnabled) {
|
|
552
|
+
throw new UsageError("attempted to set interval stickiness without enabling `intervalStickinessEnabled` feature flag");
|
|
553
|
+
}
|
|
554
|
+
}
|
|
490
555
|
/**
|
|
491
556
|
* {@inheritdoc IIntervalCollection.add}
|
|
492
557
|
*/
|
|
493
|
-
add(start, end, intervalType, props
|
|
558
|
+
add(start, end, intervalType, props) {
|
|
494
559
|
if (!this.localCollection) {
|
|
495
560
|
throw new LoggingError("attach must be called prior to adding intervals");
|
|
496
561
|
}
|
|
497
562
|
if (intervalType & IntervalType.Transient) {
|
|
498
563
|
throw new LoggingError("Can not add transient intervals");
|
|
499
564
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
565
|
+
const { startSide, endSide, startPos, endPos } = endpointPosAndSide(start, end);
|
|
566
|
+
assert(startPos !== undefined &&
|
|
567
|
+
endPos !== undefined &&
|
|
568
|
+
startSide !== undefined &&
|
|
569
|
+
endSide !== undefined, 0x793 /* start and end cannot be undefined because they were not passed in as undefined */);
|
|
570
|
+
const stickiness = computeStickinessFromSide(startPos, startSide, endPos, endSide);
|
|
571
|
+
this.assertStickinessEnabled(start, end);
|
|
572
|
+
const interval = this.localCollection.addInterval(toSequencePlace(startPos, startSide), toSequencePlace(endPos, endSide), intervalType, props);
|
|
504
573
|
if (interval) {
|
|
574
|
+
if (!this.isCollaborating && interval instanceof SequenceInterval) {
|
|
575
|
+
setSlideOnRemove(interval.start);
|
|
576
|
+
setSlideOnRemove(interval.end);
|
|
577
|
+
}
|
|
505
578
|
const serializedInterval = {
|
|
506
|
-
|
|
579
|
+
start: startPos,
|
|
580
|
+
end: endPos,
|
|
507
581
|
intervalType,
|
|
508
582
|
properties: interval.properties,
|
|
509
583
|
sequenceNumber: this.client?.getCurrentSeq() ?? 0,
|
|
510
|
-
start,
|
|
511
584
|
stickiness,
|
|
585
|
+
startSide,
|
|
586
|
+
endSide,
|
|
512
587
|
};
|
|
513
588
|
const localSeq = this.getNextLocalSeq();
|
|
514
589
|
this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
|
|
@@ -572,8 +647,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
572
647
|
}
|
|
573
648
|
const interval = this.getIntervalById(id);
|
|
574
649
|
if (interval) {
|
|
575
|
-
|
|
576
|
-
const deltaProps = interval.addProperties(props, true, UnassignedSequenceNumber);
|
|
650
|
+
const deltaProps = interval.addProperties(props, true, this.isCollaborating ? UnassignedSequenceNumber : UniversalSequenceNumber);
|
|
577
651
|
const serializedInterval = interval.serialize();
|
|
578
652
|
// Emit a change op that will only change properties. Add the ID to
|
|
579
653
|
// the property bag provided by the caller.
|
|
@@ -604,9 +678,18 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
604
678
|
if (!newInterval) {
|
|
605
679
|
return undefined;
|
|
606
680
|
}
|
|
681
|
+
if (!this.isCollaborating && newInterval instanceof SequenceInterval) {
|
|
682
|
+
setSlideOnRemove(newInterval.start);
|
|
683
|
+
setSlideOnRemove(newInterval.end);
|
|
684
|
+
}
|
|
607
685
|
const serializedInterval = interval.serialize();
|
|
608
|
-
|
|
609
|
-
|
|
686
|
+
const { startPos, startSide, endPos, endSide } = endpointPosAndSide(start, end);
|
|
687
|
+
const stickiness = computeStickinessFromSide(startPos, startSide, endPos, endSide);
|
|
688
|
+
serializedInterval.start = startPos;
|
|
689
|
+
serializedInterval.end = endPos;
|
|
690
|
+
serializedInterval.startSide = startSide;
|
|
691
|
+
serializedInterval.endSide = endSide;
|
|
692
|
+
serializedInterval.stickiness = stickiness;
|
|
610
693
|
// Emit a property bag containing only the ID, as we don't intend for this op to change any properties.
|
|
611
694
|
serializedInterval.properties = {
|
|
612
695
|
[reservedIntervalIdKey]: interval.getIntervalId(),
|
|
@@ -621,7 +704,13 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
621
704
|
// No interval to change
|
|
622
705
|
return undefined;
|
|
623
706
|
}
|
|
707
|
+
get isCollaborating() {
|
|
708
|
+
return this.client?.getCollabWindow().collaborating ?? false;
|
|
709
|
+
}
|
|
624
710
|
addPendingChange(id, serializedInterval) {
|
|
711
|
+
if (!this.isCollaborating) {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
625
714
|
if (serializedInterval.start !== undefined) {
|
|
626
715
|
this.addPendingChangeHelper(id, this.pendingChangesStart, serializedInterval);
|
|
627
716
|
}
|
|
@@ -714,7 +803,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
714
803
|
// If changeInterval gives us a new interval, work with that one. Otherwise keep working with
|
|
715
804
|
// the one we originally found in the tree.
|
|
716
805
|
newInterval =
|
|
717
|
-
this.localCollection.changeInterval(interval, start, end, op) ?? interval;
|
|
806
|
+
this.localCollection.changeInterval(interval, toOptionalSequencePlace(start, serializedInterval.startSide), toOptionalSequencePlace(end, serializedInterval.endSide), op) ?? interval;
|
|
718
807
|
}
|
|
719
808
|
const deltaProps = newInterval.addProperties(newProps, true, op.sequenceNumber);
|
|
720
809
|
if (this.onDeserialize) {
|
|
@@ -759,7 +848,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
759
848
|
if (!this.attached) {
|
|
760
849
|
throw new LoggingError("attachSequence must be called");
|
|
761
850
|
}
|
|
762
|
-
const { intervalType, properties } = serializedInterval;
|
|
851
|
+
const { intervalType, properties, stickiness, startSide, endSide } = serializedInterval;
|
|
763
852
|
const { start: startRebased, end: endRebased } = this.localSeqToRebasedInterval.get(localSeq) ?? this.computeRebasedPositions(localSeq);
|
|
764
853
|
const intervalId = properties?.[reservedIntervalIdKey];
|
|
765
854
|
const localInterval = this.localCollection?.idIntervalIndex.getIntervalById(intervalId);
|
|
@@ -769,6 +858,9 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
769
858
|
intervalType,
|
|
770
859
|
sequenceNumber: this.client?.getCurrentSeq() ?? 0,
|
|
771
860
|
properties,
|
|
861
|
+
stickiness,
|
|
862
|
+
startSide,
|
|
863
|
+
endSide,
|
|
772
864
|
};
|
|
773
865
|
if (opName === "change" &&
|
|
774
866
|
(this.hasPendingChangeStart(intervalId) || this.hasPendingChangeEnd(intervalId))) {
|
|
@@ -788,7 +880,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
788
880
|
assert(localInterval instanceof SequenceInterval, 0x3a0 /* localInterval must be `SequenceInterval` when used with client */);
|
|
789
881
|
// The rebased op may place this interval's endpoints on different segments. Calling `changeInterval` here
|
|
790
882
|
// updates the local client's state to be consistent with the emitted op.
|
|
791
|
-
this.localCollection?.changeInterval(localInterval, startRebased, endRebased, undefined, localSeq);
|
|
883
|
+
this.localCollection?.changeInterval(localInterval, toOptionalSequencePlace(startRebased, startSide), toOptionalSequencePlace(endRebased, endSide), undefined, localSeq);
|
|
792
884
|
}
|
|
793
885
|
return rebased;
|
|
794
886
|
}
|
|
@@ -800,18 +892,12 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
800
892
|
if (segoff.segment?.localRefs?.has(lref) !== true) {
|
|
801
893
|
return undefined;
|
|
802
894
|
}
|
|
803
|
-
const newSegoff = getSlideToSegoff(segoff);
|
|
895
|
+
const newSegoff = getSlideToSegoff(segoff, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint);
|
|
804
896
|
const value = segoff.segment === newSegoff.segment && segoff.offset === newSegoff.offset
|
|
805
897
|
? undefined
|
|
806
898
|
: newSegoff;
|
|
807
899
|
return value;
|
|
808
900
|
}
|
|
809
|
-
setSlideOnRemove(lref) {
|
|
810
|
-
let refType = lref.refType;
|
|
811
|
-
refType = refType & ~ReferenceType.StayOnRemove;
|
|
812
|
-
refType = refType | ReferenceType.SlideOnRemove;
|
|
813
|
-
lref.refType = refType;
|
|
814
|
-
}
|
|
815
901
|
ackInterval(interval, op) {
|
|
816
902
|
// Only SequenceIntervals need potential sliding
|
|
817
903
|
if (!(interval instanceof SequenceInterval)) {
|
|
@@ -827,10 +913,10 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
827
913
|
const hasPendingStartChange = this.hasPendingChangeStart(id);
|
|
828
914
|
const hasPendingEndChange = this.hasPendingChangeEnd(id);
|
|
829
915
|
if (!hasPendingStartChange) {
|
|
830
|
-
|
|
916
|
+
setSlideOnRemove(interval.start);
|
|
831
917
|
}
|
|
832
918
|
if (!hasPendingEndChange) {
|
|
833
|
-
|
|
919
|
+
setSlideOnRemove(interval.end);
|
|
834
920
|
}
|
|
835
921
|
const needsStartUpdate = newStart !== undefined && !hasPendingStartChange;
|
|
836
922
|
const needsEndUpdate = newEnd !== undefined && !hasPendingEndChange;
|
|
@@ -849,7 +935,8 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
849
935
|
}
|
|
850
936
|
if (needsStartUpdate) {
|
|
851
937
|
const props = interval.start.properties;
|
|
852
|
-
interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op, startReferenceSlidingPreference(interval.stickiness))
|
|
938
|
+
interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op, undefined, undefined, startReferenceSlidingPreference(interval.stickiness), startReferenceSlidingPreference(interval.stickiness) ===
|
|
939
|
+
SlidingPreference.BACKWARD);
|
|
853
940
|
if (props) {
|
|
854
941
|
interval.start.addProperties(props);
|
|
855
942
|
}
|
|
@@ -861,7 +948,8 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
861
948
|
}
|
|
862
949
|
if (needsEndUpdate) {
|
|
863
950
|
const props = interval.end.properties;
|
|
864
|
-
interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op, endReferenceSlidingPreference(interval.stickiness))
|
|
951
|
+
interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op, undefined, undefined, endReferenceSlidingPreference(interval.stickiness), endReferenceSlidingPreference(interval.stickiness) ===
|
|
952
|
+
SlidingPreference.FORWARD);
|
|
865
953
|
if (props) {
|
|
866
954
|
interval.end.addProperties(props);
|
|
867
955
|
}
|
|
@@ -891,7 +979,7 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
891
979
|
throw new LoggingError("attachSequence must be called");
|
|
892
980
|
}
|
|
893
981
|
this.localCollection.ensureSerializedId(serializedInterval);
|
|
894
|
-
const interval = this.localCollection.addInterval(serializedInterval.start, serializedInterval.end, serializedInterval.intervalType, serializedInterval.properties, op
|
|
982
|
+
const interval = this.localCollection.addInterval(toSequencePlace(serializedInterval.start, serializedInterval.startSide ?? Side.Before), toSequencePlace(serializedInterval.end, serializedInterval.endSide ?? Side.Before), serializedInterval.intervalType, serializedInterval.properties, op);
|
|
895
983
|
if (interval) {
|
|
896
984
|
if (this.onDeserialize) {
|
|
897
985
|
this.onDeserialize(interval);
|
|
@@ -1009,6 +1097,12 @@ export class IntervalCollection extends TypedEventEmitter {
|
|
|
1009
1097
|
return this.localCollection.endIntervalIndex.nextInterval(pos);
|
|
1010
1098
|
}
|
|
1011
1099
|
}
|
|
1100
|
+
function setSlideOnRemove(lref) {
|
|
1101
|
+
let refType = lref.refType;
|
|
1102
|
+
refType = refType & ~ReferenceType.StayOnRemove;
|
|
1103
|
+
refType = refType | ReferenceType.SlideOnRemove;
|
|
1104
|
+
lref.refType = refType;
|
|
1105
|
+
}
|
|
1012
1106
|
/**
|
|
1013
1107
|
* Returns an object that can be used to find the interval a given LocalReferencePosition belongs to.
|
|
1014
1108
|
* @returns undefined if the reference position is not the endpoint of any interval (e.g. it was created
|