@fluidframework/merge-tree 2.11.0 → 2.13.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 (306) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/api-report/merge-tree.legacy.alpha.api.md +50 -19
  3. package/dist/MergeTreeTextHelper.d.ts.map +1 -1
  4. package/dist/MergeTreeTextHelper.js +0 -2
  5. package/dist/MergeTreeTextHelper.js.map +1 -1
  6. package/dist/attributionPolicy.d.ts.map +1 -1
  7. package/dist/attributionPolicy.js +6 -15
  8. package/dist/attributionPolicy.js.map +1 -1
  9. package/dist/client.d.ts +3 -4
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +39 -28
  12. package/dist/client.js.map +1 -1
  13. package/dist/endOfTreeSegment.d.ts +5 -4
  14. package/dist/endOfTreeSegment.d.ts.map +1 -1
  15. package/dist/endOfTreeSegment.js.map +1 -1
  16. package/dist/index.d.ts +2 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +3 -4
  19. package/dist/index.js.map +1 -1
  20. package/dist/legacy.d.ts +2 -1
  21. package/dist/localReference.d.ts +1 -0
  22. package/dist/localReference.d.ts.map +1 -1
  23. package/dist/localReference.js +1 -0
  24. package/dist/localReference.js.map +1 -1
  25. package/dist/mergeTree.d.ts +8 -7
  26. package/dist/mergeTree.d.ts.map +1 -1
  27. package/dist/mergeTree.js +202 -211
  28. package/dist/mergeTree.js.map +1 -1
  29. package/dist/mergeTreeNodeWalk.d.ts +5 -5
  30. package/dist/mergeTreeNodeWalk.d.ts.map +1 -1
  31. package/dist/mergeTreeNodeWalk.js +3 -2
  32. package/dist/mergeTreeNodeWalk.js.map +1 -1
  33. package/dist/mergeTreeNodes.d.ts +181 -159
  34. package/dist/mergeTreeNodes.d.ts.map +1 -1
  35. package/dist/mergeTreeNodes.js +121 -109
  36. package/dist/mergeTreeNodes.js.map +1 -1
  37. package/dist/mergeTreeTracking.d.ts.map +1 -1
  38. package/dist/mergeTreeTracking.js +0 -2
  39. package/dist/mergeTreeTracking.js.map +1 -1
  40. package/dist/partialLengths.d.ts +2 -2
  41. package/dist/partialLengths.d.ts.map +1 -1
  42. package/dist/partialLengths.js +33 -27
  43. package/dist/partialLengths.js.map +1 -1
  44. package/dist/perspective.d.ts +10 -9
  45. package/dist/perspective.d.ts.map +1 -1
  46. package/dist/perspective.js +11 -4
  47. package/dist/perspective.js.map +1 -1
  48. package/dist/referencePositions.d.ts.map +1 -1
  49. package/dist/referencePositions.js +4 -1
  50. package/dist/referencePositions.js.map +1 -1
  51. package/dist/revertibles.d.ts.map +1 -1
  52. package/dist/revertibles.js +13 -11
  53. package/dist/revertibles.js.map +1 -1
  54. package/dist/segmentGroupCollection.d.ts +4 -4
  55. package/dist/segmentGroupCollection.d.ts.map +1 -1
  56. package/dist/segmentGroupCollection.js +0 -6
  57. package/dist/segmentGroupCollection.js.map +1 -1
  58. package/dist/segmentInfos.d.ts +257 -0
  59. package/dist/segmentInfos.d.ts.map +1 -0
  60. package/dist/segmentInfos.js +166 -0
  61. package/dist/segmentInfos.js.map +1 -0
  62. package/dist/snapshotLoader.d.ts.map +1 -1
  63. package/dist/snapshotLoader.js +38 -44
  64. package/dist/snapshotLoader.js.map +1 -1
  65. package/dist/snapshotV1.d.ts.map +1 -1
  66. package/dist/snapshotV1.js +9 -12
  67. package/dist/snapshotV1.js.map +1 -1
  68. package/dist/snapshotlegacy.d.ts +2 -2
  69. package/dist/snapshotlegacy.d.ts.map +1 -1
  70. package/dist/snapshotlegacy.js +5 -3
  71. package/dist/snapshotlegacy.js.map +1 -1
  72. package/dist/sortedSegmentSet.d.ts +4 -4
  73. package/dist/sortedSegmentSet.d.ts.map +1 -1
  74. package/dist/sortedSegmentSet.js +5 -8
  75. package/dist/sortedSegmentSet.js.map +1 -1
  76. package/dist/test/beastTest.spec.d.ts +0 -2
  77. package/dist/test/beastTest.spec.d.ts.map +1 -1
  78. package/dist/test/beastTest.spec.js +1 -5
  79. package/dist/test/beastTest.spec.js.map +1 -1
  80. package/dist/test/client.annotateMarker.spec.js.map +1 -1
  81. package/dist/test/client.applyMsg.spec.js +15 -12
  82. package/dist/test/client.applyMsg.spec.js.map +1 -1
  83. package/dist/test/client.attributionFarm.spec.d.ts.map +1 -1
  84. package/dist/test/client.attributionFarm.spec.js.map +1 -1
  85. package/dist/test/client.getPosition.spec.js +3 -2
  86. package/dist/test/client.getPosition.spec.js.map +1 -1
  87. package/dist/test/client.localReference.spec.js +6 -6
  88. package/dist/test/client.localReference.spec.js.map +1 -1
  89. package/dist/test/client.localReferenceFarm.spec.js.map +1 -1
  90. package/dist/test/client.rollback.spec.js.map +1 -1
  91. package/dist/test/dirname.cjs +0 -1
  92. package/dist/test/dirname.cjs.map +1 -1
  93. package/dist/test/index.d.ts +1 -1
  94. package/dist/test/index.d.ts.map +1 -1
  95. package/dist/test/index.js +2 -4
  96. package/dist/test/index.js.map +1 -1
  97. package/dist/test/mergeTree.annotate.spec.js +3 -0
  98. package/dist/test/mergeTree.annotate.spec.js.map +1 -1
  99. package/dist/test/mergeTree.insertingWalk.spec.js +1 -1
  100. package/dist/test/mergeTree.insertingWalk.spec.js.map +1 -1
  101. package/dist/test/mergeTree.markRangeRemoved.spec.js +2 -0
  102. package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  103. package/dist/test/mergeTree.walk.spec.js.map +1 -1
  104. package/dist/test/mergeTreeOperationRunner.d.ts.map +1 -1
  105. package/dist/test/mergeTreeOperationRunner.js +2 -3
  106. package/dist/test/mergeTreeOperationRunner.js.map +1 -1
  107. package/dist/test/obliterate.spec.js.map +1 -1
  108. package/dist/test/propertyManager.spec.js.map +1 -1
  109. package/dist/test/reconnectHelper.d.ts +2 -1
  110. package/dist/test/reconnectHelper.d.ts.map +1 -1
  111. package/dist/test/reconnectHelper.js.map +1 -1
  112. package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  113. package/dist/test/revertibleFarm.spec.js.map +1 -1
  114. package/dist/test/segmentGroupCollection.spec.js +15 -3
  115. package/dist/test/segmentGroupCollection.spec.js.map +1 -1
  116. package/dist/test/snapshot.utils.d.ts +2 -2
  117. package/dist/test/snapshot.utils.d.ts.map +1 -1
  118. package/dist/test/snapshot.utils.js.map +1 -1
  119. package/dist/test/sortedSegmentSet.spec.js +4 -3
  120. package/dist/test/sortedSegmentSet.spec.js.map +1 -1
  121. package/dist/test/testClient.d.ts +8 -6
  122. package/dist/test/testClient.d.ts.map +1 -1
  123. package/dist/test/testClient.js +29 -27
  124. package/dist/test/testClient.js.map +1 -1
  125. package/dist/test/testClientLogger.d.ts.map +1 -1
  126. package/dist/test/testClientLogger.js +6 -4
  127. package/dist/test/testClientLogger.js.map +1 -1
  128. package/dist/test/testUtils.d.ts +2 -2
  129. package/dist/test/testUtils.d.ts.map +1 -1
  130. package/dist/test/testUtils.js +32 -8
  131. package/dist/test/testUtils.js.map +1 -1
  132. package/dist/test/text.d.ts +2 -2
  133. package/dist/test/text.d.ts.map +1 -1
  134. package/dist/test/text.js +12 -6
  135. package/dist/test/text.js.map +1 -1
  136. package/dist/test/tracking.spec.js.map +1 -1
  137. package/dist/test/wordUnitTests.spec.d.ts.map +1 -1
  138. package/dist/test/wordUnitTests.spec.js +4 -2
  139. package/dist/test/wordUnitTests.spec.js.map +1 -1
  140. package/dist/zamboni.d.ts.map +1 -1
  141. package/dist/zamboni.js +8 -7
  142. package/dist/zamboni.js.map +1 -1
  143. package/lib/MergeTreeTextHelper.d.ts.map +1 -1
  144. package/lib/MergeTreeTextHelper.js +0 -2
  145. package/lib/MergeTreeTextHelper.js.map +1 -1
  146. package/lib/attributionPolicy.d.ts.map +1 -1
  147. package/lib/attributionPolicy.js +6 -15
  148. package/lib/attributionPolicy.js.map +1 -1
  149. package/lib/client.d.ts +3 -4
  150. package/lib/client.d.ts.map +1 -1
  151. package/lib/client.js +40 -29
  152. package/lib/client.js.map +1 -1
  153. package/lib/endOfTreeSegment.d.ts +5 -4
  154. package/lib/endOfTreeSegment.d.ts.map +1 -1
  155. package/lib/endOfTreeSegment.js.map +1 -1
  156. package/lib/index.d.ts +2 -1
  157. package/lib/index.d.ts.map +1 -1
  158. package/lib/index.js +1 -1
  159. package/lib/index.js.map +1 -1
  160. package/lib/legacy.d.ts +2 -1
  161. package/lib/localReference.d.ts +1 -0
  162. package/lib/localReference.d.ts.map +1 -1
  163. package/lib/localReference.js +1 -0
  164. package/lib/localReference.js.map +1 -1
  165. package/lib/mergeTree.d.ts +8 -7
  166. package/lib/mergeTree.d.ts.map +1 -1
  167. package/lib/mergeTree.js +192 -201
  168. package/lib/mergeTree.js.map +1 -1
  169. package/lib/mergeTreeNodeWalk.d.ts +5 -5
  170. package/lib/mergeTreeNodeWalk.d.ts.map +1 -1
  171. package/lib/mergeTreeNodeWalk.js +3 -2
  172. package/lib/mergeTreeNodeWalk.js.map +1 -1
  173. package/lib/mergeTreeNodes.d.ts +181 -159
  174. package/lib/mergeTreeNodes.d.ts.map +1 -1
  175. package/lib/mergeTreeNodes.js +115 -105
  176. package/lib/mergeTreeNodes.js.map +1 -1
  177. package/lib/mergeTreeTracking.d.ts.map +1 -1
  178. package/lib/mergeTreeTracking.js +0 -2
  179. package/lib/mergeTreeTracking.js.map +1 -1
  180. package/lib/partialLengths.d.ts +2 -2
  181. package/lib/partialLengths.d.ts.map +1 -1
  182. package/lib/partialLengths.js +30 -24
  183. package/lib/partialLengths.js.map +1 -1
  184. package/lib/perspective.d.ts +10 -9
  185. package/lib/perspective.d.ts.map +1 -1
  186. package/lib/perspective.js +11 -4
  187. package/lib/perspective.js.map +1 -1
  188. package/lib/referencePositions.d.ts.map +1 -1
  189. package/lib/referencePositions.js +4 -1
  190. package/lib/referencePositions.js.map +1 -1
  191. package/lib/revertibles.d.ts.map +1 -1
  192. package/lib/revertibles.js +11 -9
  193. package/lib/revertibles.js.map +1 -1
  194. package/lib/segmentGroupCollection.d.ts +4 -4
  195. package/lib/segmentGroupCollection.d.ts.map +1 -1
  196. package/lib/segmentGroupCollection.js +0 -6
  197. package/lib/segmentGroupCollection.js.map +1 -1
  198. package/lib/segmentInfos.d.ts +257 -0
  199. package/lib/segmentInfos.d.ts.map +1 -0
  200. package/lib/segmentInfos.js +145 -0
  201. package/lib/segmentInfos.js.map +1 -0
  202. package/lib/snapshotLoader.d.ts.map +1 -1
  203. package/lib/snapshotLoader.js +38 -44
  204. package/lib/snapshotLoader.js.map +1 -1
  205. package/lib/snapshotV1.d.ts.map +1 -1
  206. package/lib/snapshotV1.js +9 -12
  207. package/lib/snapshotV1.js.map +1 -1
  208. package/lib/snapshotlegacy.d.ts +2 -2
  209. package/lib/snapshotlegacy.d.ts.map +1 -1
  210. package/lib/snapshotlegacy.js +5 -3
  211. package/lib/snapshotlegacy.js.map +1 -1
  212. package/lib/sortedSegmentSet.d.ts +4 -4
  213. package/lib/sortedSegmentSet.d.ts.map +1 -1
  214. package/lib/sortedSegmentSet.js +5 -8
  215. package/lib/sortedSegmentSet.js.map +1 -1
  216. package/lib/test/beastTest.spec.d.ts +0 -2
  217. package/lib/test/beastTest.spec.d.ts.map +1 -1
  218. package/lib/test/beastTest.spec.js +0 -3
  219. package/lib/test/beastTest.spec.js.map +1 -1
  220. package/lib/test/client.annotateMarker.spec.js.map +1 -1
  221. package/lib/test/client.applyMsg.spec.js +15 -12
  222. package/lib/test/client.applyMsg.spec.js.map +1 -1
  223. package/lib/test/client.attributionFarm.spec.d.ts.map +1 -1
  224. package/lib/test/client.attributionFarm.spec.js.map +1 -1
  225. package/lib/test/client.getPosition.spec.js +3 -2
  226. package/lib/test/client.getPosition.spec.js.map +1 -1
  227. package/lib/test/client.localReference.spec.js +1 -1
  228. package/lib/test/client.localReference.spec.js.map +1 -1
  229. package/lib/test/client.localReferenceFarm.spec.js.map +1 -1
  230. package/lib/test/client.rollback.spec.js +1 -1
  231. package/lib/test/client.rollback.spec.js.map +1 -1
  232. package/lib/test/dirname.cjs +0 -1
  233. package/lib/test/dirname.cjs.map +1 -1
  234. package/lib/test/index.d.ts +1 -1
  235. package/lib/test/index.d.ts.map +1 -1
  236. package/lib/test/index.js +1 -1
  237. package/lib/test/index.js.map +1 -1
  238. package/lib/test/mergeTree.annotate.spec.js +3 -0
  239. package/lib/test/mergeTree.annotate.spec.js.map +1 -1
  240. package/lib/test/mergeTree.insertingWalk.spec.js +2 -2
  241. package/lib/test/mergeTree.insertingWalk.spec.js.map +1 -1
  242. package/lib/test/mergeTree.markRangeRemoved.spec.js +2 -0
  243. package/lib/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  244. package/lib/test/mergeTree.walk.spec.js.map +1 -1
  245. package/lib/test/mergeTreeOperationRunner.d.ts.map +1 -1
  246. package/lib/test/mergeTreeOperationRunner.js +1 -2
  247. package/lib/test/mergeTreeOperationRunner.js.map +1 -1
  248. package/lib/test/obliterate.spec.js.map +1 -1
  249. package/lib/test/propertyManager.spec.js.map +1 -1
  250. package/lib/test/reconnectHelper.d.ts +2 -1
  251. package/lib/test/reconnectHelper.d.ts.map +1 -1
  252. package/lib/test/reconnectHelper.js.map +1 -1
  253. package/lib/test/resetPendingSegmentsToOp.spec.js +1 -1
  254. package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  255. package/lib/test/revertibleFarm.spec.js.map +1 -1
  256. package/lib/test/segmentGroupCollection.spec.js +15 -3
  257. package/lib/test/segmentGroupCollection.spec.js.map +1 -1
  258. package/lib/test/snapshot.utils.d.ts +2 -2
  259. package/lib/test/snapshot.utils.d.ts.map +1 -1
  260. package/lib/test/snapshot.utils.js.map +1 -1
  261. package/lib/test/sortedSegmentSet.spec.js +4 -3
  262. package/lib/test/sortedSegmentSet.spec.js.map +1 -1
  263. package/lib/test/testClient.d.ts +8 -6
  264. package/lib/test/testClient.d.ts.map +1 -1
  265. package/lib/test/testClient.js +30 -28
  266. package/lib/test/testClient.js.map +1 -1
  267. package/lib/test/testClientLogger.d.ts.map +1 -1
  268. package/lib/test/testClientLogger.js +5 -3
  269. package/lib/test/testClientLogger.js.map +1 -1
  270. package/lib/test/testUtils.d.ts +2 -2
  271. package/lib/test/testUtils.d.ts.map +1 -1
  272. package/lib/test/testUtils.js +9 -8
  273. package/lib/test/testUtils.js.map +1 -1
  274. package/lib/test/text.d.ts +2 -2
  275. package/lib/test/text.d.ts.map +1 -1
  276. package/lib/test/text.js +12 -6
  277. package/lib/test/text.js.map +1 -1
  278. package/lib/test/tracking.spec.js.map +1 -1
  279. package/lib/test/wordUnitTests.spec.d.ts.map +1 -1
  280. package/lib/test/wordUnitTests.spec.js +4 -2
  281. package/lib/test/wordUnitTests.spec.js.map +1 -1
  282. package/lib/zamboni.d.ts.map +1 -1
  283. package/lib/zamboni.js +7 -6
  284. package/lib/zamboni.js.map +1 -1
  285. package/package.json +18 -18
  286. package/src/MergeTreeTextHelper.ts +2 -4
  287. package/src/attributionPolicy.ts +5 -11
  288. package/src/client.ts +55 -44
  289. package/src/endOfTreeSegment.ts +7 -4
  290. package/src/index.ts +5 -6
  291. package/src/localReference.ts +1 -0
  292. package/src/mergeTree.ts +253 -271
  293. package/src/mergeTreeNodeWalk.ts +9 -8
  294. package/src/mergeTreeNodes.ts +300 -305
  295. package/src/mergeTreeTracking.ts +0 -3
  296. package/src/partialLengths.ts +44 -25
  297. package/src/perspective.ts +36 -13
  298. package/src/referencePositions.ts +4 -1
  299. package/src/revertibles.ts +20 -16
  300. package/src/segmentGroupCollection.ts +7 -18
  301. package/src/segmentInfos.ts +377 -0
  302. package/src/snapshotLoader.ts +60 -57
  303. package/src/snapshotV1.ts +14 -16
  304. package/src/snapshotlegacy.ts +12 -17
  305. package/src/sortedSegmentSet.ts +12 -15
  306. package/src/zamboni.ts +10 -12
package/lib/mergeTree.js CHANGED
@@ -9,43 +9,29 @@ import { DataProcessingError, UsageError } from "@fluidframework/telemetry-utils
9
9
  import { DoublyLinkedList } from "./collections/index.js";
10
10
  import { NonCollabClient, TreeMaintenanceSequenceNumber, UnassignedSequenceNumber, UniversalSequenceNumber, } from "./constants.js";
11
11
  import { EndOfTreeSegment, StartOfTreeSegment } from "./endOfTreeSegment.js";
12
- import { LocalReferenceCollection, SlidingPreference, anyLocalReferencePosition, createDetachedLocalReferencePosition, filterLocalReferencePositions, } from "./localReference.js";
13
- import { MergeTreeMaintenanceType, } from "./mergeTreeDeltaCallback.js";
14
- import { NodeAction, backwardExcursion, depthFirstNodeWalk, forwardExcursion, walkAllChildSegments, } from "./mergeTreeNodeWalk.js";
15
12
  import {
16
13
  // eslint-disable-next-line import/no-deprecated
17
- CollaborationWindow, Marker, MaxNodesInBlock, MergeBlock, reservedMarkerIdKey, seqLTE, toMoveInfo, toRemovalInfo, } from "./mergeTreeNodes.js";
14
+ LocalReferenceCollection, SlidingPreference, anyLocalReferencePosition, createDetachedLocalReferencePosition, filterLocalReferencePositions, } from "./localReference.js";
15
+ import { MergeTreeMaintenanceType, } from "./mergeTreeDeltaCallback.js";
16
+ import { NodeAction, backwardExcursion, depthFirstNodeWalk, forwardExcursion, walkAllChildSegments, } from "./mergeTreeNodeWalk.js";
17
+ import { CollaborationWindow, Marker, MaxNodesInBlock, MergeBlock, assertSegmentLeaf, assignChild, isSegmentLeaf, reservedMarkerIdKey, seqLTE, } from "./mergeTreeNodes.js";
18
18
  import { createAnnotateRangeOp, createInsertSegmentOp, createRemoveRangeOp, } from "./opBuilder.js";
19
19
  import { MergeTreeDeltaType, ReferenceType, } from "./ops.js";
20
20
  import { PartialSequenceLengths } from "./partialLengths.js";
21
21
  import { PerspectiveImpl, isSegmentPresent } from "./perspective.js";
22
22
  import { createMap, extend, extendIfUndefined } from "./properties.js";
23
23
  import { DetachedReferencePosition, refGetTileLabels, refHasTileLabel, refTypeIncludesFlag, } from "./referencePositions.js";
24
- // eslint-disable-next-line import/no-deprecated
25
24
  import { SegmentGroupCollection } from "./segmentGroupCollection.js";
26
- // eslint-disable-next-line import/no-deprecated
25
+ import { assertMoved, assertRemoved, isMergeNodeInfo, isMoved, isRemoved, overwriteInfo, removeRemovalInfo, toMoveInfo, toRemovalInfo, } from "./segmentInfos.js";
27
26
  import { copyPropertiesAndManager, PropertiesManager, PropertiesRollback, } from "./segmentPropertiesManager.js";
28
27
  import { Side } from "./sequencePlace.js";
29
28
  import { SortedSegmentSet } from "./sortedSegmentSet.js";
30
29
  import { zamboniSegments } from "./zamboni.js";
31
- function markSegmentMoved(seg, moveInfo) {
32
- seg.moveDst = moveInfo.moveDst;
33
- seg.movedClientIds = [...moveInfo.movedClientIds];
34
- seg.movedSeqs = [moveInfo.movedSeq];
35
- seg.movedSeq = moveInfo.movedSeq;
36
- seg.localMovedSeq = moveInfo.localMovedSeq;
37
- seg.wasMovedOnInsert = moveInfo.wasMovedOnInsert;
38
- }
39
- function isMoved(segment) {
40
- return toMoveInfo(segment) !== undefined;
41
- }
42
- function isRemoved(segment) {
43
- return toRemovalInfo(segment) !== undefined;
44
- }
45
30
  function isRemovedAndAcked(segment) {
46
31
  const removalInfo = toRemovalInfo(segment);
47
32
  return removalInfo !== undefined && removalInfo.removedSeq !== UnassignedSequenceNumber;
48
33
  }
34
+ // eslint-disable-next-line import/no-deprecated
49
35
  function isMovedAndAcked(segment) {
50
36
  const moveInfo = toMoveInfo(segment);
51
37
  return moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber;
@@ -84,27 +70,25 @@ function ackSegment(segment, segmentGroup, opArgs) {
84
70
  return true;
85
71
  }
86
72
  case MergeTreeDeltaType.REMOVE: {
87
- const removalInfo = toRemovalInfo(segment);
88
- assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
73
+ assertRemoved(segment);
89
74
  segment.localRemovedSeq = undefined;
90
- if (removalInfo.removedSeq === UnassignedSequenceNumber) {
91
- removalInfo.removedSeq = sequenceNumber;
75
+ if (segment.removedSeq === UnassignedSequenceNumber) {
76
+ segment.removedSeq = sequenceNumber;
92
77
  return true;
93
78
  }
94
79
  return false;
95
80
  }
96
81
  case MergeTreeDeltaType.OBLITERATE:
97
82
  case MergeTreeDeltaType.OBLITERATE_SIDED: {
98
- const moveInfo = toMoveInfo(segment);
99
- assert(moveInfo !== undefined, 0x86e /* On obliterate ack, missing move info! */);
83
+ assertMoved(segment);
100
84
  const obliterateInfo = segmentGroup.obliterateInfo;
101
85
  assert(obliterateInfo !== undefined, 0xa40 /* must have obliterate info */);
102
86
  segment.localMovedSeq = obliterateInfo.localSeq = undefined;
103
- const seqIdx = moveInfo.movedSeqs.indexOf(UnassignedSequenceNumber);
87
+ const seqIdx = segment.movedSeqs.indexOf(UnassignedSequenceNumber);
104
88
  assert(seqIdx !== -1, 0x86f /* expected movedSeqs to contain unacked seq */);
105
- moveInfo.movedSeqs[seqIdx] = sequenceNumber;
106
- if (moveInfo.movedSeq === UnassignedSequenceNumber) {
107
- moveInfo.movedSeq = sequenceNumber;
89
+ segment.movedSeqs[seqIdx] = sequenceNumber;
90
+ if (segment.movedSeq === UnassignedSequenceNumber) {
91
+ segment.movedSeq = sequenceNumber;
108
92
  return true;
109
93
  }
110
94
  return false;
@@ -141,7 +125,6 @@ export function findRootMergeBlock(segmentOrNode) {
141
125
  * entries for all segments visited during excursion.
142
126
  * This can reduce the number of times the tree needs to be scanned if a range containing many
143
127
  * SlideOnRemove references is removed.
144
- * @internal
145
128
  */
146
129
  function getSlideToSegment(segment, slidingPreference = SlidingPreference.FORWARD, cache, useNewSlidingBehavior = false) {
147
130
  if (!segment ||
@@ -161,7 +144,8 @@ function getSlideToSegment(segment, slidingPreference = SlidingPreference.FORWAR
161
144
  return false;
162
145
  }
163
146
  if (cache !== undefined &&
164
- (seg.removedSeq === segment.removedSeq || seg.movedSeq === segment.movedSeq)) {
147
+ (toRemovalInfo(seg)?.removedSeq === toRemovalInfo(segment)?.removedSeq ||
148
+ toMoveInfo(seg)?.movedSeq === toMoveInfo(segment)?.movedSeq)) {
165
149
  cache.set(seg, result);
166
150
  }
167
151
  return true;
@@ -208,7 +192,7 @@ function getSlideToSegment(segment, slidingPreference = SlidingPreference.FORWAR
208
192
  * @internal
209
193
  */
210
194
  export function getSlideToSegoff(segoff, slidingPreference = SlidingPreference.FORWARD, useNewSlidingBehavior = false) {
211
- if (segoff.segment === undefined) {
195
+ if (!isSegmentLeaf(segoff.segment)) {
212
196
  return segoff;
213
197
  }
214
198
  const [segment, _] = getSlideToSegment(segoff.segment, slidingPreference, undefined, useNewSlidingBehavior);
@@ -235,7 +219,6 @@ class Obliterates {
235
219
  * See https://github.com/microsoft/FluidFramework/blob/main/packages/dds/merge-tree/docs/Obliterate.md#remote-perspective
236
220
  * for additional context
237
221
  */
238
- // eslint-disable-next-line import/no-deprecated
239
222
  this.seqOrdered = new DoublyLinkedList();
240
223
  /**
241
224
  * This contains a sorted lists of all obliterate starts
@@ -253,7 +236,6 @@ class Obliterates {
253
236
  this.mergeTree.removeLocalReferencePosition(ob.data.end);
254
237
  }
255
238
  }
256
- // eslint-disable-next-line import/no-deprecated
257
239
  addOrUpdate(obliterateInfo) {
258
240
  const { seq, start } = obliterateInfo;
259
241
  if (seq !== UnassignedSequenceNumber) {
@@ -264,14 +246,14 @@ class Obliterates {
264
246
  empty() {
265
247
  return this.startOrdered.size === 0;
266
248
  }
267
- // eslint-disable-next-line import/no-deprecated
268
249
  findOverlapping(seg) {
269
- // eslint-disable-next-line import/no-deprecated
270
250
  const overlapping = [];
271
251
  for (const start of this.startOrdered.items) {
272
- if (start.getSegment().ordinal <= seg.ordinal) {
252
+ const startSeg = start.getSegment();
253
+ if (isMergeNodeInfo(startSeg) && startSeg.ordinal <= seg.ordinal) {
273
254
  const ob = start.properties?.obliterate;
274
- if (ob.end.getSegment().ordinal >= seg.ordinal) {
255
+ const endSeg = ob.end.getSegment();
256
+ if (isMergeNodeInfo(endSeg) && endSeg.ordinal >= seg.ordinal) {
275
257
  overlapping.push(ob);
276
258
  }
277
259
  }
@@ -289,9 +271,7 @@ class Obliterates {
289
271
  export class MergeTree {
290
272
  constructor(options) {
291
273
  this.options = options;
292
- // eslint-disable-next-line import/no-deprecated
293
274
  this.collabWindow = new CollaborationWindow();
294
- // eslint-disable-next-line import/no-deprecated
295
275
  this.pendingSegments = new DoublyLinkedList();
296
276
  this.segmentsToScour = new Heap(LRUSegmentComparer);
297
277
  /**
@@ -309,6 +289,7 @@ export class MergeTree {
309
289
  return {};
310
290
  }
311
291
  const next = segment.splitAt(pos);
292
+ assertSegmentLeaf(next);
312
293
  if (segment?.segmentGroups) {
313
294
  next.segmentGroups ?? (next.segmentGroups = new SegmentGroupCollection(next));
314
295
  segment.segmentGroups.copyTo(next.segmentGroups);
@@ -371,7 +352,9 @@ export class MergeTree {
371
352
  }
372
353
  assert(refSeq !== undefined, 0x398 /* localSeq provided for local length without refSeq */);
373
354
  assert(segment.seq !== undefined, 0x399 /* segment with no seq in mergeTree */);
374
- const { seq, removedSeq, localRemovedSeq, movedSeq, localMovedSeq } = segment;
355
+ const { seq } = segment;
356
+ const { removedSeq, localRemovedSeq } = removalInfo ?? {};
357
+ const { movedSeq, localMovedSeq } = moveInfo ?? {};
375
358
  if (seq === UnassignedSequenceNumber) {
376
359
  assert(segment.localSeq !== undefined, 0x39a /* unacked segment with undefined localSeq */);
377
360
  // inserted locally, still un-acked
@@ -407,7 +390,7 @@ export class MergeTree {
407
390
  }
408
391
  addNode(block, node) {
409
392
  const index = block.childCount++;
410
- block.assignChild(node, index, false);
393
+ assignChild(block, node, index, false);
411
394
  return index;
412
395
  }
413
396
  reloadFromSegments(segments) {
@@ -501,12 +484,12 @@ export class MergeTree {
501
484
  assert(localSeq === undefined || clientId === this.collabWindow.clientId, 0x39b /* localSeq provided for non-local client */);
502
485
  let segment;
503
486
  let offset;
504
- const leaf = (leafSeg, segpos, _refSeq, _clientId, start) => {
487
+ const leaf = (leafSeg, _, start) => {
505
488
  segment = leafSeg;
506
489
  offset = start;
507
490
  return false;
508
491
  };
509
- this.nodeMap(refSeq, clientId, leaf, undefined, undefined, pos, pos + 1, localSeq);
492
+ this.nodeMap(refSeq, clientId, leaf, undefined, pos, pos + 1, localSeq);
510
493
  return { segment, offset };
511
494
  }
512
495
  /**
@@ -531,7 +514,9 @@ export class MergeTree {
531
514
  */
532
515
  slideAckedRemovedSegmentReferences(segments) {
533
516
  // References are slid in groups to preserve their order.
517
+ // eslint-disable-next-line import/no-deprecated
534
518
  let currentForwardSlideGroup = [];
519
+ // eslint-disable-next-line import/no-deprecated
535
520
  let currentBackwardSlideGroup = [];
536
521
  let currentForwardMaybeEndpoint;
537
522
  let currentForwardSlideDestination;
@@ -539,7 +524,9 @@ export class MergeTree {
539
524
  let currentBackwardMaybeEndpoint;
540
525
  let currentBackwardSlideDestination;
541
526
  let currentBackwardSlideIsForward;
542
- const slideGroup = (currentSlideDestination, currentSlideIsForward, currentSlideGroup, pred, maybeEndpoint) => {
527
+ const slideGroup = (currentSlideDestination, currentSlideIsForward,
528
+ // eslint-disable-next-line import/no-deprecated
529
+ currentSlideGroup, pred, maybeEndpoint) => {
543
530
  if (currentSlideIsForward === undefined) {
544
531
  return;
545
532
  }
@@ -547,6 +534,7 @@ export class MergeTree {
547
534
  const endpointRefsToAdd = currentSlideGroup.map((collection) => filterLocalReferencePositions(collection, (ref) => pred(ref) && !!ref.canSlideToEndpoint));
548
535
  if (maybeEndpoint) {
549
536
  const endpoint = maybeEndpoint === "start" ? this.startOfTree : this.endOfTree;
537
+ // eslint-disable-next-line import/no-deprecated
550
538
  const localRefs = LocalReferenceCollection.setOrGet(endpoint);
551
539
  if (currentSlideIsForward) {
552
540
  localRefs.addBeforeTombstones(...endpointRefsToAdd);
@@ -567,6 +555,7 @@ export class MergeTree {
567
555
  }
568
556
  }
569
557
  else {
558
+ // eslint-disable-next-line import/no-deprecated
570
559
  const localRefs = LocalReferenceCollection.setOrGet(currentSlideDestination);
571
560
  if (currentSlideIsForward) {
572
561
  localRefs.addBeforeTombstones(...nonEndpointRefsToAdd);
@@ -576,7 +565,9 @@ export class MergeTree {
576
565
  }
577
566
  }
578
567
  };
579
- const trySlideSegment = (segment, currentSlideDestination, currentSlideIsForward, currentSlideGroup, pred, slidingPreference, currentMaybeEndpoint, reassign) => {
568
+ const trySlideSegment = (segment, currentSlideDestination, currentSlideIsForward,
569
+ // eslint-disable-next-line import/no-deprecated
570
+ currentSlideGroup, pred, slidingPreference, currentMaybeEndpoint, reassign) => {
580
571
  // avoid sliding logic if this segment doesn't have any references
581
572
  // with the given sliding preference
582
573
  if (!segment.localRefs || !anyLocalReferencePosition(segment.localRefs, pred)) {
@@ -633,7 +624,6 @@ export class MergeTree {
633
624
  if (this.localPartialsComputed) {
634
625
  return;
635
626
  }
636
- // eslint-disable-next-line import/no-deprecated
637
627
  const rebaseCollabWindow = new CollaborationWindow();
638
628
  rebaseCollabWindow.loadFrom(this.collabWindow);
639
629
  if (refSeq < this.collabWindow.minSeq) {
@@ -717,24 +707,26 @@ export class MergeTree {
717
707
  */
718
708
  referencePositionToLocalPosition(refPos, refSeq = Number.MAX_SAFE_INTEGER, clientId = this.collabWindow.clientId, localSeq = this.collabWindow.localSeq) {
719
709
  const seg = refPos.getSegment();
720
- if (seg?.parent === undefined) {
710
+ if (!isSegmentLeaf(seg)) {
721
711
  // We have no idea where this reference is, because it refers to a segment which is not in the tree.
722
712
  return DetachedReferencePosition;
723
713
  }
724
714
  if (refPos.isLeaf()) {
725
- return this.getPosition(refPos, refSeq, clientId, localSeq);
715
+ return this.getPosition(seg, refSeq, clientId, localSeq);
726
716
  }
727
717
  if (refTypeIncludesFlag(refPos, ReferenceType.Transient) || seg.localRefs?.has(refPos)) {
728
718
  if (seg !== this.startOfTree &&
729
719
  seg !== this.endOfTree &&
730
720
  !isSegmentPresent(seg, { refSeq, localSeq })) {
731
721
  const forward = refPos.slidingPreference === SlidingPreference.FORWARD;
732
- const slideSeq = seg.movedSeq !== UnassignedSequenceNumber && seg.movedSeq !== undefined
733
- ? seg.movedSeq
734
- : seg.removedSeq !== UnassignedSequenceNumber && seg.removedSeq !== undefined
735
- ? seg.removedSeq
722
+ const moveInfo = toMoveInfo(seg);
723
+ const removeInfo = toRemovalInfo(seg);
724
+ const slideSeq = moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber
725
+ ? moveInfo.movedSeq
726
+ : removeInfo !== undefined && removeInfo.removedSeq !== UnassignedSequenceNumber
727
+ ? removeInfo.removedSeq
736
728
  : refSeq;
737
- const slideLocalSeq = seg.localMovedSeq ?? seg.localRemovedSeq;
729
+ const slideLocalSeq = moveInfo?.localMovedSeq ?? removeInfo?.localRemovedSeq;
738
730
  const perspective = new PerspectiveImpl(this, {
739
731
  refSeq: slideSeq,
740
732
  localSeq: slideLocalSeq,
@@ -762,11 +754,10 @@ export class MergeTree {
762
754
  searchForMarker(startPos, clientId, markerLabel, forwards = true) {
763
755
  let foundMarker;
764
756
  const { segment } = this.getContainingSegment(startPos, UniversalSequenceNumber, clientId);
765
- const segWithParent = segment;
766
- if (segWithParent?.parent === undefined) {
757
+ if (!isSegmentLeaf(segment)) {
767
758
  return undefined;
768
759
  }
769
- depthFirstNodeWalk(segWithParent.parent, segWithParent, (node) => {
760
+ depthFirstNodeWalk(segment.parent, segment, (node) => {
770
761
  if (node.isLeaf()) {
771
762
  if (Marker.is(node) && refHasTileLabel(node, markerLabel)) {
772
763
  foundMarker = node;
@@ -788,8 +779,8 @@ export class MergeTree {
788
779
  updateRoot(splitNode) {
789
780
  if (splitNode !== undefined) {
790
781
  const newRoot = this.makeBlock(2);
791
- newRoot.assignChild(this.root, 0, false);
792
- newRoot.assignChild(splitNode, 1, false);
782
+ assignChild(newRoot, this.root, 0, false);
783
+ assignChild(newRoot, splitNode, 1, false);
793
784
  this.root = newRoot;
794
785
  this.nodeUpdateOrdinals(this.root);
795
786
  this.nodeUpdateLengthNewStructure(this.root);
@@ -845,9 +836,7 @@ export class MergeTree {
845
836
  zamboniSegments(this);
846
837
  }
847
838
  }
848
- addToPendingList(segment,
849
- // eslint-disable-next-line import/no-deprecated
850
- segmentGroup, localSeq, previousProps) {
839
+ addToPendingList(segment, segmentGroup, localSeq, previousProps) {
851
840
  let _segmentGroup = segmentGroup;
852
841
  if (_segmentGroup === undefined) {
853
842
  _segmentGroup = {
@@ -867,7 +856,6 @@ export class MergeTree {
867
856
  if (previousProps) {
868
857
  _segmentGroup.previousProps.push(previousProps);
869
858
  }
870
- // eslint-disable-next-line import/no-deprecated
871
859
  const segmentGroups = (segment.segmentGroups ?? (segment.segmentGroups = new SegmentGroupCollection(segment)));
872
860
  segmentGroups.enqueue(_segmentGroup);
873
861
  return _segmentGroup;
@@ -894,7 +882,7 @@ export class MergeTree {
894
882
  if (relativePos.id) {
895
883
  marker = this.getMarkerFromId(relativePos.id);
896
884
  }
897
- if (marker) {
885
+ if (isSegmentLeaf(marker)) {
898
886
  pos = this.getPosition(marker, refseq, clientId);
899
887
  if (relativePos.before) {
900
888
  if (relativePos.offset !== undefined) {
@@ -952,7 +940,7 @@ export class MergeTree {
952
940
  }
953
941
  const segmentInfo = this.getContainingSegment(remoteClientPosition, remoteClientRefSeq, remoteClientId);
954
942
  const { currentSeq, clientId } = this.collabWindow;
955
- if (segmentInfo?.segment) {
943
+ if (isSegmentLeaf(segmentInfo?.segment)) {
956
944
  const segmentPosition = this.getPosition(segmentInfo.segment, currentSeq, clientId);
957
945
  return segmentPosition + segmentInfo.offset;
958
946
  }
@@ -973,7 +961,6 @@ export class MergeTree {
973
961
  });
974
962
  return siblingExists;
975
963
  };
976
- // eslint-disable-next-line import/no-deprecated
977
964
  let segmentGroup;
978
965
  const saveIfLocal = (locSegment) => {
979
966
  // Save segment so we can assign sequence number when acked by server
@@ -1003,92 +990,95 @@ export class MergeTree {
1003
990
  }
1004
991
  return segmentChanges;
1005
992
  };
993
+ const insertInfo = {
994
+ clientId,
995
+ seq,
996
+ localSeq,
997
+ };
1006
998
  // TODO: build tree from segs and insert all at once
1007
999
  let insertPos = pos;
1008
- for (const newSegment of newSegments) {
1009
- if (newSegment.cachedLength > 0) {
1010
- newSegment.seq = seq;
1011
- newSegment.localSeq = localSeq;
1012
- newSegment.clientId = clientId;
1013
- if (Marker.is(newSegment)) {
1014
- const markerId = newSegment.getId();
1015
- if (markerId) {
1016
- this.idToMarker.set(markerId, newSegment);
1017
- }
1000
+ for (const newSegment of newSegments
1001
+ .filter((s) => s.cachedLength > 0)
1002
+ .map((s) => overwriteInfo(s, insertInfo))) {
1003
+ if (Marker.is(newSegment)) {
1004
+ const markerId = newSegment.getId();
1005
+ if (markerId) {
1006
+ this.idToMarker.set(markerId, newSegment);
1018
1007
  }
1019
- const splitNode = this.insertingWalk(this.root, insertPos, refSeq, clientId, seq, {
1020
- leaf: onLeaf,
1021
- candidateSegment: newSegment,
1022
- continuePredicate: continueFrom,
1008
+ }
1009
+ const splitNode = this.insertingWalk(this.root, insertPos, refSeq, clientId, seq, {
1010
+ leaf: onLeaf,
1011
+ candidateSegment: newSegment,
1012
+ continuePredicate: continueFrom,
1013
+ });
1014
+ if (!isSegmentLeaf(newSegment)) {
1015
+ // Indicates an attempt to insert past the end of the merge-tree's content.
1016
+ const errorConstructor = localSeq === undefined ? DataProcessingError : UsageError;
1017
+ throw new errorConstructor("MergeTree insert failed", {
1018
+ currentSeq: this.collabWindow.currentSeq,
1019
+ minSeq: this.collabWindow.minSeq,
1020
+ segSeq: insertInfo.seq,
1023
1021
  });
1024
- if (newSegment.parent === undefined) {
1025
- // Indicates an attempt to insert past the end of the merge-tree's content.
1026
- const errorConstructor = localSeq === undefined ? DataProcessingError : UsageError;
1027
- throw new errorConstructor("MergeTree insert failed", {
1028
- currentSeq: this.collabWindow.currentSeq,
1029
- minSeq: this.collabWindow.minSeq,
1030
- segSeq: newSegment.seq,
1031
- });
1032
- }
1033
- this.updateRoot(splitNode);
1034
- insertPos += newSegment.cachedLength;
1035
- if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
1036
- saveIfLocal(newSegment);
1037
- continue;
1038
- }
1039
- let oldest;
1040
- let normalizedOldestSeq = 0;
1041
- let newest;
1042
- let normalizedNewestSeq = 0;
1043
- const movedClientIds = [];
1044
- const movedSeqs = [];
1045
- for (const ob of this.obliterates.findOverlapping(newSegment)) {
1046
- // compute a normalized seq that takes into account local seqs
1047
- // but is still comparable to remote seqs to keep the checks below easy
1048
- // REMOTE SEQUENCE NUMBERS LOCAL SEQUENCE NUMBERS
1049
- // [0, 1, 2, 3, ..., 100, ..., 1000, ..., (MAX - MaxLocalSeq), L1, L2, L3, L4, ..., L100, ..., L1000, ...(MAX)]
1050
- const normalizedObSeq = ob.seq === UnassignedSequenceNumber
1051
- ? Number.MAX_SAFE_INTEGER - this.collabWindow.localSeq + ob.localSeq
1052
- : ob.seq;
1053
- if (normalizedObSeq > refSeq) {
1054
- if (oldest === undefined || normalizedOldestSeq > normalizedObSeq) {
1055
- normalizedOldestSeq = normalizedObSeq;
1056
- oldest = ob;
1057
- movedClientIds.unshift(ob.clientId);
1058
- movedSeqs.unshift(ob.seq);
1059
- }
1060
- else {
1061
- movedClientIds.push(ob.clientId);
1062
- movedSeqs.push(ob.seq);
1063
- }
1064
- if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
1065
- normalizedNewestSeq = normalizedObSeq;
1066
- newest = ob;
1067
- }
1022
+ }
1023
+ this.updateRoot(splitNode);
1024
+ insertPos += newSegment.cachedLength;
1025
+ if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
1026
+ saveIfLocal(newSegment);
1027
+ continue;
1028
+ }
1029
+ let oldest;
1030
+ let normalizedOldestSeq = 0;
1031
+ let newest;
1032
+ let normalizedNewestSeq = 0;
1033
+ const movedClientIds = [];
1034
+ const movedSeqs = [];
1035
+ for (const ob of this.obliterates.findOverlapping(newSegment)) {
1036
+ // compute a normalized seq that takes into account local seqs
1037
+ // but is still comparable to remote seqs to keep the checks below easy
1038
+ // REMOTE SEQUENCE NUMBERS LOCAL SEQUENCE NUMBERS
1039
+ // [0, 1, 2, 3, ..., 100, ..., 1000, ..., (MAX - MaxLocalSeq), L1, L2, L3, L4, ..., L100, ..., L1000, ...(MAX)]
1040
+ const normalizedObSeq = ob.seq === UnassignedSequenceNumber
1041
+ ? Number.MAX_SAFE_INTEGER - this.collabWindow.localSeq + ob.localSeq
1042
+ : ob.seq;
1043
+ if (normalizedObSeq > refSeq) {
1044
+ if (oldest === undefined || normalizedOldestSeq > normalizedObSeq) {
1045
+ normalizedOldestSeq = normalizedObSeq;
1046
+ oldest = ob;
1047
+ movedClientIds.unshift(ob.clientId);
1048
+ movedSeqs.unshift(ob.seq);
1068
1049
  }
1069
- }
1070
- if (oldest && newest?.clientId !== clientId) {
1071
- const moveInfo = {
1072
- movedClientIds,
1073
- movedSeq: oldest.seq,
1074
- movedSeqs,
1075
- localMovedSeq: oldest.localSeq,
1076
- wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
1077
- };
1078
- markSegmentMoved(newSegment, moveInfo);
1079
- if (moveInfo.localMovedSeq !== undefined) {
1080
- assert(oldest.segmentGroup !== undefined, 0x86c /* expected segment group to exist */);
1081
- this.addToPendingList(newSegment, oldest.segmentGroup);
1050
+ else {
1051
+ movedClientIds.push(ob.clientId);
1052
+ movedSeqs.push(ob.seq);
1082
1053
  }
1083
- if (newSegment.parent) {
1084
- this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
1054
+ if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
1055
+ normalizedNewestSeq = normalizedObSeq;
1056
+ newest = ob;
1085
1057
  }
1086
1058
  }
1087
- else if (oldest && newest?.clientId === clientId) {
1088
- newSegment.prevObliterateByInserter = newest;
1059
+ }
1060
+ if (oldest && newest?.clientId !== clientId) {
1061
+ // eslint-disable-next-line import/no-deprecated
1062
+ const moveInfo = {
1063
+ movedClientIds,
1064
+ movedSeq: oldest.seq,
1065
+ movedSeqs,
1066
+ localMovedSeq: oldest.localSeq,
1067
+ wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
1068
+ };
1069
+ overwriteInfo(newSegment, moveInfo);
1070
+ if (moveInfo.localMovedSeq !== undefined) {
1071
+ assert(oldest.segmentGroup !== undefined, 0x86c /* expected segment group to exist */);
1072
+ this.addToPendingList(newSegment, oldest.segmentGroup);
1073
+ }
1074
+ if (newSegment.parent) {
1075
+ this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
1089
1076
  }
1090
- saveIfLocal(newSegment);
1091
1077
  }
1078
+ else if (oldest && newest?.clientId === clientId) {
1079
+ newSegment.prevObliterateByInserter = newest;
1080
+ }
1081
+ saveIfLocal(newSegment);
1092
1082
  }
1093
1083
  }
1094
1084
  ensureIntervalBoundary(pos, refSeq, clientId) {
@@ -1109,10 +1099,8 @@ export class MergeTree {
1109
1099
  const newSeq = seq === UnassignedSequenceNumber ? Number.MAX_SAFE_INTEGER : seq;
1110
1100
  const segSeq = node.seq === UnassignedSequenceNumber ? Number.MAX_SAFE_INTEGER - 1 : (node.seq ?? 0);
1111
1101
  return (newSeq > segSeq ||
1112
- (node.movedSeq !== undefined &&
1113
- node.movedSeq !== UnassignedSequenceNumber &&
1114
- node.movedSeq > seq) ||
1115
- (node.removedSeq !== undefined &&
1102
+ (isMoved(node) && node.movedSeq !== UnassignedSequenceNumber && node.movedSeq > seq) ||
1103
+ (isRemoved(node) &&
1116
1104
  node.removedSeq !== UnassignedSequenceNumber &&
1117
1105
  node.removedSeq > seq));
1118
1106
  }
@@ -1144,7 +1132,7 @@ export class MergeTree {
1144
1132
  const segment = child;
1145
1133
  const segmentChanges = context.leaf(segment, _pos, context);
1146
1134
  if (segmentChanges.replaceCurrent) {
1147
- block.assignChild(segmentChanges.replaceCurrent, childIndex, false);
1135
+ assignChild(block, segmentChanges.replaceCurrent, childIndex, false);
1148
1136
  segmentChanges.replaceCurrent.ordinal = child.ordinal;
1149
1137
  }
1150
1138
  if (segmentChanges.next) {
@@ -1195,7 +1183,7 @@ export class MergeTree {
1195
1183
  block.children[i] = block.children[i - 1];
1196
1184
  block.children[i].index = i;
1197
1185
  }
1198
- block.assignChild(newNode, childIndex, false);
1186
+ assignChild(block, newNode, childIndex, false);
1199
1187
  block.childCount++;
1200
1188
  block.setOrdinal(newNode, childIndex);
1201
1189
  if (block.childCount < MaxNodesInBlock) {
@@ -1224,7 +1212,7 @@ export class MergeTree {
1224
1212
  // Update ordinals to reflect lowered child count
1225
1213
  this.nodeUpdateOrdinals(node);
1226
1214
  for (let i = 0; i < halfCount; i++) {
1227
- newNode.assignChild(node.children[halfCount + i], i, false);
1215
+ assignChild(newNode, node.children[halfCount + i], i, false);
1228
1216
  node.children[halfCount + i] = undefined;
1229
1217
  }
1230
1218
  this.nodeUpdateLengthNewStructure(node);
@@ -1251,9 +1239,7 @@ export class MergeTree {
1251
1239
  * @param opArgs - The op args for the annotate op. this is passed to the merge tree callback if there is one
1252
1240
  * @param rollback - Whether this is for a local rollback and what kind
1253
1241
  */
1254
- annotateRange(start, end, propsOrAdjust, refSeq, clientId, seq, opArgs,
1255
- // eslint-disable-next-line import/no-deprecated
1256
- rollback = PropertiesRollback.None) {
1242
+ annotateRange(start, end, propsOrAdjust, refSeq, clientId, seq, opArgs, rollback = PropertiesRollback.None) {
1257
1243
  if (propsOrAdjust.adjust !== undefined) {
1258
1244
  errorIfOptionNotTrue(this.options, "mergeTreeEnableAnnotateAdjust");
1259
1245
  }
@@ -1261,7 +1247,6 @@ export class MergeTree {
1261
1247
  this.ensureIntervalBoundary(end, refSeq, clientId);
1262
1248
  const deltaSegments = [];
1263
1249
  const localSeq = seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
1264
- // eslint-disable-next-line import/no-deprecated
1265
1250
  let segmentGroup;
1266
1251
  const opObj = propsOrAdjust.props ?? propsOrAdjust.adjust;
1267
1252
  const annotateSegment = (segment) => {
@@ -1285,7 +1270,7 @@ export class MergeTree {
1285
1270
  }
1286
1271
  return true;
1287
1272
  };
1288
- this.nodeMap(refSeq, clientId, annotateSegment, undefined, undefined, start, end);
1273
+ this.nodeMap(refSeq, clientId, annotateSegment, undefined, start, end);
1289
1274
  // OpArgs == undefined => test code
1290
1275
  if (deltaSegments.length > 0) {
1291
1276
  this.mergeTreeDeltaCallback?.(opArgs, {
@@ -1306,9 +1291,9 @@ export class MergeTree {
1306
1291
  this.ensureIntervalBoundary(endPos, refSeq, clientId);
1307
1292
  let _overwrite = false;
1308
1293
  const localOverlapWithRefs = [];
1294
+ // eslint-disable-next-line import/no-deprecated
1309
1295
  const movedSegments = [];
1310
1296
  const localSeq = seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
1311
- // eslint-disable-next-line import/no-deprecated
1312
1297
  const obliterate = {
1313
1298
  clientId,
1314
1299
  end: createDetachedLocalReferencePosition(undefined),
@@ -1320,7 +1305,7 @@ export class MergeTree {
1320
1305
  };
1321
1306
  const { segment: startSeg } = this.getContainingSegment(start.pos, refSeq, clientId);
1322
1307
  const { segment: endSeg } = this.getContainingSegment(end.pos, refSeq, clientId);
1323
- assert(startSeg !== undefined && endSeg !== undefined, 0xa3f /* segments cannot be undefined */);
1308
+ assert(isSegmentLeaf(startSeg) && isSegmentLeaf(endSeg), 0xa3f /* segments cannot be undefined */);
1324
1309
  obliterate.start = this.createLocalReferencePosition(startSeg, start.side === Side.Before ? 0 : Math.max(startSeg.cachedLength - 1, 0), ReferenceType.StayOnRemove, {
1325
1310
  obliterate,
1326
1311
  });
@@ -1341,7 +1326,7 @@ export class MergeTree {
1341
1326
  this.pendingSegments.push(obliterate.segmentGroup);
1342
1327
  }
1343
1328
  this.obliterates.addOrUpdate(obliterate);
1344
- const markMoved = (segment, pos, _start, _end) => {
1329
+ const markMoved = (segment, pos) => {
1345
1330
  if ((start.side === Side.After && startPos === pos + segment.cachedLength) || // exclusive start segment
1346
1331
  (end.side === Side.Before &&
1347
1332
  endPos === pos &&
@@ -1358,23 +1343,27 @@ export class MergeTree {
1358
1343
  // Other clients will also choose not to obliterate this segment because the most recent obliteration has the same clientId
1359
1344
  return true;
1360
1345
  }
1361
- if (clientId !== segment.clientId &&
1346
+ const wasMovedOnInsert = clientId !== segment.clientId &&
1362
1347
  segment.seq !== undefined &&
1363
1348
  seq !== UnassignedSequenceNumber &&
1364
- (refSeq < segment.seq || segment.seq === UnassignedSequenceNumber)) {
1365
- segment.wasMovedOnInsert = true;
1366
- }
1349
+ (refSeq < segment.seq || segment.seq === UnassignedSequenceNumber);
1367
1350
  if (existingMoveInfo === undefined) {
1368
- segment.movedClientIds = [clientId];
1369
- segment.movedSeq = seq;
1370
- segment.localMovedSeq = localSeq;
1371
- segment.movedSeqs = [seq];
1372
- if (!toRemovalInfo(segment)) {
1373
- movedSegments.push({ segment });
1351
+ // eslint-disable-next-line import/no-deprecated
1352
+ const movedSeg = overwriteInfo(segment, {
1353
+ movedClientIds: [clientId],
1354
+ movedSeq: seq,
1355
+ localMovedSeq: localSeq,
1356
+ movedSeqs: [seq],
1357
+ wasMovedOnInsert,
1358
+ });
1359
+ if (!toRemovalInfo(movedSeg)) {
1360
+ movedSegments.push(movedSeg);
1374
1361
  }
1375
1362
  }
1376
1363
  else {
1377
1364
  _overwrite = true;
1365
+ // never move wasMovedOnInsert from true to false
1366
+ existingMoveInfo.wasMovedOnInsert || (existingMoveInfo.wasMovedOnInsert = wasMovedOnInsert);
1378
1367
  if (existingMoveInfo.movedSeq === UnassignedSequenceNumber) {
1379
1368
  // we moved this locally, but someone else moved it first
1380
1369
  // so put them at the head of the list
@@ -1393,6 +1382,7 @@ export class MergeTree {
1393
1382
  existingMoveInfo.movedSeqs.push(seq);
1394
1383
  }
1395
1384
  }
1385
+ assertMoved(segment);
1396
1386
  // Save segment so can assign moved sequence number when acked by server
1397
1387
  if (this.collabWindow.collaborating) {
1398
1388
  if (segment.movedSeq === UnassignedSequenceNumber &&
@@ -1407,7 +1397,7 @@ export class MergeTree {
1407
1397
  }
1408
1398
  return true;
1409
1399
  };
1410
- const afterMarkMoved = (node, pos, _start, _end) => {
1400
+ const afterMarkMoved = (node) => {
1411
1401
  if (_overwrite) {
1412
1402
  this.nodeUpdateLengthNewStructure(node);
1413
1403
  }
@@ -1416,21 +1406,21 @@ export class MergeTree {
1416
1406
  }
1417
1407
  return true;
1418
1408
  };
1419
- this.nodeMap(refSeq, clientId, markMoved, undefined, afterMarkMoved, start.pos, end.pos + 1, // include the segment containing the end reference
1409
+ this.nodeMap(refSeq, clientId, markMoved, afterMarkMoved, start.pos, end.pos + 1, // include the segment containing the end reference
1420
1410
  undefined, seq === UnassignedSequenceNumber ? undefined : seq);
1421
1411
  this.slideAckedRemovedSegmentReferences(localOverlapWithRefs);
1422
1412
  // opArgs == undefined => test code
1423
1413
  if (start.pos !== end.pos || start.side !== end.side) {
1424
1414
  this.mergeTreeDeltaCallback?.(opArgs, {
1425
1415
  operation: MergeTreeDeltaType.OBLITERATE,
1426
- deltaSegments: movedSegments,
1416
+ deltaSegments: movedSegments.map((segment) => ({ segment })),
1427
1417
  });
1428
1418
  }
1429
1419
  // these events are newly removed
1430
1420
  // so we slide after eventing in case the consumer wants to make reference
1431
1421
  // changes at remove time, like add a ref to track undo redo.
1432
1422
  if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
1433
- this.slideAckedRemovedSegmentReferences(movedSegments.map(({ segment }) => segment));
1423
+ this.slideAckedRemovedSegmentReferences(movedSegments);
1434
1424
  }
1435
1425
  if (this.collabWindow.collaborating &&
1436
1426
  seq !== UnassignedSequenceNumber &&
@@ -1453,19 +1443,22 @@ export class MergeTree {
1453
1443
  let _overwrite = false;
1454
1444
  this.ensureIntervalBoundary(start, refSeq, clientId);
1455
1445
  this.ensureIntervalBoundary(end, refSeq, clientId);
1456
- // eslint-disable-next-line import/no-deprecated
1457
1446
  let segmentGroup;
1447
+ // eslint-disable-next-line import/no-deprecated
1458
1448
  const removedSegments = [];
1459
1449
  const localOverlapWithRefs = [];
1460
1450
  const localSeq = seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
1461
1451
  const markRemoved = (segment, pos, _start, _end) => {
1462
1452
  const existingRemovalInfo = toRemovalInfo(segment);
1463
1453
  if (existingRemovalInfo === undefined) {
1464
- segment.removedClientIds = [clientId];
1465
- segment.removedSeq = seq;
1466
- segment.localRemovedSeq = localSeq;
1467
- if (!toMoveInfo(segment)) {
1468
- removedSegments.push({ segment });
1454
+ // eslint-disable-next-line import/no-deprecated
1455
+ const removed = overwriteInfo(segment, {
1456
+ removedClientIds: [clientId],
1457
+ removedSeq: seq,
1458
+ localRemovedSeq: localSeq,
1459
+ });
1460
+ if (!toMoveInfo(removed)) {
1461
+ removedSegments.push(removed);
1469
1462
  }
1470
1463
  }
1471
1464
  else {
@@ -1486,6 +1479,7 @@ export class MergeTree {
1486
1479
  existingRemovalInfo.removedClientIds.push(clientId);
1487
1480
  }
1488
1481
  }
1482
+ assertRemoved(segment);
1489
1483
  // Save segment so we can assign removed sequence number when acked by server
1490
1484
  if (this.collabWindow.collaborating) {
1491
1485
  if (segment.removedSeq === UnassignedSequenceNumber &&
@@ -1500,7 +1494,7 @@ export class MergeTree {
1500
1494
  }
1501
1495
  return true;
1502
1496
  };
1503
- const afterMarkRemoved = (node, pos, _start, _end) => {
1497
+ const afterMarkRemoved = (node) => {
1504
1498
  if (_overwrite) {
1505
1499
  this.nodeUpdateLengthNewStructure(node);
1506
1500
  }
@@ -1509,7 +1503,7 @@ export class MergeTree {
1509
1503
  }
1510
1504
  return true;
1511
1505
  };
1512
- this.nodeMap(refSeq, clientId, markRemoved, undefined, afterMarkRemoved, start, end);
1506
+ this.nodeMap(refSeq, clientId, markRemoved, afterMarkRemoved, start, end);
1513
1507
  // these segments are already viewed as being removed locally and are not event-ed
1514
1508
  // so can slide non-StayOnRemove refs immediately
1515
1509
  this.slideAckedRemovedSegmentReferences(localOverlapWithRefs);
@@ -1517,14 +1511,14 @@ export class MergeTree {
1517
1511
  if (removedSegments.length > 0) {
1518
1512
  this.mergeTreeDeltaCallback?.(opArgs, {
1519
1513
  operation: MergeTreeDeltaType.REMOVE,
1520
- deltaSegments: removedSegments,
1514
+ deltaSegments: removedSegments.map((segment) => ({ segment })),
1521
1515
  });
1522
1516
  }
1523
1517
  // these events are newly removed
1524
1518
  // so we slide after eventing in case the consumer wants to make reference
1525
1519
  // changes at remove time, like add a ref to track undo redo.
1526
1520
  if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
1527
- this.slideAckedRemovedSegmentReferences(removedSegments.map(({ segment }) => segment));
1521
+ this.slideAckedRemovedSegmentReferences(removedSegments);
1528
1522
  }
1529
1523
  if (this.collabWindow.collaborating &&
1530
1524
  seq !== UnassignedSequenceNumber &&
@@ -1535,24 +1529,21 @@ export class MergeTree {
1535
1529
  /**
1536
1530
  * Revert an unacked local op
1537
1531
  */
1538
- // eslint-disable-next-line import/no-deprecated
1539
1532
  rollback(op, localOpMetadata) {
1540
1533
  if (op.type === MergeTreeDeltaType.REMOVE) {
1541
- const pendingSegmentGroup = this.pendingSegments.pop?.()?.data;
1534
+ const pendingSegmentGroup = this.pendingSegments.pop()?.data;
1542
1535
  if (pendingSegmentGroup === undefined || pendingSegmentGroup !== localOpMetadata) {
1543
1536
  throw new Error("Rollback op doesn't match last edit");
1544
1537
  }
1545
1538
  // Disabling because a for of loop causes the type of segment to be ISegmentLeaf, which does not have parent information stored
1546
1539
  // eslint-disable-next-line unicorn/no-array-for-each
1547
1540
  pendingSegmentGroup.segments.forEach((segment) => {
1548
- const segmentSegmentGroup = segment?.segmentGroups?.pop?.();
1541
+ const segmentSegmentGroup = segment?.segmentGroups?.pop();
1549
1542
  assert(segmentSegmentGroup === pendingSegmentGroup, 0x3ee /* Unexpected segmentGroup in segment */);
1550
- assert(segment.removedClientIds !== undefined &&
1551
- segment.removedClientIds[0] === this.collabWindow.clientId, 0x39d /* Rollback segment removedClientId does not match local client */);
1552
- segment.removedClientIds = undefined;
1553
- segment.removedSeq = undefined;
1554
- segment.localRemovedSeq = undefined;
1555
- for (let updateNode = segment.parent; updateNode !== undefined; updateNode = updateNode.parent) {
1543
+ assert(isRemoved(segment) && segment.removedClientIds[0] === this.collabWindow.clientId, 0x39d /* Rollback segment removedClientId does not match local client */);
1544
+ let updateNode = segment.parent;
1545
+ removeRemovalInfo(segment);
1546
+ for (updateNode; updateNode !== undefined; updateNode = updateNode.parent) {
1556
1547
  this.blockUpdateLength(updateNode, UnassignedSequenceNumber, this.collabWindow.clientId);
1557
1548
  }
1558
1549
  // Note: optional chaining short-circuits:
@@ -1565,7 +1556,7 @@ export class MergeTree {
1565
1556
  }
1566
1557
  else if (op.type === MergeTreeDeltaType.INSERT ||
1567
1558
  op.type === MergeTreeDeltaType.ANNOTATE) {
1568
- const pendingSegmentGroup = this.pendingSegments.pop?.()?.data;
1559
+ const pendingSegmentGroup = this.pendingSegments.pop()?.data;
1569
1560
  if (pendingSegmentGroup === undefined ||
1570
1561
  pendingSegmentGroup !== localOpMetadata ||
1571
1562
  (op.type === MergeTreeDeltaType.ANNOTATE && !pendingSegmentGroup.previousProps)) {
@@ -1573,7 +1564,7 @@ export class MergeTree {
1573
1564
  }
1574
1565
  let i = 0;
1575
1566
  for (const segment of pendingSegmentGroup.segments) {
1576
- const segmentSegmentGroup = segment?.segmentGroups?.pop?.();
1567
+ const segmentSegmentGroup = segment?.segmentGroups?.pop();
1577
1568
  assert(segmentSegmentGroup === pendingSegmentGroup, 0x3ef /* Unexpected segmentGroup in segment */);
1578
1569
  const start = this.findRollbackPosition(segment);
1579
1570
  if (op.type === MergeTreeDeltaType.INSERT) {
@@ -1605,7 +1596,7 @@ export class MergeTree {
1605
1596
  return false;
1606
1597
  }
1607
1598
  // If not removed, increase position
1608
- if (seg.removedSeq === undefined) {
1599
+ if (!isRemoved(seg)) {
1609
1600
  segmentPosition += seg.cachedLength;
1610
1601
  }
1611
1602
  return true;
@@ -1639,8 +1630,10 @@ export class MergeTree {
1639
1630
  segment = this.endOfTree;
1640
1631
  }
1641
1632
  else {
1633
+ assertSegmentLeaf(_segment);
1642
1634
  segment = _segment;
1643
1635
  }
1636
+ // eslint-disable-next-line import/no-deprecated
1644
1637
  const localRefs = LocalReferenceCollection.setOrGet(segment);
1645
1638
  const segRef = localRefs.createLocalRef(offset, refType, properties, slidingPreference, canSlideToEndpoint);
1646
1639
  return segRef;
@@ -1702,7 +1695,7 @@ export class MergeTree {
1702
1695
  for (let i = 0; i < newOrder.length; i++) {
1703
1696
  const seg = newOrder[i];
1704
1697
  const { parent, index, ordinal } = currentOrder[i];
1705
- parent?.assignChild(seg, index, false);
1698
+ assignChild(parent, seg, index, false);
1706
1699
  seg.ordinal = ordinal;
1707
1700
  }
1708
1701
  for (const [segment, groups] of perSegmentTrackingGroups.entries()) {
@@ -1869,7 +1862,7 @@ export class MergeTree {
1869
1862
  this.ensureIntervalBoundary(end, refSeq, clientId);
1870
1863
  }
1871
1864
  }
1872
- this.nodeMap(refSeq, clientId, handler, accum, undefined, start, end, undefined, visibilitySeq);
1865
+ this.nodeMap(refSeq, clientId, (seg, pos, _start, _end) => handler(seg, pos, refSeq, clientId, _start, _end, accum), undefined, start, end, undefined, visibilitySeq);
1873
1866
  }
1874
1867
  /**
1875
1868
  * Map over all visible segments in a given range
@@ -1894,7 +1887,7 @@ export class MergeTree {
1894
1887
  * but it will not count as a segment within the range. That is, it will be
1895
1888
  * ignored for the purposes of tracking when traversal should end.
1896
1889
  */
1897
- nodeMap(refSeq, clientId, leaf, accum, post, start = 0, end, localSeq, visibilitySeq = refSeq) {
1890
+ nodeMap(refSeq, clientId, leaf, post, start = 0, end, localSeq, visibilitySeq = refSeq) {
1898
1891
  const endPos = end ?? this.nodeLength(this.root, refSeq, clientId, localSeq) ?? 0;
1899
1892
  if (endPos === start) {
1900
1893
  return;
@@ -1921,14 +1914,12 @@ export class MergeTree {
1921
1914
  return NodeAction.Skip;
1922
1915
  }
1923
1916
  if (node.isLeaf()) {
1924
- if (leaf(node, pos, refSeq, clientId, start - pos, endPos - pos, accum) === false) {
1917
+ if (leaf(node, pos, start - pos, endPos - pos) === false) {
1925
1918
  return NodeAction.Exit;
1926
1919
  }
1927
1920
  pos = nextPos;
1928
1921
  }
1929
- }, undefined, post === undefined
1930
- ? undefined
1931
- : (block) => post(block, pos, refSeq, clientId, start - pos, endPos - pos, accum));
1922
+ }, undefined, post);
1932
1923
  }
1933
1924
  }
1934
1925
  MergeTree.options = {