@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.
Files changed (225) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/README.md +4 -3
  3. package/dist/defaultMap.d.ts +1 -1
  4. package/dist/defaultMap.d.ts.map +1 -1
  5. package/dist/defaultMap.js +9 -10
  6. package/dist/defaultMap.js.map +1 -1
  7. package/dist/defaultMapInterfaces.d.ts +1 -1
  8. package/dist/defaultMapInterfaces.d.ts.map +1 -1
  9. package/dist/defaultMapInterfaces.js.map +1 -1
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +12 -9
  13. package/dist/index.js.map +1 -1
  14. package/dist/intervalCollection.d.ts +11 -424
  15. package/dist/intervalCollection.d.ts.map +1 -1
  16. package/dist/intervalCollection.js +74 -815
  17. package/dist/intervalCollection.js.map +1 -1
  18. package/dist/intervalIndex/endpointInRangeIndex.d.ts +20 -0
  19. package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
  20. package/dist/intervalIndex/endpointInRangeIndex.js +60 -0
  21. package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -0
  22. package/dist/intervalIndex/endpointIndex.d.ts +21 -0
  23. package/dist/intervalIndex/endpointIndex.d.ts.map +1 -0
  24. package/dist/intervalIndex/endpointIndex.js +42 -0
  25. package/dist/intervalIndex/endpointIndex.js.map +1 -0
  26. package/dist/intervalIndex/idIntervalIndex.d.ts +12 -0
  27. package/dist/intervalIndex/idIntervalIndex.d.ts.map +1 -0
  28. package/dist/intervalIndex/idIntervalIndex.js +41 -0
  29. package/dist/intervalIndex/idIntervalIndex.js.map +1 -0
  30. package/dist/intervalIndex/index.d.ts +5 -0
  31. package/dist/intervalIndex/index.d.ts.map +1 -1
  32. package/dist/intervalIndex/index.js +9 -1
  33. package/dist/intervalIndex/index.js.map +1 -1
  34. package/dist/intervalIndex/intervalIndex.d.ts +29 -0
  35. package/dist/intervalIndex/intervalIndex.d.ts.map +1 -0
  36. package/dist/intervalIndex/intervalIndex.js +7 -0
  37. package/dist/intervalIndex/intervalIndex.js.map +1 -0
  38. package/dist/intervalIndex/intervalIndexUtils.d.ts +17 -0
  39. package/dist/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
  40. package/dist/intervalIndex/intervalIndexUtils.js +22 -0
  41. package/dist/intervalIndex/intervalIndexUtils.js.map +1 -0
  42. package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
  43. package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
  44. package/dist/intervalIndex/overlappingIntervalsIndex.js +3 -3
  45. package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  46. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +5 -5
  47. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  48. package/dist/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
  49. package/dist/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
  50. package/dist/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
  51. package/dist/intervalIndex/startpointInRangeIndex.d.ts +20 -0
  52. package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
  53. package/dist/intervalIndex/startpointInRangeIndex.js +62 -0
  54. package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -0
  55. package/dist/intervalTree.d.ts +2 -56
  56. package/dist/intervalTree.d.ts.map +1 -1
  57. package/dist/intervalTree.js +2 -11
  58. package/dist/intervalTree.js.map +1 -1
  59. package/dist/intervals/index.d.ts +8 -0
  60. package/dist/intervals/index.d.ts.map +1 -0
  61. package/dist/intervals/index.js +23 -0
  62. package/dist/intervals/index.js.map +1 -0
  63. package/dist/intervals/interval.d.ts +88 -0
  64. package/dist/intervals/interval.d.ts.map +1 -0
  65. package/dist/intervals/interval.js +180 -0
  66. package/dist/intervals/interval.js.map +1 -0
  67. package/dist/intervals/intervalUtils.d.ts +200 -0
  68. package/dist/intervals/intervalUtils.d.ts.map +1 -0
  69. package/dist/intervals/intervalUtils.js +79 -0
  70. package/dist/intervals/intervalUtils.js.map +1 -0
  71. package/dist/intervals/sequenceInterval.d.ts +132 -0
  72. package/dist/intervals/sequenceInterval.d.ts.map +1 -0
  73. package/dist/intervals/sequenceInterval.js +313 -0
  74. package/dist/intervals/sequenceInterval.js.map +1 -0
  75. package/dist/packageVersion.d.ts +1 -1
  76. package/dist/packageVersion.js +1 -1
  77. package/dist/packageVersion.js.map +1 -1
  78. package/dist/revertibles.d.ts +1 -1
  79. package/dist/revertibles.d.ts.map +1 -1
  80. package/dist/revertibles.js +45 -52
  81. package/dist/revertibles.js.map +1 -1
  82. package/dist/sequence.d.ts +33 -4
  83. package/dist/sequence.d.ts.map +1 -1
  84. package/dist/sequence.js +91 -47
  85. package/dist/sequence.js.map +1 -1
  86. package/dist/sequenceDeltaEvent.d.ts +8 -3
  87. package/dist/sequenceDeltaEvent.d.ts.map +1 -1
  88. package/dist/sequenceDeltaEvent.js +3 -4
  89. package/dist/sequenceDeltaEvent.js.map +1 -1
  90. package/dist/sharedIntervalCollection.d.ts +2 -1
  91. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  92. package/dist/sharedIntervalCollection.js +2 -2
  93. package/dist/sharedIntervalCollection.js.map +1 -1
  94. package/dist/sharedSequence.d.ts +9 -0
  95. package/dist/sharedSequence.d.ts.map +1 -1
  96. package/dist/sharedSequence.js +9 -6
  97. package/dist/sharedSequence.js.map +1 -1
  98. package/dist/sharedString.d.ts.map +1 -1
  99. package/dist/sharedString.js +9 -29
  100. package/dist/sharedString.js.map +1 -1
  101. package/lib/defaultMap.d.ts +1 -1
  102. package/lib/defaultMap.d.ts.map +1 -1
  103. package/lib/defaultMap.js +5 -6
  104. package/lib/defaultMap.js.map +1 -1
  105. package/lib/defaultMapInterfaces.d.ts +1 -1
  106. package/lib/defaultMapInterfaces.d.ts.map +1 -1
  107. package/lib/defaultMapInterfaces.js.map +1 -1
  108. package/lib/index.d.ts +3 -3
  109. package/lib/index.d.ts.map +1 -1
  110. package/lib/index.js +3 -2
  111. package/lib/index.js.map +1 -1
  112. package/lib/intervalCollection.d.ts +11 -424
  113. package/lib/intervalCollection.d.ts.map +1 -1
  114. package/lib/intervalCollection.js +43 -776
  115. package/lib/intervalCollection.js.map +1 -1
  116. package/lib/intervalIndex/endpointInRangeIndex.d.ts +20 -0
  117. package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -0
  118. package/lib/intervalIndex/endpointInRangeIndex.js +56 -0
  119. package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -0
  120. package/lib/intervalIndex/endpointIndex.d.ts +21 -0
  121. package/lib/intervalIndex/endpointIndex.d.ts.map +1 -0
  122. package/lib/intervalIndex/endpointIndex.js +38 -0
  123. package/lib/intervalIndex/endpointIndex.js.map +1 -0
  124. package/lib/intervalIndex/idIntervalIndex.d.ts +12 -0
  125. package/lib/intervalIndex/idIntervalIndex.d.ts.map +1 -0
  126. package/lib/intervalIndex/idIntervalIndex.js +37 -0
  127. package/lib/intervalIndex/idIntervalIndex.js.map +1 -0
  128. package/lib/intervalIndex/index.d.ts +5 -0
  129. package/lib/intervalIndex/index.d.ts.map +1 -1
  130. package/lib/intervalIndex/index.js +4 -0
  131. package/lib/intervalIndex/index.js.map +1 -1
  132. package/lib/intervalIndex/intervalIndex.d.ts +29 -0
  133. package/lib/intervalIndex/intervalIndex.d.ts.map +1 -0
  134. package/lib/intervalIndex/intervalIndex.js +6 -0
  135. package/lib/intervalIndex/intervalIndex.js.map +1 -0
  136. package/lib/intervalIndex/intervalIndexUtils.d.ts +17 -0
  137. package/lib/intervalIndex/intervalIndexUtils.d.ts.map +1 -0
  138. package/lib/intervalIndex/intervalIndexUtils.js +18 -0
  139. package/lib/intervalIndex/intervalIndexUtils.js.map +1 -0
  140. package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +2 -1
  141. package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
  142. package/lib/intervalIndex/overlappingIntervalsIndex.js +1 -1
  143. package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  144. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +1 -1
  145. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  146. package/lib/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
  147. package/lib/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
  148. package/lib/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
  149. package/lib/intervalIndex/startpointInRangeIndex.d.ts +20 -0
  150. package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -0
  151. package/lib/intervalIndex/startpointInRangeIndex.js +58 -0
  152. package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -0
  153. package/lib/intervalTree.d.ts +2 -56
  154. package/lib/intervalTree.d.ts.map +1 -1
  155. package/lib/intervalTree.js +2 -11
  156. package/lib/intervalTree.js.map +1 -1
  157. package/lib/intervals/index.d.ts +8 -0
  158. package/lib/intervals/index.d.ts.map +1 -0
  159. package/lib/intervals/index.js +8 -0
  160. package/lib/intervals/index.js.map +1 -0
  161. package/lib/intervals/interval.d.ts +88 -0
  162. package/lib/intervals/interval.d.ts.map +1 -0
  163. package/lib/intervals/interval.js +175 -0
  164. package/lib/intervals/interval.js.map +1 -0
  165. package/lib/intervals/intervalUtils.d.ts +200 -0
  166. package/lib/intervals/intervalUtils.d.ts.map +1 -0
  167. package/lib/intervals/intervalUtils.js +74 -0
  168. package/lib/intervals/intervalUtils.js.map +1 -0
  169. package/lib/intervals/sequenceInterval.d.ts +132 -0
  170. package/lib/intervals/sequenceInterval.d.ts.map +1 -0
  171. package/lib/intervals/sequenceInterval.js +305 -0
  172. package/lib/intervals/sequenceInterval.js.map +1 -0
  173. package/lib/packageVersion.d.ts +1 -1
  174. package/lib/packageVersion.js +1 -1
  175. package/lib/packageVersion.js.map +1 -1
  176. package/lib/revertibles.d.ts +1 -1
  177. package/lib/revertibles.d.ts.map +1 -1
  178. package/lib/revertibles.js +28 -35
  179. package/lib/revertibles.js.map +1 -1
  180. package/lib/sequence.d.ts +33 -4
  181. package/lib/sequence.d.ts.map +1 -1
  182. package/lib/sequence.js +86 -41
  183. package/lib/sequence.js.map +1 -1
  184. package/lib/sequenceDeltaEvent.d.ts +8 -3
  185. package/lib/sequenceDeltaEvent.d.ts.map +1 -1
  186. package/lib/sequenceDeltaEvent.js +2 -3
  187. package/lib/sequenceDeltaEvent.js.map +1 -1
  188. package/lib/sharedIntervalCollection.d.ts +2 -1
  189. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  190. package/lib/sharedIntervalCollection.js +1 -1
  191. package/lib/sharedIntervalCollection.js.map +1 -1
  192. package/lib/sharedSequence.d.ts +9 -0
  193. package/lib/sharedSequence.d.ts.map +1 -1
  194. package/lib/sharedSequence.js +8 -5
  195. package/lib/sharedSequence.js.map +1 -1
  196. package/lib/sharedString.d.ts.map +1 -1
  197. package/lib/sharedString.js +9 -29
  198. package/lib/sharedString.js.map +1 -1
  199. package/package.json +29 -32
  200. package/src/defaultMap.ts +2 -1
  201. package/src/defaultMapInterfaces.ts +1 -1
  202. package/src/index.ts +18 -12
  203. package/src/intervalCollection.ts +42 -1225
  204. package/src/intervalIndex/endpointInRangeIndex.ts +104 -0
  205. package/src/intervalIndex/endpointIndex.ts +78 -0
  206. package/src/intervalIndex/idIntervalIndex.ts +58 -0
  207. package/src/intervalIndex/index.ts +5 -0
  208. package/src/intervalIndex/intervalIndex.ts +31 -0
  209. package/src/intervalIndex/intervalIndexUtils.ts +27 -0
  210. package/src/intervalIndex/overlappingIntervalsIndex.ts +2 -6
  211. package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +1 -1
  212. package/src/intervalIndex/sequenceIntervalIndexes.ts +1 -1
  213. package/src/intervalIndex/startpointInRangeIndex.ts +109 -0
  214. package/src/intervalTree.ts +3 -75
  215. package/src/intervals/index.ts +25 -0
  216. package/src/intervals/interval.ts +230 -0
  217. package/src/intervals/intervalUtils.ts +256 -0
  218. package/src/intervals/sequenceInterval.ts +494 -0
  219. package/src/packageVersion.ts +1 -1
  220. package/src/revertibles.ts +24 -13
  221. package/src/sequence.ts +100 -35
  222. package/src/sequenceDeltaEvent.ts +12 -4
  223. package/src/sharedIntervalCollection.ts +2 -3
  224. package/src/sharedSequence.ts +11 -5
  225. 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
+ };
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/sequence";
9
- export const pkgVersion = "2.0.0-dev.5.3.2.178189";
9
+ export const pkgVersion = "2.0.0-dev.6.4.0.191457";
@@ -4,7 +4,7 @@
4
4
  */
5
5
  /* eslint-disable no-bitwise */
6
6
 
7
- import { assert, unreachableCase } from "@fluidframework/common-utils";
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 "./intervalCollection";
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 (!isValidRange(startSlidePos, endSlidePos, string)) return;
432
- const int = collection.add(startSlidePos, endSlidePos, type, props);
431
+ if (isValidRange(startSlidePos, endSlidePos, string)) {
432
+ const int = collection.add(startSlidePos, endSlidePos, type, props);
433
433
 
434
- idMap.forEach((newId, oldId) => {
435
- if (intervalId === newId) {
436
- idMap.set(oldId, getUpdatedIdFromInterval(int));
437
- }
438
- });
439
- idMap.set(intervalId, int.getIntervalId());
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 (!isValidRange(startSlidePos, endSlidePos, string)) return;
457
- collection.change(id, startSlidePos, endSlidePos);
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
- if (newStart !== undefined || newEnd !== undefined) {
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
  }