@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
@@ -3,8 +3,6 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
7
-
8
6
  import { assert } from "@fluidframework/core-utils/internal";
9
7
  import { AttributionKey } from "@fluidframework/runtime-definitions/internal";
10
8
 
@@ -14,26 +12,36 @@ import {
14
12
  UnassignedSequenceNumber,
15
13
  UniversalSequenceNumber,
16
14
  } from "./constants.js";
15
+ // eslint-disable-next-line import/no-deprecated
17
16
  import { LocalReferenceCollection, type LocalReferencePosition } from "./localReference.js";
18
17
  import { TrackingGroupCollection } from "./mergeTreeTracking.js";
19
18
  import { IJSONSegment, IMarkerDef, ReferenceType } from "./ops.js";
20
19
  import { computeHierarchicalOrdinal } from "./ordinal.js";
21
20
  import type { PartialSequenceLengths } from "./partialLengths.js";
22
21
  import { PropertySet, clone, createMap, type MapLike } from "./properties.js";
23
- import {
24
- ReferencePosition,
25
- refGetTileLabels,
26
- refTypeIncludesFlag,
27
- } from "./referencePositions.js";
28
- // eslint-disable-next-line import/no-deprecated
22
+ import { ReferencePosition } from "./referencePositions.js";
29
23
  import { SegmentGroupCollection } from "./segmentGroupCollection.js";
30
- // eslint-disable-next-line import/no-deprecated
24
+ import {
25
+ isInserted,
26
+ isMergeNodeInfo as isMergeNode,
27
+ isMoved,
28
+ isRemoved,
29
+ overwriteInfo,
30
+ type IInsertionInfo,
31
+ type IMergeNodeInfo,
32
+ // eslint-disable-next-line import/no-deprecated
33
+ type IMoveInfo,
34
+ // eslint-disable-next-line import/no-deprecated
35
+ type IRemovalInfo,
36
+ type SegmentWithInfo,
37
+ } from "./segmentInfos.js";
31
38
  import { PropertiesManager } from "./segmentPropertiesManager.js";
32
39
 
33
40
  /**
34
41
  * Common properties for a node in a merge tree.
35
42
  * @legacy
36
43
  * @alpha
44
+ * @deprecated - This interface will be removed in 2.20 with no replacement.
37
45
  */
38
46
  export interface IMergeNodeCommon {
39
47
  /**
@@ -53,12 +61,20 @@ export interface IMergeNodeCommon {
53
61
  * like sequence and matrix.
54
62
  *
55
63
  * We use tiered interface to control visibility of segment properties.
56
- * This sits between ISegment and ISegmentLeaf. It should only expose
64
+ * This sits between ISegment and ISegmentPrivate. It should only expose
57
65
  * things tagged internal.
58
66
  *
67
+ * Everything added here beyond ISegment should be optional to keep the ability
68
+ * to implicitly convert between the tiered interfaces.
69
+ *
59
70
  * @internal
60
71
  */
61
- export type ISegmentInternal = ISegment & {
72
+ export type ISegmentInternal = Omit<
73
+ ISegment,
74
+ // eslint-disable-next-line import/no-deprecated
75
+ keyof IRemovalInfo | keyof IMoveInfo
76
+ > & {
77
+ // eslint-disable-next-line import/no-deprecated
62
78
  localRefs?: LocalReferenceCollection;
63
79
  };
64
80
 
@@ -67,143 +83,81 @@ export type ISegmentInternal = ISegment & {
67
83
  * This is the lowest interface and is not exported, it site below ISegment and ISegmentInternal.
68
84
  * It should only expose unexported things.
69
85
  *
86
+ * Everything added here beyond ISegmentInternal should be optional to keep the ability
87
+ * to implicitly convert between the tiered interfaces.
88
+ *
70
89
  * someday we may split tree leaves from segments, but for now they are the same
71
90
  * this is just a convenience type that makes it clear that we need something that is both a segment and a leaf node
72
91
  */
73
- export type ISegmentLeaf = ISegmentInternal & {
74
- parent?: MergeBlock;
75
- // eslint-disable-next-line import/no-deprecated
76
- segmentGroups?: SegmentGroupCollection;
77
- // eslint-disable-next-line import/no-deprecated
78
- propertyManager?: PropertiesManager;
79
- /**
80
- * If a segment is inserted into an obliterated range,
81
- * but the newest obliteration of that range was by the inserting client,
82
- * then the segment is not obliterated because it is aware of the latest obliteration.
83
- */
84
- prevObliterateByInserter?: ObliterateInfo;
85
- };
86
- export type IMergeNode = MergeBlock | ISegmentLeaf;
92
+ export type ISegmentPrivate = ISegmentInternal & // eslint-disable-next-line import/no-deprecated
93
+ Partial<IInsertionInfo & IMergeNodeInfo> & {
94
+ segmentGroups?: SegmentGroupCollection;
95
+ propertyManager?: PropertiesManager;
96
+ /**
97
+ * If a segment is inserted into an obliterated range,
98
+ * but the newest obliteration of that range was by the inserting client,
99
+ * then the segment is not obliterated because it is aware of the latest obliteration.
100
+ */
101
+ prevObliterateByInserter?: ObliterateInfo;
102
+ /**
103
+ * Whether or not this segment is a special segment denoting the start or
104
+ * end of the tree
105
+ *
106
+ * Endpoint segments are imaginary segments positioned immediately before or
107
+ * after the tree. These segments cannot be referenced by regular operations
108
+ * and exist primarily as a bucket for local references to slide onto during
109
+ * deletion of regular segments.
110
+ */
111
+ readonly endpointType?: "start" | "end";
112
+ };
87
113
 
88
114
  /**
89
- * Contains removal information associated to an {@link ISegment}.
90
- * @legacy
91
- * @alpha
115
+ * Segment leafs are segments that have both IMergeNodeInfo and IInsertionInfo. This means they
116
+ * are inserted at a position, and bound via their parent MergeBlock to the merge tree. MergeBlocks'
117
+ * children are either a segment leaf, or another merge block for interior nodes of the tree. When working
118
+ * within the tree it is generally unnecessary to use type coercions methods common to the infos, and segment
119
+ * leafs, as the children of MergeBlocks are already well typed. However, when segments come from outside the
120
+ * merge tree, like via client's public methods, it becomes necessary to use the type coercions methods
121
+ * to ensure the passed in segment objects are correctly bound to the merge tree.
92
122
  */
93
- export interface IRemovalInfo {
94
- /**
95
- * Local seq at which this segment was removed, if the removal is yet-to-be acked.
96
- */
97
- localRemovedSeq?: number;
98
- /**
99
- * Seq at which this segment was removed.
100
- */
101
- removedSeq: number;
102
- /**
103
- * List of client IDs that have removed this segment.
104
- * The client that actually removed the segment (i.e. whose removal op was sequenced first) is stored as the first
105
- * client in this list. Other clients in the list have all issued concurrent ops to remove the segment.
106
- * @remarks When this list has length \> 1, this is referred to as the "overlapping remove" case.
107
- */
108
- removedClientIds: number[];
109
- }
123
+ export type ISegmentLeaf = SegmentWithInfo<IMergeNodeInfo & IInsertionInfo>;
124
+ /**
125
+ * A type-guard which determines if the segment has segment leaf, and
126
+ * returns true if it does, along with applying strong typing.
127
+ * @param nodeLike - The segment-like object to check.
128
+ * @returns True if the segment is a segment leaf, otherwise false.
129
+ */
130
+ export const isSegmentLeaf = (segmentLike: unknown): segmentLike is ISegmentLeaf =>
131
+ isInserted(segmentLike) && isMergeNode(segmentLike);
110
132
 
111
133
  /**
112
- * Returns the removal information for a segment.
134
+ * Converts a segment-like object to a segment leaf object if possible.
113
135
  *
114
- * @internal
136
+ * @param segmentLike - The segment-like object to convert.
137
+ * @returns The segment leaf if the conversion is possible, otherwise undefined.
115
138
  */
116
- export function toRemovalInfo(
117
- maybe: Partial<IRemovalInfo> | undefined,
118
- ): IRemovalInfo | undefined {
119
- if (maybe?.removedClientIds !== undefined && maybe?.removedSeq !== undefined) {
120
- return maybe as IRemovalInfo;
121
- }
122
- assert(
123
- maybe?.removedClientIds === undefined && maybe?.removedSeq === undefined,
124
- 0x2bf /* "both removedClientIds and removedSeq should be set or not set" */,
125
- );
126
- }
127
-
139
+ export const toSegmentLeaf = (segmentLike: unknown): ISegmentLeaf | undefined =>
140
+ isSegmentLeaf(segmentLike) ? segmentLike : undefined;
128
141
  /**
129
- * Tracks information about when and where this segment was moved to.
142
+ * Asserts that the segment is a segment leaf. Usage of this function should not produce a user facing error.
130
143
  *
131
- * Note that merge-tree does not currently support moving and only supports
132
- * obliterate. The fields below include "move" in their names to avoid renaming
133
- * in the future, when moves _are_ supported.
134
- * @legacy
135
- * @alpha
144
+ * @param segmentLike - The segment-like object to check.
145
+ * @throws Will throw an error if the segment is not a segment leaf.
136
146
  */
137
- export interface IMoveInfo {
138
- /**
139
- * Local seq at which this segment was moved if the move is yet-to-be
140
- * acked.
141
- */
142
- localMovedSeq?: number;
143
-
144
- /**
145
- * The first seq at which this segment was moved.
146
- */
147
- movedSeq: number;
148
-
149
- /**
150
- * All seqs at which this segment was moved. In the case of overlapping,
151
- * concurrent moves this array will contain multiple seqs.
152
- *
153
- * The seq at `movedSeqs[i]` corresponds to the client id at `movedClientIds[i]`.
154
- *
155
- * The first element corresponds to the seq of the first move
156
- */
157
- movedSeqs: number[];
158
-
159
- /**
160
- * A reference to the inserted destination segment corresponding to this
161
- * segment's move.
162
- *
163
- * If undefined, the move was an obliterate.
164
- *
165
- * Currently this field is unused, as we only support obliterate operations
166
- */
167
- moveDst?: ReferencePosition;
168
-
169
- /**
170
- * List of client IDs that have moved this segment.
171
- *
172
- * The client that actually moved the segment (i.e. whose move op was sequenced
173
- * first) is stored as the first client in this list. Other clients in the
174
- * list have all issued concurrent ops to move the segment.
175
- */
176
- movedClientIds: number[];
177
-
178
- /**
179
- * If this segment was inserted into a concurrently moved range and
180
- * the move op was sequenced before the insertion op. In this case,
181
- * the segment is visible only to the inserting client
182
- *
183
- * `wasMovedOnInsert` only applies for acked obliterates. That is, if
184
- * a segment inserted by a remote client is moved on insertion by a local
185
- * and unacked obliterate, we do not consider it as having been moved
186
- * on insert
187
- *
188
- * If a segment is moved on insertion, its length is only ever visible to
189
- * the client that inserted the segment. This is relevant in partial length
190
- * calculations
191
- */
192
- wasMovedOnInsert: boolean;
193
- }
147
+ export const assertSegmentLeaf: (segmentLike: unknown) => asserts segmentLike is ISegmentLeaf =
148
+ (segmentLike) => assert(isSegmentLeaf(segmentLike), 0xaab /* must be segment leaf */);
149
+ /**
150
+ * This type is used for building MergeBlocks from segments and other MergeBlocks. We need this
151
+ * type as segments may not yet be bound to the tree, so lack merge node info which is required for
152
+ * segment leafs.
153
+ */
154
+ export type IMergeNodeBuilder = MergeBlock | SegmentWithInfo<IInsertionInfo>;
194
155
 
195
- export function toMoveInfo(maybe: Partial<IMoveInfo> | undefined): IMoveInfo | undefined {
196
- if (maybe?.movedClientIds !== undefined && maybe?.movedSeq !== undefined) {
197
- return maybe as IMoveInfo;
198
- }
199
- assert(
200
- maybe?.movedClientIds === undefined &&
201
- maybe?.movedSeq === undefined &&
202
- maybe?.movedSeqs === undefined &&
203
- maybe?.wasMovedOnInsert === undefined,
204
- 0x86d /* movedClientIds, movedSeq, wasMovedOnInsert, and movedSeqs should all be either set or not set */,
205
- );
206
- }
156
+ /**
157
+ * This type is used by MergeBlocks to define their children, which are either segments or other
158
+ * MergeBlocks.
159
+ */
160
+ export type IMergeNode = MergeBlock | ISegmentLeaf;
207
161
 
208
162
  /**
209
163
  * A segment representing a portion of the merge tree.
@@ -211,7 +165,7 @@ export function toMoveInfo(maybe: Partial<IMoveInfo> | undefined): IMoveInfo | u
211
165
  * @legacy
212
166
  * @alpha
213
167
  */
214
- export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo>, Partial<IMoveInfo> {
168
+ export interface ISegment {
215
169
  readonly type: string;
216
170
 
217
171
  readonly trackingCollection: TrackingGroupCollection;
@@ -223,6 +177,7 @@ export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo>, Parti
223
177
  * after the tree. These segments cannot be referenced by regular operations
224
178
  * and exist primarily as a bucket for local references to slide onto during
225
179
  * deletion of regular segments.
180
+ * @deprecated - This property will be removed in 2.20 with no replacement.
226
181
  */
227
182
  readonly endpointType?: "start" | "end";
228
183
 
@@ -254,31 +209,25 @@ export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo>, Parti
254
209
  *
255
210
  * @privateRemarks
256
211
  * See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq.
212
+ * @deprecated - This property will be removed in 2.20 with no replacement.
257
213
  */
258
214
  localSeq?: number;
259
- /**
260
- * Local seq at which this segment was removed. If this is defined, `removedSeq` will initially be set to
261
- * UnassignedSequenceNumber. However, if another client concurrently removes the same segment, `removedSeq`
262
- * will be updated to the seq at which that client removed this segment.
263
- *
264
- * Like {@link ISegment.localSeq}, this field is cleared once the local removal of the segment is acked.
265
- *
266
- * @privateRemarks
267
- * See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq.
268
- */
269
- localRemovedSeq?: number;
270
215
  /**
271
216
  * Seq at which this segment was inserted.
272
217
  * If undefined, it is assumed the segment was inserted prior to the collab window's minimum sequence number.
218
+ * @deprecated - This property will be removed in 2.20 with no replacement.
273
219
  */
274
220
  seq?: number;
275
221
  /**
276
222
  * Short clientId for the client that inserted this segment.
223
+ * @deprecated - This property will be removed in 2.20 with no replacement.
277
224
  */
278
225
  clientId: number;
279
226
  /**
280
227
  * Local references added to this segment.
228
+ * @deprecated - This property will be removed in 2.20 with no replacement.
281
229
  */
230
+ // eslint-disable-next-line import/no-deprecated
282
231
  localRefs?: LocalReferenceCollection;
283
232
  /**
284
233
  * Properties that have been added to this segment via annotation.
@@ -292,14 +241,81 @@ export interface ISegment extends IMergeNodeCommon, Partial<IRemovalInfo>, Parti
292
241
  // Changing this to something other than any would break consumers.
293
242
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
294
243
  toJSONObject(): any;
244
+ isLeaf(): this is ISegment;
245
+
246
+ /**
247
+ * {@inheritDoc @fluidframework/merge-tree#IMergeNodeCommon.index}
248
+ * @deprecated - This property will be removed in 2.20 with no replacement.
249
+ */
250
+ index: number;
251
+ /**
252
+ * {@inheritDoc @fluidframework/merge-tree#IMergeNodeCommon.ordinal}
253
+ * @deprecated - This property will be removed in 2.20 with no replacement.
254
+ */
255
+ ordinal: string;
256
+
257
+ /**
258
+ * Local seq at which this segment was removed. If this is defined, `removedSeq` will initially be set to
259
+ * UnassignedSequenceNumber. However, if another client concurrently removes the same segment, `removedSeq`
260
+ * will be updated to the seq at which that client removed this segment.
261
+ *
262
+ * Like {@link ISegment.localSeq}, this field is cleared once the local removal of the segment is acked.
263
+ *
264
+ * @privateRemarks
265
+ * See {@link CollaborationWindow.localSeq} for more information on the semantics of localSeq.
266
+ * @deprecated - This property will be removed in 2.20 with no replacement.
267
+ */
268
+ localRemovedSeq?: number;
269
+ /**
270
+ * {@inheritDoc @fluidframework/merge-tree#IRemovalInfo.removedSeq}
271
+ * @deprecated - This property will be removed in 2.20 with no replacement.
272
+ */
273
+ removedSeq?: number;
274
+ /**
275
+ * {@inheritDoc @fluidframework/merge-tree#IRemovalInfo.removedClientIds}
276
+ * @deprecated - This property will be removed in 2.20 with no replacement.
277
+ */
278
+ removedClientIds?: number[];
279
+ /**
280
+ * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.localMovedSeq}
281
+ * @deprecated - This property will be removed in 2.20 with no replacement.
282
+ */
283
+ localMovedSeq?: number;
284
+ /**
285
+ * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.movedSeq}
286
+ * @deprecated - This property will be removed in 2.20 with no replacement.
287
+ */
288
+ movedSeq?: number;
289
+
290
+ /**
291
+ * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.movedSeqs}
292
+ * @deprecated - This property will be removed in 2.20 with no replacement.
293
+ */
294
+ movedSeqs?: number[];
295
+ /**
296
+ * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.moveDst}
297
+ * @deprecated - This property will be removed in 2.20 with no replacement.
298
+ */
299
+ moveDst?: ReferencePosition;
300
+ /**
301
+ * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.movedClientIds}
302
+ * @deprecated - This property will be removed in 2.20 with no replacement.
303
+ */
304
+ movedClientIds?: number[];
305
+ /**
306
+ * {@inheritDoc @fluidframework/merge-tree#IMoveInfo.wasMovedOnInsert}
307
+ * @deprecated - This property will be removed in 2.20 with no replacement.
308
+ */
309
+ wasMovedOnInsert?: boolean;
295
310
  }
296
311
 
297
312
  /**
298
- * @internal
313
+ * Determine if a segment has been removed.
314
+ * @legacy
315
+ * @alpha
299
316
  */
300
- export interface IMarkerModifiedAction {
301
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
302
- (marker: Marker): void;
317
+ export function segmentIsRemoved(segment: ISegment): boolean {
318
+ return isRemoved(segment);
303
319
  }
304
320
 
305
321
  /**
@@ -318,68 +334,17 @@ export interface ISegmentAction<TClientData> {
318
334
  accum: TClientData,
319
335
  ): boolean;
320
336
  }
321
- /**
322
- * @internal
323
- */
324
337
  export interface ISegmentChanges {
325
- next?: ISegment;
326
- replaceCurrent?: ISegment;
327
- }
328
- /**
329
- * @internal
330
- */
331
- export interface BlockAction<TClientData> {
332
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
333
- (
334
- block: MergeBlock,
335
- pos: number,
336
- refSeq: number,
337
- clientId: number,
338
- start: number | undefined,
339
- end: number | undefined,
340
- accum: TClientData,
341
- ): boolean;
342
- }
343
-
344
- /**
345
- * @internal
346
- */
347
- export interface NodeAction<TClientData> {
348
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
349
- (
350
- node: IMergeNode,
351
- pos: number,
352
- refSeq: number,
353
- clientId: number,
354
- start: number | undefined,
355
- end: number | undefined,
356
- clientData: TClientData,
357
- ): boolean;
338
+ next?: SegmentWithInfo<IInsertionInfo>;
339
+ replaceCurrent?: SegmentWithInfo<IInsertionInfo>;
358
340
  }
359
341
 
360
- /**
361
- * @internal
362
- */
363
342
  export interface InsertContext {
364
- candidateSegment?: ISegment;
365
- leaf: (segment: ISegment | undefined, pos: number, ic: InsertContext) => ISegmentChanges;
343
+ candidateSegment?: SegmentWithInfo<IInsertionInfo>;
344
+ leaf: (segment: ISegmentLeaf | undefined, pos: number, ic: InsertContext) => ISegmentChanges;
366
345
  continuePredicate?: (continueFromBlock: MergeBlock) => boolean;
367
346
  }
368
347
 
369
- /**
370
- * @internal
371
- */
372
- export interface SegmentActions<TClientData> {
373
- leaf?: ISegmentAction<TClientData>;
374
- shift?: NodeAction<TClientData>;
375
- contains?: NodeAction<TClientData>;
376
- pre?: BlockAction<TClientData>;
377
- post?: BlockAction<TClientData>;
378
- }
379
-
380
- /**
381
- * @internal
382
- */
383
348
  export interface ObliterateInfo {
384
349
  start: LocalReferencePosition;
385
350
  end: LocalReferencePosition;
@@ -390,11 +355,8 @@ export interface ObliterateInfo {
390
355
  segmentGroup: SegmentGroup | undefined;
391
356
  }
392
357
 
393
- /**
394
- * @internal
395
- */
396
- export interface SegmentGroup<S extends ISegmentInternal = ISegmentInternal> {
397
- segments: S[];
358
+ export interface SegmentGroup {
359
+ segments: ISegmentLeaf[];
398
360
  previousProps?: PropertySet[];
399
361
  localSeq?: number;
400
362
  refSeq: number;
@@ -406,13 +368,9 @@ export interface SegmentGroup<S extends ISegmentInternal = ISegmentInternal> {
406
368
  * the MergeTree always inserts first, then checks for overflow and splits if the child count equals
407
369
  * `MaxNodesInBlock`. (i.e., `MaxNodesInBlock` contains 1 extra slot for temporary storage to
408
370
  * facilitate splits.)
409
- * @internal
410
371
  */
411
372
  export const MaxNodesInBlock = 8;
412
- /**
413
- * @internal
414
- */
415
- export class MergeBlock implements IMergeNodeCommon {
373
+ export class MergeBlock implements Partial<IMergeNodeInfo> {
416
374
  public children: IMergeNode[];
417
375
  public needsScour?: boolean;
418
376
  public parent?: MergeBlock;
@@ -433,7 +391,7 @@ export class MergeBlock implements IMergeNodeCommon {
433
391
  */
434
392
  public leftmostTiles: Readonly<MapLike<Marker>>;
435
393
 
436
- isLeaf(): this is ISegment {
394
+ isLeaf(): this is ISegmentInternal {
437
395
  return false;
438
396
  }
439
397
 
@@ -470,15 +428,22 @@ export class MergeBlock implements IMergeNodeCommon {
470
428
  index === 0 ? undefined : this.children[index - 1]?.ordinal,
471
429
  );
472
430
  }
473
-
474
- public assignChild(child: IMergeNode, index: number, updateOrdinal = true): void {
475
- child.parent = this;
476
- child.index = index;
477
- if (updateOrdinal) {
478
- this.setOrdinal(child, index);
479
- }
480
- this.children[index] = child;
481
- }
431
+ }
432
+ export function assignChild<C extends IMergeNodeBuilder>(
433
+ parent: MergeBlock,
434
+ child: C,
435
+ index: number,
436
+ updateOrdinal = true,
437
+ ): asserts child is C & IMergeNodeInfo {
438
+ const node = Object.assign<C, IMergeNodeInfo>(child, {
439
+ parent,
440
+ index,
441
+ ordinal: child.ordinal ?? "",
442
+ });
443
+ if (updateOrdinal) {
444
+ parent.setOrdinal(node, index);
445
+ }
446
+ parent.children[index] = node;
482
447
  }
483
448
 
484
449
  export function seqLTE(seq: number, minOrRefSeq: number): boolean {
@@ -490,15 +455,45 @@ export function seqLTE(seq: number, minOrRefSeq: number): boolean {
490
455
  * @alpha
491
456
  */
492
457
  export abstract class BaseSegment implements ISegment {
458
+ /**
459
+ * @deprecated - This property will be removed in 2.20 with no replacement.
460
+ */
493
461
  public clientId: number = LocalClientId;
462
+ /**
463
+ * @deprecated - This property will be removed in 2.20 with no replacement.
464
+ */
494
465
  public seq: number = UniversalSequenceNumber;
466
+ /**
467
+ * @deprecated - This property will be removed in 2.20 with no replacement.
468
+ */
495
469
  public removedSeq?: number;
470
+ /**
471
+ * @deprecated - This property will be removed in 2.20 with no replacement.
472
+ */
496
473
  public removedClientIds?: number[];
474
+ /**
475
+ * @deprecated - This property will be removed in 2.20 with no replacement.
476
+ */
497
477
  public movedSeq?: number;
478
+ /**
479
+ * @deprecated - This property will be removed in 2.20 with no replacement.
480
+ */
498
481
  public movedSeqs?: number[];
482
+ /**
483
+ * @deprecated - This property will be removed in 2.20 with no replacement.
484
+ */
499
485
  public movedClientIds?: number[];
486
+ /**
487
+ * @deprecated - This property will be removed in 2.20 with no replacement.
488
+ */
500
489
  public wasMovedOnInsert?: boolean | undefined;
490
+ /**
491
+ * @deprecated - This property will be removed in 2.20 with no replacement.
492
+ */
501
493
  public index: number = 0;
494
+ /**
495
+ * @deprecated - This property will be removed in 2.20 with no replacement.
496
+ */
502
497
  public ordinal: string = "";
503
498
  public cachedLength: number = 0;
504
499
 
@@ -509,10 +504,23 @@ export abstract class BaseSegment implements ISegment {
509
504
  public attribution?: IAttributionCollection<AttributionKey>;
510
505
 
511
506
  public properties?: PropertySet;
507
+ /**
508
+ * @deprecated - This property will be removed in 2.20 with no replacement.
509
+ */
510
+ // eslint-disable-next-line import/no-deprecated
512
511
  public localRefs?: LocalReferenceCollection;
513
512
  public abstract readonly type: string;
513
+ /**
514
+ * @deprecated - This property will be removed in 2.20 with no replacement.
515
+ */
514
516
  public localSeq?: number;
517
+ /**
518
+ * @deprecated - This property will be removed in 2.20 with no replacement.
519
+ */
515
520
  public localRemovedSeq?: number;
521
+ /**
522
+ * @deprecated - This property will be removed in 2.20 with no replacement.
523
+ */
516
524
  public localMovedSeq?: number;
517
525
 
518
526
  public constructor(properties?: PropertySet) {
@@ -530,18 +538,32 @@ export abstract class BaseSegment implements ISegment {
530
538
  }
531
539
 
532
540
  protected cloneInto(b: ISegment): void {
533
- b.clientId = this.clientId;
541
+ const seg: ISegmentPrivate = b;
542
+ if (isInserted(this)) {
543
+ overwriteInfo<IInsertionInfo>(seg, {
544
+ clientId: this.clientId,
545
+ seq: this.seq,
546
+ });
547
+ }
534
548
  // TODO: deep clone properties
535
- b.properties = clone(this.properties);
536
- b.removedClientIds = this.removedClientIds?.slice();
537
- // TODO: copy removed client overlap and branch removal info
538
- b.removedSeq = this.removedSeq;
539
- b.movedClientIds = this.movedClientIds?.slice();
540
- b.movedSeq = this.movedSeq;
541
- b.movedSeqs = this.movedSeqs;
542
- b.wasMovedOnInsert = this.wasMovedOnInsert;
543
- b.seq = this.seq;
544
- b.attribution = this.attribution?.clone();
549
+ seg.properties = clone(this.properties);
550
+ if (isRemoved(this)) {
551
+ // eslint-disable-next-line import/no-deprecated
552
+ overwriteInfo<IRemovalInfo>(seg, {
553
+ removedSeq: this.removedSeq,
554
+ removedClientIds: [...this.removedClientIds],
555
+ });
556
+ }
557
+ if (isMoved(this)) {
558
+ // eslint-disable-next-line import/no-deprecated
559
+ overwriteInfo<IMoveInfo>(seg, {
560
+ movedSeq: this.movedSeq,
561
+ movedSeqs: [...this.movedSeqs],
562
+ wasMovedOnInsert: this.wasMovedOnInsert,
563
+ movedClientIds: [...this.movedClientIds],
564
+ });
565
+ }
566
+ seg.attribution = this.attribution?.clone();
545
567
  }
546
568
 
547
569
  public canAppend(segment: ISegment): boolean {
@@ -563,35 +585,51 @@ export abstract class BaseSegment implements ISegment {
563
585
  return undefined;
564
586
  }
565
587
 
566
- const leafSegment: ISegmentLeaf | undefined = this.createSplitSegmentAt(pos);
588
+ const leafSegment: ISegmentPrivate | undefined = this.createSplitSegmentAt(pos);
567
589
 
568
590
  if (!leafSegment) {
569
591
  return undefined;
570
592
  }
571
593
 
572
- // eslint-disable-next-line @typescript-eslint/no-this-alias, unicorn/no-this-assignment
573
- const thisAsMergeSegment: ISegmentLeaf = this;
574
- leafSegment.parent = thisAsMergeSegment.parent;
575
-
576
- // Give the leaf a temporary yet valid ordinal.
577
- // when this segment is put in the tree, it will get its real ordinal,
578
- // but this ordinal meets all the necessary invariants for now.
579
- // Ordinals exist purely for lexicographical sort order and use a small set of valid bytes for each string character.
580
- // The extra handling fromCodePoint has for things like surrogate pairs is therefore unnecessary.
581
- // eslint-disable-next-line unicorn/prefer-code-point
582
- leafSegment.ordinal = this.ordinal + String.fromCharCode(0);
583
-
584
- leafSegment.removedClientIds = this.removedClientIds?.slice();
585
- leafSegment.removedSeq = this.removedSeq;
586
- leafSegment.localRemovedSeq = this.localRemovedSeq;
587
- leafSegment.seq = this.seq;
588
- leafSegment.localSeq = this.localSeq;
589
- leafSegment.clientId = this.clientId;
590
- leafSegment.movedClientIds = this.movedClientIds?.slice();
591
- leafSegment.movedSeq = this.movedSeq;
592
- leafSegment.movedSeqs = this.movedSeqs?.slice();
593
- leafSegment.localMovedSeq = this.localMovedSeq;
594
- leafSegment.wasMovedOnInsert = this.wasMovedOnInsert;
594
+ if (isMergeNode(this)) {
595
+ overwriteInfo<IMergeNodeInfo>(leafSegment, {
596
+ index: this.index + 1,
597
+ // Give the leaf a temporary yet valid ordinal.
598
+ // when this segment is put in the tree, it will get its real ordinal,
599
+ // but this ordinal meets all the necessary invariants for now.
600
+ // Ordinals exist purely for lexicographical sort order and use a small set of valid bytes for each string character.
601
+ // The extra handling fromCodePoint has for things like surrogate pairs is therefore unnecessary.
602
+ // eslint-disable-next-line unicorn/prefer-code-point
603
+ ordinal: this.ordinal + String.fromCharCode(0),
604
+ parent: this.parent,
605
+ });
606
+ }
607
+
608
+ if (isInserted(this)) {
609
+ overwriteInfo<IInsertionInfo>(leafSegment, {
610
+ seq: this.seq,
611
+ localSeq: this.localSeq,
612
+ clientId: this.clientId,
613
+ });
614
+ }
615
+ if (isRemoved(this)) {
616
+ // eslint-disable-next-line import/no-deprecated
617
+ overwriteInfo<IRemovalInfo>(leafSegment, {
618
+ removedClientIds: [...this.removedClientIds],
619
+ removedSeq: this.removedSeq,
620
+ localRemovedSeq: this.localRemovedSeq,
621
+ });
622
+ }
623
+ if (isMoved(this)) {
624
+ // eslint-disable-next-line import/no-deprecated
625
+ overwriteInfo<IMoveInfo>(leafSegment, {
626
+ movedClientIds: [...this.movedClientIds],
627
+ movedSeq: this.movedSeq,
628
+ movedSeqs: [...this.movedSeqs],
629
+ localMovedSeq: this.localMovedSeq,
630
+ wasMovedOnInsert: this.wasMovedOnInsert,
631
+ });
632
+ }
595
633
 
596
634
  this.trackingCollection.copyTo(leafSegment);
597
635
  if (this.attribution) {
@@ -606,6 +644,7 @@ export abstract class BaseSegment implements ISegment {
606
644
  public append(other: ISegment): void {
607
645
  // Note: Must call 'appendLocalRefs' before modifying this segment's length as
608
646
  // 'this.cachedLength' is used to adjust the offsets of the local refs.
647
+ // eslint-disable-next-line import/no-deprecated
609
648
  LocalReferenceCollection.append(this, other);
610
649
  if (this.attribution) {
611
650
  assert(
@@ -774,7 +813,7 @@ export class CollaborationWindow {
774
813
  * { localSeq: 1, seq: UnassignedSequenceNumber, text: "C" },
775
814
  * ]
776
815
  * ```
777
- * (note that {@link ISegment.localSeq} tracks the localSeq at which a segment was inserted)
816
+ * (note that localSeq tracks the localSeq at which a segment was inserted)
778
817
  *
779
818
  * Suppose the client then disconnects and reconnects before any of its insertions are acked. The reconnect flow will necessitate
780
819
  * that the client regenerates and resubmits ops based on its current segment state as well as the original op that was sent.
@@ -834,47 +873,3 @@ export const compareNumbers = (a: number, b: number): number => a - b;
834
873
  * Compares two strings.
835
874
  */
836
875
  export const compareStrings = (a: string, b: string): number => a.localeCompare(b);
837
-
838
- /**
839
- * Get a human-readable string for a given {@link Marker}.
840
- *
841
- * @remarks This function is intended for debugging only. The exact format of
842
- * this string should not be relied upon between versions.
843
- * @internal
844
- */
845
- export function debugMarkerToString(marker: Marker): string {
846
- let bbuf = "";
847
- if (refTypeIncludesFlag(marker, ReferenceType.Tile)) {
848
- bbuf += "Tile";
849
- }
850
- let lbuf = "";
851
- const id = marker.getId();
852
- if (id) {
853
- bbuf += ` (${id}) `;
854
- }
855
- const tileLabels = refGetTileLabels(marker);
856
- if (tileLabels) {
857
- lbuf += "tile -- ";
858
- for (let i = 0, len = tileLabels.length; i < len; i++) {
859
- const tileLabel = tileLabels[i];
860
- if (i > 0) {
861
- lbuf += "; ";
862
- }
863
- lbuf += tileLabel;
864
- }
865
- }
866
-
867
- let pbuf = "";
868
- if (marker.properties) {
869
- pbuf += JSON.stringify(marker.properties, (key, value) => {
870
- // Avoid circular reference when stringifying makers containing handles.
871
- // (Substitute a debug string instead.)
872
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
873
- const handle = !!value && value.IFluidHandle;
874
-
875
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
876
- return handle ? `#Handle(${handle.routeContext.path}/${handle.path})` : value;
877
- });
878
- }
879
- return `M ${bbuf}: ${lbuf} ${pbuf}`;
880
- }