@fluidframework/sequence 2.0.0-internal.6.3.3 → 2.0.0-internal.7.0.0

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