@fluidframework/merge-tree 1.2.1 → 2.0.0-internal.1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/DEV.md +2 -2
  2. package/README.md +1 -1
  3. package/REFERENCEPOSITIONS.md +2 -2
  4. package/dist/MergeTreeTextHelper.d.ts +23 -0
  5. package/dist/MergeTreeTextHelper.d.ts.map +1 -0
  6. package/dist/MergeTreeTextHelper.js +136 -0
  7. package/dist/MergeTreeTextHelper.js.map +1 -0
  8. package/dist/base.d.ts +2 -26
  9. package/dist/base.d.ts.map +1 -1
  10. package/dist/base.js.map +1 -1
  11. package/dist/client.d.ts +21 -12
  12. package/dist/client.d.ts.map +1 -1
  13. package/dist/client.js +87 -27
  14. package/dist/client.js.map +1 -1
  15. package/dist/collections/heap.d.ts +28 -0
  16. package/dist/collections/heap.d.ts.map +1 -0
  17. package/dist/collections/heap.js +65 -0
  18. package/dist/collections/heap.js.map +1 -0
  19. package/dist/collections/index.d.ts +11 -0
  20. package/dist/collections/index.d.ts.map +1 -0
  21. package/dist/collections/index.js +23 -0
  22. package/dist/collections/index.js.map +1 -0
  23. package/dist/collections/intervalTree.d.ts +60 -0
  24. package/dist/collections/intervalTree.d.ts.map +1 -0
  25. package/dist/collections/intervalTree.js +99 -0
  26. package/dist/collections/intervalTree.js.map +1 -0
  27. package/dist/collections/list.d.ts +39 -0
  28. package/dist/collections/list.d.ts.map +1 -0
  29. package/dist/collections/list.js +155 -0
  30. package/dist/collections/list.js.map +1 -0
  31. package/dist/collections/rbTree.d.ts +154 -0
  32. package/dist/collections/rbTree.d.ts.map +1 -0
  33. package/dist/{collections.js → collections/rbTree.js} +10 -448
  34. package/dist/collections/rbTree.js.map +1 -0
  35. package/dist/collections/stack.d.ts +16 -0
  36. package/dist/collections/stack.d.ts.map +1 -0
  37. package/dist/collections/stack.js +30 -0
  38. package/dist/collections/stack.js.map +1 -0
  39. package/dist/collections/tst.d.ts +55 -0
  40. package/dist/collections/tst.d.ts.map +1 -0
  41. package/dist/collections/tst.js +171 -0
  42. package/dist/collections/tst.js.map +1 -0
  43. package/dist/index.d.ts +3 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -2
  46. package/dist/index.js.map +1 -1
  47. package/dist/localReference.d.ts +48 -99
  48. package/dist/localReference.d.ts.map +1 -1
  49. package/dist/localReference.js +132 -169
  50. package/dist/localReference.js.map +1 -1
  51. package/dist/mergeTree.d.ts +38 -299
  52. package/dist/mergeTree.d.ts.map +1 -1
  53. package/dist/mergeTree.js +214 -598
  54. package/dist/mergeTree.js.map +1 -1
  55. package/dist/mergeTreeDeltaCallback.d.ts +1 -1
  56. package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
  57. package/dist/mergeTreeDeltaCallback.js.map +1 -1
  58. package/dist/mergeTreeNodes.d.ts +269 -0
  59. package/dist/mergeTreeNodes.d.ts.map +1 -0
  60. package/dist/mergeTreeNodes.js +383 -0
  61. package/dist/mergeTreeNodes.js.map +1 -0
  62. package/dist/mergeTreeTracking.d.ts +1 -1
  63. package/dist/mergeTreeTracking.d.ts.map +1 -1
  64. package/dist/mergeTreeTracking.js.map +1 -1
  65. package/dist/opBuilder.d.ts +1 -1
  66. package/dist/opBuilder.d.ts.map +1 -1
  67. package/dist/opBuilder.js.map +1 -1
  68. package/dist/partialLengths.d.ts +130 -15
  69. package/dist/partialLengths.d.ts.map +1 -1
  70. package/dist/partialLengths.js +230 -138
  71. package/dist/partialLengths.js.map +1 -1
  72. package/dist/properties.d.ts.map +1 -1
  73. package/dist/properties.js.map +1 -1
  74. package/dist/referencePositions.d.ts +6 -26
  75. package/dist/referencePositions.d.ts.map +1 -1
  76. package/dist/referencePositions.js.map +1 -1
  77. package/dist/segmentGroupCollection.d.ts +2 -1
  78. package/dist/segmentGroupCollection.d.ts.map +1 -1
  79. package/dist/segmentGroupCollection.js +3 -0
  80. package/dist/segmentGroupCollection.js.map +1 -1
  81. package/dist/segmentPropertiesManager.d.ts +10 -1
  82. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  83. package/dist/segmentPropertiesManager.js +41 -6
  84. package/dist/segmentPropertiesManager.js.map +1 -1
  85. package/dist/snapshotLoader.d.ts.map +1 -1
  86. package/dist/snapshotLoader.js.map +1 -1
  87. package/dist/snapshotV1.d.ts +1 -1
  88. package/dist/snapshotV1.d.ts.map +1 -1
  89. package/dist/snapshotV1.js.map +1 -1
  90. package/dist/snapshotlegacy.d.ts +5 -1
  91. package/dist/snapshotlegacy.d.ts.map +1 -1
  92. package/dist/snapshotlegacy.js +4 -0
  93. package/dist/snapshotlegacy.js.map +1 -1
  94. package/dist/sortedSegmentSet.d.ts +1 -1
  95. package/dist/sortedSegmentSet.d.ts.map +1 -1
  96. package/dist/sortedSegmentSet.js.map +1 -1
  97. package/dist/textSegment.d.ts +7 -7
  98. package/dist/textSegment.d.ts.map +1 -1
  99. package/dist/textSegment.js +3 -125
  100. package/dist/textSegment.js.map +1 -1
  101. package/lib/MergeTreeTextHelper.d.ts +23 -0
  102. package/lib/MergeTreeTextHelper.d.ts.map +1 -0
  103. package/lib/MergeTreeTextHelper.js +132 -0
  104. package/lib/MergeTreeTextHelper.js.map +1 -0
  105. package/lib/base.d.ts +2 -26
  106. package/lib/base.d.ts.map +1 -1
  107. package/lib/base.js.map +1 -1
  108. package/lib/client.d.ts +21 -12
  109. package/lib/client.d.ts.map +1 -1
  110. package/lib/client.js +85 -25
  111. package/lib/client.js.map +1 -1
  112. package/lib/collections/heap.d.ts +28 -0
  113. package/lib/collections/heap.d.ts.map +1 -0
  114. package/lib/collections/heap.js +61 -0
  115. package/lib/collections/heap.js.map +1 -0
  116. package/lib/collections/index.d.ts +11 -0
  117. package/lib/collections/index.d.ts.map +1 -0
  118. package/lib/collections/index.js +11 -0
  119. package/lib/collections/index.js.map +1 -0
  120. package/lib/collections/intervalTree.d.ts +60 -0
  121. package/lib/collections/intervalTree.d.ts.map +1 -0
  122. package/lib/collections/intervalTree.js +94 -0
  123. package/lib/collections/intervalTree.js.map +1 -0
  124. package/lib/collections/list.d.ts +39 -0
  125. package/lib/collections/list.d.ts.map +1 -0
  126. package/lib/collections/list.js +149 -0
  127. package/lib/collections/list.js.map +1 -0
  128. package/lib/collections/rbTree.d.ts +154 -0
  129. package/lib/collections/rbTree.d.ts.map +1 -0
  130. package/lib/{collections.js → collections/rbTree.js} +9 -439
  131. package/lib/collections/rbTree.js.map +1 -0
  132. package/lib/collections/stack.d.ts +16 -0
  133. package/lib/collections/stack.d.ts.map +1 -0
  134. package/lib/collections/stack.js +26 -0
  135. package/lib/collections/stack.js.map +1 -0
  136. package/lib/collections/tst.d.ts +55 -0
  137. package/lib/collections/tst.d.ts.map +1 -0
  138. package/lib/collections/tst.js +167 -0
  139. package/lib/collections/tst.js.map +1 -0
  140. package/lib/index.d.ts +3 -1
  141. package/lib/index.d.ts.map +1 -1
  142. package/lib/index.js +3 -1
  143. package/lib/index.js.map +1 -1
  144. package/lib/localReference.d.ts +48 -99
  145. package/lib/localReference.d.ts.map +1 -1
  146. package/lib/localReference.js +132 -170
  147. package/lib/localReference.js.map +1 -1
  148. package/lib/mergeTree.d.ts +38 -299
  149. package/lib/mergeTree.d.ts.map +1 -1
  150. package/lib/mergeTree.js +190 -563
  151. package/lib/mergeTree.js.map +1 -1
  152. package/lib/mergeTreeDeltaCallback.d.ts +1 -1
  153. package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
  154. package/lib/mergeTreeDeltaCallback.js.map +1 -1
  155. package/lib/mergeTreeNodes.d.ts +269 -0
  156. package/lib/mergeTreeNodes.d.ts.map +1 -0
  157. package/lib/mergeTreeNodes.js +369 -0
  158. package/lib/mergeTreeNodes.js.map +1 -0
  159. package/lib/mergeTreeTracking.d.ts +1 -1
  160. package/lib/mergeTreeTracking.d.ts.map +1 -1
  161. package/lib/mergeTreeTracking.js.map +1 -1
  162. package/lib/opBuilder.d.ts +1 -1
  163. package/lib/opBuilder.d.ts.map +1 -1
  164. package/lib/opBuilder.js.map +1 -1
  165. package/lib/partialLengths.d.ts +130 -15
  166. package/lib/partialLengths.d.ts.map +1 -1
  167. package/lib/partialLengths.js +227 -135
  168. package/lib/partialLengths.js.map +1 -1
  169. package/lib/properties.d.ts.map +1 -1
  170. package/lib/properties.js.map +1 -1
  171. package/lib/referencePositions.d.ts +6 -26
  172. package/lib/referencePositions.d.ts.map +1 -1
  173. package/lib/referencePositions.js.map +1 -1
  174. package/lib/segmentGroupCollection.d.ts +2 -1
  175. package/lib/segmentGroupCollection.d.ts.map +1 -1
  176. package/lib/segmentGroupCollection.js +3 -0
  177. package/lib/segmentGroupCollection.js.map +1 -1
  178. package/lib/segmentPropertiesManager.d.ts +10 -1
  179. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  180. package/lib/segmentPropertiesManager.js +41 -6
  181. package/lib/segmentPropertiesManager.js.map +1 -1
  182. package/lib/snapshotLoader.d.ts.map +1 -1
  183. package/lib/snapshotLoader.js.map +1 -1
  184. package/lib/snapshotV1.d.ts +1 -1
  185. package/lib/snapshotV1.d.ts.map +1 -1
  186. package/lib/snapshotV1.js.map +1 -1
  187. package/lib/snapshotlegacy.d.ts +5 -1
  188. package/lib/snapshotlegacy.d.ts.map +1 -1
  189. package/lib/snapshotlegacy.js +4 -0
  190. package/lib/snapshotlegacy.js.map +1 -1
  191. package/lib/sortedSegmentSet.d.ts +1 -1
  192. package/lib/sortedSegmentSet.d.ts.map +1 -1
  193. package/lib/sortedSegmentSet.js.map +1 -1
  194. package/lib/textSegment.d.ts +7 -7
  195. package/lib/textSegment.d.ts.map +1 -1
  196. package/lib/textSegment.js +1 -122
  197. package/lib/textSegment.js.map +1 -1
  198. package/package.json +93 -17
  199. package/src/MergeTreeTextHelper.ts +172 -0
  200. package/src/base.ts +2 -35
  201. package/src/client.ts +114 -30
  202. package/src/collections/heap.ts +75 -0
  203. package/src/collections/index.ts +11 -0
  204. package/src/collections/intervalTree.ts +140 -0
  205. package/src/collections/list.ts +165 -0
  206. package/src/{collections.ts → collections/rbTree.ts} +79 -538
  207. package/src/collections/stack.ts +27 -0
  208. package/src/collections/tst.ts +212 -0
  209. package/src/index.ts +8 -2
  210. package/src/localReference.ts +152 -203
  211. package/src/mergeTree.ts +265 -868
  212. package/src/mergeTreeDeltaCallback.ts +1 -1
  213. package/src/mergeTreeNodes.ts +676 -0
  214. package/src/mergeTreeTracking.ts +1 -1
  215. package/src/opBuilder.ts +1 -1
  216. package/src/partialLengths.ts +295 -150
  217. package/src/properties.ts +1 -0
  218. package/src/referencePositions.ts +7 -27
  219. package/src/segmentGroupCollection.ts +5 -1
  220. package/src/segmentPropertiesManager.ts +45 -6
  221. package/src/snapshotLoader.ts +2 -1
  222. package/src/snapshotV1.ts +2 -2
  223. package/src/snapshotlegacy.ts +6 -2
  224. package/src/sortedSegmentSet.ts +1 -1
  225. package/src/textSegment.ts +10 -157
  226. package/dist/collections.d.ts +0 -197
  227. package/dist/collections.d.ts.map +0 -1
  228. package/dist/collections.js.map +0 -1
  229. package/lib/collections.d.ts +0 -197
  230. package/lib/collections.d.ts.map +0 -1
  231. package/lib/collections.js.map +0 -1
package/dist/mergeTree.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.MergeTree = exports.clientSeqComparer = exports.internedSpaces = exports.compareStrings = exports.compareNumbers = exports.CollaborationWindow = exports.IncrementalMapState = exports.IncrementalExecOp = exports.Marker = exports.reservedMarkerSimpleTypeKey = exports.reservedMarkerIdKey = exports.BaseSegment = exports.MergeBlock = exports.MaxNodesInBlock = exports.ordinalToArray = exports.MergeNode = exports.toRemovalInfo = void 0;
7
+ exports.MergeTree = exports.clientSeqComparer = void 0;
8
8
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
9
9
  /* eslint-disable @typescript-eslint/consistent-type-assertions */
10
10
  /* eslint-disable @typescript-eslint/prefer-optional-chain, no-bitwise */
@@ -13,39 +13,104 @@ const container_utils_1 = require("@fluidframework/container-utils");
13
13
  const collections_1 = require("./collections");
14
14
  const constants_1 = require("./constants");
15
15
  const localReference_1 = require("./localReference");
16
+ const mergeTreeNodes_1 = require("./mergeTreeNodes");
16
17
  const mergeTreeDeltaCallback_1 = require("./mergeTreeDeltaCallback");
17
- const mergeTreeTracking_1 = require("./mergeTreeTracking");
18
18
  const ops_1 = require("./ops");
19
19
  const partialLengths_1 = require("./partialLengths");
20
20
  const properties_1 = require("./properties");
21
21
  const referencePositions_1 = require("./referencePositions");
22
- const segmentGroupCollection_1 = require("./segmentGroupCollection");
23
22
  const segmentPropertiesManager_1 = require("./segmentPropertiesManager");
24
- function toRemovalInfo(maybe) {
25
- if ((maybe === null || maybe === void 0 ? void 0 : maybe.removedClientIds) !== undefined && (maybe === null || maybe === void 0 ? void 0 : maybe.removedSeq) !== undefined) {
26
- return maybe;
27
- }
28
- (0, common_utils_1.assert)((maybe === null || maybe === void 0 ? void 0 : maybe.removedClientIds) === undefined && (maybe === null || maybe === void 0 ? void 0 : maybe.removedSeq) === undefined, 0x2bf /* "both removedClientIds and removedSeq should be set or not set" */);
29
- }
30
- exports.toRemovalInfo = toRemovalInfo;
23
+ const minListenerComparer = {
24
+ min: { minRequired: Number.MIN_VALUE, onMinGE: () => { (0, common_utils_1.assert)(false, 0x048 /* "onMinGE()" */); } },
25
+ compare: (a, b) => a.minRequired - b.minRequired,
26
+ };
31
27
  function isRemoved(segment) {
32
- return toRemovalInfo(segment) !== undefined;
28
+ return (0, mergeTreeNodes_1.toRemovalInfo)(segment) !== undefined;
33
29
  }
34
30
  function isRemovedAndAcked(segment) {
35
- const removalInfo = toRemovalInfo(segment);
31
+ const removalInfo = (0, mergeTreeNodes_1.toRemovalInfo)(segment);
36
32
  return removalInfo !== undefined && removalInfo.removedSeq !== constants_1.UnassignedSequenceNumber;
37
33
  }
38
- class MergeNode {
39
- constructor() {
40
- this.index = 0;
41
- this.ordinal = "";
42
- this.cachedLength = 0;
34
+ function nodeTotalLength(mergeTree, node) {
35
+ if (!node.isLeaf()) {
36
+ return node.cachedLength;
43
37
  }
44
- isLeaf() {
45
- return false;
38
+ return mergeTree.localNetLength(node);
39
+ }
40
+ const LRUSegmentComparer = {
41
+ min: { maxSeq: -2 },
42
+ compare: (a, b) => a.maxSeq - b.maxSeq,
43
+ };
44
+ function applyLeafRangeMarker(marker, searchInfo) {
45
+ for (const rangeLabel of searchInfo.rangeLabels) {
46
+ if ((0, referencePositions_1.refHasRangeLabel)(marker, rangeLabel)) {
47
+ let currentStack = searchInfo.stacks[rangeLabel];
48
+ if (currentStack === undefined) {
49
+ currentStack = new collections_1.Stack();
50
+ searchInfo.stacks[rangeLabel] = currentStack;
51
+ }
52
+ applyRangeReference(currentStack, marker);
53
+ }
54
+ }
55
+ }
56
+ function recordRangeLeaf(segment, segpos, refSeq, clientId, start, end, searchInfo) {
57
+ if (mergeTreeNodes_1.Marker.is(segment)) {
58
+ if (segment.refType &
59
+ (ops_1.ReferenceType.NestBegin | ops_1.ReferenceType.NestEnd)) {
60
+ applyLeafRangeMarker(segment, searchInfo);
61
+ }
62
+ }
63
+ return false;
64
+ }
65
+ function rangeShift(node, segpos, refSeq, clientId, offset, end, searchInfo) {
66
+ var _a;
67
+ if (node.isLeaf()) {
68
+ const seg = node;
69
+ if ((((_a = searchInfo.mergeTree.localNetLength(seg)) !== null && _a !== void 0 ? _a : 0) > 0) && mergeTreeNodes_1.Marker.is(seg)) {
70
+ if (seg.refType &
71
+ (ops_1.ReferenceType.NestBegin | ops_1.ReferenceType.NestEnd)) {
72
+ applyLeafRangeMarker(seg, searchInfo);
73
+ }
74
+ }
75
+ }
76
+ else {
77
+ const block = node;
78
+ applyStackDelta(searchInfo.stacks, block.rangeStacks);
79
+ }
80
+ return true;
81
+ }
82
+ function recordTileStart(segment, segpos, refSeq, clientId, start, end, searchInfo) {
83
+ if (mergeTreeNodes_1.Marker.is(segment)) {
84
+ if ((0, referencePositions_1.refHasTileLabel)(segment, searchInfo.tileLabel)) {
85
+ searchInfo.tile = segment;
86
+ }
87
+ }
88
+ return false;
89
+ }
90
+ function tileShift(node, segpos, refSeq, clientId, offset, end, searchInfo) {
91
+ if (node.isLeaf()) {
92
+ const seg = node;
93
+ if ((searchInfo.mergeTree.localNetLength(seg) > 0) && mergeTreeNodes_1.Marker.is(seg)) {
94
+ if ((0, referencePositions_1.refHasTileLabel)(seg, searchInfo.tileLabel)) {
95
+ searchInfo.tile = seg;
96
+ }
97
+ }
98
+ }
99
+ else {
100
+ const block = node;
101
+ let marker;
102
+ if (searchInfo.posPrecedesTile) {
103
+ marker = block.rightmostTiles[searchInfo.tileLabel];
104
+ }
105
+ else {
106
+ marker = block.leftmostTiles[searchInfo.tileLabel];
107
+ }
108
+ if (marker !== undefined) {
109
+ searchInfo.tile = marker;
110
+ }
46
111
  }
112
+ return true;
47
113
  }
48
- exports.MergeNode = MergeNode;
49
114
  function addTile(tile, tiles) {
50
115
  const tileLabels = (0, referencePositions_1.refGetTileLabels)(tile);
51
116
  if (tileLabels) {
@@ -111,7 +176,7 @@ function addNodeReferences(mergeTree, node, rightmostTiles, leftmostTiles, range
111
176
  if (node.isLeaf()) {
112
177
  const segment = node;
113
178
  if (((_a = mergeTree.localNetLength(segment)) !== null && _a !== void 0 ? _a : 0) > 0) {
114
- if (Marker.is(segment)) {
179
+ if (mergeTreeNodes_1.Marker.is(segment)) {
115
180
  const markerId = segment.getId();
116
181
  // Also in insertMarker but need for reload segs case
117
182
  // can add option for this only from reload segs
@@ -154,72 +219,31 @@ function addNodeReferences(mergeTree, node, rightmostTiles, leftmostTiles, range
154
219
  const block = node;
155
220
  applyStackDelta(rangeStacks, block.rangeStacks);
156
221
  (0, properties_1.extend)(rightmostTiles, block.rightmostTiles);
157
- (0, properties_1.extendIfUndefined)(leftmostTiles, block.leftmostTiles);
222
+ extendIfUndefined(leftmostTiles, block.leftmostTiles);
158
223
  }
159
224
  }
160
- function ordinalToArray(ord) {
161
- const a = [];
162
- if (ord) {
163
- for (let i = 0, len = ord.length; i < len; i++) {
164
- a.push(ord.charCodeAt(i));
165
- }
166
- }
167
- return a;
168
- }
169
- exports.ordinalToArray = ordinalToArray;
170
- // Note that the actual branching factor of the MergeTree is `MaxNodesInBlock - 1`. This is because
171
- // the MergeTree always inserts first, then checks for overflow and splits if the child count equals
172
- // `MaxNodesInBlock`. (i.e., `MaxNodesInBlock` contains 1 extra slot for temporary storage to
173
- // facilitate splits.)
174
- exports.MaxNodesInBlock = 8;
175
- class MergeBlock extends MergeNode {
176
- constructor(childCount) {
177
- super();
178
- this.childCount = childCount;
179
- this.children = new Array(exports.MaxNodesInBlock);
180
- }
181
- hierBlock() {
182
- return undefined;
183
- }
184
- setOrdinal(child, index) {
185
- let childCount = this.childCount;
186
- if (childCount === 8) {
187
- childCount = 7;
188
- }
189
- (0, common_utils_1.assert)((childCount >= 1) && (childCount <= 7), 0x040 /* "Child count is not within [1,7] range!" */);
190
- let localOrdinal;
191
- const ordinalWidth = 1 << (exports.MaxNodesInBlock - (childCount + 1));
192
- if (index === 0) {
193
- localOrdinal = ordinalWidth - 1;
194
- }
195
- else {
196
- const prevOrd = this.children[index - 1].ordinal;
197
- const prevOrdCode = prevOrd.charCodeAt(prevOrd.length - 1);
198
- localOrdinal = prevOrdCode + ordinalWidth;
199
- }
200
- child.ordinal = this.ordinal + String.fromCharCode(localOrdinal);
201
- (0, common_utils_1.assert)(child.ordinal.length === (this.ordinal.length + 1), 0x041 /* "Unexpected child ordinal length!" */);
202
- if (index > 0) {
203
- (0, common_utils_1.assert)(child.ordinal > this.children[index - 1].ordinal, 0x042);
204
- }
205
- }
206
- assignChild(child, index, updateOrdinal = true) {
207
- child.parent = this;
208
- child.index = index;
209
- if (updateOrdinal) {
210
- this.setOrdinal(child, index);
225
+ function extendIfUndefined(base, extension) {
226
+ if (extension !== undefined) {
227
+ // eslint-disable-next-line no-restricted-syntax
228
+ for (const key in extension) {
229
+ if (base[key] === undefined) {
230
+ base[key] = extension[key];
231
+ }
211
232
  }
212
- this.children[index] = child;
213
233
  }
234
+ return base;
214
235
  }
215
- exports.MergeBlock = MergeBlock;
216
- class HierMergeBlock extends MergeBlock {
236
+ class HierMergeBlock extends mergeTreeNodes_1.MergeBlock {
217
237
  constructor(childCount) {
218
238
  super(childCount);
219
239
  this.rightmostTiles = (0, properties_1.createMap)();
220
240
  this.leftmostTiles = (0, properties_1.createMap)();
221
241
  this.rangeStacks = (0, properties_1.createMap)();
222
242
  }
243
+ /**
244
+ * @deprecated for internal use only. public export will be removed.
245
+ * @internal
246
+ */
223
247
  addNodeReferences(mergeTree, node) {
224
248
  addNodeReferences(mergeTree, node, this.rightmostTiles, this.leftmostTiles, this.rangeStacks);
225
249
  }
@@ -231,7 +255,7 @@ class HierMergeBlock extends MergeBlock {
231
255
  // eslint-disable-next-line guard-for-in, no-restricted-syntax
232
256
  for (const key in this.rangeStacks) {
233
257
  const stack = this.rangeStacks[key];
234
- strbuf += internedSpaces(indentCount);
258
+ strbuf += (0, mergeTreeNodes_1.internedSpaces)(indentCount);
235
259
  strbuf += `${key}: `;
236
260
  for (const item of stack.items) {
237
261
  strbuf += `${item.toString()} `;
@@ -241,424 +265,24 @@ class HierMergeBlock extends MergeBlock {
241
265
  return strbuf;
242
266
  }
243
267
  }
244
- function nodeTotalLength(mergeTree, node) {
245
- if (!node.isLeaf()) {
246
- return node.cachedLength;
247
- }
248
- return mergeTree.localNetLength(node);
249
- }
250
- class BaseSegment extends MergeNode {
251
- constructor() {
252
- super(...arguments);
253
- this.clientId = constants_1.LocalClientId;
254
- this.seq = constants_1.UniversalSequenceNumber;
255
- this.segmentGroups = new segmentGroupCollection_1.SegmentGroupCollection(this);
256
- this.trackingCollection = new mergeTreeTracking_1.TrackingGroupCollection(this);
257
- }
258
- addProperties(newProps, op, seq, collabWindow) {
259
- if (!this.propertyManager) {
260
- this.propertyManager = new segmentPropertiesManager_1.PropertiesManager();
261
- }
262
- if (!this.properties) {
263
- this.properties = (0, properties_1.createMap)();
264
- }
265
- return this.propertyManager.addProperties(this.properties, newProps, op, seq, collabWindow && collabWindow.collaborating);
266
- }
267
- hasProperty(key) {
268
- return !!this.properties && (this.properties[key] !== undefined);
269
- }
270
- isLeaf() {
271
- return true;
272
- }
273
- cloneInto(b) {
274
- var _a;
275
- b.clientId = this.clientId;
276
- // TODO: deep clone properties
277
- b.properties = (0, properties_1.clone)(this.properties);
278
- b.removedClientIds = (_a = this.removedClientIds) === null || _a === void 0 ? void 0 : _a.slice();
279
- // TODO: copy removed client overlap and branch removal info
280
- b.removedSeq = this.removedSeq;
281
- b.seq = this.seq;
282
- }
283
- canAppend(segment) {
284
- return false;
285
- }
286
- addSerializedProps(jseg) {
287
- if (this.properties) {
288
- jseg.props = this.properties;
289
- }
290
- }
291
- ack(segmentGroup, opArgs, mergeTree) {
292
- const currentSegmentGroup = this.segmentGroups.dequeue();
293
- (0, common_utils_1.assert)(currentSegmentGroup === segmentGroup, 0x043 /* "On ack, unexpected segmentGroup!" */);
294
- switch (opArgs.op.type) {
295
- case ops_1.MergeTreeDeltaType.ANNOTATE:
296
- (0, common_utils_1.assert)(!!this.propertyManager, 0x044 /* "On annotate ack, missing segment property manager!" */);
297
- this.propertyManager.ackPendingProperties(opArgs.op);
298
- return true;
299
- case ops_1.MergeTreeDeltaType.INSERT:
300
- (0, common_utils_1.assert)(this.seq === constants_1.UnassignedSequenceNumber, 0x045 /* "On insert, seq number already assigned!" */);
301
- this.seq = opArgs.sequencedMessage.sequenceNumber;
302
- this.localSeq = undefined;
303
- return true;
304
- case ops_1.MergeTreeDeltaType.REMOVE:
305
- const removalInfo = toRemovalInfo(this);
306
- (0, common_utils_1.assert)(removalInfo !== undefined, 0x046 /* "On remove ack, missing removal info!" */);
307
- this.localRemovedSeq = undefined;
308
- if (removalInfo.removedSeq === constants_1.UnassignedSequenceNumber) {
309
- removalInfo.removedSeq = opArgs.sequencedMessage.sequenceNumber;
310
- return true;
311
- }
312
- return false;
313
- default:
314
- throw new Error(`${opArgs.op.type} is in unrecognized operation type`);
315
- }
316
- }
317
- splitAt(pos) {
318
- var _a;
319
- if (pos > 0) {
320
- const leafSegment = this.createSplitSegmentAt(pos);
321
- if (leafSegment) {
322
- this.copyPropertiesTo(leafSegment);
323
- leafSegment.parent = this.parent;
324
- // Give the leaf a temporary yet valid ordinal.
325
- // when this segment is put in the tree, it will get it's real ordinal,
326
- // but this ordinal meets all the necessary invariants for now.
327
- leafSegment.ordinal = this.ordinal + String.fromCharCode(0);
328
- leafSegment.removedClientIds = (_a = this.removedClientIds) === null || _a === void 0 ? void 0 : _a.slice();
329
- leafSegment.removedSeq = this.removedSeq;
330
- leafSegment.localRemovedSeq = this.localRemovedSeq;
331
- leafSegment.seq = this.seq;
332
- leafSegment.localSeq = this.localSeq;
333
- leafSegment.clientId = this.clientId;
334
- this.segmentGroups.copyTo(leafSegment);
335
- this.trackingCollection.copyTo(leafSegment);
336
- if (this.localRefs) {
337
- this.localRefs.split(pos, leafSegment);
338
- }
339
- }
340
- return leafSegment;
341
- }
342
- }
343
- copyPropertiesTo(other) {
344
- if (this.propertyManager) {
345
- if (this.properties) {
346
- other.propertyManager = new segmentPropertiesManager_1.PropertiesManager();
347
- other.properties = this.propertyManager.copyTo(this.properties, other.properties, other.propertyManager);
348
- }
349
- }
350
- }
351
- }
352
- exports.BaseSegment = BaseSegment;
353
- exports.reservedMarkerIdKey = "markerId";
354
- exports.reservedMarkerSimpleTypeKey = "markerSimpleType";
355
- class Marker extends BaseSegment {
356
- constructor(refType) {
357
- super();
358
- this.refType = refType;
359
- this.type = Marker.type;
360
- this.cachedLength = 1;
361
- }
362
- static is(segment) {
363
- return segment.type === Marker.type;
364
- }
365
- static make(refType, props) {
366
- const marker = new Marker(refType);
367
- if (props) {
368
- marker.addProperties(props);
369
- }
370
- return marker;
371
- }
372
- toJSONObject() {
373
- const obj = { marker: { refType: this.refType } };
374
- super.addSerializedProps(obj);
375
- return obj;
376
- }
377
- static fromJSONObject(spec) {
378
- if (spec && typeof spec === "object" && "marker" in spec) {
379
- return Marker.make(spec.marker.refType, spec.props);
380
- }
381
- return undefined;
382
- }
383
- clone() {
384
- const b = Marker.make(this.refType, this.properties);
385
- this.cloneInto(b);
386
- return b;
387
- }
388
- getSegment() {
389
- return this;
390
- }
391
- getOffset() {
392
- return 0;
393
- }
394
- hasSimpleType(simpleTypeName) {
395
- return !!this.properties &&
396
- this.properties[exports.reservedMarkerSimpleTypeKey] === simpleTypeName;
397
- }
398
- getProperties() {
399
- return this.properties;
400
- }
401
- getId() {
402
- if (this.properties && this.properties[exports.reservedMarkerIdKey]) {
403
- return this.properties[exports.reservedMarkerIdKey];
404
- }
405
- }
406
- /**
407
- * @deprecated - use refHasTileLabels
408
- */
409
- hasTileLabels() {
410
- return (0, referencePositions_1.refHasTileLabels)(this);
411
- }
412
- /**
413
- * @deprecated - use refHasRangeLabels
414
- */
415
- hasRangeLabels() {
416
- return (0, referencePositions_1.refHasRangeLabels)(this);
417
- }
418
- /**
419
- * @deprecated - use refHasTileLabel
420
- */
421
- hasTileLabel(label) {
422
- return (0, referencePositions_1.refHasTileLabel)(this, label);
423
- }
424
- /**
425
- * @deprecated - use refHasRangeLabel
426
- */
427
- hasRangeLabel(label) {
428
- return (0, referencePositions_1.refHasRangeLabel)(this, label);
429
- }
430
- /**
431
- * @deprecated - use refGetTileLabels
432
- */
433
- getTileLabels() {
434
- return (0, referencePositions_1.refGetTileLabels)(this);
435
- }
436
- /**
437
- * @deprecated - use refGetRangeLabels
438
- */
439
- getRangeLabels() {
440
- return (0, referencePositions_1.refGetRangeLabels)(this);
441
- }
442
- toString() {
443
- let bbuf = "";
444
- if ((0, referencePositions_1.refTypeIncludesFlag)(this, ops_1.ReferenceType.Tile)) {
445
- bbuf += "Tile";
446
- }
447
- if ((0, referencePositions_1.refTypeIncludesFlag)(this, ops_1.ReferenceType.NestBegin)) {
448
- if (bbuf.length > 0) {
449
- bbuf += "; ";
450
- }
451
- bbuf += "RangeBegin";
452
- }
453
- if ((0, referencePositions_1.refTypeIncludesFlag)(this, ops_1.ReferenceType.NestEnd)) {
454
- if (bbuf.length > 0) {
455
- bbuf += "; ";
456
- }
457
- bbuf += "RangeEnd";
458
- }
459
- let lbuf = "";
460
- const id = this.getId();
461
- if (id) {
462
- bbuf += ` (${id}) `;
463
- }
464
- const tileLabels = (0, referencePositions_1.refGetTileLabels)(this);
465
- if (tileLabels) {
466
- lbuf += "tile -- ";
467
- for (let i = 0, len = tileLabels.length; i < len; i++) {
468
- const tileLabel = tileLabels[i];
469
- if (i > 0) {
470
- lbuf += "; ";
471
- }
472
- lbuf += tileLabel;
473
- }
474
- }
475
- const rangeLabels = (0, referencePositions_1.refGetRangeLabels)(this);
476
- if (rangeLabels) {
477
- let rangeKind = "begin";
478
- if ((0, referencePositions_1.refTypeIncludesFlag)(this, ops_1.ReferenceType.NestEnd)) {
479
- rangeKind = "end";
480
- }
481
- if (tileLabels) {
482
- lbuf += " ";
483
- }
484
- lbuf += `range ${rangeKind} -- `;
485
- const labels = rangeLabels;
486
- for (let i = 0, len = labels.length; i < len; i++) {
487
- const rangeLabel = labels[i];
488
- if (i > 0) {
489
- lbuf += "; ";
490
- }
491
- lbuf += rangeLabel;
492
- }
493
- }
494
- let pbuf = "";
495
- if (this.properties) {
496
- pbuf += JSON.stringify(this.properties, (key, value) => {
497
- // Avoid circular reference when stringifying makers containing handles.
498
- // (Substitute a debug string instead.)
499
- const handle = !!value && value.IFluidHandle;
500
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
501
- return handle
502
- ? `#Handle(${handle.routeContext.path}/${handle.path})`
503
- : value;
504
- });
505
- }
506
- return `M ${bbuf}: ${lbuf} ${pbuf}`;
507
- }
508
- createSplitSegmentAt(pos) {
509
- return undefined;
510
- }
511
- canAppend(segment) {
512
- return false;
513
- }
514
- append() { throw new Error("Can not append to marker"); }
515
- }
516
- exports.Marker = Marker;
517
- Marker.type = "Marker";
518
- var IncrementalExecOp;
519
- (function (IncrementalExecOp) {
520
- IncrementalExecOp[IncrementalExecOp["Go"] = 0] = "Go";
521
- IncrementalExecOp[IncrementalExecOp["Stop"] = 1] = "Stop";
522
- IncrementalExecOp[IncrementalExecOp["Yield"] = 2] = "Yield";
523
- })(IncrementalExecOp = exports.IncrementalExecOp || (exports.IncrementalExecOp = {}));
524
- class IncrementalMapState {
525
- constructor(block, actions, pos, refSeq, clientId, context, start, end, childIndex = 0) {
526
- this.block = block;
527
- this.actions = actions;
528
- this.pos = pos;
529
- this.refSeq = refSeq;
530
- this.clientId = clientId;
531
- this.context = context;
532
- this.start = start;
533
- this.end = end;
534
- this.childIndex = childIndex;
535
- this.op = IncrementalExecOp.Go;
536
- }
537
- }
538
- exports.IncrementalMapState = IncrementalMapState;
539
- class CollaborationWindow {
540
- constructor() {
541
- this.clientId = constants_1.LocalClientId;
542
- this.collaborating = false;
543
- // Lowest-numbered segment in window; no client can reference a state before this one
544
- this.minSeq = 0;
545
- // Highest-numbered segment in window and current
546
- // reference segment for this client
547
- this.currentSeq = 0;
548
- this.localSeq = 0;
549
- }
550
- loadFrom(a) {
551
- this.clientId = a.clientId;
552
- this.collaborating = a.collaborating;
553
- this.minSeq = a.minSeq;
554
- this.currentSeq = a.currentSeq;
555
- }
556
- }
557
- exports.CollaborationWindow = CollaborationWindow;
558
- const compareNumbers = (a, b) => a - b;
559
- exports.compareNumbers = compareNumbers;
560
- const compareStrings = (a, b) => a.localeCompare(b);
561
- exports.compareStrings = compareStrings;
562
- const indentStrings = ["", " ", " "];
563
- function internedSpaces(n) {
564
- if (indentStrings[n] === undefined) {
565
- indentStrings[n] = "";
566
- for (let i = 0; i < n; i++) {
567
- indentStrings[n] += " ";
568
- }
569
- }
570
- return indentStrings[n];
571
- }
572
- exports.internedSpaces = internedSpaces;
268
+ /**
269
+ * @deprecated for internal use only. public export will be removed.
270
+ * @internal
271
+ */
573
272
  exports.clientSeqComparer = {
574
273
  min: { refSeq: -1, clientId: "" },
575
274
  compare: (a, b) => a.refSeq - b.refSeq,
576
275
  };
577
- const LRUSegmentComparer = {
578
- min: { maxSeq: -2 },
579
- compare: (a, b) => a.maxSeq - b.maxSeq,
580
- };
581
- function applyLeafRangeMarker(marker, searchInfo) {
582
- for (const rangeLabel of searchInfo.rangeLabels) {
583
- if ((0, referencePositions_1.refHasRangeLabel)(marker, rangeLabel)) {
584
- let currentStack = searchInfo.stacks[rangeLabel];
585
- if (currentStack === undefined) {
586
- currentStack = new collections_1.Stack();
587
- searchInfo.stacks[rangeLabel] = currentStack;
588
- }
589
- applyRangeReference(currentStack, marker);
590
- }
591
- }
592
- }
593
- function recordRangeLeaf(segment, segpos, refSeq, clientId, start, end, searchInfo) {
594
- if (Marker.is(segment)) {
595
- if (segment.refType &
596
- (ops_1.ReferenceType.NestBegin | ops_1.ReferenceType.NestEnd)) {
597
- applyLeafRangeMarker(segment, searchInfo);
598
- }
599
- }
600
- return false;
601
- }
602
- function rangeShift(node, segpos, refSeq, clientId, offset, end, searchInfo) {
603
- var _a;
604
- if (node.isLeaf()) {
605
- const seg = node;
606
- if ((((_a = searchInfo.mergeTree.localNetLength(seg)) !== null && _a !== void 0 ? _a : 0) > 0) && Marker.is(seg)) {
607
- if (seg.refType &
608
- (ops_1.ReferenceType.NestBegin | ops_1.ReferenceType.NestEnd)) {
609
- applyLeafRangeMarker(seg, searchInfo);
610
- }
611
- }
612
- }
613
- else {
614
- const block = node;
615
- applyStackDelta(searchInfo.stacks, block.rangeStacks);
616
- }
617
- return true;
618
- }
619
- function recordTileStart(segment, segpos, refSeq, clientId, start, end, searchInfo) {
620
- if (Marker.is(segment)) {
621
- if ((0, referencePositions_1.refHasTileLabel)(segment, searchInfo.tileLabel)) {
622
- searchInfo.tile = segment;
623
- }
624
- }
625
- return false;
626
- }
627
- function tileShift(node, segpos, refSeq, clientId, offset, end, searchInfo) {
628
- if (node.isLeaf()) {
629
- const seg = node;
630
- if ((searchInfo.mergeTree.localNetLength(seg) > 0) && Marker.is(seg)) {
631
- if ((0, referencePositions_1.refHasTileLabel)(seg, searchInfo.tileLabel)) {
632
- searchInfo.tile = seg;
633
- }
634
- }
635
- }
636
- else {
637
- const block = node;
638
- let marker;
639
- if (searchInfo.posPrecedesTile) {
640
- marker = block.rightmostTiles[searchInfo.tileLabel];
641
- }
642
- else {
643
- marker = block.leftmostTiles[searchInfo.tileLabel];
644
- }
645
- if (marker !== undefined) {
646
- searchInfo.tile = marker;
647
- }
648
- }
649
- return true;
650
- }
651
- const minListenerComparer = {
652
- min: { minRequired: Number.MIN_VALUE, onMinGE: () => { (0, common_utils_1.assert)(false, 0x048 /* "onMinGE()" */); } },
653
- compare: (a, b) => a.minRequired - b.minRequired,
654
- };
655
- // Represents a sequence of text segments
276
+ /**
277
+ * @deprecated for internal use only. public export will be removed.
278
+ * @internal
279
+ */
656
280
  class MergeTree {
657
281
  // TODO: make and use interface describing options
658
282
  constructor(options) {
659
283
  this.options = options;
660
284
  this.blockUpdateActions = MergeTree.initBlockUpdateActions;
661
- this.collabWindow = new CollaborationWindow();
285
+ this.collabWindow = new mergeTreeNodes_1.CollaborationWindow();
662
286
  // TODO: add remove on segment remove
663
287
  // for now assume only markers have ids and so point directly at the Segment
664
288
  // if we need to have pointers to non-markers, we can change to point at local refs
@@ -712,7 +336,7 @@ class MergeTree {
712
336
  return b;
713
337
  }
714
338
  localNetLength(segment) {
715
- const removalInfo = toRemovalInfo(segment);
339
+ const removalInfo = (0, mergeTreeNodes_1.toRemovalInfo)(segment);
716
340
  if (removalInfo !== undefined) {
717
341
  return 0;
718
342
  }
@@ -733,7 +357,7 @@ class MergeTree {
733
357
  reloadFromSegments(segments) {
734
358
  // This code assumes that a later call to `startCollaboration()` will initialize partial lengths.
735
359
  (0, common_utils_1.assert)(!this.collabWindow.collaborating, 0x049 /* "Trying to reload from segments while collaborating!" */);
736
- const maxChildren = exports.MaxNodesInBlock - 1;
360
+ const maxChildren = mergeTreeNodes_1.MaxNodesInBlock - 1;
737
361
  // Starting with the leaf segments, recursively builds the B-Tree layer by layer from the bottom up.
738
362
  const buildMergeBlock = (nodes) => {
739
363
  const blockCount = Math.ceil(nodes.length / maxChildren); // Compute # blocks require for this level of B-Tree
@@ -792,7 +416,7 @@ class MergeTree {
792
416
  }
793
417
  }
794
418
  underflow(node) {
795
- return node.childCount < (exports.MaxNodesInBlock / 2);
419
+ return node.childCount < (mergeTreeNodes_1.MaxNodesInBlock / 2);
796
420
  }
797
421
  scourNode(node, holdNodes) {
798
422
  let prevSegment;
@@ -879,14 +503,14 @@ class MergeTree {
879
503
  childBlock.parent = undefined;
880
504
  }
881
505
  const totalNodeCount = holdNodes.length;
882
- const halfCount = exports.MaxNodesInBlock / 2;
883
- let childCount = Math.min(exports.MaxNodesInBlock - 1, Math.floor(totalNodeCount / halfCount));
506
+ const halfCount = mergeTreeNodes_1.MaxNodesInBlock / 2;
507
+ let childCount = Math.min(mergeTreeNodes_1.MaxNodesInBlock - 1, Math.floor(totalNodeCount / halfCount));
884
508
  if (childCount < 1) {
885
509
  childCount = 1;
886
510
  }
887
511
  const baseCount = Math.floor(totalNodeCount / childCount);
888
512
  let extraCount = totalNodeCount % childCount;
889
- const packedBlocks = new Array(exports.MaxNodesInBlock);
513
+ const packedBlocks = new Array(mergeTreeNodes_1.MaxNodesInBlock);
890
514
  let readCount = 0;
891
515
  for (let nodeIndex = 0; nodeIndex < childCount; nodeIndex++) {
892
516
  let nodeCount = baseCount;
@@ -965,7 +589,7 @@ class MergeTree {
965
589
  liveCount: 0,
966
590
  histo: [],
967
591
  };
968
- for (let k = 0; k < exports.MaxNodesInBlock; k++) {
592
+ for (let k = 0; k < mergeTreeNodes_1.MaxNodesInBlock; k++) {
969
593
  stats.histo[k] = 0;
970
594
  }
971
595
  for (let i = 0; i < block.childCount; i++) {
@@ -978,7 +602,7 @@ class MergeTree {
978
602
  stats.leafCount += childStats.leafCount;
979
603
  stats.removedLeafCount += childStats.removedLeafCount;
980
604
  stats.liveCount += childStats.liveCount;
981
- for (let j = 0; j < exports.MaxNodesInBlock; j++) {
605
+ for (let j = 0; j < mergeTreeNodes_1.MaxNodesInBlock; j++) {
982
606
  stats.histo[j] += childStats.histo[j];
983
607
  }
984
608
  }
@@ -1040,12 +664,12 @@ class MergeTree {
1040
664
  }
1041
665
  /**
1042
666
  * @internal must only be used by client
1043
- * @param segoff - The segment and offset to slide from
1044
- * @returns The segment and offset to slide to
667
+ * @param segment - The segment to slide from
668
+ * @returns The segment to
1045
669
  */
1046
- _getSlideToSegment(segoff) {
1047
- if (!segoff.segment || !isRemovedAndAcked(segoff.segment)) {
1048
- return segoff;
670
+ _getSlideToSegment(segment) {
671
+ if (!segment || !isRemovedAndAcked(segment)) {
672
+ return segment;
1049
673
  }
1050
674
  let slideToSegment;
1051
675
  const goFurtherToFindSlideToSegment = (seg) => {
@@ -1056,19 +680,13 @@ class MergeTree {
1056
680
  return true;
1057
681
  };
1058
682
  // Slide to the next farthest valid segment in the tree.
1059
- this.rightExcursion(segoff.segment, goFurtherToFindSlideToSegment);
683
+ this.rightExcursion(segment, goFurtherToFindSlideToSegment);
1060
684
  if (slideToSegment) {
1061
- return { segment: slideToSegment, offset: 0 };
685
+ return slideToSegment;
1062
686
  }
1063
687
  // If no such segment is found, slide to the last valid segment.
1064
- this.leftExcursion(segoff.segment, goFurtherToFindSlideToSegment);
1065
- // Workaround TypeScript issue (https://github.com/microsoft/TypeScript/issues/9998)
1066
- slideToSegment = slideToSegment;
1067
- if (slideToSegment) {
1068
- // If slid nearer then offset should be at the end of the segment
1069
- return { segment: slideToSegment, offset: slideToSegment.cachedLength - 1 };
1070
- }
1071
- return { segment: undefined, offset: 0 };
688
+ this.leftExcursion(segment, goFurtherToFindSlideToSegment);
689
+ return slideToSegment;
1072
690
  }
1073
691
  /**
1074
692
  * This method should only be called when the current client sequence number is
@@ -1080,27 +698,23 @@ class MergeTree {
1080
698
  var _a, _b, _c, _d, _e;
1081
699
  (0, common_utils_1.assert)(isRemovedAndAcked(segment), 0x2f1 /* slideReferences from a segment which has not been removed and acked */);
1082
700
  (0, common_utils_1.assert)(!!segment.localRefs, 0x2f2 /* Ref not in the segment localRefs */);
1083
- const newSegoff = this._getSlideToSegment({ segment, offset: 0 });
1084
- const newSegment = newSegoff.segment;
1085
- if (newSegment && !newSegment.localRefs) {
1086
- newSegment.localRefs = new localReference_1.LocalReferenceCollection(newSegment);
1087
- }
1088
- for (const ref of refsToSlide) {
1089
- (_b = (_a = ref.callbacks) === null || _a === void 0 ? void 0 : _a.beforeSlide) === null || _b === void 0 ? void 0 : _b.call(_a);
1090
- const removedRef = segment.localRefs.removeLocalRef(ref);
1091
- (0, common_utils_1.assert)(ref === removedRef, 0x2f3 /* Ref not in the segment localRefs */);
1092
- if (!newSegment) {
1093
- // No valid segments (all nodes removed or not yet created)
1094
- ref.segment = undefined;
1095
- ref.offset = 0;
701
+ const newSegment = this._getSlideToSegment(segment);
702
+ if (newSegment) {
703
+ const localRefs = (_a = newSegment.localRefs) !== null && _a !== void 0 ? _a : (newSegment.localRefs = new localReference_1.LocalReferenceCollection(newSegment));
704
+ if (newSegment.ordinal < segment.ordinal) {
705
+ localRefs.addAfterTombstones(refsToSlide);
1096
706
  }
1097
707
  else {
1098
- ref.segment = newSegment;
1099
- ref.offset = (_c = newSegoff.offset) !== null && _c !== void 0 ? _c : 0;
1100
- (0, common_utils_1.assert)(!!newSegment.localRefs, 0x2f4 /* localRefs must be allocated */);
1101
- newSegment.localRefs.addLocalRef(ref);
708
+ localRefs.addBeforeTombstones(refsToSlide);
709
+ }
710
+ }
711
+ else {
712
+ for (const ref of refsToSlide) {
713
+ (_c = (_b = ref.callbacks) === null || _b === void 0 ? void 0 : _b.beforeSlide) === null || _c === void 0 ? void 0 : _c.call(_b);
714
+ (0, localReference_1.assertLocalReferences)(ref);
715
+ ref.link(undefined, 0, undefined);
716
+ (_e = (_d = ref.callbacks) === null || _d === void 0 ? void 0 : _d.afterSlide) === null || _e === void 0 ? void 0 : _e.call(_d);
1102
717
  }
1103
- (_e = (_d = ref.callbacks) === null || _d === void 0 ? void 0 : _d.afterSlide) === null || _e === void 0 ? void 0 : _e.call(_d);
1104
718
  }
1105
719
  // TODO is it required to update the path lengths?
1106
720
  if (newSegment) {
@@ -1112,30 +726,24 @@ class MergeTree {
1112
726
  return;
1113
727
  }
1114
728
  const refsToSlide = [];
1115
- const refsToStay = [];
1116
729
  for (const lref of segment.localRefs) {
1117
730
  if ((0, referencePositions_1.refTypeIncludesFlag)(lref, ops_1.ReferenceType.StayOnRemove)) {
1118
- refsToStay.push(lref);
731
+ continue;
1119
732
  }
1120
- else if ((0, referencePositions_1.refTypeIncludesFlag)(lref, ops_1.ReferenceType.SlideOnRemove)) {
1121
- if (pending) {
1122
- refsToStay.push(lref);
1123
- }
1124
- else {
733
+ if ((0, referencePositions_1.refTypeIncludesFlag)(lref, ops_1.ReferenceType.SlideOnRemove)) {
734
+ if (!pending) {
1125
735
  refsToSlide.push(lref);
1126
736
  }
1127
737
  }
738
+ else {
739
+ segment.localRefs.removeLocalRef(lref);
740
+ }
1128
741
  }
1129
742
  // Rethink implementation of keeping and sliding refs once other reference
1130
743
  // changes are complete. This works but is fragile and possibly slow.
1131
744
  if (!pending) {
1132
745
  this.slideReferences(segment, refsToSlide);
1133
746
  }
1134
- segment.localRefs.clear();
1135
- for (const lref of refsToStay) {
1136
- lref.segment = segment;
1137
- segment.localRefs.addLocalRef(lref);
1138
- }
1139
747
  }
1140
748
  blockLength(node, refSeq, clientId) {
1141
749
  if ((this.collabWindow.collaborating) && (clientId !== this.collabWindow.clientId)) {
@@ -1162,7 +770,7 @@ class MergeTree {
1162
770
  }
1163
771
  else {
1164
772
  const segment = node;
1165
- const removalInfo = toRemovalInfo(segment);
773
+ const removalInfo = (0, mergeTreeNodes_1.toRemovalInfo)(segment);
1166
774
  if (removalInfo !== undefined
1167
775
  && removalInfo.removedSeq !== constants_1.UnassignedSequenceNumber
1168
776
  && removalInfo.removedSeq <= refSeq) {
@@ -1228,13 +836,25 @@ class MergeTree {
1228
836
  }
1229
837
  }
1230
838
  referencePositionToLocalPosition(refPos, refSeq = this.collabWindow.currentSeq, clientId = this.collabWindow.clientId) {
839
+ var _a;
1231
840
  const seg = refPos.getSegment();
1232
- if (seg && seg.parent) {
1233
- const offset = !seg.removedSeq ? refPos.getOffset() : 0;
841
+ if ((seg === null || seg === void 0 ? void 0 : seg.parent) === undefined) {
842
+ return referencePositions_1.DetachedReferencePosition;
843
+ }
844
+ if (refPos.isLeaf()) {
845
+ return this.getPosition(refPos, refSeq, clientId);
846
+ }
847
+ if ((0, referencePositions_1.refTypeIncludesFlag)(refPos, ops_1.ReferenceType.Transient)
848
+ || ((_a = seg.localRefs) === null || _a === void 0 ? void 0 : _a.has(refPos))) {
849
+ const offset = isRemoved(seg) ? 0 : refPos.getOffset();
1234
850
  return offset + this.getPosition(seg, refSeq, clientId);
1235
851
  }
1236
- return localReference_1.LocalReference.DetachedPosition;
852
+ return referencePositions_1.DetachedReferencePosition;
1237
853
  }
854
+ /**
855
+ * @deprecated for internal use only. public export will be removed.
856
+ * @internal
857
+ */
1238
858
  getStackContext(startPos, clientId, rangeLabels) {
1239
859
  const searchInfo = {
1240
860
  mergeTree: this,
@@ -1265,7 +885,7 @@ class MergeTree {
1265
885
  }
1266
886
  else {
1267
887
  const localRef = searchInfo.tile;
1268
- pos = localRef.toPosition();
888
+ pos = this.referencePositionToLocalPosition(localRef, constants_1.UniversalSequenceNumber, clientId);
1269
889
  }
1270
890
  return { tile: searchInfo.tile, pos };
1271
891
  }
@@ -1406,13 +1026,23 @@ class MergeTree {
1406
1026
  this.zamboniSegments();
1407
1027
  }
1408
1028
  }
1409
- addToPendingList(segment, segmentGroup, localSeq) {
1029
+ addToPendingList(segment, segmentGroup, localSeq, previousProps) {
1410
1030
  let _segmentGroup = segmentGroup;
1411
1031
  if (_segmentGroup === undefined) {
1412
1032
  // TODO: review the cast
1413
1033
  _segmentGroup = { segments: [], localSeq };
1034
+ if (previousProps) {
1035
+ _segmentGroup.previousProps = [];
1036
+ }
1414
1037
  this.pendingSegments.enqueue(_segmentGroup);
1415
1038
  }
1039
+ if ((!_segmentGroup.previousProps && previousProps) ||
1040
+ (_segmentGroup.previousProps && !previousProps)) {
1041
+ throw new Error("All segments in group should have previousProps or none");
1042
+ }
1043
+ if (previousProps) {
1044
+ _segmentGroup.previousProps.push(previousProps);
1045
+ }
1416
1046
  segment.segmentGroups.enqueue(_segmentGroup);
1417
1047
  return _segmentGroup;
1418
1048
  }
@@ -1483,7 +1113,7 @@ class MergeTree {
1483
1113
  let block = segment.parent;
1484
1114
  let ordinalUpdateNode = block;
1485
1115
  while (block !== undefined) {
1486
- if (block.childCount >= exports.MaxNodesInBlock) {
1116
+ if (block.childCount >= mergeTreeNodes_1.MaxNodesInBlock) {
1487
1117
  const splitNode = this.split(block);
1488
1118
  if (block === this.root) {
1489
1119
  this.updateRoot(splitNode);
@@ -1548,7 +1178,7 @@ class MergeTree {
1548
1178
  insertSegment.seq = constants_1.UniversalSequenceNumber;
1549
1179
  }
1550
1180
  insertSegment.clientId = clientId;
1551
- if (Marker.is(insertSegment)) {
1181
+ if (mergeTreeNodes_1.Marker.is(insertSegment)) {
1552
1182
  const markerId = insertSegment.getId();
1553
1183
  if (markerId) {
1554
1184
  this.mapIdToSegment(markerId, insertSegment);
@@ -1597,7 +1227,7 @@ class MergeTree {
1597
1227
  }
1598
1228
  }
1599
1229
  insertChildNode(block, child, childIndex) {
1600
- (0, common_utils_1.assert)(block.childCount < exports.MaxNodesInBlock, 0x051 /* "Too many children on merge block!" */);
1230
+ (0, common_utils_1.assert)(block.childCount < mergeTreeNodes_1.MaxNodesInBlock, 0x051 /* "Too many children on merge block!" */);
1601
1231
  for (let i = block.childCount; i > childIndex; i--) {
1602
1232
  block.children[i] = block.children[i - 1];
1603
1233
  block.children[i].index = i;
@@ -1656,7 +1286,7 @@ class MergeTree {
1656
1286
  newSegment.seq = seq;
1657
1287
  newSegment.localSeq = localSeq;
1658
1288
  newSegment.clientId = clientId;
1659
- if (Marker.is(newSegment)) {
1289
+ if (mergeTreeNodes_1.Marker.is(newSegment)) {
1660
1290
  const markerId = newSegment.getId();
1661
1291
  if (markerId) {
1662
1292
  this.mapIdToSegment(markerId, newSegment);
@@ -1853,7 +1483,7 @@ class MergeTree {
1853
1483
  block.assignChild(newNode, childIndex, false);
1854
1484
  block.childCount++;
1855
1485
  block.setOrdinal(newNode, childIndex);
1856
- if (block.childCount < exports.MaxNodesInBlock) {
1486
+ if (block.childCount < mergeTreeNodes_1.MaxNodesInBlock) {
1857
1487
  if (fromSplit) {
1858
1488
  this.nodeUpdateOrdinals(fromSplit);
1859
1489
  }
@@ -1875,7 +1505,7 @@ class MergeTree {
1875
1505
  }
1876
1506
  }
1877
1507
  split(node) {
1878
- const halfCount = exports.MaxNodesInBlock / 2;
1508
+ const halfCount = mergeTreeNodes_1.MaxNodesInBlock / 2;
1879
1509
  const newNode = this.makeBlock(halfCount);
1880
1510
  node.childCount = halfCount;
1881
1511
  // Update ordinals to reflect lowered child count
@@ -1907,19 +1537,20 @@ class MergeTree {
1907
1537
  * @param clientId - The id of the client making the annotate
1908
1538
  * @param seq - The sequence number of the annotate operation
1909
1539
  * @param opArgs - The op args for the annotate op. this is passed to the merge tree callback if there is one
1540
+ * @param rollback - Whether this is for a local rollback and what kind
1910
1541
  */
1911
- annotateRange(start, end, props, combiningOp, refSeq, clientId, seq, opArgs) {
1542
+ annotateRange(start, end, props, combiningOp, refSeq, clientId, seq, opArgs, rollback = segmentPropertiesManager_1.PropertiesRollback.None) {
1912
1543
  this.ensureIntervalBoundary(start, refSeq, clientId);
1913
1544
  this.ensureIntervalBoundary(end, refSeq, clientId);
1914
1545
  const deltaSegments = [];
1915
1546
  const localSeq = seq === constants_1.UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
1916
1547
  let segmentGroup;
1917
1548
  const annotateSegment = (segment) => {
1918
- const propertyDeltas = segment.addProperties(props, combiningOp, seq, this.collabWindow);
1549
+ const propertyDeltas = segment.addProperties(props, combiningOp, seq, this.collabWindow, rollback);
1919
1550
  deltaSegments.push({ segment, propertyDeltas });
1920
1551
  if (this.collabWindow.collaborating) {
1921
1552
  if (seq === constants_1.UnassignedSequenceNumber) {
1922
- segmentGroup = this.addToPendingList(segment, segmentGroup, localSeq);
1553
+ segmentGroup = this.addToPendingList(segment, segmentGroup, localSeq, propertyDeltas ? propertyDeltas : {});
1923
1554
  }
1924
1555
  else {
1925
1556
  if (MergeTree.options.zamboniSegments) {
@@ -1949,10 +1580,11 @@ class MergeTree {
1949
1580
  this.ensureIntervalBoundary(end, refSeq, clientId);
1950
1581
  let segmentGroup;
1951
1582
  const removedSegments = [];
1952
- const segmentsWithRefs = [];
1583
+ const localOverlapWithRefs = [];
1953
1584
  const localSeq = seq === constants_1.UnassignedSequenceNumber ? ++this.collabWindow.localSeq : undefined;
1954
1585
  const markRemoved = (segment, pos, _start, _end) => {
1955
- const existingRemovalInfo = toRemovalInfo(segment);
1586
+ var _a;
1587
+ const existingRemovalInfo = (0, mergeTreeNodes_1.toRemovalInfo)(segment);
1956
1588
  if (existingRemovalInfo !== undefined) {
1957
1589
  _overwrite = true;
1958
1590
  if (existingRemovalInfo.removedSeq === constants_1.UnassignedSequenceNumber) {
@@ -1962,7 +1594,9 @@ class MergeTree {
1962
1594
  // keep first removal at the head.
1963
1595
  existingRemovalInfo.removedClientIds.unshift(clientId);
1964
1596
  existingRemovalInfo.removedSeq = seq;
1965
- segment.localRemovedSeq = undefined;
1597
+ if (((_a = segment.localRefs) === null || _a === void 0 ? void 0 : _a.empty) === false) {
1598
+ localOverlapWithRefs.push(segment);
1599
+ }
1966
1600
  }
1967
1601
  else {
1968
1602
  // Do not replace earlier sequence number for remove
@@ -1975,9 +1609,6 @@ class MergeTree {
1975
1609
  segment.localRemovedSeq = localSeq;
1976
1610
  removedSegments.push({ segment });
1977
1611
  }
1978
- if (segment.localRefs && !segment.localRefs.empty) {
1979
- segmentsWithRefs.push(segment);
1980
- }
1981
1612
  // Save segment so can assign removed sequence number when acked by server
1982
1613
  if (this.collabWindow.collaborating) {
1983
1614
  if (segment.removedSeq === constants_1.UnassignedSequenceNumber && clientId === this.collabWindow.clientId) {
@@ -2001,10 +1632,10 @@ class MergeTree {
2001
1632
  return true;
2002
1633
  };
2003
1634
  this.mapRange({ leaf: markRemoved, post: afterMarkRemoved }, refSeq, clientId, undefined, start, end);
2004
- const pending = this.collabWindow.collaborating && clientId === this.collabWindow.clientId;
2005
- for (const segment of segmentsWithRefs) {
2006
- this.updateSegmentRefsAfterMarkRemoved(segment, pending);
2007
- }
1635
+ // these segments are already viewed as being removed locally and are not event-ed
1636
+ // so can slide non-StayOnRemove refs immediately
1637
+ localOverlapWithRefs.forEach((s) => this.slideReferences(s, Array.from(s.localRefs)
1638
+ .filter((localRef) => !(0, referencePositions_1.refTypeIncludesFlag)(localRef, ops_1.ReferenceType.StayOnRemove))));
2008
1639
  // opArgs == undefined => test code
2009
1640
  if (this.mergeTreeDeltaCallback && removedSegments.length > 0) {
2010
1641
  this.mergeTreeDeltaCallback(opArgs, {
@@ -2012,6 +1643,11 @@ class MergeTree {
2012
1643
  deltaSegments: removedSegments,
2013
1644
  });
2014
1645
  }
1646
+ const pending = this.collabWindow.collaborating && clientId === this.collabWindow.clientId;
1647
+ // these events are newly removed
1648
+ // so we slide after eventing in case the consumer wants to make reference
1649
+ // changes at remove time, like add a ref to track undo redo.
1650
+ removedSegments.forEach((rSeg) => this.updateSegmentRefsAfterMarkRemoved(rSeg.segment, pending));
2015
1651
  if (this.collabWindow.collaborating && (seq !== constants_1.UnassignedSequenceNumber)) {
2016
1652
  if (MergeTree.options.zamboniSegments) {
2017
1653
  this.zamboniSegments();
@@ -2021,7 +1657,7 @@ class MergeTree {
2021
1657
  nodeUpdateLengthNewStructure(node, recur = false) {
2022
1658
  this.blockUpdate(node);
2023
1659
  if (this.collabWindow.collaborating) {
2024
- node.partialLengths = partialLengths_1.PartialSequenceLengths.combine(this, node, this.collabWindow, recur);
1660
+ node.partialLengths = partialLengths_1.PartialSequenceLengths.combine(node, this.collabWindow, recur);
2025
1661
  }
2026
1662
  }
2027
1663
  removeLocalReferencePosition(lref) {
@@ -2035,7 +1671,7 @@ class MergeTree {
2035
1671
  return removedRefs;
2036
1672
  }
2037
1673
  }
2038
- createLocalReferencePosition(segment, offset, refType, properties, client) {
1674
+ createLocalReferencePosition(segment, offset, refType, properties) {
2039
1675
  var _a;
2040
1676
  if (isRemoved(segment)) {
2041
1677
  if (!(0, referencePositions_1.refTypeIncludesFlag)(refType, ops_1.ReferenceType.SlideOnRemove | ops_1.ReferenceType.Transient)) {
@@ -2044,34 +1680,10 @@ class MergeTree {
2044
1680
  }
2045
1681
  const localRefs = (_a = segment.localRefs) !== null && _a !== void 0 ? _a : new localReference_1.LocalReferenceCollection(segment);
2046
1682
  segment.localRefs = localRefs;
2047
- const segRef = localRefs.createLocalRef(offset, refType, properties, client);
1683
+ const segRef = localRefs.createLocalRef(offset, refType, properties);
2048
1684
  this.blockUpdatePathLengths(segment.parent, constants_1.TreeMaintenanceSequenceNumber, constants_1.LocalClientId);
2049
1685
  return segRef;
2050
1686
  }
2051
- /**
2052
- * @deprecated - use removeLocalReferencePosition
2053
- */
2054
- removeLocalReference(segment, lref) {
2055
- if (segment.localRefs) {
2056
- const removedRef = segment.localRefs.removeLocalRef(lref);
2057
- if (removedRef) {
2058
- this.blockUpdatePathLengths(segment.parent, constants_1.TreeMaintenanceSequenceNumber, constants_1.LocalClientId);
2059
- }
2060
- }
2061
- }
2062
- /**
2063
- * @deprecated - use createLocalReference
2064
- */
2065
- addLocalReference(lref) {
2066
- const segment = lref.segment;
2067
- let localRefs = segment.localRefs;
2068
- if (!localRefs) {
2069
- localRefs = new localReference_1.LocalReferenceCollection(segment);
2070
- segment.localRefs = localRefs;
2071
- }
2072
- localRefs.addLocalRef(lref);
2073
- this.blockUpdatePathLengths(segment.parent, constants_1.TreeMaintenanceSequenceNumber, constants_1.LocalClientId);
2074
- }
2075
1687
  blockUpdate(block) {
2076
1688
  var _a;
2077
1689
  let len = 0;
@@ -2085,7 +1697,7 @@ class MergeTree {
2085
1697
  const child = block.children[i];
2086
1698
  len += (_a = nodeTotalLength(this, child)) !== null && _a !== void 0 ? _a : 0;
2087
1699
  if (hierBlock) {
2088
- hierBlock.addNodeReferences(this, child);
1700
+ addNodeReferences(this, child, hierBlock.rightmostTiles, hierBlock.leftmostTiles, hierBlock.rangeStacks);
2089
1701
  }
2090
1702
  if (this.blockUpdateActions) {
2091
1703
  this.blockUpdateActions.child(block, i);
@@ -2113,10 +1725,10 @@ class MergeTree {
2113
1725
  if (node.partialLengths !== undefined
2114
1726
  && MergeTree.options.incrementalUpdate
2115
1727
  && clientId !== constants_1.NonCollabClient) {
2116
- node.partialLengths.update(this, node, seq, clientId, this.collabWindow);
1728
+ node.partialLengths.update(node, seq, clientId, this.collabWindow);
2117
1729
  }
2118
1730
  else {
2119
- node.partialLengths = partialLengths_1.PartialSequenceLengths.combine(this, node, this.collabWindow);
1731
+ node.partialLengths = partialLengths_1.PartialSequenceLengths.combine(node, this.collabWindow);
2120
1732
  }
2121
1733
  }
2122
1734
  }
@@ -2135,12 +1747,16 @@ class MergeTree {
2135
1747
  }
2136
1748
  this.nodeMap(this.root, actions, 0, refSeq, clientId, accum, start, end);
2137
1749
  }
1750
+ /**
1751
+ * @deprecated for internal use only. public export will be removed.
1752
+ * @internal
1753
+ */
2138
1754
  incrementalBlockMap(stateStack) {
2139
1755
  var _a;
2140
1756
  while (!stateStack.empty()) {
2141
1757
  // We already check the stack is not empty
2142
1758
  const state = stateStack.top();
2143
- if (state.op !== IncrementalExecOp.Go) {
1759
+ if (state.op !== mergeTreeNodes_1.IncrementalExecOp.Go) {
2144
1760
  return;
2145
1761
  }
2146
1762
  if (state.childIndex === 0) {
@@ -2154,12 +1770,12 @@ class MergeTree {
2154
1770
  state.actions.pre(state);
2155
1771
  }
2156
1772
  }
2157
- if ((state.op === IncrementalExecOp.Go) && (state.childIndex < state.block.childCount)) {
1773
+ if ((state.op === mergeTreeNodes_1.IncrementalExecOp.Go) && (state.childIndex < state.block.childCount)) {
2158
1774
  const child = state.block.children[state.childIndex];
2159
1775
  const len = (_a = this.nodeLength(child, state.refSeq, state.clientId)) !== null && _a !== void 0 ? _a : 0;
2160
1776
  if ((len > 0) && (state.start < len) && (state.end > 0)) {
2161
1777
  if (!child.isLeaf()) {
2162
- const childState = new IncrementalMapState(child, state.actions, state.pos, state.refSeq, state.clientId, state.context, state.start, state.end, 0);
1778
+ const childState = new mergeTreeNodes_1.IncrementalMapState(child, state.actions, state.pos, state.refSeq, state.clientId, state.context, state.start, state.end, 0);
2163
1779
  stateStack.push(childState);
2164
1780
  }
2165
1781
  else {
@@ -2173,7 +1789,7 @@ class MergeTree {
2173
1789
  }
2174
1790
  else {
2175
1791
  if (state.childIndex === state.block.childCount) {
2176
- if ((state.op === IncrementalExecOp.Go) && state.actions.post) {
1792
+ if ((state.op === mergeTreeNodes_1.IncrementalExecOp.Go) && state.actions.post) {
2177
1793
  state.actions.post(state);
2178
1794
  }
2179
1795
  stateStack.pop();