@fluidframework/sequence 2.0.0-dev.6.4.0.192049 → 2.0.0-dev.7.2.0.204906

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 (226) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +130 -0
  3. package/api-extractor.json +1 -1
  4. package/api-report/sequence.api.md +717 -0
  5. package/dist/defaultMap.d.ts +1 -1
  6. package/dist/defaultMap.d.ts.map +1 -1
  7. package/dist/defaultMap.js +6 -6
  8. package/dist/defaultMap.js.map +1 -1
  9. package/dist/defaultMapInterfaces.d.ts +22 -2
  10. package/dist/defaultMapInterfaces.d.ts.map +1 -1
  11. package/dist/defaultMapInterfaces.js.map +1 -1
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +2 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/intervalCollection.d.ts +164 -16
  17. package/dist/intervalCollection.d.ts.map +1 -1
  18. package/dist/intervalCollection.js +174 -54
  19. package/dist/intervalCollection.js.map +1 -1
  20. package/dist/intervalIndex/endpointInRangeIndex.d.ts +17 -3
  21. package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
  22. package/dist/intervalIndex/endpointInRangeIndex.js +12 -6
  23. package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -1
  24. package/dist/intervalIndex/endpointIndex.d.ts +19 -2
  25. package/dist/intervalIndex/endpointIndex.d.ts.map +1 -1
  26. package/dist/intervalIndex/endpointIndex.js +10 -5
  27. package/dist/intervalIndex/endpointIndex.js.map +1 -1
  28. package/dist/intervalIndex/idIntervalIndex.d.ts +6 -0
  29. package/dist/intervalIndex/idIntervalIndex.d.ts.map +1 -1
  30. package/dist/intervalIndex/idIntervalIndex.js +3 -0
  31. package/dist/intervalIndex/idIntervalIndex.js.map +1 -1
  32. package/dist/intervalIndex/index.d.ts +4 -4
  33. package/dist/intervalIndex/index.d.ts.map +1 -1
  34. package/dist/intervalIndex/index.js +5 -1
  35. package/dist/intervalIndex/index.js.map +1 -1
  36. package/dist/intervalIndex/intervalIndex.d.ts +1 -0
  37. package/dist/intervalIndex/intervalIndex.d.ts.map +1 -1
  38. package/dist/intervalIndex/intervalIndex.js.map +1 -1
  39. package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +17 -6
  40. package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
  41. package/dist/intervalIndex/overlappingIntervalsIndex.js +17 -4
  42. package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  43. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.d.ts +5 -2
  44. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
  45. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +9 -1
  46. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  47. package/dist/intervalIndex/sequenceIntervalIndexes.d.ts +2 -1
  48. package/dist/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
  49. package/dist/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
  50. package/dist/intervalIndex/startpointInRangeIndex.d.ts +17 -3
  51. package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
  52. package/dist/intervalIndex/startpointInRangeIndex.js +12 -8
  53. package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -1
  54. package/dist/intervalTree.d.ts +1 -1
  55. package/dist/intervalTree.d.ts.map +1 -1
  56. package/dist/intervals/interval.d.ts +4 -2
  57. package/dist/intervals/interval.d.ts.map +1 -1
  58. package/dist/intervals/interval.js +14 -5
  59. package/dist/intervals/interval.js.map +1 -1
  60. package/dist/intervals/intervalUtils.d.ts +51 -18
  61. package/dist/intervals/intervalUtils.d.ts.map +1 -1
  62. package/dist/intervals/intervalUtils.js +18 -10
  63. package/dist/intervals/intervalUtils.js.map +1 -1
  64. package/dist/intervals/sequenceInterval.d.ts +28 -13
  65. package/dist/intervals/sequenceInterval.d.ts.map +1 -1
  66. package/dist/intervals/sequenceInterval.js +124 -43
  67. package/dist/intervals/sequenceInterval.js.map +1 -1
  68. package/dist/localValues.d.ts.map +1 -1
  69. package/dist/localValues.js.map +1 -1
  70. package/dist/packageVersion.d.ts +1 -1
  71. package/dist/packageVersion.js +1 -1
  72. package/dist/packageVersion.js.map +1 -1
  73. package/dist/revertibles.d.ts +3 -15
  74. package/dist/revertibles.d.ts.map +1 -1
  75. package/dist/revertibles.js +11 -19
  76. package/dist/revertibles.js.map +1 -1
  77. package/dist/sequence-alpha.d.ts +1587 -0
  78. package/dist/sequence-beta.d.ts +1507 -0
  79. package/dist/sequence-public.d.ts +1507 -0
  80. package/dist/sequence-untrimmed.d.ts +1759 -0
  81. package/dist/sequence.d.ts +8 -4
  82. package/dist/sequence.d.ts.map +1 -1
  83. package/dist/sequence.js +53 -48
  84. package/dist/sequence.js.map +1 -1
  85. package/dist/sequenceDeltaEvent.d.ts +4 -0
  86. package/dist/sequenceDeltaEvent.d.ts.map +1 -1
  87. package/dist/sequenceDeltaEvent.js +3 -0
  88. package/dist/sequenceDeltaEvent.js.map +1 -1
  89. package/dist/sequenceFactory.d.ts +3 -0
  90. package/dist/sequenceFactory.d.ts.map +1 -1
  91. package/dist/sequenceFactory.js +4 -1
  92. package/dist/sequenceFactory.js.map +1 -1
  93. package/dist/sharedIntervalCollection.d.ts +5 -0
  94. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  95. package/dist/sharedIntervalCollection.js +11 -9
  96. package/dist/sharedIntervalCollection.js.map +1 -1
  97. package/dist/sharedSequence.d.ts +6 -3
  98. package/dist/sharedSequence.d.ts.map +1 -1
  99. package/dist/sharedSequence.js +10 -8
  100. package/dist/sharedSequence.js.map +1 -1
  101. package/dist/sharedString.d.ts +17 -2
  102. package/dist/sharedString.d.ts.map +1 -1
  103. package/dist/sharedString.js +21 -7
  104. package/dist/sharedString.js.map +1 -1
  105. package/dist/tsdoc-metadata.json +1 -1
  106. package/lib/defaultMap.d.ts +1 -1
  107. package/lib/defaultMap.d.ts.map +1 -1
  108. package/lib/defaultMap.js +6 -6
  109. package/lib/defaultMap.js.map +1 -1
  110. package/lib/defaultMapInterfaces.d.ts +22 -2
  111. package/lib/defaultMapInterfaces.d.ts.map +1 -1
  112. package/lib/defaultMapInterfaces.js.map +1 -1
  113. package/lib/index.d.ts +2 -2
  114. package/lib/index.d.ts.map +1 -1
  115. package/lib/index.js +1 -1
  116. package/lib/index.js.map +1 -1
  117. package/lib/intervalCollection.d.ts +164 -16
  118. package/lib/intervalCollection.d.ts.map +1 -1
  119. package/lib/intervalCollection.js +172 -55
  120. package/lib/intervalCollection.js.map +1 -1
  121. package/lib/intervalIndex/endpointInRangeIndex.d.ts +17 -3
  122. package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
  123. package/lib/intervalIndex/endpointInRangeIndex.js +12 -7
  124. package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -1
  125. package/lib/intervalIndex/endpointIndex.d.ts +19 -2
  126. package/lib/intervalIndex/endpointIndex.d.ts.map +1 -1
  127. package/lib/intervalIndex/endpointIndex.js +10 -6
  128. package/lib/intervalIndex/endpointIndex.js.map +1 -1
  129. package/lib/intervalIndex/idIntervalIndex.d.ts +6 -0
  130. package/lib/intervalIndex/idIntervalIndex.d.ts.map +1 -1
  131. package/lib/intervalIndex/idIntervalIndex.js +3 -0
  132. package/lib/intervalIndex/idIntervalIndex.js.map +1 -1
  133. package/lib/intervalIndex/index.d.ts +4 -4
  134. package/lib/intervalIndex/index.d.ts.map +1 -1
  135. package/lib/intervalIndex/index.js +4 -4
  136. package/lib/intervalIndex/index.js.map +1 -1
  137. package/lib/intervalIndex/intervalIndex.d.ts +1 -0
  138. package/lib/intervalIndex/intervalIndex.d.ts.map +1 -1
  139. package/lib/intervalIndex/intervalIndex.js.map +1 -1
  140. package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +17 -6
  141. package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
  142. package/lib/intervalIndex/overlappingIntervalsIndex.js +18 -5
  143. package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  144. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.d.ts +5 -2
  145. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
  146. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +9 -1
  147. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  148. package/lib/intervalIndex/sequenceIntervalIndexes.d.ts +2 -1
  149. package/lib/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
  150. package/lib/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
  151. package/lib/intervalIndex/startpointInRangeIndex.d.ts +17 -3
  152. package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
  153. package/lib/intervalIndex/startpointInRangeIndex.js +12 -9
  154. package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -1
  155. package/lib/intervalTree.d.ts +1 -1
  156. package/lib/intervalTree.d.ts.map +1 -1
  157. package/lib/intervals/interval.d.ts +4 -2
  158. package/lib/intervals/interval.d.ts.map +1 -1
  159. package/lib/intervals/interval.js +14 -5
  160. package/lib/intervals/interval.js.map +1 -1
  161. package/lib/intervals/intervalUtils.d.ts +51 -18
  162. package/lib/intervals/intervalUtils.d.ts.map +1 -1
  163. package/lib/intervals/intervalUtils.js +14 -6
  164. package/lib/intervals/intervalUtils.js.map +1 -1
  165. package/lib/intervals/sequenceInterval.d.ts +28 -13
  166. package/lib/intervals/sequenceInterval.d.ts.map +1 -1
  167. package/lib/intervals/sequenceInterval.js +125 -42
  168. package/lib/intervals/sequenceInterval.js.map +1 -1
  169. package/lib/localValues.d.ts.map +1 -1
  170. package/lib/localValues.js.map +1 -1
  171. package/lib/packageVersion.d.ts +1 -1
  172. package/lib/packageVersion.js +1 -1
  173. package/lib/packageVersion.js.map +1 -1
  174. package/lib/revertibles.d.ts +3 -15
  175. package/lib/revertibles.d.ts.map +1 -1
  176. package/lib/revertibles.js +11 -19
  177. package/lib/revertibles.js.map +1 -1
  178. package/lib/sequence.d.ts +8 -4
  179. package/lib/sequence.d.ts.map +1 -1
  180. package/lib/sequence.js +56 -49
  181. package/lib/sequence.js.map +1 -1
  182. package/lib/sequenceDeltaEvent.d.ts +4 -0
  183. package/lib/sequenceDeltaEvent.d.ts.map +1 -1
  184. package/lib/sequenceDeltaEvent.js +3 -0
  185. package/lib/sequenceDeltaEvent.js.map +1 -1
  186. package/lib/sequenceFactory.d.ts +3 -0
  187. package/lib/sequenceFactory.d.ts.map +1 -1
  188. package/lib/sequenceFactory.js +4 -1
  189. package/lib/sequenceFactory.js.map +1 -1
  190. package/lib/sharedIntervalCollection.d.ts +5 -0
  191. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  192. package/lib/sharedIntervalCollection.js +11 -9
  193. package/lib/sharedIntervalCollection.js.map +1 -1
  194. package/lib/sharedSequence.d.ts +6 -3
  195. package/lib/sharedSequence.d.ts.map +1 -1
  196. package/lib/sharedSequence.js +10 -8
  197. package/lib/sharedSequence.js.map +1 -1
  198. package/lib/sharedString.d.ts +17 -2
  199. package/lib/sharedString.d.ts.map +1 -1
  200. package/lib/sharedString.js +21 -7
  201. package/lib/sharedString.js.map +1 -1
  202. package/package.json +31 -30
  203. package/src/defaultMapInterfaces.ts +22 -2
  204. package/src/index.ts +4 -1
  205. package/src/intervalCollection.ts +423 -82
  206. package/src/intervalIndex/endpointInRangeIndex.ts +23 -11
  207. package/src/intervalIndex/endpointIndex.ts +22 -9
  208. package/src/intervalIndex/idIntervalIndex.ts +7 -1
  209. package/src/intervalIndex/index.ts +12 -3
  210. package/src/intervalIndex/intervalIndex.ts +1 -0
  211. package/src/intervalIndex/overlappingIntervalsIndex.ts +40 -15
  212. package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +10 -1
  213. package/src/intervalIndex/sequenceIntervalIndexes.ts +2 -1
  214. package/src/intervalIndex/startpointInRangeIndex.ts +23 -18
  215. package/src/intervals/interval.ts +35 -8
  216. package/src/intervals/intervalUtils.ts +61 -27
  217. package/src/intervals/sequenceInterval.ts +197 -47
  218. package/src/localValues.ts +4 -1
  219. package/src/packageVersion.ts +1 -1
  220. package/src/revertibles.ts +14 -36
  221. package/src/sequence.ts +14 -5
  222. package/src/sequenceDeltaEvent.ts +4 -0
  223. package/src/sequenceFactory.ts +4 -1
  224. package/src/sharedIntervalCollection.ts +5 -0
  225. package/src/sharedSequence.ts +6 -3
  226. package/src/sharedString.ts +25 -2
@@ -12,8 +12,11 @@ import {
12
12
  SlidingPreference,
13
13
  } from "@fluidframework/merge-tree";
14
14
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
15
+ import { SequencePlace, Side } from "../intervalCollection";
16
+
15
17
  /**
16
18
  * Basic interval abstraction
19
+ * @public
17
20
  */
18
21
  export interface IInterval {
19
22
  /**
@@ -46,10 +49,11 @@ export interface IInterval {
46
49
  */
47
50
  modify(
48
51
  label: string,
49
- start: number | undefined,
50
- end: number | undefined,
52
+ start: SequencePlace | undefined,
53
+ end: SequencePlace | undefined,
51
54
  op?: ISequencedDocumentMessage,
52
55
  localSeq?: number,
56
+ useNewSlidingBehavior?: boolean,
53
57
  ): IInterval | undefined;
54
58
  /**
55
59
  * @returns whether this interval overlaps with `b`.
@@ -77,8 +81,14 @@ export const IntervalOpType = {
77
81
  POSITION_REMOVE: "positionRemove",
78
82
  } as const;
79
83
 
84
+ /**
85
+ * @public
86
+ */
80
87
  export enum IntervalType {
81
88
  Simple = 0x0,
89
+ /**
90
+ * @deprecated this functionality is no longer supported and will be removed
91
+ */
82
92
  Nest = 0x1,
83
93
 
84
94
  /**
@@ -111,16 +121,24 @@ export interface ISerializedInterval {
111
121
  */
112
122
  sequenceNumber: number;
113
123
  /** Start position of the interval */
114
- start: number;
124
+ start: number | "start" | "end";
115
125
  /** End position of the interval */
116
- end: number;
126
+ end: number | "start" | "end";
117
127
  /** Interval type to create */
118
128
  intervalType: IntervalType;
129
+ /**
130
+ * The stickiness of this interval
131
+ */
119
132
  stickiness?: IntervalStickiness;
133
+ startSide?: Side;
134
+ endSide?: Side;
120
135
  /** Any properties the interval has */
121
136
  properties?: PropertySet;
122
137
  }
123
138
 
139
+ /**
140
+ * @public
141
+ */
124
142
  export interface ISerializableInterval extends IInterval {
125
143
  /** Serializable bag of properties associated with the interval. */
126
144
  properties: PropertySet;
@@ -158,25 +176,34 @@ export type SerializedIntervalDelta = Omit<ISerializedInterval, "start" | "end"
158
176
  *
159
177
  * Intervals are of the format:
160
178
  *
161
- * [start, end, sequenceNumber, intervalType, properties, stickiness?]
179
+ * [
180
+ * start,
181
+ * end,
182
+ * sequenceNumber,
183
+ * intervalType,
184
+ * properties,
185
+ * stickiness?,
186
+ * startSide?,
187
+ * endSide?,
188
+ * ]
162
189
  */
163
190
  export type CompressedSerializedInterval =
164
- | [number, number, number, IntervalType, PropertySet, IntervalStickiness]
165
- | [number, number, number, IntervalType, PropertySet];
191
+ | [
192
+ number | "start" | "end",
193
+ number | "start" | "end",
194
+ number,
195
+ IntervalType,
196
+ PropertySet,
197
+ IntervalStickiness,
198
+ ]
199
+ | [number | "start" | "end", number | "start" | "end", number, IntervalType, PropertySet];
166
200
 
167
201
  /**
168
202
  * @sealed
203
+ * @deprecated The methods within have substitutions
204
+ * @public
169
205
  */
170
206
  export interface IIntervalHelpers<TInterval extends ISerializableInterval> {
171
- /**
172
- * @deprecated Use the method `IInterval.compareEnd` instead
173
- */
174
- compareEnds(a: TInterval, b: TInterval): number;
175
-
176
- /**
177
- * @deprecated Use the method `IInterval.compareStart` instead
178
- */
179
- compareStarts?(a: TInterval, b: TInterval): number;
180
207
  /**
181
208
  *
182
209
  * @param label - label of the interval collection this interval is being added to. This parameter is
@@ -187,17 +214,20 @@ export interface IIntervalHelpers<TInterval extends ISerializableInterval> {
187
214
  * @param intervalType - Type of interval to create. Default is SlideOnRemove
188
215
  * @param op - If this create came from a remote client, op that created it. Default is undefined (i.e. local)
189
216
  * @param fromSnapshot - If this create came from loading a snapshot. Default is false.
190
- * @param stickiness - {@link (IntervalStickiness:type)} to apply to the added interval.
217
+ * @param startSide - The side on which the start position lays. See
218
+ * {@link SequencePlace} for additional context
219
+ * @param endSide - The side on which the end position lays. See
220
+ * {@link SequencePlace} for additional context
191
221
  */
192
222
  create(
193
223
  label: string,
194
- start: number | undefined,
195
- end: number | undefined,
224
+ start: SequencePlace | undefined,
225
+ end: SequencePlace | undefined,
196
226
  client: Client | undefined,
197
227
  intervalType: IntervalType,
198
228
  op?: ISequencedDocumentMessage,
199
229
  fromSnapshot?: boolean,
200
- stickiness?: IntervalStickiness,
230
+ useNewSlidingBehavior?: boolean,
201
231
  ): TInterval;
202
232
  }
203
233
 
@@ -207,6 +237,8 @@ export interface IIntervalHelpers<TInterval extends ISerializableInterval> {
207
237
  *
208
238
  * Note that interval stickiness is currently an experimental feature and must
209
239
  * be explicitly enabled with the `intervalStickinessEnabled` flag
240
+ *
241
+ * @internal
210
242
  */
211
243
  export const IntervalStickiness = {
212
244
  /**
@@ -238,19 +270,21 @@ export const IntervalStickiness = {
238
270
  *
239
271
  * Note that interval stickiness is currently an experimental feature and must
240
272
  * be explicitly enabled with the `intervalStickinessEnabled` flag
273
+ *
274
+ * @internal
241
275
  */
242
- export type IntervalStickiness = typeof IntervalStickiness[keyof typeof IntervalStickiness];
276
+ export type IntervalStickiness = (typeof IntervalStickiness)[keyof typeof IntervalStickiness];
243
277
 
244
- export function endReferenceSlidingPreference(stickiness: IntervalStickiness): SlidingPreference {
245
- // if any end stickiness, prefer sliding forwards
246
- return (stickiness & IntervalStickiness.END) !== 0
278
+ export function startReferenceSlidingPreference(stickiness: IntervalStickiness): SlidingPreference {
279
+ // if any start stickiness, prefer sliding backwards
280
+ return (stickiness & IntervalStickiness.START) === 0
247
281
  ? SlidingPreference.FORWARD
248
282
  : SlidingPreference.BACKWARD;
249
283
  }
250
284
 
251
- export function startReferenceSlidingPreference(stickiness: IntervalStickiness): SlidingPreference {
252
- // if any start stickiness, prefer sliding backwards
253
- return (stickiness & IntervalStickiness.START) !== 0
285
+ export function endReferenceSlidingPreference(stickiness: IntervalStickiness): SlidingPreference {
286
+ // if any end stickiness, prefer sliding forwards
287
+ return (stickiness & IntervalStickiness.END) === 0
254
288
  ? SlidingPreference.BACKWARD
255
289
  : SlidingPreference.FORWARD;
256
290
  }
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  /* eslint-disable no-bitwise */
7
+ /* eslint-disable import/no-deprecated */
7
8
 
8
9
  import {
9
10
  Client,
@@ -26,6 +27,13 @@ import {
26
27
  import { assert } from "@fluidframework/core-utils";
27
28
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
28
29
  import { UsageError } from "@fluidframework/telemetry-utils";
30
+ import {
31
+ SequencePlace,
32
+ Side,
33
+ computeStickinessFromSide,
34
+ endpointPosAndSide,
35
+ sidesFromStickiness,
36
+ } from "../intervalCollection";
29
37
  import {
30
38
  IIntervalHelpers,
31
39
  ISerializableInterval,
@@ -38,14 +46,42 @@ import {
38
46
 
39
47
  const reservedIntervalIdKey = "intervalId";
40
48
 
49
+ function compareSides(sideA: Side, sideB: Side): number {
50
+ if (sideA === sideB) {
51
+ return 0;
52
+ }
53
+
54
+ if (sideA === Side.Before) {
55
+ return 1;
56
+ }
57
+
58
+ return -1;
59
+ }
60
+
61
+ function minSide(sideA: Side, sideB: Side): Side {
62
+ if (sideA === Side.After && sideB === Side.After) {
63
+ return Side.After;
64
+ }
65
+
66
+ return Side.Before;
67
+ }
68
+
69
+ function maxSide(sideA: Side, sideB: Side): Side {
70
+ if (sideA === Side.Before && sideB === Side.Before) {
71
+ return Side.Before;
72
+ }
73
+
74
+ return Side.After;
75
+ }
76
+
41
77
  /**
42
78
  * Interval implementation whose ends are associated with positions in a mutatable sequence.
43
79
  * As such, when content is inserted into the middle of the interval, the interval expands to
44
80
  * include that content.
45
81
  *
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.
82
+ * @remarks The endpoints' positions should be treated exclusively to get
83
+ * reasonable behavior. E.g., an interval referring to "hello" in "hello world"
84
+ * should have a start position of 0 and an end position of 5.
49
85
  *
50
86
  * To see why, consider what happens if "llo wor" is removed from the string to make "held".
51
87
  * The interval's startpoint remains on the "h" (it isn't altered), but the interval's endpoint
@@ -55,9 +91,16 @@ const reservedIntervalIdKey = "intervalId";
55
91
  * If the interval endpoint was treated inclusively, the interval would now refer to "hel", which
56
92
  * is undesirable.
57
93
  *
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.
94
+ * Since the endpoints of an interval are treated exclusively but cannot be greater
95
+ * than or equal to the length of the associated sequence, there exist special
96
+ * endpoint segments, "start" and "end", which represent the position immediately
97
+ * before or immediately after the string respectively.
98
+ *
99
+ * If a `SequenceInterval` is created on a sequence with the
100
+ * `mergeTreeReferencesCanSlideToEndpoint` feature flag set to true, the endpoints
101
+ * of the interval that are exclusive will have the ability to slide to these
102
+ * special endpoint segments.
103
+ * @public
61
104
  */
62
105
  export class SequenceInterval implements ISerializableInterval {
63
106
  /**
@@ -70,6 +113,20 @@ export class SequenceInterval implements ISerializableInterval {
70
113
  */
71
114
  public propertyManager: PropertiesManager;
72
115
 
116
+ /**
117
+ * @internal
118
+ */
119
+ public get stickiness(): IntervalStickiness {
120
+ const startSegment = this.start.getSegment();
121
+ const endSegment = this.end.getSegment();
122
+ return computeStickinessFromSide(
123
+ startSegment?.endpointType,
124
+ this.startSide,
125
+ endSegment?.endpointType,
126
+ this.endSide,
127
+ );
128
+ }
129
+
73
130
  constructor(
74
131
  private readonly client: Client,
75
132
  /**
@@ -84,7 +141,8 @@ export class SequenceInterval implements ISerializableInterval {
84
141
  public end: LocalReferencePosition,
85
142
  public intervalType: IntervalType,
86
143
  props?: PropertySet,
87
- public readonly stickiness: IntervalStickiness = IntervalStickiness.END,
144
+ public readonly startSide: Side = Side.Before,
145
+ public readonly endSide: Side = Side.Before,
88
146
  ) {
89
147
  this.propertyManager = new PropertiesManager();
90
148
  this.properties = {};
@@ -136,19 +194,20 @@ export class SequenceInterval implements ISerializableInterval {
136
194
  public serialize(): ISerializedInterval {
137
195
  const startPosition = this.client.localReferencePositionToPosition(this.start);
138
196
  const endPosition = this.client.localReferencePositionToPosition(this.end);
197
+ const { startSide, endSide } = sidesFromStickiness(this.stickiness);
139
198
  const serializedInterval: ISerializedInterval = {
140
199
  end: endPosition,
141
200
  intervalType: this.intervalType,
142
201
  sequenceNumber: this.client.getCurrentSeq(),
143
202
  start: startPosition,
203
+ stickiness: this.stickiness,
204
+ startSide,
205
+ endSide,
144
206
  };
145
207
 
146
208
  if (this.properties) {
147
209
  serializedInterval.properties = this.properties;
148
210
  }
149
- if (this.stickiness !== IntervalStickiness.END) {
150
- serializedInterval.stickiness = this.stickiness;
151
- }
152
211
 
153
212
  return serializedInterval;
154
213
  }
@@ -163,7 +222,8 @@ export class SequenceInterval implements ISerializableInterval {
163
222
  this.end,
164
223
  this.intervalType,
165
224
  this.properties,
166
- this.stickiness,
225
+ this.startSide,
226
+ this.endSide,
167
227
  );
168
228
  }
169
229
 
@@ -196,14 +256,26 @@ export class SequenceInterval implements ISerializableInterval {
196
256
  * {@inheritDoc IInterval.compareStart}
197
257
  */
198
258
  public compareStart(b: SequenceInterval) {
199
- return compareReferencePositions(this.start, b.start);
259
+ const dist = compareReferencePositions(this.start, b.start);
260
+
261
+ if (dist === 0) {
262
+ return compareSides(this.startSide, b.startSide);
263
+ }
264
+
265
+ return dist;
200
266
  }
201
267
 
202
268
  /**
203
269
  * {@inheritDoc IInterval.compareEnd}
204
270
  */
205
- public compareEnd(b: SequenceInterval) {
206
- return compareReferencePositions(this.end, b.end);
271
+ public compareEnd(b: SequenceInterval): number {
272
+ const dist = compareReferencePositions(this.end, b.end);
273
+
274
+ if (dist === 0) {
275
+ return compareSides(b.endSide, this.endSide);
276
+ }
277
+
278
+ return dist;
207
279
  }
208
280
 
209
281
  /**
@@ -230,11 +302,33 @@ export class SequenceInterval implements ISerializableInterval {
230
302
  * @internal
231
303
  */
232
304
  public union(b: SequenceInterval) {
305
+ const newStart = minReferencePosition(this.start, b.start);
306
+ const newEnd = maxReferencePosition(this.end, b.end);
307
+
308
+ let startSide: Side;
309
+
310
+ if (this.start === b.start) {
311
+ startSide = minSide(this.startSide, b.startSide);
312
+ } else {
313
+ startSide = this.start === newStart ? this.startSide : b.startSide;
314
+ }
315
+
316
+ let endSide: Side;
317
+
318
+ if (this.end === b.end) {
319
+ endSide = maxSide(this.endSide, b.endSide);
320
+ } else {
321
+ endSide = this.end === newEnd ? this.endSide : b.endSide;
322
+ }
323
+
233
324
  return new SequenceInterval(
234
325
  this.client,
235
- minReferencePosition(this.start, b.start),
236
- maxReferencePosition(this.end, b.end),
326
+ newStart,
327
+ newEnd,
237
328
  this.intervalType,
329
+ undefined,
330
+ startSide,
331
+ endSide,
238
332
  );
239
333
  }
240
334
 
@@ -267,12 +361,19 @@ export class SequenceInterval implements ISerializableInterval {
267
361
  */
268
362
  public modify(
269
363
  label: string,
270
- start: number,
271
- end: number,
364
+ start: SequencePlace | undefined,
365
+ end: SequencePlace | undefined,
272
366
  op?: ISequencedDocumentMessage,
273
367
  localSeq?: number,
274
- stickiness: IntervalStickiness = IntervalStickiness.END,
368
+ useNewSlidingBehavior: boolean = false,
275
369
  ) {
370
+ const { startSide, endSide, startPos, endPos } = endpointPosAndSide(start, end);
371
+ const stickiness = computeStickinessFromSide(
372
+ startPos ?? this.start.getSegment()?.endpointType,
373
+ startSide ?? this.startSide,
374
+ endPos ?? this.end.getSegment()?.endpointType,
375
+ endSide ?? this.endSide,
376
+ );
276
377
  const getRefType = (baseType: ReferenceType): ReferenceType => {
277
378
  let refType = baseType;
278
379
  if (op === undefined) {
@@ -283,15 +384,17 @@ export class SequenceInterval implements ISerializableInterval {
283
384
  };
284
385
 
285
386
  let startRef = this.start;
286
- if (start !== undefined) {
387
+ if (startPos !== undefined) {
287
388
  startRef = createPositionReference(
288
389
  this.client,
289
- start,
390
+ startPos,
290
391
  getRefType(this.start.refType),
291
392
  op,
292
393
  undefined,
293
394
  localSeq,
294
395
  startReferenceSlidingPreference(stickiness),
396
+ startReferenceSlidingPreference(stickiness) === SlidingPreference.BACKWARD,
397
+ useNewSlidingBehavior,
295
398
  );
296
399
  if (this.start.properties) {
297
400
  startRef.addProperties(this.start.properties);
@@ -299,22 +402,32 @@ export class SequenceInterval implements ISerializableInterval {
299
402
  }
300
403
 
301
404
  let endRef = this.end;
302
- if (end !== undefined) {
405
+ if (endPos !== undefined) {
303
406
  endRef = createPositionReference(
304
407
  this.client,
305
- end,
408
+ endPos,
306
409
  getRefType(this.end.refType),
307
410
  op,
308
411
  undefined,
309
412
  localSeq,
310
413
  endReferenceSlidingPreference(stickiness),
414
+ endReferenceSlidingPreference(stickiness) === SlidingPreference.FORWARD,
415
+ useNewSlidingBehavior,
311
416
  );
312
417
  if (this.end.properties) {
313
418
  endRef.addProperties(this.end.properties);
314
419
  }
315
420
  }
316
421
 
317
- const newInterval = new SequenceInterval(this.client, startRef, endRef, this.intervalType);
422
+ const newInterval = new SequenceInterval(
423
+ this.client,
424
+ startRef,
425
+ endRef,
426
+ this.intervalType,
427
+ undefined,
428
+ startSide ?? this.startSide,
429
+ endSide ?? this.endSide,
430
+ );
318
431
  if (this.properties) {
319
432
  newInterval.initializeProperties();
320
433
  this.propertyManager.copyTo(
@@ -338,13 +451,25 @@ export class SequenceInterval implements ISerializableInterval {
338
451
 
339
452
  export function createPositionReferenceFromSegoff(
340
453
  client: Client,
341
- segoff: { segment: ISegment | undefined; offset: number | undefined },
454
+ segoff: { segment: ISegment | undefined; offset: number | undefined } | "start" | "end",
342
455
  refType: ReferenceType,
343
456
  op?: ISequencedDocumentMessage,
344
457
  localSeq?: number,
345
458
  fromSnapshot?: boolean,
346
459
  slidingPreference?: SlidingPreference,
460
+ canSlideToEndpoint?: boolean,
347
461
  ): LocalReferencePosition {
462
+ if (segoff === "start" || segoff === "end") {
463
+ return client.createLocalReferencePosition(
464
+ segoff,
465
+ undefined,
466
+ refType,
467
+ undefined,
468
+ slidingPreference,
469
+ canSlideToEndpoint,
470
+ );
471
+ }
472
+
348
473
  if (segoff.segment) {
349
474
  const ref = client.createLocalReferencePosition(
350
475
  segoff.segment,
@@ -352,6 +477,7 @@ export function createPositionReferenceFromSegoff(
352
477
  refType,
353
478
  undefined,
354
479
  slidingPreference,
480
+ canSlideToEndpoint,
355
481
  );
356
482
  return ref;
357
483
  }
@@ -375,30 +501,40 @@ export function createPositionReferenceFromSegoff(
375
501
 
376
502
  function createPositionReference(
377
503
  client: Client,
378
- pos: number,
504
+ pos: number | "start" | "end",
379
505
  refType: ReferenceType,
380
506
  op?: ISequencedDocumentMessage,
381
507
  fromSnapshot?: boolean,
382
508
  localSeq?: number,
383
509
  slidingPreference?: SlidingPreference,
510
+ exclusive: boolean = false,
511
+ useNewSlidingBehavior: boolean = false,
384
512
  ): LocalReferencePosition {
385
513
  let segoff;
514
+
386
515
  if (op) {
387
516
  assert(
388
517
  (refType & ReferenceType.SlideOnRemove) !== 0,
389
518
  0x2f5 /* op create references must be SlideOnRemove */,
390
519
  );
391
- segoff = client.getContainingSegment(pos, {
392
- referenceSequenceNumber: op.referenceSequenceNumber,
393
- clientId: op.clientId,
394
- });
395
- segoff = getSlideToSegoff(segoff);
520
+ if (pos === "start" || pos === "end") {
521
+ segoff = pos;
522
+ } else {
523
+ segoff = client.getContainingSegment(pos, {
524
+ referenceSequenceNumber: op.referenceSequenceNumber,
525
+ clientId: op.clientId,
526
+ });
527
+ segoff = getSlideToSegoff(segoff, undefined, useNewSlidingBehavior);
528
+ }
396
529
  } else {
397
530
  assert(
398
531
  (refType & ReferenceType.SlideOnRemove) === 0 || !!fromSnapshot,
399
532
  0x2f6 /* SlideOnRemove references must be op created */,
400
533
  );
401
- segoff = client.getContainingSegment(pos, undefined, localSeq);
534
+ segoff =
535
+ pos === "start" || pos === "end"
536
+ ? pos
537
+ : client.getContainingSegment(pos, undefined, localSeq);
402
538
  }
403
539
 
404
540
  return createPositionReferenceFromSegoff(
@@ -409,19 +545,32 @@ function createPositionReference(
409
545
  localSeq,
410
546
  fromSnapshot,
411
547
  slidingPreference,
548
+ exclusive,
412
549
  );
413
550
  }
414
551
 
415
552
  export function createSequenceInterval(
416
553
  label: string,
417
- start: number,
418
- end: number,
554
+ start: SequencePlace | undefined,
555
+ end: SequencePlace | undefined,
419
556
  client: Client,
420
557
  intervalType: IntervalType,
421
558
  op?: ISequencedDocumentMessage,
422
559
  fromSnapshot?: boolean,
423
- stickiness: IntervalStickiness = IntervalStickiness.END,
560
+ useNewSlidingBehavior: boolean = false,
424
561
  ): SequenceInterval {
562
+ const { startPos, startSide, endPos, endSide } = endpointPosAndSide(
563
+ start ?? "start",
564
+ end ?? "end",
565
+ );
566
+ assert(
567
+ startPos !== undefined &&
568
+ endPos !== undefined &&
569
+ startSide !== undefined &&
570
+ endSide !== undefined,
571
+ 0x794 /* start and end cannot be undefined because they were not passed in as undefined */,
572
+ );
573
+ const stickiness = computeStickinessFromSide(startPos, startSide, endPos, endSide);
425
574
  let beginRefType = ReferenceType.RangeBegin;
426
575
  let endRefType = ReferenceType.RangeEnd;
427
576
  if (intervalType === IntervalType.Transient) {
@@ -435,7 +584,7 @@ export function createSequenceInterval(
435
584
  // All non-transient interval references must eventually be SlideOnRemove
436
585
  // To ensure eventual consistency, they must start as StayOnRemove when
437
586
  // pending (created locally and creation op is not acked)
438
- if (op || fromSnapshot) {
587
+ if (op ?? fromSnapshot) {
439
588
  beginRefType |= ReferenceType.SlideOnRemove;
440
589
  endRefType |= ReferenceType.SlideOnRemove;
441
590
  } else {
@@ -446,22 +595,26 @@ export function createSequenceInterval(
446
595
 
447
596
  const startLref = createPositionReference(
448
597
  client,
449
- start,
598
+ startPos,
450
599
  beginRefType,
451
600
  op,
452
601
  fromSnapshot,
453
602
  undefined,
454
603
  startReferenceSlidingPreference(stickiness),
604
+ startReferenceSlidingPreference(stickiness) === SlidingPreference.BACKWARD,
605
+ useNewSlidingBehavior,
455
606
  );
456
607
 
457
608
  const endLref = createPositionReference(
458
609
  client,
459
- end,
610
+ endPos,
460
611
  endRefType,
461
612
  op,
462
613
  fromSnapshot,
463
614
  undefined,
464
615
  endReferenceSlidingPreference(stickiness),
616
+ endReferenceSlidingPreference(stickiness) === SlidingPreference.FORWARD,
617
+ useNewSlidingBehavior,
465
618
  );
466
619
 
467
620
  const rangeProp = {
@@ -476,19 +629,16 @@ export function createSequenceInterval(
476
629
  endLref,
477
630
  intervalType,
478
631
  rangeProp,
479
- stickiness,
632
+ startSide,
633
+ endSide,
480
634
  );
481
635
  return ival;
482
636
  }
483
637
 
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
-
638
+ /**
639
+ * @deprecated The methods within have substitutions
640
+ * @public
641
+ */
490
642
  export const sequenceIntervalHelpers: IIntervalHelpers<SequenceInterval> = {
491
- compareEnds: compareSequenceIntervalEnds,
492
- compareStarts: compareSequenceIntervalStarts,
493
643
  create: createSequenceInterval,
494
644
  };
@@ -58,7 +58,10 @@ export class ValueTypeLocalValue<T> implements ILocalValue<T> {
58
58
  * @param value - The instance of the value type stored within
59
59
  * @param valueType - The type object of the value type stored within
60
60
  */
61
- constructor(public readonly value: T, private readonly valueType: IValueType<T>) {}
61
+ constructor(
62
+ public readonly value: T,
63
+ private readonly valueType: IValueType<T>,
64
+ ) {}
62
65
 
63
66
  /**
64
67
  * {@inheritDoc ILocalValue."type"}
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/sequence";
9
- export const pkgVersion = "2.0.0-dev.6.4.0.192049";
9
+ export const pkgVersion = "2.0.0-dev.7.2.0.204906";