@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
@@ -3,26 +3,47 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  /* eslint-disable no-bitwise */
6
+ /* eslint-disable import/no-deprecated */
6
7
  import { TypedEventEmitter } from "@fluid-internal/client-utils";
7
8
  import { assert } from "@fluidframework/core-utils";
8
- import { addProperties, createMap, getSlideToSegoff, MergeTreeDeltaType, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, DetachedReferencePosition, } from "@fluidframework/merge-tree";
9
+ import { addProperties, createMap, getSlideToSegoff, MergeTreeDeltaType, ReferenceType, refTypeIncludesFlag, reservedRangeLabelsKey, UnassignedSequenceNumber, DetachedReferencePosition, UniversalSequenceNumber, SlidingPreference, } from "@fluidframework/merge-tree";
9
10
  import { LoggingError, UsageError } from "@fluidframework/telemetry-utils";
10
11
  import { v4 as uuid } from "uuid";
11
12
  import { IntervalOpType, IntervalStickiness, IntervalType, SequenceInterval, createPositionReferenceFromSegoff, endReferenceSlidingPreference, startReferenceSlidingPreference, sequenceIntervalHelpers, createInterval, } from "./intervals";
12
- import { createEndpointIndex, createIdIntervalIndex, createOverlappingIntervalsIndex, } from "./intervalIndex";
13
+ import { EndpointIndex, OverlappingIntervalsIndex, createIdIntervalIndex, } from "./intervalIndex";
14
+ /**
15
+ * Defines a side relative to a character in a sequence.
16
+ *
17
+ * @remarks See {@link SequencePlace} for additional context on usage.
18
+ * @public
19
+ */
20
+ export var Side;
21
+ (function (Side) {
22
+ Side[Side["Before"] = 0] = "Before";
23
+ Side[Side["After"] = 1] = "After";
24
+ })(Side || (Side = {}));
13
25
  const reservedIntervalIdKey = "intervalId";
26
+ export function sidesFromStickiness(stickiness) {
27
+ const startSide = (stickiness & IntervalStickiness.START) !== 0 ? Side.After : Side.Before;
28
+ const endSide = (stickiness & IntervalStickiness.END) !== 0 ? Side.Before : Side.After;
29
+ return { startSide, endSide };
30
+ }
14
31
  /**
15
32
  * Decompress an interval after loading a summary from JSON. The exact format
16
33
  * of this compression is unspecified and subject to change
17
34
  */
18
35
  function decompressInterval(interval, label) {
36
+ const stickiness = interval[5] ?? IntervalStickiness.END;
37
+ const { startSide, endSide } = sidesFromStickiness(stickiness);
19
38
  return {
20
39
  start: interval[0],
21
40
  end: interval[1],
22
41
  sequenceNumber: interval[2],
23
42
  intervalType: interval[3],
24
43
  properties: { ...interval[4], [reservedRangeLabelsKey]: [label] },
25
- stickiness: interval[5],
44
+ stickiness,
45
+ startSide,
46
+ endSide,
26
47
  };
27
48
  }
28
49
  /**
@@ -31,7 +52,7 @@ function decompressInterval(interval, label) {
31
52
  */
32
53
  function compressInterval(interval) {
33
54
  const { start, end, sequenceNumber, intervalType, properties } = interval;
34
- const base = [
55
+ let base = [
35
56
  start,
36
57
  end,
37
58
  sequenceNumber,
@@ -41,29 +62,60 @@ function compressInterval(interval) {
41
62
  { ...properties, [reservedRangeLabelsKey]: undefined },
42
63
  ];
43
64
  if (interval.stickiness !== undefined && interval.stickiness !== IntervalStickiness.END) {
44
- base.push(interval.stickiness);
65
+ // reassignment to make it easier for typescript to reason about types
66
+ base = [...base, interval.stickiness];
45
67
  }
46
68
  return base;
47
69
  }
70
+ export function endpointPosAndSide(start, end) {
71
+ const startIsPlainEndpoint = typeof start === "number" || start === "start" || start === "end";
72
+ const endIsPlainEndpoint = typeof end === "number" || end === "start" || end === "end";
73
+ const startSide = startIsPlainEndpoint ? Side.Before : start?.side;
74
+ const endSide = endIsPlainEndpoint ? Side.Before : end?.side;
75
+ const startPos = startIsPlainEndpoint ? start : start?.pos;
76
+ const endPos = endIsPlainEndpoint ? end : end?.pos;
77
+ return {
78
+ startSide,
79
+ endSide,
80
+ startPos,
81
+ endPos,
82
+ };
83
+ }
84
+ function toSequencePlace(pos, side) {
85
+ return typeof pos === "number" ? { pos, side } : pos;
86
+ }
87
+ function toOptionalSequencePlace(pos, side = Side.Before) {
88
+ return typeof pos === "number" ? { pos, side } : pos;
89
+ }
90
+ export function computeStickinessFromSide(startPos = -1, startSide = Side.Before, endPos = -1, endSide = Side.Before) {
91
+ let stickiness = IntervalStickiness.NONE;
92
+ if (startSide === Side.After || startPos === "start") {
93
+ stickiness |= IntervalStickiness.START;
94
+ }
95
+ if (endSide === Side.Before || endPos === "end") {
96
+ stickiness |= IntervalStickiness.END;
97
+ }
98
+ return stickiness;
99
+ }
48
100
  export function createIntervalIndex() {
49
101
  const helpers = {
50
- compareEnds: (a, b) => a.end - b.end,
51
102
  create: createInterval,
52
103
  };
53
- const lc = new LocalIntervalCollection(undefined, "", helpers);
104
+ const lc = new LocalIntervalCollection(undefined, "", helpers, {});
54
105
  return lc;
55
106
  }
56
107
  export class LocalIntervalCollection {
57
- constructor(client, label, helpers,
108
+ constructor(client, label, helpers, options,
58
109
  /** Callback invoked each time one of the endpoints of an interval slides. */
59
110
  onPositionChange) {
60
111
  this.client = client;
61
112
  this.label = label;
62
113
  this.helpers = helpers;
114
+ this.options = options;
63
115
  this.onPositionChange = onPositionChange;
64
- this.overlappingIntervalsIndex = createOverlappingIntervalsIndex(client, helpers);
116
+ this.overlappingIntervalsIndex = new OverlappingIntervalsIndex(client, helpers);
65
117
  this.idIntervalIndex = createIdIntervalIndex();
66
- this.endIntervalIndex = createEndpointIndex(client, helpers);
118
+ this.endIntervalIndex = new EndpointIndex(client, helpers);
67
119
  this.indexes = new Set([
68
120
  this.overlappingIntervalsIndex,
69
121
  this.idIntervalIndex,
@@ -117,12 +169,12 @@ export class LocalIntervalCollection {
117
169
  this.removeIntervalFromIndexes(interval);
118
170
  this.removeIntervalListeners(interval);
119
171
  }
120
- createInterval(start, end, intervalType, op, stickiness = IntervalStickiness.END) {
121
- return this.helpers.create(this.label, start, end, this.client, intervalType, op, undefined, stickiness);
172
+ createInterval(start, end, intervalType, op) {
173
+ return this.helpers.create(this.label, start, end, this.client, intervalType, op, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint);
122
174
  }
123
- addInterval(start, end, intervalType, props, op, stickiness = IntervalStickiness.END) {
175
+ addInterval(start, end, intervalType, props, op) {
124
176
  var _a;
125
- const interval = this.createInterval(start, end, intervalType, op, stickiness);
177
+ const interval = this.createInterval(start, end, intervalType, op);
126
178
  if (interval) {
127
179
  if (!interval.properties) {
128
180
  interval.properties = createMap();
@@ -159,7 +211,7 @@ export class LocalIntervalCollection {
159
211
  this.addIntervalListeners(interval);
160
212
  }
161
213
  changeInterval(interval, start, end, op, localSeq) {
162
- const newInterval = interval.modify(this.label, start, end, op, localSeq);
214
+ const newInterval = interval.modify(this.label, start, end, op, localSeq, this.options.mergeTreeReferencesCanSlideToEndpoint);
163
215
  if (newInterval) {
164
216
  this.removeExistingInterval(interval);
165
217
  this.add(newInterval);
@@ -182,7 +234,7 @@ export class LocalIntervalCollection {
182
234
  // either, so this must be special-cased.
183
235
  return ref;
184
236
  }
185
- return this.client.createLocalReferencePosition(segment, ref.getOffset(), ReferenceType.Transient, ref.properties, ref.slidingPreference);
237
+ return this.client.createLocalReferencePosition(segment, ref.getOffset(), ReferenceType.Transient, ref.properties, ref.slidingPreference, ref.canSlideToEndpoint);
186
238
  };
187
239
  if (interval instanceof SequenceInterval) {
188
240
  let previousInterval;
@@ -239,7 +291,6 @@ SequenceIntervalCollectionValueType._ops = makeOpsMap();
239
291
  class IntervalCollectionFactory {
240
292
  load(emitter, raw = [], options) {
241
293
  const helpers = {
242
- compareEnds: (a, b) => a.end - b.end,
243
294
  create: createInterval,
244
295
  };
245
296
  const collection = new IntervalCollection(helpers, false, emitter, raw, options);
@@ -336,10 +387,18 @@ class IntervalCollectionIterator {
336
387
  };
337
388
  }
338
389
  }
390
+ // solely for type checking in the implementation of add - will be removed once
391
+ // deprecated signatures are removed
392
+ const isSequencePlace = (place) => {
393
+ return typeof place === "number" || typeof place === "string" || place.pos !== undefined;
394
+ };
339
395
  /**
340
396
  * {@inheritdoc IIntervalCollection}
341
397
  */
342
398
  export class IntervalCollection extends TypedEventEmitter {
399
+ get attached() {
400
+ return !!this.localCollection;
401
+ }
343
402
  /** @internal */
344
403
  constructor(helpers, requiresClient, emitter, serializedIntervals, options = {}) {
345
404
  super();
@@ -355,9 +414,6 @@ export class IntervalCollection extends TypedEventEmitter {
355
414
  ? serializedIntervals
356
415
  : serializedIntervals.intervals.map((i) => decompressInterval(i, serializedIntervals.label));
357
416
  }
358
- get attached() {
359
- return !!this.localCollection;
360
- }
361
417
  /**
362
418
  * {@inheritdoc IIntervalCollection.attachIndex}
363
419
  */
@@ -390,6 +446,9 @@ export class IntervalCollection extends TypedEventEmitter {
390
446
  if (!this.client) {
391
447
  throw new LoggingError("mergeTree client must exist");
392
448
  }
449
+ if (pos === "start" || pos === "end") {
450
+ return pos;
451
+ }
393
452
  const { clientId } = this.client.getCollabWindow();
394
453
  const { segment, offset } = this.client.getContainingSegment(pos, {
395
454
  referenceSequenceNumber: seqNumberFrom,
@@ -397,7 +456,7 @@ export class IntervalCollection extends TypedEventEmitter {
397
456
  }, localSeq);
398
457
  // if segment is undefined, it slid off the string
399
458
  assert(segment !== undefined, 0x54e /* No segment found */);
400
- const segoff = getSlideToSegoff({ segment, offset }) ?? segment;
459
+ const segoff = getSlideToSegoff({ segment, offset }, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint) ?? segment;
401
460
  // case happens when rebasing op, but concurrently entire string has been deleted
402
461
  if (segoff.segment === undefined || segoff.offset === undefined) {
403
462
  return DetachedReferencePosition;
@@ -436,12 +495,18 @@ export class IntervalCollection extends TypedEventEmitter {
436
495
  }
437
496
  });
438
497
  }
439
- this.localCollection = new LocalIntervalCollection(client, label, this.helpers, (interval, previousInterval) => this.emitChange(interval, previousInterval, true, true));
498
+ this.localCollection = new LocalIntervalCollection(client, label, this.helpers, this.options, (interval, previousInterval) => this.emitChange(interval, previousInterval, true, true));
440
499
  if (this.savedSerializedIntervals) {
441
500
  for (const serializedInterval of this.savedSerializedIntervals) {
442
501
  this.localCollection.ensureSerializedId(serializedInterval);
443
- const { start, end, intervalType, properties, stickiness } = serializedInterval;
444
- const interval = this.helpers.create(label, start, end, client, intervalType, undefined, true, stickiness);
502
+ const { start: startPos, end: endPos, intervalType, properties, startSide, endSide, } = serializedInterval;
503
+ const start = typeof startPos === "number" && startSide !== undefined
504
+ ? { pos: startPos, side: startSide }
505
+ : startPos;
506
+ const end = typeof endPos === "number" && endSide !== undefined
507
+ ? { pos: endPos, side: endSide }
508
+ : endPos;
509
+ const interval = this.helpers.create(label, start, end, client, intervalType, undefined, true, this.options.mergeTreeReferencesCanSlideToEndpoint);
445
510
  if (properties) {
446
511
  interval.addProperties(properties);
447
512
  }
@@ -487,28 +552,59 @@ export class IntervalCollection extends TypedEventEmitter {
487
552
  }
488
553
  return this.localCollection.idIntervalIndex.getIntervalById(id);
489
554
  }
490
- /**
491
- * {@inheritdoc IIntervalCollection.add}
492
- */
493
- add(start, end, intervalType, props, stickiness = IntervalStickiness.END) {
555
+ assertStickinessEnabled(start, end) {
556
+ if (!(typeof start === "number" && typeof end === "number") &&
557
+ !this.options.intervalStickinessEnabled) {
558
+ throw new UsageError("attempted to set interval stickiness without enabling `intervalStickinessEnabled` feature flag");
559
+ }
560
+ }
561
+ add(start, end, intervalType, props) {
562
+ let intStart;
563
+ let intEnd;
564
+ let type;
565
+ let properties;
566
+ if (isSequencePlace(start)) {
567
+ intStart = start;
568
+ assert(end !== undefined, 0x7c0 /* end must be defined */);
569
+ intEnd = end;
570
+ assert(intervalType !== undefined, 0x7c1 /* intervalType must be defined */);
571
+ type = intervalType;
572
+ properties = props;
573
+ }
574
+ else {
575
+ intStart = start.start;
576
+ intEnd = start.end;
577
+ type = IntervalType.SlideOnRemove;
578
+ properties = start.props;
579
+ }
494
580
  if (!this.localCollection) {
495
581
  throw new LoggingError("attach must be called prior to adding intervals");
496
582
  }
497
- if (intervalType & IntervalType.Transient) {
583
+ if (type & IntervalType.Transient) {
498
584
  throw new LoggingError("Can not add transient intervals");
499
585
  }
500
- if (stickiness !== IntervalStickiness.END && !this.options.intervalStickinessEnabled) {
501
- throw new UsageError("attempted to set interval stickiness without enabling `intervalStickinessEnabled` feature flag");
502
- }
503
- const interval = this.localCollection.addInterval(start, end, intervalType, props, undefined, stickiness);
586
+ const { startSide, endSide, startPos, endPos } = endpointPosAndSide(intStart, intEnd);
587
+ assert(startPos !== undefined &&
588
+ endPos !== undefined &&
589
+ startSide !== undefined &&
590
+ endSide !== undefined, 0x793 /* start and end cannot be undefined because they were not passed in as undefined */);
591
+ const stickiness = computeStickinessFromSide(startPos, startSide, endPos, endSide);
592
+ this.assertStickinessEnabled(intStart, intEnd);
593
+ const interval = this.localCollection.addInterval(toSequencePlace(startPos, startSide), toSequencePlace(endPos, endSide), type, properties);
504
594
  if (interval) {
595
+ if (!this.isCollaborating && interval instanceof SequenceInterval) {
596
+ setSlideOnRemove(interval.start);
597
+ setSlideOnRemove(interval.end);
598
+ }
505
599
  const serializedInterval = {
506
- end,
507
- intervalType,
600
+ start: startPos,
601
+ end: endPos,
602
+ intervalType: type,
508
603
  properties: interval.properties,
509
604
  sequenceNumber: this.client?.getCurrentSeq() ?? 0,
510
- start,
511
605
  stickiness,
606
+ startSide,
607
+ endSide,
512
608
  };
513
609
  const localSeq = this.getNextLocalSeq();
514
610
  this.localSeqToSerializedInterval.set(localSeq, serializedInterval);
@@ -572,8 +668,7 @@ export class IntervalCollection extends TypedEventEmitter {
572
668
  }
573
669
  const interval = this.getIntervalById(id);
574
670
  if (interval) {
575
- // Pass Unassigned as the sequence number to indicate that this is a local op that is waiting for an ack.
576
- const deltaProps = interval.addProperties(props, true, UnassignedSequenceNumber);
671
+ const deltaProps = interval.addProperties(props, true, this.isCollaborating ? UnassignedSequenceNumber : UniversalSequenceNumber);
577
672
  const serializedInterval = interval.serialize();
578
673
  // Emit a change op that will only change properties. Add the ID to
579
674
  // the property bag provided by the caller.
@@ -604,9 +699,18 @@ export class IntervalCollection extends TypedEventEmitter {
604
699
  if (!newInterval) {
605
700
  return undefined;
606
701
  }
702
+ if (!this.isCollaborating && newInterval instanceof SequenceInterval) {
703
+ setSlideOnRemove(newInterval.start);
704
+ setSlideOnRemove(newInterval.end);
705
+ }
607
706
  const serializedInterval = interval.serialize();
608
- serializedInterval.start = start;
609
- serializedInterval.end = end;
707
+ const { startPos, startSide, endPos, endSide } = endpointPosAndSide(start, end);
708
+ const stickiness = computeStickinessFromSide(startPos, startSide, endPos, endSide);
709
+ serializedInterval.start = startPos;
710
+ serializedInterval.end = endPos;
711
+ serializedInterval.startSide = startSide;
712
+ serializedInterval.endSide = endSide;
713
+ serializedInterval.stickiness = stickiness;
610
714
  // Emit a property bag containing only the ID, as we don't intend for this op to change any properties.
611
715
  serializedInterval.properties = {
612
716
  [reservedIntervalIdKey]: interval.getIntervalId(),
@@ -621,7 +725,13 @@ export class IntervalCollection extends TypedEventEmitter {
621
725
  // No interval to change
622
726
  return undefined;
623
727
  }
728
+ get isCollaborating() {
729
+ return this.client?.getCollabWindow().collaborating ?? false;
730
+ }
624
731
  addPendingChange(id, serializedInterval) {
732
+ if (!this.isCollaborating) {
733
+ return;
734
+ }
625
735
  if (serializedInterval.start !== undefined) {
626
736
  this.addPendingChangeHelper(id, this.pendingChangesStart, serializedInterval);
627
737
  }
@@ -714,7 +824,7 @@ export class IntervalCollection extends TypedEventEmitter {
714
824
  // If changeInterval gives us a new interval, work with that one. Otherwise keep working with
715
825
  // the one we originally found in the tree.
716
826
  newInterval =
717
- this.localCollection.changeInterval(interval, start, end, op) ?? interval;
827
+ this.localCollection.changeInterval(interval, toOptionalSequencePlace(start, serializedInterval.startSide), toOptionalSequencePlace(end, serializedInterval.endSide), op) ?? interval;
718
828
  }
719
829
  const deltaProps = newInterval.addProperties(newProps, true, op.sequenceNumber);
720
830
  if (this.onDeserialize) {
@@ -759,7 +869,7 @@ export class IntervalCollection extends TypedEventEmitter {
759
869
  if (!this.attached) {
760
870
  throw new LoggingError("attachSequence must be called");
761
871
  }
762
- const { intervalType, properties } = serializedInterval;
872
+ const { intervalType, properties, stickiness, startSide, endSide } = serializedInterval;
763
873
  const { start: startRebased, end: endRebased } = this.localSeqToRebasedInterval.get(localSeq) ?? this.computeRebasedPositions(localSeq);
764
874
  const intervalId = properties?.[reservedIntervalIdKey];
765
875
  const localInterval = this.localCollection?.idIntervalIndex.getIntervalById(intervalId);
@@ -769,8 +879,12 @@ export class IntervalCollection extends TypedEventEmitter {
769
879
  intervalType,
770
880
  sequenceNumber: this.client?.getCurrentSeq() ?? 0,
771
881
  properties,
882
+ stickiness,
883
+ startSide,
884
+ endSide,
772
885
  };
773
886
  if (opName === "change" &&
887
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- ?? is not logically equivalent when .hasPendingChangeStart returns false.
774
888
  (this.hasPendingChangeStart(intervalId) || this.hasPendingChangeEnd(intervalId))) {
775
889
  this.removePendingChange(serializedInterval);
776
890
  this.addPendingChange(intervalId, rebased);
@@ -788,7 +902,7 @@ export class IntervalCollection extends TypedEventEmitter {
788
902
  assert(localInterval instanceof SequenceInterval, 0x3a0 /* localInterval must be `SequenceInterval` when used with client */);
789
903
  // The rebased op may place this interval's endpoints on different segments. Calling `changeInterval` here
790
904
  // updates the local client's state to be consistent with the emitted op.
791
- this.localCollection?.changeInterval(localInterval, startRebased, endRebased, undefined, localSeq);
905
+ this.localCollection?.changeInterval(localInterval, toOptionalSequencePlace(startRebased, startSide), toOptionalSequencePlace(endRebased, endSide), undefined, localSeq);
792
906
  }
793
907
  return rebased;
794
908
  }
@@ -800,18 +914,12 @@ export class IntervalCollection extends TypedEventEmitter {
800
914
  if (segoff.segment?.localRefs?.has(lref) !== true) {
801
915
  return undefined;
802
916
  }
803
- const newSegoff = getSlideToSegoff(segoff);
917
+ const newSegoff = getSlideToSegoff(segoff, undefined, this.options.mergeTreeReferencesCanSlideToEndpoint);
804
918
  const value = segoff.segment === newSegoff.segment && segoff.offset === newSegoff.offset
805
919
  ? undefined
806
920
  : newSegoff;
807
921
  return value;
808
922
  }
809
- setSlideOnRemove(lref) {
810
- let refType = lref.refType;
811
- refType = refType & ~ReferenceType.StayOnRemove;
812
- refType = refType | ReferenceType.SlideOnRemove;
813
- lref.refType = refType;
814
- }
815
923
  ackInterval(interval, op) {
816
924
  // Only SequenceIntervals need potential sliding
817
925
  if (!(interval instanceof SequenceInterval)) {
@@ -827,10 +935,10 @@ export class IntervalCollection extends TypedEventEmitter {
827
935
  const hasPendingStartChange = this.hasPendingChangeStart(id);
828
936
  const hasPendingEndChange = this.hasPendingChangeEnd(id);
829
937
  if (!hasPendingStartChange) {
830
- this.setSlideOnRemove(interval.start);
938
+ setSlideOnRemove(interval.start);
831
939
  }
832
940
  if (!hasPendingEndChange) {
833
- this.setSlideOnRemove(interval.end);
941
+ setSlideOnRemove(interval.end);
834
942
  }
835
943
  const needsStartUpdate = newStart !== undefined && !hasPendingStartChange;
836
944
  const needsEndUpdate = newEnd !== undefined && !hasPendingEndChange;
@@ -849,7 +957,8 @@ export class IntervalCollection extends TypedEventEmitter {
849
957
  }
850
958
  if (needsStartUpdate) {
851
959
  const props = interval.start.properties;
852
- interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op, startReferenceSlidingPreference(interval.stickiness));
960
+ interval.start = createPositionReferenceFromSegoff(this.client, newStart, interval.start.refType, op, undefined, undefined, startReferenceSlidingPreference(interval.stickiness), startReferenceSlidingPreference(interval.stickiness) ===
961
+ SlidingPreference.BACKWARD);
853
962
  if (props) {
854
963
  interval.start.addProperties(props);
855
964
  }
@@ -861,7 +970,8 @@ export class IntervalCollection extends TypedEventEmitter {
861
970
  }
862
971
  if (needsEndUpdate) {
863
972
  const props = interval.end.properties;
864
- interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op, endReferenceSlidingPreference(interval.stickiness));
973
+ interval.end = createPositionReferenceFromSegoff(this.client, newEnd, interval.end.refType, op, undefined, undefined, endReferenceSlidingPreference(interval.stickiness), endReferenceSlidingPreference(interval.stickiness) ===
974
+ SlidingPreference.FORWARD);
865
975
  if (props) {
866
976
  interval.end.addProperties(props);
867
977
  }
@@ -891,7 +1001,7 @@ export class IntervalCollection extends TypedEventEmitter {
891
1001
  throw new LoggingError("attachSequence must be called");
892
1002
  }
893
1003
  this.localCollection.ensureSerializedId(serializedInterval);
894
- const interval = this.localCollection.addInterval(serializedInterval.start, serializedInterval.end, serializedInterval.intervalType, serializedInterval.properties, op, serializedInterval.stickiness);
1004
+ const interval = this.localCollection.addInterval(toSequencePlace(serializedInterval.start, serializedInterval.startSide ?? Side.Before), toSequencePlace(serializedInterval.end, serializedInterval.endSide ?? Side.Before), serializedInterval.intervalType, serializedInterval.properties, op);
895
1005
  if (interval) {
896
1006
  if (this.onDeserialize) {
897
1007
  this.onDeserialize(interval);
@@ -1009,11 +1119,18 @@ export class IntervalCollection extends TypedEventEmitter {
1009
1119
  return this.localCollection.endIntervalIndex.nextInterval(pos);
1010
1120
  }
1011
1121
  }
1122
+ function setSlideOnRemove(lref) {
1123
+ let refType = lref.refType;
1124
+ refType = refType & ~ReferenceType.StayOnRemove;
1125
+ refType = refType | ReferenceType.SlideOnRemove;
1126
+ lref.refType = refType;
1127
+ }
1012
1128
  /**
1013
1129
  * Returns an object that can be used to find the interval a given LocalReferencePosition belongs to.
1014
1130
  * @returns undefined if the reference position is not the endpoint of any interval (e.g. it was created
1015
1131
  * on the merge tree directly by app code), otherwise an {@link IntervalLocator} for the interval this
1016
1132
  * endpoint is a part of.
1133
+ * @public
1017
1134
  */
1018
1135
  export function intervalLocatorFromEndpoint(potentialEndpoint) {
1019
1136
  const { interval, [reservedRangeLabelsKey]: collectionNameArray } = potentialEndpoint.properties ?? {};