@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/src/mergeTree.ts CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  } from "./constants.js";
21
21
  import { EndOfTreeSegment, StartOfTreeSegment } from "./endOfTreeSegment.js";
22
22
  import {
23
+ // eslint-disable-next-line import/no-deprecated
23
24
  LocalReferenceCollection,
24
25
  LocalReferencePosition,
25
26
  SlidingPreference,
@@ -42,27 +43,24 @@ import {
42
43
  walkAllChildSegments,
43
44
  } from "./mergeTreeNodeWalk.js";
44
45
  import {
45
- BlockAction,
46
- // eslint-disable-next-line import/no-deprecated
47
46
  CollaborationWindow,
48
47
  IMergeNode,
49
- IMoveInfo,
50
- IRemovalInfo,
51
48
  ISegmentAction,
52
49
  ISegmentChanges,
53
- ISegmentLeaf,
54
50
  InsertContext,
55
51
  Marker,
56
52
  MaxNodesInBlock,
57
53
  MergeBlock,
58
- // eslint-disable-next-line import/no-deprecated
59
54
  SegmentGroup,
55
+ assertSegmentLeaf,
56
+ assignChild,
57
+ isSegmentLeaf,
60
58
  reservedMarkerIdKey,
61
59
  seqLTE,
62
- toMoveInfo,
63
- toRemovalInfo,
60
+ type IMergeNodeBuilder,
64
61
  type ISegmentInternal,
65
- // eslint-disable-next-line import/no-deprecated
62
+ type ISegmentLeaf,
63
+ type ISegmentPrivate,
66
64
  type ObliterateInfo,
67
65
  } from "./mergeTreeNodes.js";
68
66
  import type { TrackingGroup } from "./mergeTreeTracking.js";
@@ -87,9 +85,24 @@ import {
87
85
  refHasTileLabel,
88
86
  refTypeIncludesFlag,
89
87
  } from "./referencePositions.js";
90
- // eslint-disable-next-line import/no-deprecated
91
88
  import { SegmentGroupCollection } from "./segmentGroupCollection.js";
92
- // eslint-disable-next-line import/no-deprecated
89
+ import {
90
+ assertMoved,
91
+ assertRemoved,
92
+ isMergeNodeInfo,
93
+ isMoved,
94
+ isRemoved,
95
+ overwriteInfo,
96
+ removeRemovalInfo,
97
+ toMoveInfo,
98
+ toRemovalInfo,
99
+ type IInsertionInfo,
100
+ // eslint-disable-next-line import/no-deprecated
101
+ type IMoveInfo,
102
+ // eslint-disable-next-line import/no-deprecated
103
+ type IRemovalInfo,
104
+ type SegmentWithInfo,
105
+ } from "./segmentInfos.js";
93
106
  import {
94
107
  copyPropertiesAndManager,
95
108
  PropertiesManager,
@@ -100,34 +113,21 @@ import { Side, type InteriorSequencePlace } from "./sequencePlace.js";
100
113
  import { SortedSegmentSet } from "./sortedSegmentSet.js";
101
114
  import { zamboniSegments } from "./zamboni.js";
102
115
 
103
- function markSegmentMoved(seg: ISegmentLeaf, moveInfo: IMoveInfo): void {
104
- seg.moveDst = moveInfo.moveDst;
105
- seg.movedClientIds = [...moveInfo.movedClientIds];
106
- seg.movedSeqs = [moveInfo.movedSeq];
107
- seg.movedSeq = moveInfo.movedSeq;
108
- seg.localMovedSeq = moveInfo.localMovedSeq;
109
- seg.wasMovedOnInsert = moveInfo.wasMovedOnInsert;
110
- }
111
-
112
- function isMoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
113
- return toMoveInfo(segment) !== undefined;
114
- }
115
-
116
- function isRemoved(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
117
- return toRemovalInfo(segment) !== undefined;
118
- }
119
-
120
- function isRemovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IRemovalInfo {
116
+ function isRemovedAndAcked(
117
+ segment: ISegmentPrivate,
118
+ // eslint-disable-next-line import/no-deprecated
119
+ ): segment is ISegmentLeaf & IRemovalInfo {
121
120
  const removalInfo = toRemovalInfo(segment);
122
121
  return removalInfo !== undefined && removalInfo.removedSeq !== UnassignedSequenceNumber;
123
122
  }
124
123
 
125
- function isMovedAndAcked(segment: ISegmentLeaf): segment is ISegmentLeaf & IMoveInfo {
124
+ // eslint-disable-next-line import/no-deprecated
125
+ function isMovedAndAcked(segment: ISegmentPrivate): segment is ISegmentLeaf & IMoveInfo {
126
126
  const moveInfo = toMoveInfo(segment);
127
127
  return moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber;
128
128
  }
129
129
 
130
- function isRemovedAndAckedOrMovedAndAcked(segment: ISegmentLeaf): boolean {
130
+ function isRemovedAndAckedOrMovedAndAcked(segment: ISegmentPrivate): boolean {
131
131
  return isRemovedAndAcked(segment) || isMovedAndAcked(segment);
132
132
  }
133
133
 
@@ -180,11 +180,10 @@ function ackSegment(
180
180
  }
181
181
 
182
182
  case MergeTreeDeltaType.REMOVE: {
183
- const removalInfo: IRemovalInfo | undefined = toRemovalInfo(segment);
184
- assert(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
183
+ assertRemoved(segment);
185
184
  segment.localRemovedSeq = undefined;
186
- if (removalInfo.removedSeq === UnassignedSequenceNumber) {
187
- removalInfo.removedSeq = sequenceNumber;
185
+ if (segment.removedSeq === UnassignedSequenceNumber) {
186
+ segment.removedSeq = sequenceNumber;
188
187
  return true;
189
188
  }
190
189
  return false;
@@ -192,17 +191,16 @@ function ackSegment(
192
191
 
193
192
  case MergeTreeDeltaType.OBLITERATE:
194
193
  case MergeTreeDeltaType.OBLITERATE_SIDED: {
195
- const moveInfo: IMoveInfo | undefined = toMoveInfo(segment);
196
- assert(moveInfo !== undefined, 0x86e /* On obliterate ack, missing move info! */);
194
+ assertMoved(segment);
197
195
  const obliterateInfo = segmentGroup.obliterateInfo;
198
196
  assert(obliterateInfo !== undefined, 0xa40 /* must have obliterate info */);
199
197
  segment.localMovedSeq = obliterateInfo.localSeq = undefined;
200
- const seqIdx = moveInfo.movedSeqs.indexOf(UnassignedSequenceNumber);
198
+ const seqIdx = segment.movedSeqs.indexOf(UnassignedSequenceNumber);
201
199
  assert(seqIdx !== -1, 0x86f /* expected movedSeqs to contain unacked seq */);
202
- moveInfo.movedSeqs[seqIdx] = sequenceNumber;
200
+ segment.movedSeqs[seqIdx] = sequenceNumber;
203
201
 
204
- if (moveInfo.movedSeq === UnassignedSequenceNumber) {
205
- moveInfo.movedSeq = sequenceNumber;
202
+ if (segment.movedSeq === UnassignedSequenceNumber) {
203
+ segment.movedSeq = sequenceNumber;
206
204
  return true;
207
205
  }
208
206
 
@@ -395,7 +393,6 @@ export function findRootMergeBlock(
395
393
  * entries for all segments visited during excursion.
396
394
  * This can reduce the number of times the tree needs to be scanned if a range containing many
397
395
  * SlideOnRemove references is removed.
398
- * @internal
399
396
  */
400
397
  function getSlideToSegment(
401
398
  segment: ISegmentLeaf | undefined,
@@ -424,7 +421,8 @@ function getSlideToSegment(
424
421
  }
425
422
  if (
426
423
  cache !== undefined &&
427
- (seg.removedSeq === segment.removedSeq || seg.movedSeq === segment.movedSeq)
424
+ (toRemovalInfo(seg)?.removedSeq === toRemovalInfo(segment)?.removedSeq ||
425
+ toMoveInfo(seg)?.movedSeq === toMoveInfo(segment)?.movedSeq)
428
426
  ) {
429
427
  cache.set(seg, result);
430
428
  }
@@ -482,7 +480,7 @@ export function getSlideToSegoff(
482
480
  segment: ISegmentInternal | undefined;
483
481
  offset: number | undefined;
484
482
  } {
485
- if (segoff.segment === undefined) {
483
+ if (!isSegmentLeaf(segoff.segment)) {
486
484
  return segoff;
487
485
  }
488
486
  const [segment, _] = getSlideToSegment(
@@ -517,7 +515,7 @@ class Obliterates {
517
515
  * See https://github.com/microsoft/FluidFramework/blob/main/packages/dds/merge-tree/docs/Obliterate.md#remote-perspective
518
516
  * for additional context
519
517
  */
520
- // eslint-disable-next-line import/no-deprecated
518
+
521
519
  private readonly seqOrdered = new DoublyLinkedList<ObliterateInfo>();
522
520
 
523
521
  /**
@@ -539,7 +537,6 @@ class Obliterates {
539
537
  }
540
538
  }
541
539
 
542
- // eslint-disable-next-line import/no-deprecated
543
540
  public addOrUpdate(obliterateInfo: ObliterateInfo): void {
544
541
  const { seq, start } = obliterateInfo;
545
542
  if (seq !== UnassignedSequenceNumber) {
@@ -552,14 +549,14 @@ class Obliterates {
552
549
  return this.startOrdered.size === 0;
553
550
  }
554
551
 
555
- // eslint-disable-next-line import/no-deprecated
556
552
  public findOverlapping(seg: ISegmentLeaf): Iterable<ObliterateInfo> {
557
- // eslint-disable-next-line import/no-deprecated
558
553
  const overlapping: ObliterateInfo[] = [];
559
554
  for (const start of this.startOrdered.items) {
560
- if (start.getSegment()!.ordinal <= seg.ordinal) {
555
+ const startSeg = start.getSegment();
556
+ if (isMergeNodeInfo(startSeg) && startSeg.ordinal <= seg.ordinal) {
561
557
  const ob = start.properties?.obliterate as ObliterateInfo;
562
- if (ob.end.getSegment()!.ordinal >= seg.ordinal) {
558
+ const endSeg = ob.end.getSegment();
559
+ if (isMergeNodeInfo(endSeg) && endSeg.ordinal >= seg.ordinal) {
563
560
  overlapping.push(ob);
564
561
  }
565
562
  } else {
@@ -583,10 +580,8 @@ export class MergeTree {
583
580
 
584
581
  private static readonly theUnfinishedNode = { childCount: -1 } as unknown as MergeBlock;
585
582
 
586
- // eslint-disable-next-line import/no-deprecated
587
583
  public readonly collabWindow = new CollaborationWindow();
588
584
 
589
- // eslint-disable-next-line import/no-deprecated
590
585
  public readonly pendingSegments = new DoublyLinkedList<SegmentGroup>();
591
586
 
592
587
  public readonly segmentsToScour = new Heap<LRUSegment>(LRUSegmentComparer);
@@ -665,7 +660,9 @@ export class MergeTree {
665
660
  0x398 /* localSeq provided for local length without refSeq */,
666
661
  );
667
662
  assert(segment.seq !== undefined, 0x399 /* segment with no seq in mergeTree */);
668
- const { seq, removedSeq, localRemovedSeq, movedSeq, localMovedSeq } = segment;
663
+ const { seq } = segment;
664
+ const { removedSeq, localRemovedSeq } = removalInfo ?? {};
665
+ const { movedSeq, localMovedSeq } = moveInfo ?? {};
669
666
  if (seq === UnassignedSequenceNumber) {
670
667
  assert(
671
668
  segment.localSeq !== undefined,
@@ -707,13 +704,13 @@ export class MergeTree {
707
704
  }
708
705
  }
709
706
 
710
- private addNode(block: MergeBlock, node: IMergeNode): number {
707
+ private addNode(block: MergeBlock, node: IMergeNodeBuilder): number {
711
708
  const index = block.childCount++;
712
- block.assignChild(node, index, false);
709
+ assignChild(block, node, index, false);
713
710
  return index;
714
711
  }
715
712
 
716
- public reloadFromSegments(segments: ISegmentLeaf[]): void {
713
+ public reloadFromSegments(segments: SegmentWithInfo<IInsertionInfo>[]): void {
717
714
  // This code assumes that a later call to `startCollaboration()` will initialize partial lengths.
718
715
  assert(
719
716
  !this.collabWindow.collaborating,
@@ -723,7 +720,7 @@ export class MergeTree {
723
720
  const maxChildren = MaxNodesInBlock - 1;
724
721
 
725
722
  // Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
726
- const buildMergeBlock = (nodes: IMergeNode[]): IRootMergeBlock => {
723
+ const buildMergeBlock = (nodes: IMergeNodeBuilder[]): IRootMergeBlock => {
727
724
  const blockCount = Math.ceil(nodes.length / maxChildren); // Compute # blocks require for this level of B-Tree
728
725
  const blocks: MergeBlock[] = Array.from({ length: blockCount }); // Pre-alloc array to collect nodes
729
726
 
@@ -779,8 +776,8 @@ export class MergeTree {
779
776
 
780
777
  // TODO: 'seq' may be less than the current sequence number when inserting pre-ACKed
781
778
  // segments from a snapshot. We currently skip these for now.
782
- if (leaf.parent!.needsScour !== true && seq > this.collabWindow.currentSeq) {
783
- leaf.parent!.needsScour = true;
779
+ if (leaf.parent.needsScour !== true && seq > this.collabWindow.currentSeq) {
780
+ leaf.parent.needsScour = true;
784
781
  this.segmentsToScour.add({ segment: leaf, maxSeq: seq });
785
782
  }
786
783
  }
@@ -824,34 +821,28 @@ export class MergeTree {
824
821
  return totalOffset;
825
822
  }
826
823
 
827
- public getContainingSegment<T extends ISegmentLeaf>(
824
+ public getContainingSegment(
828
825
  pos: number,
829
826
  refSeq: number,
830
827
  clientId: number,
831
828
  localSeq?: number,
832
829
  ): {
833
- segment: T | undefined;
830
+ segment: ISegmentLeaf | undefined;
834
831
  offset: number | undefined;
835
832
  } {
836
833
  assert(
837
834
  localSeq === undefined || clientId === this.collabWindow.clientId,
838
835
  0x39b /* localSeq provided for non-local client */,
839
836
  );
840
- let segment: T | undefined;
837
+ let segment: ISegmentLeaf | undefined;
841
838
  let offset: number | undefined;
842
839
 
843
- const leaf = (
844
- leafSeg: ISegmentLeaf,
845
- segpos: number,
846
- _refSeq: number,
847
- _clientId: number,
848
- start: number,
849
- ): boolean => {
850
- segment = leafSeg as T;
840
+ const leaf = (leafSeg: ISegmentLeaf, _: number, start: number): boolean => {
841
+ segment = leafSeg;
851
842
  offset = start;
852
843
  return false;
853
844
  };
854
- this.nodeMap(refSeq, clientId, leaf, undefined, undefined, pos, pos + 1, localSeq);
845
+ this.nodeMap(refSeq, clientId, leaf, undefined, pos, pos + 1, localSeq);
855
846
  return { segment, offset };
856
847
  }
857
848
 
@@ -877,7 +868,9 @@ export class MergeTree {
877
868
  */
878
869
  private slideAckedRemovedSegmentReferences(segments: ISegmentLeaf[]): void {
879
870
  // References are slid in groups to preserve their order.
871
+ // eslint-disable-next-line import/no-deprecated
880
872
  let currentForwardSlideGroup: LocalReferenceCollection[] = [];
873
+ // eslint-disable-next-line import/no-deprecated
881
874
  let currentBackwardSlideGroup: LocalReferenceCollection[] = [];
882
875
 
883
876
  let currentForwardMaybeEndpoint: "start" | "end" | undefined;
@@ -891,6 +884,7 @@ export class MergeTree {
891
884
  const slideGroup = (
892
885
  currentSlideDestination: ISegmentLeaf | undefined,
893
886
  currentSlideIsForward: boolean | undefined,
887
+ // eslint-disable-next-line import/no-deprecated
894
888
  currentSlideGroup: LocalReferenceCollection[],
895
889
  pred: (ref: LocalReferencePosition) => boolean,
896
890
  maybeEndpoint: "start" | "end" | undefined,
@@ -915,6 +909,7 @@ export class MergeTree {
915
909
 
916
910
  if (maybeEndpoint) {
917
911
  const endpoint = maybeEndpoint === "start" ? this.startOfTree : this.endOfTree;
912
+ // eslint-disable-next-line import/no-deprecated
918
913
  const localRefs = LocalReferenceCollection.setOrGet(endpoint);
919
914
  if (currentSlideIsForward) {
920
915
  localRefs.addBeforeTombstones(...endpointRefsToAdd);
@@ -934,6 +929,7 @@ export class MergeTree {
934
929
  }
935
930
  }
936
931
  } else {
932
+ // eslint-disable-next-line import/no-deprecated
937
933
  const localRefs = LocalReferenceCollection.setOrGet(currentSlideDestination);
938
934
  if (currentSlideIsForward) {
939
935
  localRefs.addBeforeTombstones(...nonEndpointRefsToAdd);
@@ -947,11 +943,13 @@ export class MergeTree {
947
943
  segment: ISegmentLeaf,
948
944
  currentSlideDestination: ISegmentLeaf | undefined,
949
945
  currentSlideIsForward: boolean | undefined,
946
+ // eslint-disable-next-line import/no-deprecated
950
947
  currentSlideGroup: LocalReferenceCollection[],
951
948
  pred: (ref: LocalReferencePosition) => boolean,
952
949
  slidingPreference: SlidingPreference,
953
950
  currentMaybeEndpoint: "start" | "end" | undefined,
954
951
  reassign: (
952
+ // eslint-disable-next-line import/no-deprecated
955
953
  localRefs: LocalReferenceCollection,
956
954
  slideToSegment: ISegmentLeaf | undefined,
957
955
  slideIsForward: boolean,
@@ -1074,7 +1072,6 @@ export class MergeTree {
1074
1072
  return;
1075
1073
  }
1076
1074
 
1077
- // eslint-disable-next-line import/no-deprecated
1078
1075
  const rebaseCollabWindow = new CollaborationWindow();
1079
1076
  rebaseCollabWindow.loadFrom(this.collabWindow);
1080
1077
  if (refSeq < this.collabWindow.minSeq) {
@@ -1197,13 +1194,13 @@ export class MergeTree {
1197
1194
  clientId = this.collabWindow.clientId,
1198
1195
  localSeq: number | undefined = this.collabWindow.localSeq,
1199
1196
  ): number {
1200
- const seg: ISegmentLeaf | undefined = refPos.getSegment();
1201
- if (seg?.parent === undefined) {
1197
+ const seg = refPos.getSegment();
1198
+ if (!isSegmentLeaf(seg)) {
1202
1199
  // We have no idea where this reference is, because it refers to a segment which is not in the tree.
1203
1200
  return DetachedReferencePosition;
1204
1201
  }
1205
1202
  if (refPos.isLeaf()) {
1206
- return this.getPosition(refPos, refSeq, clientId, localSeq);
1203
+ return this.getPosition(seg, refSeq, clientId, localSeq);
1207
1204
  }
1208
1205
  if (refTypeIncludesFlag(refPos, ReferenceType.Transient) || seg.localRefs?.has(refPos)) {
1209
1206
  if (
@@ -1212,13 +1209,15 @@ export class MergeTree {
1212
1209
  !isSegmentPresent(seg, { refSeq, localSeq })
1213
1210
  ) {
1214
1211
  const forward = refPos.slidingPreference === SlidingPreference.FORWARD;
1212
+ const moveInfo = toMoveInfo(seg);
1213
+ const removeInfo = toRemovalInfo(seg);
1215
1214
  const slideSeq =
1216
- seg.movedSeq !== UnassignedSequenceNumber && seg.movedSeq !== undefined
1217
- ? seg.movedSeq
1218
- : seg.removedSeq !== UnassignedSequenceNumber && seg.removedSeq !== undefined
1219
- ? seg.removedSeq
1215
+ moveInfo !== undefined && moveInfo.movedSeq !== UnassignedSequenceNumber
1216
+ ? moveInfo.movedSeq
1217
+ : removeInfo !== undefined && removeInfo.removedSeq !== UnassignedSequenceNumber
1218
+ ? removeInfo.removedSeq
1220
1219
  : refSeq;
1221
- const slideLocalSeq = seg.localMovedSeq ?? seg.localRemovedSeq;
1220
+ const slideLocalSeq = moveInfo?.localMovedSeq ?? removeInfo?.localRemovedSeq;
1222
1221
  const perspective = new PerspectiveImpl(this, {
1223
1222
  refSeq: slideSeq,
1224
1223
  localSeq: slideLocalSeq,
@@ -1255,14 +1254,13 @@ export class MergeTree {
1255
1254
  let foundMarker: Marker | undefined;
1256
1255
 
1257
1256
  const { segment } = this.getContainingSegment(startPos, UniversalSequenceNumber, clientId);
1258
- const segWithParent: ISegmentLeaf | undefined = segment;
1259
- if (segWithParent?.parent === undefined) {
1257
+ if (!isSegmentLeaf(segment)) {
1260
1258
  return undefined;
1261
1259
  }
1262
1260
 
1263
1261
  depthFirstNodeWalk(
1264
- segWithParent.parent,
1265
- segWithParent,
1262
+ segment.parent,
1263
+ segment,
1266
1264
  (node) => {
1267
1265
  if (node.isLeaf()) {
1268
1266
  if (Marker.is(node) && refHasTileLabel(node, markerLabel)) {
@@ -1293,8 +1291,8 @@ export class MergeTree {
1293
1291
  private updateRoot(splitNode: MergeBlock | undefined): void {
1294
1292
  if (splitNode !== undefined) {
1295
1293
  const newRoot = this.makeBlock(2);
1296
- newRoot.assignChild(this.root, 0, false);
1297
- newRoot.assignChild(splitNode, 1, false);
1294
+ assignChild(newRoot, this.root, 0, false);
1295
+ assignChild(newRoot, splitNode, 1, false);
1298
1296
  this.root = newRoot;
1299
1297
  this.nodeUpdateOrdinals(this.root);
1300
1298
  this.nodeUpdateLengthNewStructure(this.root);
@@ -1322,8 +1320,8 @@ export class MergeTree {
1322
1320
  if (MergeTree.options.zamboniSegments) {
1323
1321
  this.addToLRUSet(pendingSegment, seq);
1324
1322
  }
1325
- if (!nodesToUpdate.includes(pendingSegment.parent!)) {
1326
- nodesToUpdate.push(pendingSegment.parent!);
1323
+ if (!nodesToUpdate.includes(pendingSegment.parent)) {
1324
+ nodesToUpdate.push(pendingSegment.parent);
1327
1325
  }
1328
1326
  deltaSegments.push({
1329
1327
  segment: pendingSegment,
@@ -1364,11 +1362,10 @@ export class MergeTree {
1364
1362
 
1365
1363
  private addToPendingList(
1366
1364
  segment: ISegmentLeaf,
1367
- // eslint-disable-next-line import/no-deprecated
1365
+
1368
1366
  segmentGroup?: SegmentGroup,
1369
1367
  localSeq?: number,
1370
1368
  previousProps?: PropertySet,
1371
- // eslint-disable-next-line import/no-deprecated
1372
1369
  ): SegmentGroup {
1373
1370
  let _segmentGroup = segmentGroup;
1374
1371
  if (_segmentGroup === undefined) {
@@ -1392,7 +1389,7 @@ export class MergeTree {
1392
1389
  if (previousProps) {
1393
1390
  _segmentGroup.previousProps!.push(previousProps);
1394
1391
  }
1395
- // eslint-disable-next-line import/no-deprecated
1392
+
1396
1393
  const segmentGroups = (segment.segmentGroups ??= new SegmentGroupCollection(segment));
1397
1394
  segmentGroups.enqueue(_segmentGroup);
1398
1395
  return _segmentGroup;
@@ -1425,7 +1422,7 @@ export class MergeTree {
1425
1422
  if (relativePos.id) {
1426
1423
  marker = this.getMarkerFromId(relativePos.id);
1427
1424
  }
1428
- if (marker) {
1425
+ if (isSegmentLeaf(marker)) {
1429
1426
  pos = this.getPosition(marker, refseq, clientId);
1430
1427
  if (relativePos.before) {
1431
1428
  if (relativePos.offset !== undefined) {
@@ -1443,7 +1440,7 @@ export class MergeTree {
1443
1440
 
1444
1441
  public insertSegments(
1445
1442
  pos: number,
1446
- segments: ISegmentLeaf[],
1443
+ segments: ISegmentPrivate[],
1447
1444
  refSeq: number,
1448
1445
  clientId: number,
1449
1446
  seq: number,
@@ -1510,7 +1507,7 @@ export class MergeTree {
1510
1507
 
1511
1508
  const { currentSeq, clientId } = this.collabWindow;
1512
1509
 
1513
- if (segmentInfo?.segment) {
1510
+ if (isSegmentLeaf(segmentInfo?.segment)) {
1514
1511
  const segmentPosition = this.getPosition(segmentInfo.segment, currentSeq, clientId);
1515
1512
  return segmentPosition + segmentInfo.offset!;
1516
1513
  } else {
@@ -1520,7 +1517,7 @@ export class MergeTree {
1520
1517
  }
1521
1518
  }
1522
1519
 
1523
- private blockInsert<T extends ISegmentLeaf>(
1520
+ private blockInsert<T extends ISegmentPrivate>(
1524
1521
  pos: number,
1525
1522
  refSeq: number,
1526
1523
  clientId: number,
@@ -1538,7 +1535,7 @@ export class MergeTree {
1538
1535
  });
1539
1536
  return siblingExists;
1540
1537
  };
1541
- // eslint-disable-next-line import/no-deprecated
1538
+
1542
1539
  let segmentGroup: SegmentGroup;
1543
1540
  const saveIfLocal = (locSegment: ISegmentLeaf): void => {
1544
1541
  // Save segment so we can assign sequence number when acked by server
@@ -1553,10 +1550,10 @@ export class MergeTree {
1553
1550
  // In all other cases this has to be true (checked by addToLRUSet):
1554
1551
  // locSegment.seq > this.collabWindow.currentSeq
1555
1552
  else if (
1556
- locSegment.seq! > this.collabWindow.minSeq &&
1553
+ locSegment.seq > this.collabWindow.minSeq &&
1557
1554
  MergeTree.options.zamboniSegments
1558
1555
  ) {
1559
- this.addToLRUSet(locSegment, locSegment.seq!);
1556
+ this.addToLRUSet(locSegment, locSegment.seq);
1560
1557
  }
1561
1558
  }
1562
1559
  };
@@ -1565,6 +1562,7 @@ export class MergeTree {
1565
1562
  _pos: number,
1566
1563
  context: InsertContext,
1567
1564
  // Keeping this function within the scope of blockInsert for readability.
1565
+ // eslint-disable-next-line unicorn/consistent-function-scoping
1568
1566
  ): ISegmentChanges => {
1569
1567
  const segmentChanges: ISegmentChanges = {};
1570
1568
  if (segment) {
@@ -1577,106 +1575,109 @@ export class MergeTree {
1577
1575
  return segmentChanges;
1578
1576
  };
1579
1577
 
1578
+ const insertInfo: IInsertionInfo = {
1579
+ clientId,
1580
+ seq,
1581
+ localSeq,
1582
+ };
1580
1583
  // TODO: build tree from segs and insert all at once
1581
1584
  let insertPos = pos;
1582
- for (const newSegment of newSegments) {
1583
- if (newSegment.cachedLength > 0) {
1584
- newSegment.seq = seq;
1585
- newSegment.localSeq = localSeq;
1586
- newSegment.clientId = clientId;
1587
- if (Marker.is(newSegment)) {
1588
- const markerId = newSegment.getId();
1589
- if (markerId) {
1590
- this.idToMarker.set(markerId, newSegment);
1591
- }
1585
+ for (const newSegment of newSegments
1586
+ .filter((s) => s.cachedLength > 0)
1587
+ .map((s) => overwriteInfo(s, insertInfo))) {
1588
+ if (Marker.is(newSegment)) {
1589
+ const markerId = newSegment.getId();
1590
+ if (markerId) {
1591
+ this.idToMarker.set(markerId, newSegment);
1592
1592
  }
1593
+ }
1593
1594
 
1594
- const splitNode = this.insertingWalk(this.root, insertPos, refSeq, clientId, seq, {
1595
- leaf: onLeaf,
1596
- candidateSegment: newSegment,
1597
- continuePredicate: continueFrom,
1598
- });
1595
+ const splitNode = this.insertingWalk(this.root, insertPos, refSeq, clientId, seq, {
1596
+ leaf: onLeaf,
1597
+ candidateSegment: newSegment,
1598
+ continuePredicate: continueFrom,
1599
+ });
1599
1600
 
1600
- if (newSegment.parent === undefined) {
1601
- // Indicates an attempt to insert past the end of the merge-tree's content.
1602
- const errorConstructor = localSeq === undefined ? DataProcessingError : UsageError;
1603
- throw new errorConstructor("MergeTree insert failed", {
1604
- currentSeq: this.collabWindow.currentSeq,
1605
- minSeq: this.collabWindow.minSeq,
1606
- segSeq: newSegment.seq,
1607
- });
1608
- }
1601
+ if (!isSegmentLeaf(newSegment)) {
1602
+ // Indicates an attempt to insert past the end of the merge-tree's content.
1603
+ const errorConstructor = localSeq === undefined ? DataProcessingError : UsageError;
1604
+ throw new errorConstructor("MergeTree insert failed", {
1605
+ currentSeq: this.collabWindow.currentSeq,
1606
+ minSeq: this.collabWindow.minSeq,
1607
+ segSeq: insertInfo.seq,
1608
+ });
1609
+ }
1609
1610
 
1610
- this.updateRoot(splitNode);
1611
+ this.updateRoot(splitNode);
1611
1612
 
1612
- insertPos += newSegment.cachedLength;
1613
+ insertPos += newSegment.cachedLength;
1613
1614
 
1614
- if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
1615
- saveIfLocal(newSegment);
1616
- continue;
1617
- }
1615
+ if (!this.options?.mergeTreeEnableObliterate || this.obliterates.empty()) {
1616
+ saveIfLocal(newSegment);
1617
+ continue;
1618
+ }
1618
1619
 
1619
- let oldest: ObliterateInfo | undefined;
1620
- let normalizedOldestSeq: number = 0;
1621
- let newest: ObliterateInfo | undefined;
1622
- let normalizedNewestSeq: number = 0;
1623
- const movedClientIds: number[] = [];
1624
- const movedSeqs: number[] = [];
1625
- for (const ob of this.obliterates.findOverlapping(newSegment)) {
1626
- // compute a normalized seq that takes into account local seqs
1627
- // but is still comparable to remote seqs to keep the checks below easy
1628
- // REMOTE SEQUENCE NUMBERS LOCAL SEQUENCE NUMBERS
1629
- // [0, 1, 2, 3, ..., 100, ..., 1000, ..., (MAX - MaxLocalSeq), L1, L2, L3, L4, ..., L100, ..., L1000, ...(MAX)]
1630
- const normalizedObSeq =
1631
- ob.seq === UnassignedSequenceNumber
1632
- ? Number.MAX_SAFE_INTEGER - this.collabWindow.localSeq + ob.localSeq!
1633
- : ob.seq;
1634
- if (normalizedObSeq > refSeq) {
1635
- if (oldest === undefined || normalizedOldestSeq > normalizedObSeq) {
1636
- normalizedOldestSeq = normalizedObSeq;
1637
- oldest = ob;
1638
- movedClientIds.unshift(ob.clientId);
1639
- movedSeqs.unshift(ob.seq);
1640
- } else {
1641
- movedClientIds.push(ob.clientId);
1642
- movedSeqs.push(ob.seq);
1643
- }
1644
- if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
1645
- normalizedNewestSeq = normalizedObSeq;
1646
- newest = ob;
1647
- }
1620
+ let oldest: ObliterateInfo | undefined;
1621
+ let normalizedOldestSeq: number = 0;
1622
+ let newest: ObliterateInfo | undefined;
1623
+ let normalizedNewestSeq: number = 0;
1624
+ const movedClientIds: number[] = [];
1625
+ const movedSeqs: number[] = [];
1626
+ for (const ob of this.obliterates.findOverlapping(newSegment)) {
1627
+ // compute a normalized seq that takes into account local seqs
1628
+ // but is still comparable to remote seqs to keep the checks below easy
1629
+ // REMOTE SEQUENCE NUMBERS LOCAL SEQUENCE NUMBERS
1630
+ // [0, 1, 2, 3, ..., 100, ..., 1000, ..., (MAX - MaxLocalSeq), L1, L2, L3, L4, ..., L100, ..., L1000, ...(MAX)]
1631
+ const normalizedObSeq =
1632
+ ob.seq === UnassignedSequenceNumber
1633
+ ? Number.MAX_SAFE_INTEGER - this.collabWindow.localSeq + ob.localSeq!
1634
+ : ob.seq;
1635
+ if (normalizedObSeq > refSeq) {
1636
+ if (oldest === undefined || normalizedOldestSeq > normalizedObSeq) {
1637
+ normalizedOldestSeq = normalizedObSeq;
1638
+ oldest = ob;
1639
+ movedClientIds.unshift(ob.clientId);
1640
+ movedSeqs.unshift(ob.seq);
1641
+ } else {
1642
+ movedClientIds.push(ob.clientId);
1643
+ movedSeqs.push(ob.seq);
1644
+ }
1645
+ if (newest === undefined || normalizedNewestSeq < normalizedObSeq) {
1646
+ normalizedNewestSeq = normalizedObSeq;
1647
+ newest = ob;
1648
1648
  }
1649
1649
  }
1650
+ }
1650
1651
 
1651
- if (oldest && newest?.clientId !== clientId) {
1652
- const moveInfo: IMoveInfo = {
1653
- movedClientIds,
1654
- movedSeq: oldest.seq,
1655
- movedSeqs,
1656
- localMovedSeq: oldest.localSeq,
1657
- wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
1658
- };
1659
-
1660
- markSegmentMoved(newSegment, moveInfo);
1652
+ if (oldest && newest?.clientId !== clientId) {
1653
+ // eslint-disable-next-line import/no-deprecated
1654
+ const moveInfo: IMoveInfo = {
1655
+ movedClientIds,
1656
+ movedSeq: oldest.seq,
1657
+ movedSeqs,
1658
+ localMovedSeq: oldest.localSeq,
1659
+ wasMovedOnInsert: oldest.seq !== UnassignedSequenceNumber,
1660
+ };
1661
1661
 
1662
- if (moveInfo.localMovedSeq !== undefined) {
1663
- assert(
1664
- oldest.segmentGroup !== undefined,
1665
- 0x86c /* expected segment group to exist */,
1666
- );
1662
+ overwriteInfo(newSegment, moveInfo);
1667
1663
 
1668
- this.addToPendingList(newSegment, oldest.segmentGroup);
1669
- }
1664
+ if (moveInfo.localMovedSeq !== undefined) {
1665
+ assert(
1666
+ oldest.segmentGroup !== undefined,
1667
+ 0x86c /* expected segment group to exist */,
1668
+ );
1670
1669
 
1671
- if (newSegment.parent) {
1672
- this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
1673
- }
1674
- } else if (oldest && newest?.clientId === clientId) {
1675
- newSegment.prevObliterateByInserter = newest;
1670
+ this.addToPendingList(newSegment, oldest.segmentGroup);
1676
1671
  }
1677
1672
 
1678
- saveIfLocal(newSegment);
1673
+ if (newSegment.parent) {
1674
+ this.blockUpdatePathLengths(newSegment.parent, seq, clientId);
1675
+ }
1676
+ } else if (oldest && newest?.clientId === clientId) {
1677
+ newSegment.prevObliterateByInserter = newest;
1679
1678
  }
1679
+
1680
+ saveIfLocal(newSegment);
1680
1681
  }
1681
1682
  }
1682
1683
 
@@ -1688,7 +1689,8 @@ export class MergeTree {
1688
1689
  return {};
1689
1690
  }
1690
1691
 
1691
- const next: ISegmentLeaf = segment.splitAt(pos)!;
1692
+ const next = segment.splitAt(pos)!;
1693
+ assertSegmentLeaf(next);
1692
1694
 
1693
1695
  if (segment?.segmentGroups) {
1694
1696
  next.segmentGroups ??= new SegmentGroupCollection(next);
@@ -1744,10 +1746,8 @@ export class MergeTree {
1744
1746
 
1745
1747
  return (
1746
1748
  newSeq > segSeq ||
1747
- (node.movedSeq !== undefined &&
1748
- node.movedSeq !== UnassignedSequenceNumber &&
1749
- node.movedSeq > seq) ||
1750
- (node.removedSeq !== undefined &&
1749
+ (isMoved(node) && node.movedSeq !== UnassignedSequenceNumber && node.movedSeq > seq) ||
1750
+ (isRemoved(node) &&
1751
1751
  node.removedSeq !== UnassignedSequenceNumber &&
1752
1752
  node.removedSeq > seq)
1753
1753
  );
@@ -1770,7 +1770,7 @@ export class MergeTree {
1770
1770
  const children = block.children;
1771
1771
  let childIndex: number;
1772
1772
  let child: IMergeNode;
1773
- let newNode: IMergeNode | undefined;
1773
+ let newNode: IMergeNodeBuilder | undefined;
1774
1774
  let fromSplit: MergeBlock | undefined;
1775
1775
  for (childIndex = 0; childIndex < block.childCount; childIndex++) {
1776
1776
  child = children[childIndex];
@@ -1794,7 +1794,7 @@ export class MergeTree {
1794
1794
  const segment = child;
1795
1795
  const segmentChanges = context.leaf(segment, _pos, context);
1796
1796
  if (segmentChanges.replaceCurrent) {
1797
- block.assignChild(segmentChanges.replaceCurrent, childIndex, false);
1797
+ assignChild(block, segmentChanges.replaceCurrent, childIndex, false);
1798
1798
  segmentChanges.replaceCurrent.ordinal = child.ordinal;
1799
1799
  }
1800
1800
  if (segmentChanges.next) {
@@ -1847,7 +1847,7 @@ export class MergeTree {
1847
1847
  block.children[i] = block.children[i - 1];
1848
1848
  block.children[i].index = i;
1849
1849
  }
1850
- block.assignChild(newNode, childIndex, false);
1850
+ assignChild(block, newNode, childIndex, false);
1851
1851
  block.childCount++;
1852
1852
  block.setOrdinal(newNode, childIndex);
1853
1853
  if (block.childCount < MaxNodesInBlock) {
@@ -1882,7 +1882,7 @@ export class MergeTree {
1882
1882
  // Update ordinals to reflect lowered child count
1883
1883
  this.nodeUpdateOrdinals(node);
1884
1884
  for (let i = 0; i < halfCount; i++) {
1885
- newNode.assignChild(node.children[halfCount + i], i, false);
1885
+ assignChild(newNode, node.children[halfCount + i], i, false);
1886
1886
  node.children[halfCount + i] = undefined!;
1887
1887
  }
1888
1888
  this.nodeUpdateLengthNewStructure(node);
@@ -1919,7 +1919,7 @@ export class MergeTree {
1919
1919
  clientId: number,
1920
1920
  seq: number,
1921
1921
  opArgs: IMergeTreeDeltaOpArgs,
1922
- // eslint-disable-next-line import/no-deprecated
1922
+
1923
1923
  rollback: PropertiesRollback = PropertiesRollback.None,
1924
1924
  ): void {
1925
1925
  if (propsOrAdjust.adjust !== undefined) {
@@ -1931,7 +1931,7 @@ export class MergeTree {
1931
1931
  const deltaSegments: IMergeTreeSegmentDelta[] = [];
1932
1932
  const localSeq =
1933
1933
  seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
1934
- // eslint-disable-next-line import/no-deprecated
1934
+
1935
1935
  let segmentGroup: SegmentGroup | undefined;
1936
1936
  const opObj = propsOrAdjust.props ?? propsOrAdjust.adjust;
1937
1937
  const annotateSegment = (segment: ISegmentLeaf): boolean => {
@@ -1972,7 +1972,7 @@ export class MergeTree {
1972
1972
  return true;
1973
1973
  };
1974
1974
 
1975
- this.nodeMap(refSeq, clientId, annotateSegment, undefined, undefined, start, end);
1975
+ this.nodeMap(refSeq, clientId, annotateSegment, undefined, start, end);
1976
1976
 
1977
1977
  // OpArgs == undefined => test code
1978
1978
  if (deltaSegments.length > 0) {
@@ -2006,10 +2006,11 @@ export class MergeTree {
2006
2006
 
2007
2007
  let _overwrite = false;
2008
2008
  const localOverlapWithRefs: ISegmentLeaf[] = [];
2009
- const movedSegments: IMergeTreeSegmentDelta[] = [];
2009
+ // eslint-disable-next-line import/no-deprecated
2010
+ const movedSegments: SegmentWithInfo<IMoveInfo, ISegmentLeaf>[] = [];
2010
2011
  const localSeq =
2011
2012
  seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
2012
- // eslint-disable-next-line import/no-deprecated
2013
+
2013
2014
  const obliterate: ObliterateInfo = {
2014
2015
  clientId,
2015
2016
  end: createDetachedLocalReferencePosition(undefined),
@@ -2023,7 +2024,7 @@ export class MergeTree {
2023
2024
  const { segment: startSeg } = this.getContainingSegment(start.pos, refSeq, clientId);
2024
2025
  const { segment: endSeg } = this.getContainingSegment(end.pos, refSeq, clientId);
2025
2026
  assert(
2026
- startSeg !== undefined && endSeg !== undefined,
2027
+ isSegmentLeaf(startSeg) && isSegmentLeaf(endSeg),
2027
2028
  0xa3f /* segments cannot be undefined */,
2028
2029
  );
2029
2030
 
@@ -2060,12 +2061,7 @@ export class MergeTree {
2060
2061
  }
2061
2062
  this.obliterates.addOrUpdate(obliterate);
2062
2063
 
2063
- const markMoved = (
2064
- segment: ISegmentLeaf,
2065
- pos: number,
2066
- _start: number,
2067
- _end: number,
2068
- ): boolean => {
2064
+ const markMoved = (segment: ISegmentLeaf, pos: number): boolean => {
2069
2065
  if (
2070
2066
  (start.side === Side.After && startPos === pos + segment.cachedLength) || // exclusive start segment
2071
2067
  (end.side === Side.Before &&
@@ -2085,26 +2081,29 @@ export class MergeTree {
2085
2081
  return true;
2086
2082
  }
2087
2083
 
2088
- if (
2084
+ const wasMovedOnInsert =
2089
2085
  clientId !== segment.clientId &&
2090
2086
  segment.seq !== undefined &&
2091
2087
  seq !== UnassignedSequenceNumber &&
2092
- (refSeq < segment.seq || segment.seq === UnassignedSequenceNumber)
2093
- ) {
2094
- segment.wasMovedOnInsert = true;
2095
- }
2088
+ (refSeq < segment.seq || segment.seq === UnassignedSequenceNumber);
2096
2089
 
2097
2090
  if (existingMoveInfo === undefined) {
2098
- segment.movedClientIds = [clientId];
2099
- segment.movedSeq = seq;
2100
- segment.localMovedSeq = localSeq;
2101
- segment.movedSeqs = [seq];
2091
+ // eslint-disable-next-line import/no-deprecated
2092
+ const movedSeg = overwriteInfo<IMoveInfo, ISegmentLeaf>(segment, {
2093
+ movedClientIds: [clientId],
2094
+ movedSeq: seq,
2095
+ localMovedSeq: localSeq,
2096
+ movedSeqs: [seq],
2097
+ wasMovedOnInsert,
2098
+ });
2102
2099
 
2103
- if (!toRemovalInfo(segment)) {
2104
- movedSegments.push({ segment });
2100
+ if (!toRemovalInfo(movedSeg)) {
2101
+ movedSegments.push(movedSeg);
2105
2102
  }
2106
2103
  } else {
2107
2104
  _overwrite = true;
2105
+ // never move wasMovedOnInsert from true to false
2106
+ existingMoveInfo.wasMovedOnInsert ||= wasMovedOnInsert;
2108
2107
  if (existingMoveInfo.movedSeq === UnassignedSequenceNumber) {
2109
2108
  // we moved this locally, but someone else moved it first
2110
2109
  // so put them at the head of the list
@@ -2123,7 +2122,7 @@ export class MergeTree {
2123
2122
  existingMoveInfo.movedSeqs.push(seq);
2124
2123
  }
2125
2124
  }
2126
-
2125
+ assertMoved(segment);
2127
2126
  // Save segment so can assign moved sequence number when acked by server
2128
2127
  if (this.collabWindow.collaborating) {
2129
2128
  if (
@@ -2144,12 +2143,7 @@ export class MergeTree {
2144
2143
  return true;
2145
2144
  };
2146
2145
 
2147
- const afterMarkMoved = (
2148
- node: MergeBlock,
2149
- pos: number,
2150
- _start: number,
2151
- _end: number,
2152
- ): boolean => {
2146
+ const afterMarkMoved = (node: MergeBlock): boolean => {
2153
2147
  if (_overwrite) {
2154
2148
  this.nodeUpdateLengthNewStructure(node);
2155
2149
  } else {
@@ -2162,7 +2156,6 @@ export class MergeTree {
2162
2156
  refSeq,
2163
2157
  clientId,
2164
2158
  markMoved,
2165
- undefined,
2166
2159
  afterMarkMoved,
2167
2160
  start.pos,
2168
2161
  end.pos + 1, // include the segment containing the end reference
@@ -2175,7 +2168,7 @@ export class MergeTree {
2175
2168
  if (start.pos !== end.pos || start.side !== end.side) {
2176
2169
  this.mergeTreeDeltaCallback?.(opArgs, {
2177
2170
  operation: MergeTreeDeltaType.OBLITERATE,
2178
- deltaSegments: movedSegments,
2171
+ deltaSegments: movedSegments.map((segment) => ({ segment })),
2179
2172
  });
2180
2173
  }
2181
2174
 
@@ -2183,7 +2176,7 @@ export class MergeTree {
2183
2176
  // so we slide after eventing in case the consumer wants to make reference
2184
2177
  // changes at remove time, like add a ref to track undo redo.
2185
2178
  if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
2186
- this.slideAckedRemovedSegmentReferences(movedSegments.map(({ segment }) => segment));
2179
+ this.slideAckedRemovedSegmentReferences(movedSegments);
2187
2180
  }
2188
2181
 
2189
2182
  if (
@@ -2237,9 +2230,10 @@ export class MergeTree {
2237
2230
  let _overwrite = false;
2238
2231
  this.ensureIntervalBoundary(start, refSeq, clientId);
2239
2232
  this.ensureIntervalBoundary(end, refSeq, clientId);
2240
- // eslint-disable-next-line import/no-deprecated
2233
+
2241
2234
  let segmentGroup: SegmentGroup;
2242
- const removedSegments: IMergeTreeSegmentDelta[] = [];
2235
+ // eslint-disable-next-line import/no-deprecated
2236
+ const removedSegments: SegmentWithInfo<IRemovalInfo, ISegmentLeaf>[] = [];
2243
2237
  const localOverlapWithRefs: ISegmentLeaf[] = [];
2244
2238
  const localSeq =
2245
2239
  seq === UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
@@ -2252,12 +2246,15 @@ export class MergeTree {
2252
2246
  const existingRemovalInfo = toRemovalInfo(segment);
2253
2247
 
2254
2248
  if (existingRemovalInfo === undefined) {
2255
- segment.removedClientIds = [clientId];
2256
- segment.removedSeq = seq;
2257
- segment.localRemovedSeq = localSeq;
2249
+ // eslint-disable-next-line import/no-deprecated
2250
+ const removed = overwriteInfo<IRemovalInfo, ISegmentLeaf>(segment, {
2251
+ removedClientIds: [clientId],
2252
+ removedSeq: seq,
2253
+ localRemovedSeq: localSeq,
2254
+ });
2258
2255
 
2259
- if (!toMoveInfo(segment)) {
2260
- removedSegments.push({ segment });
2256
+ if (!toMoveInfo(removed)) {
2257
+ removedSegments.push(removed);
2261
2258
  }
2262
2259
  } else {
2263
2260
  _overwrite = true;
@@ -2277,7 +2274,7 @@ export class MergeTree {
2277
2274
  existingRemovalInfo.removedClientIds.push(clientId);
2278
2275
  }
2279
2276
  }
2280
-
2277
+ assertRemoved(segment);
2281
2278
  // Save segment so we can assign removed sequence number when acked by server
2282
2279
  if (this.collabWindow.collaborating) {
2283
2280
  if (
@@ -2293,12 +2290,7 @@ export class MergeTree {
2293
2290
  }
2294
2291
  return true;
2295
2292
  };
2296
- const afterMarkRemoved = (
2297
- node: MergeBlock,
2298
- pos: number,
2299
- _start: number,
2300
- _end: number,
2301
- ): boolean => {
2293
+ const afterMarkRemoved = (node: MergeBlock): boolean => {
2302
2294
  if (_overwrite) {
2303
2295
  this.nodeUpdateLengthNewStructure(node);
2304
2296
  } else {
@@ -2306,7 +2298,7 @@ export class MergeTree {
2306
2298
  }
2307
2299
  return true;
2308
2300
  };
2309
- this.nodeMap(refSeq, clientId, markRemoved, undefined, afterMarkRemoved, start, end);
2301
+ this.nodeMap(refSeq, clientId, markRemoved, afterMarkRemoved, start, end);
2310
2302
  // these segments are already viewed as being removed locally and are not event-ed
2311
2303
  // so can slide non-StayOnRemove refs immediately
2312
2304
  this.slideAckedRemovedSegmentReferences(localOverlapWithRefs);
@@ -2314,14 +2306,14 @@ export class MergeTree {
2314
2306
  if (removedSegments.length > 0) {
2315
2307
  this.mergeTreeDeltaCallback?.(opArgs, {
2316
2308
  operation: MergeTreeDeltaType.REMOVE,
2317
- deltaSegments: removedSegments,
2309
+ deltaSegments: removedSegments.map((segment) => ({ segment })),
2318
2310
  });
2319
2311
  }
2320
2312
  // these events are newly removed
2321
2313
  // so we slide after eventing in case the consumer wants to make reference
2322
2314
  // changes at remove time, like add a ref to track undo redo.
2323
2315
  if (!this.collabWindow.collaborating || clientId !== this.collabWindow.clientId) {
2324
- this.slideAckedRemovedSegmentReferences(removedSegments.map(({ segment }) => segment));
2316
+ this.slideAckedRemovedSegmentReferences(removedSegments);
2325
2317
  }
2326
2318
 
2327
2319
  if (
@@ -2336,36 +2328,30 @@ export class MergeTree {
2336
2328
  /**
2337
2329
  * Revert an unacked local op
2338
2330
  */
2339
- // eslint-disable-next-line import/no-deprecated
2331
+
2340
2332
  public rollback(op: IMergeTreeDeltaOp, localOpMetadata: SegmentGroup): void {
2341
2333
  if (op.type === MergeTreeDeltaType.REMOVE) {
2342
- const pendingSegmentGroup = this.pendingSegments.pop?.()?.data;
2334
+ const pendingSegmentGroup = this.pendingSegments.pop()?.data;
2343
2335
  if (pendingSegmentGroup === undefined || pendingSegmentGroup !== localOpMetadata) {
2344
2336
  throw new Error("Rollback op doesn't match last edit");
2345
2337
  }
2346
2338
  // Disabling because a for of loop causes the type of segment to be ISegmentLeaf, which does not have parent information stored
2347
2339
  // eslint-disable-next-line unicorn/no-array-for-each
2348
2340
  pendingSegmentGroup.segments.forEach((segment: ISegmentLeaf) => {
2349
- const segmentSegmentGroup = segment?.segmentGroups?.pop?.();
2341
+ const segmentSegmentGroup = segment?.segmentGroups?.pop();
2350
2342
  assert(
2351
2343
  segmentSegmentGroup === pendingSegmentGroup,
2352
2344
  0x3ee /* Unexpected segmentGroup in segment */,
2353
2345
  );
2354
2346
 
2355
2347
  assert(
2356
- segment.removedClientIds !== undefined &&
2357
- segment.removedClientIds[0] === this.collabWindow.clientId,
2348
+ isRemoved(segment) && segment.removedClientIds[0] === this.collabWindow.clientId,
2358
2349
  0x39d /* Rollback segment removedClientId does not match local client */,
2359
2350
  );
2360
- segment.removedClientIds = undefined;
2361
- segment.removedSeq = undefined;
2362
- segment.localRemovedSeq = undefined;
2351
+ let updateNode: MergeBlock | undefined = segment.parent;
2352
+ removeRemovalInfo(segment);
2363
2353
 
2364
- for (
2365
- let updateNode = segment.parent;
2366
- updateNode !== undefined;
2367
- updateNode = updateNode.parent
2368
- ) {
2354
+ for (updateNode; updateNode !== undefined; updateNode = updateNode.parent) {
2369
2355
  this.blockUpdateLength(
2370
2356
  updateNode,
2371
2357
  UnassignedSequenceNumber,
@@ -2387,7 +2373,7 @@ export class MergeTree {
2387
2373
  op.type === MergeTreeDeltaType.INSERT ||
2388
2374
  op.type === MergeTreeDeltaType.ANNOTATE
2389
2375
  ) {
2390
- const pendingSegmentGroup = this.pendingSegments.pop?.()?.data;
2376
+ const pendingSegmentGroup = this.pendingSegments.pop()?.data;
2391
2377
  if (
2392
2378
  pendingSegmentGroup === undefined ||
2393
2379
  pendingSegmentGroup !== localOpMetadata ||
@@ -2396,8 +2382,8 @@ export class MergeTree {
2396
2382
  throw new Error("Rollback op doesn't match last edit");
2397
2383
  }
2398
2384
  let i = 0;
2399
- for (const segment of pendingSegmentGroup.segments as ISegmentLeaf[]) {
2400
- const segmentSegmentGroup = segment?.segmentGroups?.pop?.();
2385
+ for (const segment of pendingSegmentGroup.segments) {
2386
+ const segmentSegmentGroup = segment?.segmentGroups?.pop();
2401
2387
  assert(
2402
2388
  segmentSegmentGroup === pendingSegmentGroup,
2403
2389
  0x3ef /* Unexpected segmentGroup in segment */,
@@ -2449,7 +2435,7 @@ export class MergeTree {
2449
2435
  }
2450
2436
 
2451
2437
  // If not removed, increase position
2452
- if (seg.removedSeq === undefined) {
2438
+ if (!isRemoved(seg)) {
2453
2439
  segmentPosition += seg.cachedLength;
2454
2440
  }
2455
2441
 
@@ -2470,7 +2456,7 @@ export class MergeTree {
2470
2456
  public removeLocalReferencePosition(
2471
2457
  lref: LocalReferencePosition,
2472
2458
  ): LocalReferencePosition | undefined {
2473
- const segment: ISegmentLeaf | undefined = lref.getSegment();
2459
+ const segment: ISegmentPrivate | undefined = lref.getSegment();
2474
2460
  return segment?.localRefs?.removeLocalRef(lref);
2475
2461
  }
2476
2462
 
@@ -2478,7 +2464,7 @@ export class MergeTree {
2478
2464
  endOfTree = new EndOfTreeSegment(this);
2479
2465
 
2480
2466
  public createLocalReferencePosition(
2481
- _segment: ISegmentLeaf | "start" | "end",
2467
+ _segment: ISegmentPrivate | "start" | "end",
2482
2468
  offset: number,
2483
2469
  refType: ReferenceType,
2484
2470
  properties: PropertySet | undefined,
@@ -2499,7 +2485,6 @@ export class MergeTree {
2499
2485
  "Can only create SlideOnRemove or Transient local reference position on a removed or obliterated segment",
2500
2486
  );
2501
2487
  }
2502
-
2503
2488
  let segment: ISegmentLeaf;
2504
2489
 
2505
2490
  if (_segment === "start") {
@@ -2507,9 +2492,11 @@ export class MergeTree {
2507
2492
  } else if (_segment === "end") {
2508
2493
  segment = this.endOfTree;
2509
2494
  } else {
2495
+ assertSegmentLeaf(_segment);
2510
2496
  segment = _segment;
2511
2497
  }
2512
2498
 
2499
+ // eslint-disable-next-line import/no-deprecated
2513
2500
  const localRefs = LocalReferenceCollection.setOrGet(segment);
2514
2501
 
2515
2502
  const segRef = localRefs.createLocalRef(
@@ -2594,7 +2581,7 @@ export class MergeTree {
2594
2581
  for (let i = 0; i < newOrder.length; i++) {
2595
2582
  const seg = newOrder[i];
2596
2583
  const { parent, index, ordinal } = currentOrder[i];
2597
- parent?.assignChild(seg, index, false);
2584
+ assignChild(parent, seg, index, false);
2598
2585
  seg.ordinal = ordinal;
2599
2586
  }
2600
2587
 
@@ -2792,8 +2779,7 @@ export class MergeTree {
2792
2779
  this.nodeMap(
2793
2780
  refSeq,
2794
2781
  clientId,
2795
- handler,
2796
- accum,
2782
+ (seg, pos, _start, _end) => handler(seg, pos, refSeq, clientId, _start, _end, accum),
2797
2783
  undefined,
2798
2784
  start,
2799
2785
  end,
@@ -2825,12 +2811,11 @@ export class MergeTree {
2825
2811
  * but it will not count as a segment within the range. That is, it will be
2826
2812
  * ignored for the purposes of tracking when traversal should end.
2827
2813
  */
2828
- private nodeMap<TClientData>(
2814
+ private nodeMap(
2829
2815
  refSeq: number,
2830
2816
  clientId: number,
2831
- leaf: ISegmentAction<TClientData>,
2832
- accum: TClientData,
2833
- post?: BlockAction<TClientData>,
2817
+ leaf: (segment: ISegmentLeaf, pos: number, start: number, end: number) => boolean,
2818
+ post?: (block: MergeBlock) => boolean,
2834
2819
  start: number = 0,
2835
2820
  end?: number,
2836
2821
  localSeq?: number,
@@ -2876,17 +2861,14 @@ export class MergeTree {
2876
2861
  }
2877
2862
 
2878
2863
  if (node.isLeaf()) {
2879
- if (leaf(node, pos, refSeq, clientId, start - pos, endPos - pos, accum) === false) {
2864
+ if (leaf(node, pos, start - pos, endPos - pos) === false) {
2880
2865
  return NodeAction.Exit;
2881
2866
  }
2882
2867
  pos = nextPos;
2883
2868
  }
2884
2869
  },
2885
2870
  undefined,
2886
- post === undefined
2887
- ? undefined
2888
- : (block): boolean =>
2889
- post(block, pos, refSeq, clientId, start - pos, endPos - pos, accum),
2871
+ post,
2890
2872
  );
2891
2873
  }
2892
2874
  }