@fluidframework/sequence 2.0.0-dev.5.3.2.178189 → 2.0.0-dev.6.4.0.191457
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 +114 -0
- package/README.md +4 -3
- package/dist/defaultMap.d.ts +1 -1
- package/dist/defaultMap.d.ts.map +1 -1
- package/dist/defaultMap.js +9 -10
- package/dist/defaultMap.js.map +1 -1
- package/dist/defaultMapInterfaces.d.ts +1 -1
- package/dist/defaultMapInterfaces.d.ts.map +1 -1
- package/dist/defaultMapInterfaces.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/intervalCollection.d.ts +11 -424
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +74 -815
- package/dist/intervalCollection.js.map +1 -1
- package/dist/intervalIndex/endpointInRangeIndex.d.ts +20 -0
- package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
- package/dist/intervalIndex/endpointInRangeIndex.js +60 -0
- package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -0
- package/dist/intervalIndex/endpointIndex.d.ts +21 -0
- package/dist/intervalIndex/endpointIndex.d.ts.map +1 -0
- package/dist/intervalIndex/endpointIndex.js +42 -0
- package/dist/intervalIndex/endpointIndex.js.map +1 -0
- package/dist/intervalIndex/idIntervalIndex.d.ts +12 -0
- package/dist/intervalIndex/idIntervalIndex.d.ts.map +1 -0
- package/dist/intervalIndex/idIntervalIndex.js +41 -0
- package/dist/intervalIndex/idIntervalIndex.js.map +1 -0
- package/dist/intervalIndex/index.d.ts +5 -0
- package/dist/intervalIndex/index.d.ts.map +1 -1
- package/dist/intervalIndex/index.js +9 -1
- package/dist/intervalIndex/index.js.map +1 -1
- package/dist/intervalIndex/intervalIndex.d.ts +29 -0
- package/dist/intervalIndex/intervalIndex.d.ts.map +1 -0
- package/dist/intervalIndex/intervalIndex.js +7 -0
- package/dist/intervalIndex/intervalIndex.js.map +1 -0
- package/dist/intervalIndex/intervalIndexUtils.d.ts +17 -0
- package/dist/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
- package/dist/intervalIndex/intervalIndexUtils.js +22 -0
- package/dist/intervalIndex/intervalIndexUtils.js.map +1 -0
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.js +3 -3
- package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +5 -5
- 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 +20 -0
- package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
- package/dist/intervalIndex/startpointInRangeIndex.js +62 -0
- package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -0
- package/dist/intervalTree.d.ts +2 -56
- package/dist/intervalTree.d.ts.map +1 -1
- package/dist/intervalTree.js +2 -11
- package/dist/intervalTree.js.map +1 -1
- package/dist/intervals/index.d.ts +8 -0
- package/dist/intervals/index.d.ts.map +1 -0
- package/dist/intervals/index.js +23 -0
- package/dist/intervals/index.js.map +1 -0
- package/dist/intervals/interval.d.ts +88 -0
- package/dist/intervals/interval.d.ts.map +1 -0
- package/dist/intervals/interval.js +180 -0
- package/dist/intervals/interval.js.map +1 -0
- package/dist/intervals/intervalUtils.d.ts +200 -0
- package/dist/intervals/intervalUtils.d.ts.map +1 -0
- package/dist/intervals/intervalUtils.js +79 -0
- package/dist/intervals/intervalUtils.js.map +1 -0
- package/dist/intervals/sequenceInterval.d.ts +132 -0
- package/dist/intervals/sequenceInterval.d.ts.map +1 -0
- package/dist/intervals/sequenceInterval.js +313 -0
- package/dist/intervals/sequenceInterval.js.map +1 -0
- 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 +1 -1
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +45 -52
- package/dist/revertibles.js.map +1 -1
- package/dist/sequence.d.ts +33 -4
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +91 -47
- 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 +3 -4
- package/dist/sequenceDeltaEvent.js.map +1 -1
- package/dist/sharedIntervalCollection.d.ts +2 -1
- package/dist/sharedIntervalCollection.d.ts.map +1 -1
- package/dist/sharedIntervalCollection.js +2 -2
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedSequence.d.ts +9 -0
- package/dist/sharedSequence.d.ts.map +1 -1
- package/dist/sharedSequence.js +9 -6
- package/dist/sharedSequence.js.map +1 -1
- package/dist/sharedString.d.ts.map +1 -1
- package/dist/sharedString.js +9 -29
- package/dist/sharedString.js.map +1 -1
- package/lib/defaultMap.d.ts +1 -1
- package/lib/defaultMap.d.ts.map +1 -1
- package/lib/defaultMap.js +5 -6
- package/lib/defaultMap.js.map +1 -1
- package/lib/defaultMapInterfaces.d.ts +1 -1
- package/lib/defaultMapInterfaces.d.ts.map +1 -1
- package/lib/defaultMapInterfaces.js.map +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/intervalCollection.d.ts +11 -424
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +43 -776
- package/lib/intervalCollection.js.map +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.d.ts +20 -0
- package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
- package/lib/intervalIndex/endpointInRangeIndex.js +56 -0
- package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -0
- package/lib/intervalIndex/endpointIndex.d.ts +21 -0
- package/lib/intervalIndex/endpointIndex.d.ts.map +1 -0
- package/lib/intervalIndex/endpointIndex.js +38 -0
- package/lib/intervalIndex/endpointIndex.js.map +1 -0
- package/lib/intervalIndex/idIntervalIndex.d.ts +12 -0
- package/lib/intervalIndex/idIntervalIndex.d.ts.map +1 -0
- package/lib/intervalIndex/idIntervalIndex.js +37 -0
- package/lib/intervalIndex/idIntervalIndex.js.map +1 -0
- package/lib/intervalIndex/index.d.ts +5 -0
- package/lib/intervalIndex/index.d.ts.map +1 -1
- package/lib/intervalIndex/index.js +4 -0
- package/lib/intervalIndex/index.js.map +1 -1
- package/lib/intervalIndex/intervalIndex.d.ts +29 -0
- package/lib/intervalIndex/intervalIndex.d.ts.map +1 -0
- package/lib/intervalIndex/intervalIndex.js +6 -0
- package/lib/intervalIndex/intervalIndex.js.map +1 -0
- package/lib/intervalIndex/intervalIndexUtils.d.ts +17 -0
- package/lib/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
- package/lib/intervalIndex/intervalIndexUtils.js +18 -0
- package/lib/intervalIndex/intervalIndexUtils.js.map +1 -0
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +1 -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 +20 -0
- package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
- package/lib/intervalIndex/startpointInRangeIndex.js +58 -0
- package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -0
- package/lib/intervalTree.d.ts +2 -56
- package/lib/intervalTree.d.ts.map +1 -1
- package/lib/intervalTree.js +2 -11
- package/lib/intervalTree.js.map +1 -1
- package/lib/intervals/index.d.ts +8 -0
- package/lib/intervals/index.d.ts.map +1 -0
- package/lib/intervals/index.js +8 -0
- package/lib/intervals/index.js.map +1 -0
- package/lib/intervals/interval.d.ts +88 -0
- package/lib/intervals/interval.d.ts.map +1 -0
- package/lib/intervals/interval.js +175 -0
- package/lib/intervals/interval.js.map +1 -0
- package/lib/intervals/intervalUtils.d.ts +200 -0
- package/lib/intervals/intervalUtils.d.ts.map +1 -0
- package/lib/intervals/intervalUtils.js +74 -0
- package/lib/intervals/intervalUtils.js.map +1 -0
- package/lib/intervals/sequenceInterval.d.ts +132 -0
- package/lib/intervals/sequenceInterval.d.ts.map +1 -0
- package/lib/intervals/sequenceInterval.js +305 -0
- package/lib/intervals/sequenceInterval.js.map +1 -0
- 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 +1 -1
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +28 -35
- package/lib/revertibles.js.map +1 -1
- package/lib/sequence.d.ts +33 -4
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +86 -41
- 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 +2 -3
- package/lib/sequenceDeltaEvent.js.map +1 -1
- package/lib/sharedIntervalCollection.d.ts +2 -1
- package/lib/sharedIntervalCollection.d.ts.map +1 -1
- package/lib/sharedIntervalCollection.js +1 -1
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedSequence.d.ts +9 -0
- package/lib/sharedSequence.d.ts.map +1 -1
- package/lib/sharedSequence.js +8 -5
- package/lib/sharedSequence.js.map +1 -1
- package/lib/sharedString.d.ts.map +1 -1
- package/lib/sharedString.js +9 -29
- package/lib/sharedString.js.map +1 -1
- package/package.json +29 -32
- package/src/defaultMap.ts +2 -1
- package/src/defaultMapInterfaces.ts +1 -1
- package/src/index.ts +18 -12
- package/src/intervalCollection.ts +42 -1225
- package/src/intervalIndex/endpointInRangeIndex.ts +104 -0
- package/src/intervalIndex/endpointIndex.ts +78 -0
- package/src/intervalIndex/idIntervalIndex.ts +58 -0
- package/src/intervalIndex/index.ts +5 -0
- package/src/intervalIndex/intervalIndex.ts +31 -0
- package/src/intervalIndex/intervalIndexUtils.ts +27 -0
- package/src/intervalIndex/overlappingIntervalsIndex.ts +2 -6
- package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +1 -1
- package/src/intervalIndex/sequenceIntervalIndexes.ts +1 -1
- package/src/intervalIndex/startpointInRangeIndex.ts +109 -0
- package/src/intervalTree.ts +3 -75
- package/src/intervals/index.ts +25 -0
- package/src/intervals/interval.ts +230 -0
- package/src/intervals/intervalUtils.ts +256 -0
- package/src/intervals/sequenceInterval.ts +494 -0
- package/src/packageVersion.ts +1 -1
- package/src/revertibles.ts +24 -13
- package/src/sequence.ts +100 -35
- package/src/sequenceDeltaEvent.ts +12 -4
- package/src/sharedIntervalCollection.ts +2 -3
- package/src/sharedSequence.ts +11 -5
- package/src/sharedString.ts +8 -25
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* eslint-disable no-bitwise */
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
Client,
|
|
10
|
+
ICombiningOp,
|
|
11
|
+
ISegment,
|
|
12
|
+
LocalReferencePosition,
|
|
13
|
+
PropertiesManager,
|
|
14
|
+
PropertySet,
|
|
15
|
+
ReferenceType,
|
|
16
|
+
SlidingPreference,
|
|
17
|
+
compareReferencePositions,
|
|
18
|
+
createDetachedLocalReferencePosition,
|
|
19
|
+
createMap,
|
|
20
|
+
getSlideToSegoff,
|
|
21
|
+
maxReferencePosition,
|
|
22
|
+
minReferencePosition,
|
|
23
|
+
refTypeIncludesFlag,
|
|
24
|
+
reservedRangeLabelsKey,
|
|
25
|
+
} from "@fluidframework/merge-tree";
|
|
26
|
+
import { assert } from "@fluidframework/core-utils";
|
|
27
|
+
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
|
28
|
+
import { UsageError } from "@fluidframework/telemetry-utils";
|
|
29
|
+
import {
|
|
30
|
+
IIntervalHelpers,
|
|
31
|
+
ISerializableInterval,
|
|
32
|
+
ISerializedInterval,
|
|
33
|
+
IntervalStickiness,
|
|
34
|
+
IntervalType,
|
|
35
|
+
endReferenceSlidingPreference,
|
|
36
|
+
startReferenceSlidingPreference,
|
|
37
|
+
} from "./intervalUtils";
|
|
38
|
+
|
|
39
|
+
const reservedIntervalIdKey = "intervalId";
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Interval implementation whose ends are associated with positions in a mutatable sequence.
|
|
43
|
+
* As such, when content is inserted into the middle of the interval, the interval expands to
|
|
44
|
+
* include that content.
|
|
45
|
+
*
|
|
46
|
+
* @remarks The endpoint's position should be treated exclusively to get reasonable behavior--i.e.
|
|
47
|
+
* an interval referring to "hello" in "hello world" should have a start position of 0 and an end
|
|
48
|
+
* position of 5.
|
|
49
|
+
*
|
|
50
|
+
* To see why, consider what happens if "llo wor" is removed from the string to make "held".
|
|
51
|
+
* The interval's startpoint remains on the "h" (it isn't altered), but the interval's endpoint
|
|
52
|
+
* slides forward to the next unremoved position, which is the "l" in "held".
|
|
53
|
+
* Users would generally expect the interval to now refer to "he" (as it is the subset of content
|
|
54
|
+
* remaining after the removal), hence the "l" should be excluded.
|
|
55
|
+
* If the interval endpoint was treated inclusively, the interval would now refer to "hel", which
|
|
56
|
+
* is undesirable.
|
|
57
|
+
*
|
|
58
|
+
* Since the end of an interval is treated exclusively but cannot be greater than or equal to the
|
|
59
|
+
* length of the associated sequence, application models which leverage interval collections should
|
|
60
|
+
* consider inserting a marker at the end of the sequence to represent the end of the content.
|
|
61
|
+
*/
|
|
62
|
+
export class SequenceInterval implements ISerializableInterval {
|
|
63
|
+
/**
|
|
64
|
+
* {@inheritDoc ISerializableInterval.properties}
|
|
65
|
+
*/
|
|
66
|
+
public properties: PropertySet;
|
|
67
|
+
/**
|
|
68
|
+
* {@inheritDoc ISerializableInterval.propertyManager}
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
public propertyManager: PropertiesManager;
|
|
72
|
+
|
|
73
|
+
constructor(
|
|
74
|
+
private readonly client: Client,
|
|
75
|
+
/**
|
|
76
|
+
* Start endpoint of this interval.
|
|
77
|
+
* @remarks This endpoint can be resolved into a character position using the SharedString it's a part of.
|
|
78
|
+
*/
|
|
79
|
+
public start: LocalReferencePosition,
|
|
80
|
+
/**
|
|
81
|
+
* End endpoint of this interval.
|
|
82
|
+
* @remarks This endpoint can be resolved into a character position using the SharedString it's a part of.
|
|
83
|
+
*/
|
|
84
|
+
public end: LocalReferencePosition,
|
|
85
|
+
public intervalType: IntervalType,
|
|
86
|
+
props?: PropertySet,
|
|
87
|
+
public readonly stickiness: IntervalStickiness = IntervalStickiness.END,
|
|
88
|
+
) {
|
|
89
|
+
this.propertyManager = new PropertiesManager();
|
|
90
|
+
this.properties = {};
|
|
91
|
+
|
|
92
|
+
if (props) {
|
|
93
|
+
this.addProperties(props);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private callbacks?: Record<"beforePositionChange" | "afterPositionChange", () => void>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Subscribes to position change events on this interval if there are no current listeners.
|
|
101
|
+
* @internal
|
|
102
|
+
*/
|
|
103
|
+
public addPositionChangeListeners(
|
|
104
|
+
beforePositionChange: () => void,
|
|
105
|
+
afterPositionChange: () => void,
|
|
106
|
+
): void {
|
|
107
|
+
if (this.callbacks === undefined) {
|
|
108
|
+
this.callbacks = {
|
|
109
|
+
beforePositionChange,
|
|
110
|
+
afterPositionChange,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const startCbs = (this.start.callbacks ??= {});
|
|
114
|
+
const endCbs = (this.end.callbacks ??= {});
|
|
115
|
+
startCbs.beforeSlide = endCbs.beforeSlide = beforePositionChange;
|
|
116
|
+
startCbs.afterSlide = endCbs.afterSlide = afterPositionChange;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Removes the currently subscribed position change listeners.
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
public removePositionChangeListeners(): void {
|
|
125
|
+
if (this.callbacks) {
|
|
126
|
+
this.callbacks = undefined;
|
|
127
|
+
this.start.callbacks = undefined;
|
|
128
|
+
this.end.callbacks = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* {@inheritDoc ISerializableInterval.serialize}
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
public serialize(): ISerializedInterval {
|
|
137
|
+
const startPosition = this.client.localReferencePositionToPosition(this.start);
|
|
138
|
+
const endPosition = this.client.localReferencePositionToPosition(this.end);
|
|
139
|
+
const serializedInterval: ISerializedInterval = {
|
|
140
|
+
end: endPosition,
|
|
141
|
+
intervalType: this.intervalType,
|
|
142
|
+
sequenceNumber: this.client.getCurrentSeq(),
|
|
143
|
+
start: startPosition,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (this.properties) {
|
|
147
|
+
serializedInterval.properties = this.properties;
|
|
148
|
+
}
|
|
149
|
+
if (this.stickiness !== IntervalStickiness.END) {
|
|
150
|
+
serializedInterval.stickiness = this.stickiness;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return serializedInterval;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* {@inheritDoc IInterval.clone}
|
|
158
|
+
*/
|
|
159
|
+
public clone() {
|
|
160
|
+
return new SequenceInterval(
|
|
161
|
+
this.client,
|
|
162
|
+
this.start,
|
|
163
|
+
this.end,
|
|
164
|
+
this.intervalType,
|
|
165
|
+
this.properties,
|
|
166
|
+
this.stickiness,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* {@inheritDoc IInterval.compare}
|
|
172
|
+
*/
|
|
173
|
+
public compare(b: SequenceInterval) {
|
|
174
|
+
const startResult = this.compareStart(b);
|
|
175
|
+
if (startResult === 0) {
|
|
176
|
+
const endResult = this.compareEnd(b);
|
|
177
|
+
if (endResult === 0) {
|
|
178
|
+
const thisId = this.getIntervalId();
|
|
179
|
+
if (thisId) {
|
|
180
|
+
const bId = b.getIntervalId();
|
|
181
|
+
if (bId) {
|
|
182
|
+
return thisId > bId ? 1 : thisId < bId ? -1 : 0;
|
|
183
|
+
}
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
return 0;
|
|
187
|
+
} else {
|
|
188
|
+
return endResult;
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
return startResult;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* {@inheritDoc IInterval.compareStart}
|
|
197
|
+
*/
|
|
198
|
+
public compareStart(b: SequenceInterval) {
|
|
199
|
+
return compareReferencePositions(this.start, b.start);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* {@inheritDoc IInterval.compareEnd}
|
|
204
|
+
*/
|
|
205
|
+
public compareEnd(b: SequenceInterval) {
|
|
206
|
+
return compareReferencePositions(this.end, b.end);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* {@inheritDoc IInterval.overlaps}
|
|
211
|
+
*/
|
|
212
|
+
public overlaps(b: SequenceInterval) {
|
|
213
|
+
const result =
|
|
214
|
+
compareReferencePositions(this.start, b.end) <= 0 &&
|
|
215
|
+
compareReferencePositions(this.end, b.start) >= 0;
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* {@inheritDoc ISerializableInterval.getIntervalId}
|
|
221
|
+
*/
|
|
222
|
+
public getIntervalId(): string {
|
|
223
|
+
const id = this.properties?.[reservedIntervalIdKey];
|
|
224
|
+
assert(id !== undefined, 0x5e2 /* interval ID should not be undefined */);
|
|
225
|
+
return `${id}`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* {@inheritDoc IInterval.union}
|
|
230
|
+
* @internal
|
|
231
|
+
*/
|
|
232
|
+
public union(b: SequenceInterval) {
|
|
233
|
+
return new SequenceInterval(
|
|
234
|
+
this.client,
|
|
235
|
+
minReferencePosition(this.start, b.start),
|
|
236
|
+
maxReferencePosition(this.end, b.end),
|
|
237
|
+
this.intervalType,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* {@inheritDoc ISerializableInterval.addProperties}
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
public addProperties(
|
|
246
|
+
newProps: PropertySet,
|
|
247
|
+
collab: boolean = false,
|
|
248
|
+
seq?: number,
|
|
249
|
+
op?: ICombiningOp,
|
|
250
|
+
): PropertySet | undefined {
|
|
251
|
+
this.initializeProperties();
|
|
252
|
+
return this.propertyManager.addProperties(this.properties, newProps, op, seq, collab);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @returns whether this interval overlaps two numerical positions.
|
|
257
|
+
*/
|
|
258
|
+
public overlapsPos(bstart: number, bend: number) {
|
|
259
|
+
const startPos = this.client.localReferencePositionToPosition(this.start);
|
|
260
|
+
const endPos = this.client.localReferencePositionToPosition(this.end);
|
|
261
|
+
return endPos > bstart && startPos < bend;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* {@inheritDoc IInterval.modify}
|
|
266
|
+
* @internal
|
|
267
|
+
*/
|
|
268
|
+
public modify(
|
|
269
|
+
label: string,
|
|
270
|
+
start: number,
|
|
271
|
+
end: number,
|
|
272
|
+
op?: ISequencedDocumentMessage,
|
|
273
|
+
localSeq?: number,
|
|
274
|
+
stickiness: IntervalStickiness = IntervalStickiness.END,
|
|
275
|
+
) {
|
|
276
|
+
const getRefType = (baseType: ReferenceType): ReferenceType => {
|
|
277
|
+
let refType = baseType;
|
|
278
|
+
if (op === undefined) {
|
|
279
|
+
refType &= ~ReferenceType.SlideOnRemove;
|
|
280
|
+
refType |= ReferenceType.StayOnRemove;
|
|
281
|
+
}
|
|
282
|
+
return refType;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
let startRef = this.start;
|
|
286
|
+
if (start !== undefined) {
|
|
287
|
+
startRef = createPositionReference(
|
|
288
|
+
this.client,
|
|
289
|
+
start,
|
|
290
|
+
getRefType(this.start.refType),
|
|
291
|
+
op,
|
|
292
|
+
undefined,
|
|
293
|
+
localSeq,
|
|
294
|
+
startReferenceSlidingPreference(stickiness),
|
|
295
|
+
);
|
|
296
|
+
if (this.start.properties) {
|
|
297
|
+
startRef.addProperties(this.start.properties);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let endRef = this.end;
|
|
302
|
+
if (end !== undefined) {
|
|
303
|
+
endRef = createPositionReference(
|
|
304
|
+
this.client,
|
|
305
|
+
end,
|
|
306
|
+
getRefType(this.end.refType),
|
|
307
|
+
op,
|
|
308
|
+
undefined,
|
|
309
|
+
localSeq,
|
|
310
|
+
endReferenceSlidingPreference(stickiness),
|
|
311
|
+
);
|
|
312
|
+
if (this.end.properties) {
|
|
313
|
+
endRef.addProperties(this.end.properties);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const newInterval = new SequenceInterval(this.client, startRef, endRef, this.intervalType);
|
|
318
|
+
if (this.properties) {
|
|
319
|
+
newInterval.initializeProperties();
|
|
320
|
+
this.propertyManager.copyTo(
|
|
321
|
+
this.properties,
|
|
322
|
+
newInterval.properties,
|
|
323
|
+
newInterval.propertyManager,
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
return newInterval;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private initializeProperties(): void {
|
|
330
|
+
if (!this.propertyManager) {
|
|
331
|
+
this.propertyManager = new PropertiesManager();
|
|
332
|
+
}
|
|
333
|
+
if (!this.properties) {
|
|
334
|
+
this.properties = createMap<any>();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function createPositionReferenceFromSegoff(
|
|
340
|
+
client: Client,
|
|
341
|
+
segoff: { segment: ISegment | undefined; offset: number | undefined },
|
|
342
|
+
refType: ReferenceType,
|
|
343
|
+
op?: ISequencedDocumentMessage,
|
|
344
|
+
localSeq?: number,
|
|
345
|
+
fromSnapshot?: boolean,
|
|
346
|
+
slidingPreference?: SlidingPreference,
|
|
347
|
+
): LocalReferencePosition {
|
|
348
|
+
if (segoff.segment) {
|
|
349
|
+
const ref = client.createLocalReferencePosition(
|
|
350
|
+
segoff.segment,
|
|
351
|
+
segoff.offset,
|
|
352
|
+
refType,
|
|
353
|
+
undefined,
|
|
354
|
+
slidingPreference,
|
|
355
|
+
);
|
|
356
|
+
return ref;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Creating references on detached segments is allowed for:
|
|
360
|
+
// - Transient segments
|
|
361
|
+
// - References coming from a remote client (location may have been concurrently removed)
|
|
362
|
+
// - References being rebased to a new sequence number
|
|
363
|
+
// (segment they originally referred to may have been removed with no suitable replacement)
|
|
364
|
+
if (
|
|
365
|
+
!op &&
|
|
366
|
+
!localSeq &&
|
|
367
|
+
!fromSnapshot &&
|
|
368
|
+
!refTypeIncludesFlag(refType, ReferenceType.Transient)
|
|
369
|
+
) {
|
|
370
|
+
throw new UsageError("Non-transient references need segment");
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return createDetachedLocalReferencePosition(refType);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function createPositionReference(
|
|
377
|
+
client: Client,
|
|
378
|
+
pos: number,
|
|
379
|
+
refType: ReferenceType,
|
|
380
|
+
op?: ISequencedDocumentMessage,
|
|
381
|
+
fromSnapshot?: boolean,
|
|
382
|
+
localSeq?: number,
|
|
383
|
+
slidingPreference?: SlidingPreference,
|
|
384
|
+
): LocalReferencePosition {
|
|
385
|
+
let segoff;
|
|
386
|
+
if (op) {
|
|
387
|
+
assert(
|
|
388
|
+
(refType & ReferenceType.SlideOnRemove) !== 0,
|
|
389
|
+
0x2f5 /* op create references must be SlideOnRemove */,
|
|
390
|
+
);
|
|
391
|
+
segoff = client.getContainingSegment(pos, {
|
|
392
|
+
referenceSequenceNumber: op.referenceSequenceNumber,
|
|
393
|
+
clientId: op.clientId,
|
|
394
|
+
});
|
|
395
|
+
segoff = getSlideToSegoff(segoff);
|
|
396
|
+
} else {
|
|
397
|
+
assert(
|
|
398
|
+
(refType & ReferenceType.SlideOnRemove) === 0 || !!fromSnapshot,
|
|
399
|
+
0x2f6 /* SlideOnRemove references must be op created */,
|
|
400
|
+
);
|
|
401
|
+
segoff = client.getContainingSegment(pos, undefined, localSeq);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return createPositionReferenceFromSegoff(
|
|
405
|
+
client,
|
|
406
|
+
segoff,
|
|
407
|
+
refType,
|
|
408
|
+
op,
|
|
409
|
+
localSeq,
|
|
410
|
+
fromSnapshot,
|
|
411
|
+
slidingPreference,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export function createSequenceInterval(
|
|
416
|
+
label: string,
|
|
417
|
+
start: number,
|
|
418
|
+
end: number,
|
|
419
|
+
client: Client,
|
|
420
|
+
intervalType: IntervalType,
|
|
421
|
+
op?: ISequencedDocumentMessage,
|
|
422
|
+
fromSnapshot?: boolean,
|
|
423
|
+
stickiness: IntervalStickiness = IntervalStickiness.END,
|
|
424
|
+
): SequenceInterval {
|
|
425
|
+
let beginRefType = ReferenceType.RangeBegin;
|
|
426
|
+
let endRefType = ReferenceType.RangeEnd;
|
|
427
|
+
if (intervalType === IntervalType.Transient) {
|
|
428
|
+
beginRefType = ReferenceType.Transient;
|
|
429
|
+
endRefType = ReferenceType.Transient;
|
|
430
|
+
} else {
|
|
431
|
+
if (intervalType === IntervalType.Nest) {
|
|
432
|
+
beginRefType = ReferenceType.NestBegin;
|
|
433
|
+
endRefType = ReferenceType.NestEnd;
|
|
434
|
+
}
|
|
435
|
+
// All non-transient interval references must eventually be SlideOnRemove
|
|
436
|
+
// To ensure eventual consistency, they must start as StayOnRemove when
|
|
437
|
+
// pending (created locally and creation op is not acked)
|
|
438
|
+
if (op || fromSnapshot) {
|
|
439
|
+
beginRefType |= ReferenceType.SlideOnRemove;
|
|
440
|
+
endRefType |= ReferenceType.SlideOnRemove;
|
|
441
|
+
} else {
|
|
442
|
+
beginRefType |= ReferenceType.StayOnRemove;
|
|
443
|
+
endRefType |= ReferenceType.StayOnRemove;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const startLref = createPositionReference(
|
|
448
|
+
client,
|
|
449
|
+
start,
|
|
450
|
+
beginRefType,
|
|
451
|
+
op,
|
|
452
|
+
fromSnapshot,
|
|
453
|
+
undefined,
|
|
454
|
+
startReferenceSlidingPreference(stickiness),
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
const endLref = createPositionReference(
|
|
458
|
+
client,
|
|
459
|
+
end,
|
|
460
|
+
endRefType,
|
|
461
|
+
op,
|
|
462
|
+
fromSnapshot,
|
|
463
|
+
undefined,
|
|
464
|
+
endReferenceSlidingPreference(stickiness),
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
const rangeProp = {
|
|
468
|
+
[reservedRangeLabelsKey]: [label],
|
|
469
|
+
};
|
|
470
|
+
startLref.addProperties(rangeProp);
|
|
471
|
+
endLref.addProperties(rangeProp);
|
|
472
|
+
|
|
473
|
+
const ival = new SequenceInterval(
|
|
474
|
+
client,
|
|
475
|
+
startLref,
|
|
476
|
+
endLref,
|
|
477
|
+
intervalType,
|
|
478
|
+
rangeProp,
|
|
479
|
+
stickiness,
|
|
480
|
+
);
|
|
481
|
+
return ival;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export const compareSequenceIntervalEnds = (a: SequenceInterval, b: SequenceInterval): number =>
|
|
485
|
+
compareReferencePositions(a.end, b.end);
|
|
486
|
+
|
|
487
|
+
export const compareSequenceIntervalStarts = (a: SequenceInterval, b: SequenceInterval): number =>
|
|
488
|
+
compareReferencePositions(a.start, b.start);
|
|
489
|
+
|
|
490
|
+
export const sequenceIntervalHelpers: IIntervalHelpers<SequenceInterval> = {
|
|
491
|
+
compareEnds: compareSequenceIntervalEnds,
|
|
492
|
+
compareStarts: compareSequenceIntervalStarts,
|
|
493
|
+
create: createSequenceInterval,
|
|
494
|
+
};
|
package/src/packageVersion.ts
CHANGED
package/src/revertibles.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/* eslint-disable no-bitwise */
|
|
6
6
|
|
|
7
|
-
import { assert, unreachableCase } from "@fluidframework/
|
|
7
|
+
import { assert, unreachableCase } from "@fluidframework/core-utils";
|
|
8
8
|
import {
|
|
9
9
|
appendToMergeTreeDeltaRevertibles,
|
|
10
10
|
discardMergeTreeDeltaRevertible,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
SortedSet,
|
|
21
21
|
getSlideToSegoff,
|
|
22
22
|
} from "@fluidframework/merge-tree";
|
|
23
|
-
import { IntervalOpType, SequenceInterval } from "./
|
|
23
|
+
import { IntervalOpType, SequenceInterval } from "./intervals";
|
|
24
24
|
import { SharedString, SharedStringSegment } from "./sharedString";
|
|
25
25
|
import { ISequenceDeltaRange, SequenceDeltaEvent } from "./sequenceDeltaEvent";
|
|
26
26
|
|
|
@@ -428,15 +428,16 @@ function revertLocalDelete(
|
|
|
428
428
|
const type = revertible.interval.intervalType;
|
|
429
429
|
// reusing the id causes eventual consistency bugs, so it is removed here and recreated in add
|
|
430
430
|
const { intervalId, ...props } = revertible.interval.properties;
|
|
431
|
-
if (
|
|
432
|
-
|
|
431
|
+
if (isValidRange(startSlidePos, endSlidePos, string)) {
|
|
432
|
+
const int = collection.add(startSlidePos, endSlidePos, type, props);
|
|
433
433
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
434
|
+
idMap.forEach((newId, oldId) => {
|
|
435
|
+
if (intervalId === newId) {
|
|
436
|
+
idMap.set(oldId, getUpdatedIdFromInterval(int));
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
idMap.set(intervalId, int.getIntervalId());
|
|
440
|
+
}
|
|
440
441
|
|
|
441
442
|
string.removeLocalReferencePosition(revertible.start);
|
|
442
443
|
string.removeLocalReferencePosition(revertible.end);
|
|
@@ -453,8 +454,9 @@ function revertLocalChange(
|
|
|
453
454
|
const startSlidePos = getSlidePosition(string, revertible.start, start);
|
|
454
455
|
const end = string.localReferencePositionToPosition(revertible.end);
|
|
455
456
|
const endSlidePos = getSlidePosition(string, revertible.end, end);
|
|
456
|
-
if (
|
|
457
|
-
|
|
457
|
+
if (isValidRange(startSlidePos, endSlidePos, string)) {
|
|
458
|
+
collection.change(id, startSlidePos, endSlidePos);
|
|
459
|
+
}
|
|
458
460
|
|
|
459
461
|
string.removeLocalReferencePosition(revertible.start);
|
|
460
462
|
string.removeLocalReferencePosition(revertible.end);
|
|
@@ -545,7 +547,16 @@ function revertLocalSequenceRemove(
|
|
|
545
547
|
restoredRanges,
|
|
546
548
|
sharedString,
|
|
547
549
|
);
|
|
548
|
-
|
|
550
|
+
// only move interval if start <= end
|
|
551
|
+
if (
|
|
552
|
+
(newStart === undefined &&
|
|
553
|
+
newEnd !== undefined &&
|
|
554
|
+
sharedString.localReferencePositionToPosition(interval.start) <= newEnd) ||
|
|
555
|
+
(newEnd === undefined &&
|
|
556
|
+
newStart !== undefined &&
|
|
557
|
+
sharedString.localReferencePositionToPosition(interval.end) >= newStart) ||
|
|
558
|
+
(newStart !== undefined && newEnd !== undefined && newStart <= newEnd)
|
|
559
|
+
) {
|
|
549
560
|
intervalCollection.change(intervalId, newStart, newEnd);
|
|
550
561
|
}
|
|
551
562
|
}
|