@fluidframework/merge-tree 2.30.0 → 2.31.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 (308) hide show
  1. package/CHANGELOG.md +403 -399
  2. package/api-report/merge-tree.legacy.alpha.api.md +1 -0
  3. package/dist/MergeTreeTextHelper.d.ts +9 -3
  4. package/dist/MergeTreeTextHelper.d.ts.map +1 -1
  5. package/dist/MergeTreeTextHelper.js +5 -5
  6. package/dist/MergeTreeTextHelper.js.map +1 -1
  7. package/dist/client.d.ts +7 -13
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +136 -110
  10. package/dist/client.js.map +1 -1
  11. package/dist/endOfTreeSegment.d.ts +12 -8
  12. package/dist/endOfTreeSegment.d.ts.map +1 -1
  13. package/dist/endOfTreeSegment.js +2 -4
  14. package/dist/endOfTreeSegment.js.map +1 -1
  15. package/dist/index.d.ts +6 -3
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -3
  18. package/dist/index.js.map +1 -1
  19. package/dist/mergeTree.d.ts +37 -23
  20. package/dist/mergeTree.d.ts.map +1 -1
  21. package/dist/mergeTree.js +400 -483
  22. package/dist/mergeTree.js.map +1 -1
  23. package/dist/mergeTreeDeltaCallback.d.ts +4 -8
  24. package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
  25. package/dist/mergeTreeDeltaCallback.js.map +1 -1
  26. package/dist/mergeTreeNodes.d.ts +32 -10
  27. package/dist/mergeTreeNodes.d.ts.map +1 -1
  28. package/dist/mergeTreeNodes.js +43 -28
  29. package/dist/mergeTreeNodes.js.map +1 -1
  30. package/dist/partialLengths.d.ts +2 -2
  31. package/dist/partialLengths.d.ts.map +1 -1
  32. package/dist/partialLengths.js +181 -109
  33. package/dist/partialLengths.js.map +1 -1
  34. package/dist/perspective.d.ts +8 -27
  35. package/dist/perspective.d.ts.map +1 -1
  36. package/dist/perspective.js +7 -67
  37. package/dist/perspective.js.map +1 -1
  38. package/dist/revertibles.d.ts.map +1 -1
  39. package/dist/revertibles.js +2 -2
  40. package/dist/revertibles.js.map +1 -1
  41. package/dist/segmentInfos.d.ts +20 -106
  42. package/dist/segmentInfos.d.ts.map +1 -1
  43. package/dist/segmentInfos.js +28 -42
  44. package/dist/segmentInfos.js.map +1 -1
  45. package/dist/segmentPropertiesManager.d.ts +1 -14
  46. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  47. package/dist/segmentPropertiesManager.js +3 -17
  48. package/dist/segmentPropertiesManager.js.map +1 -1
  49. package/dist/snapshotLoader.d.ts.map +1 -1
  50. package/dist/snapshotLoader.js +62 -19
  51. package/dist/snapshotLoader.js.map +1 -1
  52. package/dist/snapshotV1.d.ts.map +1 -1
  53. package/dist/snapshotV1.js +55 -24
  54. package/dist/snapshotV1.js.map +1 -1
  55. package/dist/snapshotlegacy.d.ts.map +1 -1
  56. package/dist/snapshotlegacy.js +6 -9
  57. package/dist/snapshotlegacy.js.map +1 -1
  58. package/dist/stamps.d.ts +1 -1
  59. package/dist/stamps.js +1 -1
  60. package/dist/stamps.js.map +1 -1
  61. package/dist/test/Insertion.perf.spec.js +6 -51
  62. package/dist/test/Insertion.perf.spec.js.map +1 -1
  63. package/dist/test/PartialLengths.perf.spec.js +18 -25
  64. package/dist/test/PartialLengths.perf.spec.js.map +1 -1
  65. package/dist/test/Removal.perf.spec.js +13 -41
  66. package/dist/test/Removal.perf.spec.js.map +1 -1
  67. package/dist/test/beastTest.spec.d.ts.map +1 -1
  68. package/dist/test/beastTest.spec.js +41 -66
  69. package/dist/test/beastTest.spec.js.map +1 -1
  70. package/dist/test/client.annotateMarker.spec.js +1 -11
  71. package/dist/test/client.annotateMarker.spec.js.map +1 -1
  72. package/dist/test/client.applyMsg.spec.js +14 -14
  73. package/dist/test/client.applyMsg.spec.js.map +1 -1
  74. package/dist/test/client.getPosition.spec.js +1 -1
  75. package/dist/test/client.getPosition.spec.js.map +1 -1
  76. package/dist/test/client.localReference.spec.js +1 -1
  77. package/dist/test/client.localReference.spec.js.map +1 -1
  78. package/dist/test/client.rollback.spec.js +49 -58
  79. package/dist/test/client.rollback.spec.js.map +1 -1
  80. package/dist/test/client.rollbackFarm.spec.js +1 -1
  81. package/dist/test/client.rollbackFarm.spec.js.map +1 -1
  82. package/dist/test/client.searchForMarker.spec.js +4 -21
  83. package/dist/test/client.searchForMarker.spec.js.map +1 -1
  84. package/dist/test/index.d.ts +2 -2
  85. package/dist/test/index.d.ts.map +1 -1
  86. package/dist/test/index.js +2 -6
  87. package/dist/test/index.js.map +1 -1
  88. package/dist/test/mergeTree.annotate.deltaCallback.spec.js +14 -59
  89. package/dist/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
  90. package/dist/test/mergeTree.annotate.spec.js +47 -63
  91. package/dist/test/mergeTree.annotate.spec.js.map +1 -1
  92. package/dist/test/mergeTree.insert.deltaCallback.spec.js +9 -62
  93. package/dist/test/mergeTree.insert.deltaCallback.spec.js.map +1 -1
  94. package/dist/test/mergeTree.insertingWalk.spec.js +59 -125
  95. package/dist/test/mergeTree.insertingWalk.spec.js.map +1 -1
  96. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +12 -93
  97. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
  98. package/dist/test/mergeTree.markRangeRemoved.spec.js +10 -7
  99. package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  100. package/dist/test/mergeTree.walk.spec.js +2 -14
  101. package/dist/test/mergeTree.walk.spec.js.map +1 -1
  102. package/dist/test/mergeTreeOperationRunner.js +2 -2
  103. package/dist/test/mergeTreeOperationRunner.js.map +1 -1
  104. package/dist/test/obliterate.concurrent.spec.js +18 -23
  105. package/dist/test/obliterate.concurrent.spec.js.map +1 -1
  106. package/dist/test/obliterate.partialLength.spec.js +166 -136
  107. package/dist/test/obliterate.partialLength.spec.js.map +1 -1
  108. package/dist/test/obliterate.spec.js +16 -126
  109. package/dist/test/obliterate.spec.js.map +1 -1
  110. package/dist/test/partialLength.spec.js +28 -196
  111. package/dist/test/partialLength.spec.js.map +1 -1
  112. package/dist/test/perspective.spec.js +34 -0
  113. package/dist/test/perspective.spec.js.map +1 -1
  114. package/dist/test/propertyManager.spec.js +1 -1
  115. package/dist/test/propertyManager.spec.js.map +1 -1
  116. package/dist/test/resetPendingSegmentsToOp.spec.js +0 -2
  117. package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  118. package/dist/test/segmentGroupCollection.spec.js +10 -4
  119. package/dist/test/segmentGroupCollection.spec.js.map +1 -1
  120. package/dist/test/testClient.d.ts +1 -0
  121. package/dist/test/testClient.d.ts.map +1 -1
  122. package/dist/test/testClient.js +16 -26
  123. package/dist/test/testClient.js.map +1 -1
  124. package/dist/test/testClientLogger.d.ts.map +1 -1
  125. package/dist/test/testClientLogger.js +3 -10
  126. package/dist/test/testClientLogger.js.map +1 -1
  127. package/dist/test/testServer.d.ts +2 -1
  128. package/dist/test/testServer.d.ts.map +1 -1
  129. package/dist/test/testServer.js +7 -5
  130. package/dist/test/testServer.js.map +1 -1
  131. package/dist/test/testUtils.d.ts +36 -56
  132. package/dist/test/testUtils.d.ts.map +1 -1
  133. package/dist/test/testUtils.js +68 -77
  134. package/dist/test/testUtils.js.map +1 -1
  135. package/dist/test/text.d.ts +2 -2
  136. package/dist/test/text.d.ts.map +1 -1
  137. package/dist/test/text.js +5 -2
  138. package/dist/test/text.js.map +1 -1
  139. package/dist/textSegment.d.ts +0 -6
  140. package/dist/textSegment.d.ts.map +1 -1
  141. package/dist/textSegment.js.map +1 -1
  142. package/dist/zamboni.d.ts.map +1 -1
  143. package/dist/zamboni.js +53 -26
  144. package/dist/zamboni.js.map +1 -1
  145. package/lib/MergeTreeTextHelper.d.ts +9 -3
  146. package/lib/MergeTreeTextHelper.d.ts.map +1 -1
  147. package/lib/MergeTreeTextHelper.js +5 -5
  148. package/lib/MergeTreeTextHelper.js.map +1 -1
  149. package/lib/client.d.ts +7 -13
  150. package/lib/client.d.ts.map +1 -1
  151. package/lib/client.js +117 -116
  152. package/lib/client.js.map +1 -1
  153. package/lib/endOfTreeSegment.d.ts +12 -8
  154. package/lib/endOfTreeSegment.d.ts.map +1 -1
  155. package/lib/endOfTreeSegment.js +2 -4
  156. package/lib/endOfTreeSegment.js.map +1 -1
  157. package/lib/index.d.ts +6 -3
  158. package/lib/index.d.ts.map +1 -1
  159. package/lib/index.js +1 -1
  160. package/lib/index.js.map +1 -1
  161. package/lib/mergeTree.d.ts +37 -23
  162. package/lib/mergeTree.d.ts.map +1 -1
  163. package/lib/mergeTree.js +381 -488
  164. package/lib/mergeTree.js.map +1 -1
  165. package/lib/mergeTreeDeltaCallback.d.ts +4 -8
  166. package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
  167. package/lib/mergeTreeDeltaCallback.js.map +1 -1
  168. package/lib/mergeTreeNodes.d.ts +32 -10
  169. package/lib/mergeTreeNodes.d.ts.map +1 -1
  170. package/lib/mergeTreeNodes.js +42 -29
  171. package/lib/mergeTreeNodes.js.map +1 -1
  172. package/lib/partialLengths.d.ts +2 -2
  173. package/lib/partialLengths.d.ts.map +1 -1
  174. package/lib/partialLengths.js +160 -111
  175. package/lib/partialLengths.js.map +1 -1
  176. package/lib/perspective.d.ts +8 -27
  177. package/lib/perspective.d.ts.map +1 -1
  178. package/lib/perspective.js +8 -68
  179. package/lib/perspective.js.map +1 -1
  180. package/lib/revertibles.d.ts.map +1 -1
  181. package/lib/revertibles.js +2 -2
  182. package/lib/revertibles.js.map +1 -1
  183. package/lib/segmentInfos.d.ts +20 -106
  184. package/lib/segmentInfos.d.ts.map +1 -1
  185. package/lib/segmentInfos.js +26 -37
  186. package/lib/segmentInfos.js.map +1 -1
  187. package/lib/segmentPropertiesManager.d.ts +1 -14
  188. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  189. package/lib/segmentPropertiesManager.js +2 -16
  190. package/lib/segmentPropertiesManager.js.map +1 -1
  191. package/lib/snapshotLoader.d.ts.map +1 -1
  192. package/lib/snapshotLoader.js +39 -19
  193. package/lib/snapshotLoader.js.map +1 -1
  194. package/lib/snapshotV1.d.ts.map +1 -1
  195. package/lib/snapshotV1.js +34 -26
  196. package/lib/snapshotV1.js.map +1 -1
  197. package/lib/snapshotlegacy.d.ts.map +1 -1
  198. package/lib/snapshotlegacy.js +7 -10
  199. package/lib/snapshotlegacy.js.map +1 -1
  200. package/lib/stamps.d.ts +1 -1
  201. package/lib/stamps.js +1 -1
  202. package/lib/stamps.js.map +1 -1
  203. package/lib/test/Insertion.perf.spec.js +6 -51
  204. package/lib/test/Insertion.perf.spec.js.map +1 -1
  205. package/lib/test/PartialLengths.perf.spec.js +18 -25
  206. package/lib/test/PartialLengths.perf.spec.js.map +1 -1
  207. package/lib/test/Removal.perf.spec.js +13 -41
  208. package/lib/test/Removal.perf.spec.js.map +1 -1
  209. package/lib/test/beastTest.spec.d.ts.map +1 -1
  210. package/lib/test/beastTest.spec.js +42 -67
  211. package/lib/test/beastTest.spec.js.map +1 -1
  212. package/lib/test/client.annotateMarker.spec.js +1 -11
  213. package/lib/test/client.annotateMarker.spec.js.map +1 -1
  214. package/lib/test/client.applyMsg.spec.js +14 -14
  215. package/lib/test/client.applyMsg.spec.js.map +1 -1
  216. package/lib/test/client.getPosition.spec.js +1 -1
  217. package/lib/test/client.getPosition.spec.js.map +1 -1
  218. package/lib/test/client.localReference.spec.js +1 -1
  219. package/lib/test/client.localReference.spec.js.map +1 -1
  220. package/lib/test/client.rollback.spec.js +50 -59
  221. package/lib/test/client.rollback.spec.js.map +1 -1
  222. package/lib/test/client.rollbackFarm.spec.js +1 -1
  223. package/lib/test/client.rollbackFarm.spec.js.map +1 -1
  224. package/lib/test/client.searchForMarker.spec.js +4 -21
  225. package/lib/test/client.searchForMarker.spec.js.map +1 -1
  226. package/lib/test/index.d.ts +2 -2
  227. package/lib/test/index.d.ts.map +1 -1
  228. package/lib/test/index.js +1 -1
  229. package/lib/test/index.js.map +1 -1
  230. package/lib/test/mergeTree.annotate.deltaCallback.spec.js +15 -60
  231. package/lib/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -1
  232. package/lib/test/mergeTree.annotate.spec.js +48 -64
  233. package/lib/test/mergeTree.annotate.spec.js.map +1 -1
  234. package/lib/test/mergeTree.insert.deltaCallback.spec.js +10 -63
  235. package/lib/test/mergeTree.insert.deltaCallback.spec.js.map +1 -1
  236. package/lib/test/mergeTree.insertingWalk.spec.js +61 -127
  237. package/lib/test/mergeTree.insertingWalk.spec.js.map +1 -1
  238. package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +13 -94
  239. package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
  240. package/lib/test/mergeTree.markRangeRemoved.spec.js +10 -7
  241. package/lib/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  242. package/lib/test/mergeTree.walk.spec.js +2 -14
  243. package/lib/test/mergeTree.walk.spec.js.map +1 -1
  244. package/lib/test/mergeTreeOperationRunner.js +3 -3
  245. package/lib/test/mergeTreeOperationRunner.js.map +1 -1
  246. package/lib/test/obliterate.concurrent.spec.js +18 -23
  247. package/lib/test/obliterate.concurrent.spec.js.map +1 -1
  248. package/lib/test/obliterate.partialLength.spec.js +167 -137
  249. package/lib/test/obliterate.partialLength.spec.js.map +1 -1
  250. package/lib/test/obliterate.spec.js +17 -127
  251. package/lib/test/obliterate.spec.js.map +1 -1
  252. package/lib/test/partialLength.spec.js +29 -197
  253. package/lib/test/partialLength.spec.js.map +1 -1
  254. package/lib/test/perspective.spec.js +34 -0
  255. package/lib/test/perspective.spec.js.map +1 -1
  256. package/lib/test/propertyManager.spec.js +2 -2
  257. package/lib/test/propertyManager.spec.js.map +1 -1
  258. package/lib/test/resetPendingSegmentsToOp.spec.js +0 -2
  259. package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  260. package/lib/test/segmentGroupCollection.spec.js +10 -4
  261. package/lib/test/segmentGroupCollection.spec.js.map +1 -1
  262. package/lib/test/testClient.d.ts +1 -0
  263. package/lib/test/testClient.d.ts.map +1 -1
  264. package/lib/test/testClient.js +18 -28
  265. package/lib/test/testClient.js.map +1 -1
  266. package/lib/test/testClientLogger.d.ts.map +1 -1
  267. package/lib/test/testClientLogger.js +3 -10
  268. package/lib/test/testClientLogger.js.map +1 -1
  269. package/lib/test/testServer.d.ts +2 -1
  270. package/lib/test/testServer.d.ts.map +1 -1
  271. package/lib/test/testServer.js +7 -5
  272. package/lib/test/testServer.js.map +1 -1
  273. package/lib/test/testUtils.d.ts +36 -56
  274. package/lib/test/testUtils.d.ts.map +1 -1
  275. package/lib/test/testUtils.js +66 -48
  276. package/lib/test/testUtils.js.map +1 -1
  277. package/lib/test/text.d.ts +2 -2
  278. package/lib/test/text.d.ts.map +1 -1
  279. package/lib/test/text.js +6 -3
  280. package/lib/test/text.js.map +1 -1
  281. package/lib/textSegment.d.ts +0 -6
  282. package/lib/textSegment.d.ts.map +1 -1
  283. package/lib/textSegment.js.map +1 -1
  284. package/lib/tsdoc-metadata.json +1 -1
  285. package/lib/zamboni.d.ts.map +1 -1
  286. package/lib/zamboni.js +32 -28
  287. package/lib/zamboni.js.map +1 -1
  288. package/package.json +17 -20
  289. package/src/MergeTreeTextHelper.ts +17 -12
  290. package/src/client.ts +141 -197
  291. package/src/endOfTreeSegment.ts +11 -8
  292. package/src/index.ts +4 -3
  293. package/src/mergeTree.ts +482 -633
  294. package/src/mergeTreeDeltaCallback.ts +4 -8
  295. package/src/mergeTreeNodes.ts +66 -45
  296. package/src/partialLengths.ts +181 -137
  297. package/src/perspective.ts +17 -95
  298. package/src/revertibles.ts +2 -7
  299. package/src/segmentInfos.ts +48 -141
  300. package/src/segmentPropertiesManager.ts +2 -16
  301. package/src/snapshotLoader.ts +62 -30
  302. package/src/snapshotV1.ts +36 -28
  303. package/src/snapshotlegacy.ts +7 -16
  304. package/src/stamps.ts +1 -1
  305. package/src/textSegment.ts +0 -13
  306. package/src/zamboni.ts +38 -32
  307. package/tsconfig.json +1 -0
  308. package/prettier.config.cjs +0 -8
@@ -5,9 +5,9 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const node_assert_1 = require("node:assert");
8
- const constants_js_1 = require("../constants.js");
9
8
  const mergeTree_js_1 = require("../mergeTree.js");
10
9
  const mergeTreeDeltaCallback_js_1 = require("../mergeTreeDeltaCallback.js");
10
+ const mergeTreeNodes_js_1 = require("../mergeTreeNodes.js");
11
11
  const ops_js_1 = require("../ops.js");
12
12
  const textSegment_js_1 = require("../textSegment.js");
13
13
  const testUtils_js_1 = require("./testUtils.js");
@@ -17,15 +17,7 @@ describe("MergeTree", () => {
17
17
  let currentSequenceNumber;
18
18
  beforeEach(() => {
19
19
  mergeTree = new mergeTree_js_1.MergeTree();
20
- (0, testUtils_js_1.insertSegments)({
21
- mergeTree,
22
- pos: 0,
23
- segments: [textSegment_js_1.TextSegment.make("hello world!")],
24
- refSeq: constants_js_1.UniversalSequenceNumber,
25
- clientId: constants_js_1.LocalClientId,
26
- seq: constants_js_1.UniversalSequenceNumber,
27
- opArgs: undefined,
28
- });
20
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make("hello world!")], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
29
21
  currentSequenceNumber = 0;
30
22
  mergeTree.startCollaboration(localClientId,
31
23
  /* minSeq: */ currentSequenceNumber,
@@ -37,67 +29,31 @@ describe("MergeTree", () => {
37
29
  mergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs) => {
38
30
  eventCalled++;
39
31
  };
40
- (0, testUtils_js_1.insertText)({
41
- mergeTree,
42
- pos: 0,
43
- refSeq: currentSequenceNumber,
44
- clientId: localClientId,
45
- seq: constants_js_1.UnassignedSequenceNumber,
46
- text: "more ",
47
- props: undefined,
48
- opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
49
- });
32
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make("more ")], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } });
50
33
  node_assert_1.strict.equal(eventCalled, 1);
51
34
  });
52
35
  it("Insert ending text", () => {
53
- const textLength = mergeTree.getLength(currentSequenceNumber, localClientId);
36
+ const textLength = mergeTree.getLength(mergeTree.localPerspective);
54
37
  let eventCalled = 0;
55
38
  mergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs) => {
56
39
  eventCalled++;
57
40
  };
58
- (0, testUtils_js_1.insertText)({
59
- mergeTree,
60
- pos: textLength,
61
- refSeq: currentSequenceNumber,
62
- clientId: localClientId,
63
- seq: constants_js_1.UnassignedSequenceNumber,
64
- text: "more ",
65
- props: undefined,
66
- opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
67
- });
41
+ mergeTree.insertSegments(textLength, [textSegment_js_1.TextSegment.make("more ")], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } });
68
42
  node_assert_1.strict.equal(eventCalled, 1);
69
43
  });
70
44
  it("Insert middle text", () => {
71
45
  const count = (0, testUtils_js_1.countOperations)(mergeTree);
72
- (0, testUtils_js_1.insertText)({
73
- mergeTree,
74
- pos: 4,
75
- refSeq: currentSequenceNumber,
76
- clientId: localClientId,
77
- seq: constants_js_1.UnassignedSequenceNumber,
78
- text: "more ",
79
- props: undefined,
80
- opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
81
- });
46
+ mergeTree.insertSegments(4, [textSegment_js_1.TextSegment.make("more ")], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } });
82
47
  node_assert_1.strict.deepStrictEqual(count, {
83
48
  [ops_js_1.MergeTreeDeltaType.INSERT]: 1,
84
49
  [mergeTreeDeltaCallback_js_1.MergeTreeMaintenanceType.SPLIT]: 1,
85
50
  });
86
51
  });
87
52
  it("Insert text remote", () => {
88
- const remoteClientId = 35;
53
+ const remoteClient = (0, testUtils_js_1.makeRemoteClient)({ clientId: 35 });
89
54
  let remoteSequenceNumber = currentSequenceNumber;
90
55
  const count = (0, testUtils_js_1.countOperations)(mergeTree);
91
- (0, testUtils_js_1.insertText)({
92
- mergeTree,
93
- pos: 0,
94
- refSeq: currentSequenceNumber,
95
- clientId: remoteClientId,
96
- seq: ++remoteSequenceNumber,
97
- text: "more ",
98
- props: undefined,
99
- opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
100
- });
56
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make("more ")], remoteClient.perspectiveAt({ refSeq: currentSequenceNumber }), remoteClient.stampAt({ seq: ++remoteSequenceNumber }), { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } });
101
57
  node_assert_1.strict.deepStrictEqual(count, {
102
58
  [ops_js_1.MergeTreeDeltaType.INSERT]: 1,
103
59
  });
@@ -106,16 +62,7 @@ describe("MergeTree", () => {
106
62
  describe("insertMarker", () => {
107
63
  it("Insert marker", () => {
108
64
  const count = (0, testUtils_js_1.countOperations)(mergeTree);
109
- (0, testUtils_js_1.insertMarker)({
110
- mergeTree,
111
- pos: 4,
112
- refSeq: currentSequenceNumber,
113
- clientId: localClientId,
114
- seq: constants_js_1.UnassignedSequenceNumber,
115
- behaviors: ops_js_1.ReferenceType.Simple,
116
- props: undefined,
117
- opArgs: { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } },
118
- });
65
+ mergeTree.insertSegments(4, [mergeTreeNodes_js_1.Marker.make(ops_js_1.ReferenceType.Simple)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), { op: { type: ops_js_1.MergeTreeDeltaType.INSERT } });
119
66
  node_assert_1.strict.deepStrictEqual(count, {
120
67
  [ops_js_1.MergeTreeDeltaType.INSERT]: 1,
121
68
  [mergeTreeDeltaCallback_js_1.MergeTreeMaintenanceType.SPLIT]: 1,
@@ -1 +1 @@
1
- {"version":3,"file":"mergeTree.insert.deltaCallback.spec.js","sourceRoot":"","sources":["../../src/test/mergeTree.insert.deltaCallback.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport {\n\tLocalClientId,\n\tUnassignedSequenceNumber,\n\tUniversalSequenceNumber,\n} from \"../constants.js\";\nimport { MergeTree } from \"../mergeTree.js\";\nimport { MergeTreeMaintenanceType } from \"../mergeTreeDeltaCallback.js\";\nimport { MergeTreeDeltaType, ReferenceType } from \"../ops.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport { countOperations, insertMarker, insertSegments, insertText } from \"./testUtils.js\";\n\ndescribe(\"MergeTree\", () => {\n\tlet mergeTree: MergeTree;\n\tconst localClientId = 17;\n\tlet currentSequenceNumber: number;\n\tbeforeEach(() => {\n\t\tmergeTree = new MergeTree();\n\t\tinsertSegments({\n\t\t\tmergeTree,\n\t\t\tpos: 0,\n\t\t\tsegments: [TextSegment.make(\"hello world!\")],\n\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\tclientId: LocalClientId,\n\t\t\tseq: UniversalSequenceNumber,\n\t\t\topArgs: undefined,\n\t\t});\n\n\t\tcurrentSequenceNumber = 0;\n\t\tmergeTree.startCollaboration(\n\t\t\tlocalClientId,\n\t\t\t/* minSeq: */ currentSequenceNumber,\n\t\t\t/* currentSeq: */ currentSequenceNumber,\n\t\t);\n\t});\n\n\tdescribe(\"insertText\", () => {\n\t\tit(\"Insert starting text\", () => {\n\t\t\tlet eventCalled: number = 0;\n\n\t\t\tmergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs): void => {\n\t\t\t\teventCalled++;\n\t\t\t};\n\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 0,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\ttext: \"more \",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: { op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t});\n\n\t\t\tassert.equal(eventCalled, 1);\n\t\t});\n\n\t\tit(\"Insert ending text\", () => {\n\t\t\tconst textLength = mergeTree.getLength(currentSequenceNumber, localClientId);\n\t\t\tlet eventCalled: number = 0;\n\n\t\t\tmergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs): void => {\n\t\t\t\teventCalled++;\n\t\t\t};\n\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: textLength,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\ttext: \"more \",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: { op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t});\n\n\t\t\tassert.equal(eventCalled, 1);\n\t\t});\n\n\t\tit(\"Insert middle text\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 4,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\ttext: \"more \",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: { op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t});\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.INSERT]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 1,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Insert text remote\", () => {\n\t\t\tconst remoteClientId: number = 35;\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 0,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: remoteClientId,\n\t\t\t\tseq: ++remoteSequenceNumber,\n\t\t\t\ttext: \"more \",\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: { op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t});\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.INSERT]: 1,\n\t\t\t});\n\t\t});\n\t});\n\tdescribe(\"insertMarker\", () => {\n\t\tit(\"Insert marker\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tinsertMarker({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 4,\n\t\t\t\trefSeq: currentSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\tbehaviors: ReferenceType.Simple,\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: { op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t});\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.INSERT]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 1,\n\t\t\t});\n\t\t});\n\t});\n});\n"]}
1
+ {"version":3,"file":"mergeTree.insert.deltaCallback.spec.js","sourceRoot":"","sources":["../../src/test/mergeTree.insert.deltaCallback.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { MergeTree } from \"../mergeTree.js\";\nimport { MergeTreeMaintenanceType } from \"../mergeTreeDeltaCallback.js\";\nimport { Marker } from \"../mergeTreeNodes.js\";\nimport { MergeTreeDeltaType, ReferenceType } from \"../ops.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport { countOperations, makeRemoteClient } from \"./testUtils.js\";\n\ndescribe(\"MergeTree\", () => {\n\tlet mergeTree: MergeTree;\n\tconst localClientId = 17;\n\tlet currentSequenceNumber: number;\n\tbeforeEach(() => {\n\t\tmergeTree = new MergeTree();\n\t\tmergeTree.insertSegments(\n\t\t\t0,\n\t\t\t[TextSegment.make(\"hello world!\")],\n\t\t\tmergeTree.localPerspective,\n\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\tundefined,\n\t\t);\n\n\t\tcurrentSequenceNumber = 0;\n\t\tmergeTree.startCollaboration(\n\t\t\tlocalClientId,\n\t\t\t/* minSeq: */ currentSequenceNumber,\n\t\t\t/* currentSeq: */ currentSequenceNumber,\n\t\t);\n\t});\n\n\tdescribe(\"insertText\", () => {\n\t\tit(\"Insert starting text\", () => {\n\t\t\tlet eventCalled: number = 0;\n\n\t\t\tmergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs): void => {\n\t\t\t\teventCalled++;\n\t\t\t};\n\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t0,\n\t\t\t\t[TextSegment.make(\"more \")],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t{ op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t);\n\n\t\t\tassert.equal(eventCalled, 1);\n\t\t});\n\n\t\tit(\"Insert ending text\", () => {\n\t\t\tconst textLength = mergeTree.getLength(mergeTree.localPerspective);\n\t\t\tlet eventCalled: number = 0;\n\n\t\t\tmergeTree.mergeTreeDeltaCallback = (opArgs, deltaArgs): void => {\n\t\t\t\teventCalled++;\n\t\t\t};\n\n\t\t\tmergeTree.insertSegments(\n\t\t\t\ttextLength,\n\t\t\t\t[TextSegment.make(\"more \")],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t{ op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t);\n\n\t\t\tassert.equal(eventCalled, 1);\n\t\t});\n\n\t\tit(\"Insert middle text\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t4,\n\t\t\t\t[TextSegment.make(\"more \")],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t{ op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.INSERT]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 1,\n\t\t\t});\n\t\t});\n\n\t\tit(\"Insert text remote\", () => {\n\t\t\tconst remoteClient = makeRemoteClient({ clientId: 35 });\n\t\t\tlet remoteSequenceNumber = currentSequenceNumber;\n\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t0,\n\t\t\t\t[TextSegment.make(\"more \")],\n\t\t\t\tremoteClient.perspectiveAt({ refSeq: currentSequenceNumber }),\n\t\t\t\tremoteClient.stampAt({ seq: ++remoteSequenceNumber }),\n\t\t\t\t{ op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.INSERT]: 1,\n\t\t\t});\n\t\t});\n\t});\n\tdescribe(\"insertMarker\", () => {\n\t\tit(\"Insert marker\", () => {\n\t\t\tconst count = countOperations(mergeTree);\n\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t4,\n\t\t\t\t[Marker.make(ReferenceType.Simple)],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t{ op: { type: MergeTreeDeltaType.INSERT } },\n\t\t\t);\n\n\t\t\tassert.deepStrictEqual(count, {\n\t\t\t\t[MergeTreeDeltaType.INSERT]: 1,\n\t\t\t\t[MergeTreeMaintenanceType.SPLIT]: 1,\n\t\t\t});\n\t\t});\n\t});\n});\n"]}
@@ -19,15 +19,7 @@ const treeFactories = [
19
19
  create: () => {
20
20
  const initialText = "hello world";
21
21
  const mergeTree = new mergeTree_js_1.MergeTree();
22
- (0, testUtils_js_1.insertSegments)({
23
- mergeTree,
24
- pos: 0,
25
- segments: [textSegment_js_1.TextSegment.make(initialText)],
26
- refSeq: constants_js_1.UniversalSequenceNumber,
27
- clientId: constants_js_1.LocalClientId,
28
- seq: constants_js_1.UniversalSequenceNumber,
29
- opArgs: undefined,
30
- });
22
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make(initialText)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
31
23
  mergeTree.startCollaboration(localClientId,
32
24
  /* minSeq: */ constants_js_1.UniversalSequenceNumber,
33
25
  /* currentSeq: */ constants_js_1.UniversalSequenceNumber);
@@ -45,31 +37,14 @@ const treeFactories = [
45
37
  create: () => {
46
38
  let initialText = "0";
47
39
  const mergeTree = new mergeTree_js_1.MergeTree();
48
- (0, testUtils_js_1.insertSegments)({
49
- mergeTree,
50
- pos: 0,
51
- segments: [textSegment_js_1.TextSegment.make(initialText)],
52
- refSeq: constants_js_1.UniversalSequenceNumber,
53
- clientId: constants_js_1.LocalClientId,
54
- seq: constants_js_1.UniversalSequenceNumber,
55
- opArgs: undefined,
56
- });
40
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make(initialText)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
57
41
  for (let i = 1; i < mergeTreeNodes_js_1.MaxNodesInBlock - 1; i++) {
58
42
  const text = i.toString();
59
- (0, testUtils_js_1.insertText)({
60
- mergeTree,
61
- pos: mergeTree.getLength(constants_js_1.UniversalSequenceNumber, localClientId),
62
- refSeq: constants_js_1.UniversalSequenceNumber,
63
- clientId: localClientId,
64
- seq: constants_js_1.UniversalSequenceNumber,
65
- text,
66
- props: undefined,
67
- opArgs: undefined,
68
- });
43
+ mergeTree.insertSegments(mergeTree.getLength(mergeTree.localPerspective), [textSegment_js_1.TextSegment.make(text)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
69
44
  initialText += text;
70
45
  }
71
46
  const textHelper = new MergeTreeTextHelper_js_1.MergeTreeTextHelper(mergeTree);
72
- node_assert_1.strict.equal(textHelper.getText(constants_js_1.UniversalSequenceNumber, localClientId), initialText);
47
+ node_assert_1.strict.equal(textHelper.getText(mergeTree.localPerspective), initialText);
73
48
  const nodes = [mergeTree.root];
74
49
  while (nodes.length > 0) {
75
50
  const node = nodes.pop();
@@ -96,35 +71,18 @@ const treeFactories = [
96
71
  create: () => {
97
72
  let initialText = "0";
98
73
  const mergeTree = new mergeTree_js_1.MergeTree();
99
- (0, testUtils_js_1.insertSegments)({
100
- mergeTree,
101
- pos: 0,
102
- segments: [textSegment_js_1.TextSegment.make(initialText)],
103
- refSeq: constants_js_1.UniversalSequenceNumber,
104
- clientId: constants_js_1.LocalClientId,
105
- seq: constants_js_1.UniversalSequenceNumber,
106
- opArgs: undefined,
107
- });
74
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make(initialText)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
108
75
  for (let i = 1; i < mergeTreeNodes_js_1.MaxNodesInBlock * 4; i++) {
109
76
  const text = i.toString();
110
- (0, testUtils_js_1.insertText)({
111
- mergeTree,
112
- pos: mergeTree.getLength(constants_js_1.UniversalSequenceNumber, localClientId),
113
- refSeq: constants_js_1.UniversalSequenceNumber,
114
- clientId: localClientId,
115
- seq: constants_js_1.UniversalSequenceNumber,
116
- text,
117
- props: undefined,
118
- opArgs: undefined,
119
- });
77
+ mergeTree.insertSegments(mergeTree.getLength(mergeTree.localPerspective), [textSegment_js_1.TextSegment.make(text)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
120
78
  initialText += text;
121
79
  }
122
80
  const remove = Math.round(initialText.length / 4);
123
81
  // remove from start
124
- mergeTree.markRangeRemoved(0, remove, constants_js_1.UniversalSequenceNumber, localClientId, constants_js_1.UniversalSequenceNumber, undefined);
82
+ mergeTree.markRangeRemoved(0, remove, mergeTree.localPerspective, { clientId: localClientId, seq: constants_js_1.UniversalSequenceNumber }, undefined);
125
83
  initialText = initialText.slice(Math.max(0, remove));
126
84
  // remove from end
127
- mergeTree.markRangeRemoved(initialText.length - remove, initialText.length, constants_js_1.UniversalSequenceNumber, localClientId, constants_js_1.UniversalSequenceNumber, undefined);
85
+ mergeTree.markRangeRemoved(initialText.length - remove, initialText.length, mergeTree.localPerspective, { clientId: localClientId, seq: constants_js_1.UniversalSequenceNumber }, undefined);
128
86
  initialText = initialText.slice(0, Math.max(0, initialText.length - remove));
129
87
  mergeTree.startCollaboration(localClientId,
130
88
  /* minSeq: */ constants_js_1.UniversalSequenceNumber,
@@ -154,50 +112,23 @@ describe("MergeTree.insertingWalk", () => {
154
112
  });
155
113
  describe("insertText", () => {
156
114
  it("at beginning", () => {
157
- (0, testUtils_js_1.insertText)({
158
- mergeTree: testData.mergeTree,
159
- pos: 0,
160
- refSeq: testData.refSeq,
161
- clientId: localClientId,
162
- seq: constants_js_1.UnassignedSequenceNumber,
163
- text: "a",
164
- props: undefined,
165
- opArgs: undefined,
166
- });
167
- node_assert_1.strict.equal(testData.mergeTree.getLength(testData.refSeq, localClientId), testData.initialText.length + 1);
168
- const currentValue = testData.textHelper.getText(testData.refSeq, localClientId);
115
+ testData.mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make("a")], testData.mergeTree.localPerspective, testData.mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
116
+ node_assert_1.strict.equal(testData.mergeTree.getLength(testData.mergeTree.localPerspective), testData.initialText.length + 1);
117
+ const currentValue = testData.textHelper.getText(testData.mergeTree.localPerspective);
169
118
  node_assert_1.strict.equal(currentValue.length, testData.initialText.length + 1);
170
119
  node_assert_1.strict.equal(currentValue, `a${testData.initialText}`);
171
120
  });
172
121
  it("at end", () => {
173
- (0, testUtils_js_1.insertText)({
174
- mergeTree: testData.mergeTree,
175
- pos: testData.initialText.length,
176
- refSeq: testData.refSeq,
177
- clientId: localClientId,
178
- seq: constants_js_1.UnassignedSequenceNumber,
179
- text: "a",
180
- props: undefined,
181
- opArgs: undefined,
182
- });
183
- node_assert_1.strict.equal(testData.mergeTree.getLength(testData.refSeq, localClientId), testData.initialText.length + 1);
184
- const currentValue = testData.textHelper.getText(testData.refSeq, localClientId);
122
+ testData.mergeTree.insertSegments(testData.initialText.length, [textSegment_js_1.TextSegment.make("a")], testData.mergeTree.localPerspective, testData.mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
123
+ node_assert_1.strict.equal(testData.mergeTree.getLength(testData.mergeTree.localPerspective), testData.initialText.length + 1);
124
+ const currentValue = testData.textHelper.getText(testData.mergeTree.localPerspective);
185
125
  node_assert_1.strict.equal(currentValue.length, testData.initialText.length + 1);
186
126
  node_assert_1.strict.equal(currentValue, `${testData.initialText}a`);
187
127
  });
188
128
  it("in middle", () => {
189
- (0, testUtils_js_1.insertText)({
190
- mergeTree: testData.mergeTree,
191
- pos: testData.middle,
192
- refSeq: testData.refSeq,
193
- clientId: localClientId,
194
- seq: constants_js_1.UnassignedSequenceNumber,
195
- text: "a",
196
- props: undefined,
197
- opArgs: undefined,
198
- });
199
- node_assert_1.strict.equal(testData.mergeTree.getLength(testData.refSeq, localClientId), testData.initialText.length + 1);
200
- const currentValue = testData.textHelper.getText(testData.refSeq, localClientId);
129
+ testData.mergeTree.insertSegments(testData.middle, [textSegment_js_1.TextSegment.make("a")], testData.mergeTree.localPerspective, testData.mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
130
+ node_assert_1.strict.equal(testData.mergeTree.getLength(testData.mergeTree.localPerspective), testData.initialText.length + 1);
131
+ const currentValue = testData.textHelper.getText(testData.mergeTree.localPerspective);
201
132
  node_assert_1.strict.equal(currentValue.length, testData.initialText.length + 1);
202
133
  node_assert_1.strict.equal(currentValue, `${testData.initialText.slice(0, Math.max(0, testData.middle))}` +
203
134
  "a" +
@@ -210,57 +141,25 @@ describe("MergeTree.insertingWalk", () => {
210
141
  let initialText = "0";
211
142
  let seq = 0;
212
143
  const mergeTree = new mergeTree_js_1.MergeTree();
144
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make(initialText)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
213
145
  mergeTree.startCollaboration(localClientId, 0, seq);
214
- (0, testUtils_js_1.insertSegments)({
215
- mergeTree,
216
- pos: 0,
217
- segments: [textSegment_js_1.TextSegment.make(initialText)],
218
- refSeq: constants_js_1.UniversalSequenceNumber,
219
- clientId: localClientId,
220
- seq: constants_js_1.UniversalSequenceNumber,
221
- opArgs: undefined,
222
- });
223
146
  for (let i = 1; i < mergeTreeNodes_js_1.MaxNodesInBlock; i++) {
224
147
  const text = String.fromCodePoint(i + 64);
225
- (0, testUtils_js_1.insertText)({
226
- mergeTree,
227
- pos: 0,
228
- refSeq: constants_js_1.UniversalSequenceNumber,
229
- clientId: localClientId,
230
- seq: constants_js_1.UnassignedSequenceNumber,
231
- text,
232
- props: undefined,
233
- opArgs: undefined,
234
- });
148
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make(text)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
235
149
  initialText += text;
236
150
  }
237
151
  const textHelper = new MergeTreeTextHelper_js_1.MergeTreeTextHelper(mergeTree);
238
152
  node_assert_1.strict.equal(mergeTree.root.childCount, 2);
239
- node_assert_1.strict.equal(textHelper.getText(0, localClientId), "GFEDCBA0");
153
+ node_assert_1.strict.equal(textHelper.getText(mergeTree.localPerspective), "GFEDCBA0");
240
154
  // Remove "DCBA"
241
- (0, testUtils_js_1.markRangeRemoved)({
242
- mergeTree,
243
- start: 3,
244
- end: 7,
245
- refSeq: constants_js_1.UniversalSequenceNumber,
246
- clientId: localClientId,
247
- seq: constants_js_1.UnassignedSequenceNumber,
248
- overwrite: false,
249
- opArgs: undefined,
250
- });
251
- node_assert_1.strict.equal(textHelper.getText(0, localClientId), "GFE0");
155
+ mergeTree.markRangeRemoved(3, 7, mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
156
+ node_assert_1.strict.equal(textHelper.getText(mergeTree.localPerspective), "GFE0");
252
157
  // Simulate another client inserting concurrently with the above operations. Because
253
158
  // all segments but the 0 are unacked, this insert should place the segment directly
254
159
  // before the 0. Prior to this regression test, an issue with `rightExcursion` in the
255
160
  // merge conflict logic instead caused the segment to be placed before the removed segments.
256
- (0, testUtils_js_1.insertText)({
257
- mergeTree,
258
- pos: 0,
259
- refSeq: constants_js_1.UniversalSequenceNumber,
260
- clientId: localClientId + 1,
261
- seq: ++seq,
262
- text: "x",
263
- });
161
+ const remoteClient = (0, testUtils_js_1.makeRemoteClient)({ clientId: localClientId + 1 });
162
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make("x")], remoteClient.perspectiveAt({ refSeq: 0 }), remoteClient.stampAt({ seq: ++seq }), undefined);
264
163
  const segments = [];
265
164
  (0, mergeTreeNodeWalk_js_1.walkAllChildSegments)(mergeTree.root, (seg) => {
266
165
  if (textSegment_js_1.TextSegment.is(seg)) {
@@ -275,5 +174,40 @@ describe("MergeTree.insertingWalk", () => {
275
174
  });
276
175
  node_assert_1.strict.deepStrictEqual(segments, ["G", "F", "E", "(D)", "(C)", "(B)", "(A)", "x", "0"]);
277
176
  });
177
+ // Inserting walk previously unnecessarily called `blockUpdate` for blocks even when no segment changes happened (e.g.
178
+ // we called `ensureIntervalBoundary` but there was already a segment boundary at the position we wanted to ensure had one).
179
+ it("avoids calling blockUpdate excessively", () => {
180
+ const seq = 1;
181
+ const mergeTree = new mergeTree_js_1.MergeTree();
182
+ mergeTree.startCollaboration(localClientId, 0, seq);
183
+ for (const char of [..."hello world"]) {
184
+ mergeTree.insertSegments(mergeTree.getLength(mergeTree.localPerspective), [textSegment_js_1.TextSegment.make(char)], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined /* opArgs */);
185
+ }
186
+ const originalBlockUpdate =
187
+ // eslint-disable-next-line @typescript-eslint/dot-notation
188
+ mergeTree["blockUpdate"].bind(mergeTree);
189
+ const blockUpdateCallLog = [];
190
+ // eslint-disable-next-line @typescript-eslint/dot-notation
191
+ mergeTree["blockUpdate"] = (block) => {
192
+ // This is called in the middle of updating lots of merge-tree bookkeeping, so we don't want to do too much
193
+ // advanced stuff here. However, walking the tree and concatenating all the text (ignoring other segment properties)
194
+ // should be safe.
195
+ let text = "";
196
+ (0, mergeTreeNodeWalk_js_1.walkAllChildSegments)(block, (seg) => {
197
+ if (textSegment_js_1.TextSegment.is(seg)) {
198
+ text += seg.text;
199
+ }
200
+ return true;
201
+ });
202
+ blockUpdateCallLog.push(text);
203
+ originalBlockUpdate(block);
204
+ };
205
+ mergeTree.insertSegments(0, [textSegment_js_1.TextSegment.make("Ot")], mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined /* opArgs */);
206
+ node_assert_1.strict.deepEqual(blockUpdateCallLog, ["Othell", "Othello world"]);
207
+ blockUpdateCallLog.length = 0;
208
+ mergeTree.markRangeRemoved(0, "Othello world".length, mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
209
+ // The log ignores presence of segments. The important thing is that we only have one entry per block here.
210
+ node_assert_1.strict.deepEqual(blockUpdateCallLog, ["Othell", "o world", "Othello world"]);
211
+ });
278
212
  });
279
213
  //# sourceMappingURL=mergeTree.insertingWalk.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mergeTree.insertingWalk.spec.js","sourceRoot":"","sources":["../../src/test/mergeTree.insertingWalk.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { MergeTreeTextHelper } from \"../MergeTreeTextHelper.js\";\nimport {\n\tLocalClientId,\n\tUnassignedSequenceNumber,\n\tUniversalSequenceNumber,\n} from \"../constants.js\";\nimport { MergeTree } from \"../mergeTree.js\";\nimport { walkAllChildSegments } from \"../mergeTreeNodeWalk.js\";\nimport { MergeBlock, MaxNodesInBlock, segmentIsRemoved } from \"../mergeTreeNodes.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport {\n\tinsertSegments,\n\tinsertText,\n\tmarkRangeRemoved,\n\tnodeOrdinalsHaveIntegrity,\n} from \"./testUtils.js\";\n\ninterface ITestTreeFactory {\n\treadonly create: () => ITestData;\n\treadonly name: string;\n}\n\ninterface ITestData {\n\treadonly mergeTree: MergeTree;\n\treadonly textHelper: MergeTreeTextHelper;\n\treadonly initialText: string;\n\treadonly middle: number;\n\treadonly refSeq: number;\n}\n\nconst localClientId = 17;\nconst treeFactories: ITestTreeFactory[] = [\n\t{\n\t\tcreate: (): ITestData => {\n\t\t\tconst initialText = \"hello world\";\n\t\t\tconst mergeTree = new MergeTree();\n\t\t\tinsertSegments({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 0,\n\t\t\t\tsegments: [TextSegment.make(initialText)],\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\tclientId: LocalClientId,\n\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\t\t\tmergeTree.startCollaboration(\n\t\t\t\tlocalClientId,\n\t\t\t\t/* minSeq: */ UniversalSequenceNumber,\n\t\t\t\t/* currentSeq: */ UniversalSequenceNumber,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinitialText,\n\t\t\t\tmergeTree,\n\t\t\t\tmiddle: Math.round(initialText.length / 2),\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\ttextHelper: new MergeTreeTextHelper(mergeTree),\n\t\t\t};\n\t\t},\n\t\tname: \"single segment tree\",\n\t},\n\t{\n\t\tcreate: (): ITestData => {\n\t\t\tlet initialText = \"0\";\n\t\t\tconst mergeTree = new MergeTree();\n\t\t\tinsertSegments({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 0,\n\t\t\t\tsegments: [TextSegment.make(initialText)],\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\tclientId: LocalClientId,\n\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\t\t\tfor (let i = 1; i < MaxNodesInBlock - 1; i++) {\n\t\t\t\tconst text = i.toString();\n\t\t\t\tinsertText({\n\t\t\t\t\tmergeTree,\n\t\t\t\t\tpos: mergeTree.getLength(UniversalSequenceNumber, localClientId),\n\t\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\t\tclientId: localClientId,\n\t\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\t\ttext,\n\t\t\t\t\tprops: undefined,\n\t\t\t\t\topArgs: undefined,\n\t\t\t\t});\n\t\t\t\tinitialText += text;\n\t\t\t}\n\n\t\t\tconst textHelper = new MergeTreeTextHelper(mergeTree);\n\t\t\tassert.equal(textHelper.getText(UniversalSequenceNumber, localClientId), initialText);\n\n\t\t\tconst nodes: MergeBlock[] = [mergeTree.root];\n\t\t\twhile (nodes.length > 0) {\n\t\t\t\tconst node = nodes.pop()!;\n\t\t\t\tassert.equal(node.childCount, MaxNodesInBlock - 1);\n\t\t\t\tconst childrenBlocks = node.children\n\t\t\t\t\t.map((v) => v as MergeBlock)\n\t\t\t\t\t.filter((v) => v === undefined);\n\t\t\t\tnodes.push(...childrenBlocks);\n\t\t\t}\n\n\t\t\tmergeTree.startCollaboration(\n\t\t\t\tlocalClientId,\n\t\t\t\t/* minSeq: */ UniversalSequenceNumber,\n\t\t\t\t/* currentSeq: */ UniversalSequenceNumber,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinitialText,\n\t\t\t\tmergeTree,\n\t\t\t\tmiddle: Math.round(MaxNodesInBlock / 2),\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\ttextHelper,\n\t\t\t};\n\t\t},\n\t\tname: \"Full single layer tree\",\n\t},\n\t{\n\t\tcreate: (): ITestData => {\n\t\t\tlet initialText = \"0\";\n\t\t\tconst mergeTree = new MergeTree();\n\t\t\tinsertSegments({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 0,\n\t\t\t\tsegments: [TextSegment.make(initialText)],\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\tclientId: LocalClientId,\n\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\t\t\tfor (let i = 1; i < MaxNodesInBlock * 4; i++) {\n\t\t\t\tconst text = i.toString();\n\t\t\t\tinsertText({\n\t\t\t\t\tmergeTree,\n\t\t\t\t\tpos: mergeTree.getLength(UniversalSequenceNumber, localClientId),\n\t\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\t\tclientId: localClientId,\n\t\t\t\t\tseq: UniversalSequenceNumber,\n\t\t\t\t\ttext,\n\t\t\t\t\tprops: undefined,\n\t\t\t\t\topArgs: undefined,\n\t\t\t\t});\n\t\t\t\tinitialText += text;\n\t\t\t}\n\n\t\t\tconst remove = Math.round(initialText.length / 4);\n\t\t\t// remove from start\n\t\t\tmergeTree.markRangeRemoved(\n\t\t\t\t0,\n\t\t\t\tremove,\n\t\t\t\tUniversalSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUniversalSequenceNumber,\n\t\t\t\tundefined as never,\n\t\t\t);\n\t\t\tinitialText = initialText.slice(Math.max(0, remove));\n\n\t\t\t// remove from end\n\t\t\tmergeTree.markRangeRemoved(\n\t\t\t\tinitialText.length - remove,\n\t\t\t\tinitialText.length,\n\t\t\t\tUniversalSequenceNumber,\n\t\t\t\tlocalClientId,\n\t\t\t\tUniversalSequenceNumber,\n\t\t\t\tundefined as never,\n\t\t\t);\n\t\t\tinitialText = initialText.slice(0, Math.max(0, initialText.length - remove));\n\n\t\t\tmergeTree.startCollaboration(\n\t\t\t\tlocalClientId,\n\t\t\t\t/* minSeq: */ UniversalSequenceNumber,\n\t\t\t\t/* currentSeq: */ UniversalSequenceNumber,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tinitialText,\n\t\t\t\tmergeTree,\n\t\t\t\tmiddle: Math.round(initialText.length / 2),\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\ttextHelper: new MergeTreeTextHelper(mergeTree),\n\t\t\t};\n\t\t},\n\t\tname: \"Tree with remove segments\",\n\t},\n];\n\ndescribe(\"MergeTree.insertingWalk\", () => {\n\tfor (const tf of treeFactories) {\n\t\tdescribe(tf.name, () => {\n\t\t\tconst treeFactory = tf;\n\t\t\tlet testData: ITestData;\n\t\t\tbeforeEach(() => {\n\t\t\t\ttestData = treeFactory.create();\n\t\t\t\tassert(nodeOrdinalsHaveIntegrity(testData.mergeTree.root));\n\t\t\t});\n\t\t\tafterEach(() => {\n\t\t\t\tassert(nodeOrdinalsHaveIntegrity(testData.mergeTree.root));\n\t\t\t});\n\t\t\tdescribe(\"insertText\", () => {\n\t\t\t\tit(\"at beginning\", () => {\n\t\t\t\t\tinsertText({\n\t\t\t\t\t\tmergeTree: testData.mergeTree,\n\t\t\t\t\t\tpos: 0,\n\t\t\t\t\t\trefSeq: testData.refSeq,\n\t\t\t\t\t\tclientId: localClientId,\n\t\t\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\t\t\ttext: \"a\",\n\t\t\t\t\t\tprops: undefined,\n\t\t\t\t\t\topArgs: undefined,\n\t\t\t\t\t});\n\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttestData.mergeTree.getLength(testData.refSeq, localClientId),\n\t\t\t\t\t\ttestData.initialText.length + 1,\n\t\t\t\t\t);\n\t\t\t\t\tconst currentValue = testData.textHelper.getText(testData.refSeq, localClientId);\n\t\t\t\t\tassert.equal(currentValue.length, testData.initialText.length + 1);\n\t\t\t\t\tassert.equal(currentValue, `a${testData.initialText}`);\n\t\t\t\t});\n\n\t\t\t\tit(\"at end\", () => {\n\t\t\t\t\tinsertText({\n\t\t\t\t\t\tmergeTree: testData.mergeTree,\n\t\t\t\t\t\tpos: testData.initialText.length,\n\t\t\t\t\t\trefSeq: testData.refSeq,\n\t\t\t\t\t\tclientId: localClientId,\n\t\t\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\t\t\ttext: \"a\",\n\t\t\t\t\t\tprops: undefined,\n\t\t\t\t\t\topArgs: undefined,\n\t\t\t\t\t});\n\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttestData.mergeTree.getLength(testData.refSeq, localClientId),\n\t\t\t\t\t\ttestData.initialText.length + 1,\n\t\t\t\t\t);\n\t\t\t\t\tconst currentValue = testData.textHelper.getText(testData.refSeq, localClientId);\n\t\t\t\t\tassert.equal(currentValue.length, testData.initialText.length + 1);\n\t\t\t\t\tassert.equal(currentValue, `${testData.initialText}a`);\n\t\t\t\t});\n\n\t\t\t\tit(\"in middle\", () => {\n\t\t\t\t\tinsertText({\n\t\t\t\t\t\tmergeTree: testData.mergeTree,\n\t\t\t\t\t\tpos: testData.middle,\n\t\t\t\t\t\trefSeq: testData.refSeq,\n\t\t\t\t\t\tclientId: localClientId,\n\t\t\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\t\t\ttext: \"a\",\n\t\t\t\t\t\tprops: undefined,\n\t\t\t\t\t\topArgs: undefined,\n\t\t\t\t\t});\n\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttestData.mergeTree.getLength(testData.refSeq, localClientId),\n\t\t\t\t\t\ttestData.initialText.length + 1,\n\t\t\t\t\t);\n\t\t\t\t\tconst currentValue = testData.textHelper.getText(testData.refSeq, localClientId);\n\t\t\t\t\tassert.equal(currentValue.length, testData.initialText.length + 1);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t`${testData.initialText.slice(0, Math.max(0, testData.middle))}` +\n\t\t\t\t\t\t\t\"a\" +\n\t\t\t\t\t\t\t`${testData.initialText.slice(Math.max(0, testData.middle))}`,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t}\n\n\tit(\"handles conflicts involving removed segments across block boundaries\", () => {\n\t\tlet initialText = \"0\";\n\t\tlet seq = 0;\n\t\tconst mergeTree = new MergeTree();\n\t\tmergeTree.startCollaboration(localClientId, 0, seq);\n\t\tinsertSegments({\n\t\t\tmergeTree,\n\t\t\tpos: 0,\n\t\t\tsegments: [TextSegment.make(initialText)],\n\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\tclientId: localClientId,\n\t\t\tseq: UniversalSequenceNumber,\n\t\t\topArgs: undefined,\n\t\t});\n\t\tfor (let i = 1; i < MaxNodesInBlock; i++) {\n\t\t\tconst text = String.fromCodePoint(i + 64);\n\t\t\tinsertText({\n\t\t\t\tmergeTree,\n\t\t\t\tpos: 0,\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\tclientId: localClientId,\n\t\t\t\tseq: UnassignedSequenceNumber,\n\t\t\t\ttext,\n\t\t\t\tprops: undefined,\n\t\t\t\topArgs: undefined,\n\t\t\t});\n\t\t\tinitialText += text;\n\t\t}\n\n\t\tconst textHelper = new MergeTreeTextHelper(mergeTree);\n\n\t\tassert.equal(mergeTree.root.childCount, 2);\n\t\tassert.equal(textHelper.getText(0, localClientId), \"GFEDCBA0\");\n\t\t// Remove \"DCBA\"\n\t\tmarkRangeRemoved({\n\t\t\tmergeTree,\n\t\t\tstart: 3,\n\t\t\tend: 7,\n\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\tclientId: localClientId,\n\t\t\tseq: UnassignedSequenceNumber,\n\t\t\toverwrite: false,\n\t\t\topArgs: undefined as never,\n\t\t});\n\t\tassert.equal(textHelper.getText(0, localClientId), \"GFE0\");\n\t\t// Simulate another client inserting concurrently with the above operations. Because\n\t\t// all segments but the 0 are unacked, this insert should place the segment directly\n\t\t// before the 0. Prior to this regression test, an issue with `rightExcursion` in the\n\t\t// merge conflict logic instead caused the segment to be placed before the removed segments.\n\t\tinsertText({\n\t\t\tmergeTree,\n\t\t\tpos: 0,\n\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\tclientId: localClientId + 1,\n\t\t\tseq: ++seq,\n\t\t\ttext: \"x\",\n\t\t});\n\n\t\tconst segments: string[] = [];\n\t\twalkAllChildSegments(mergeTree.root, (seg) => {\n\t\t\tif (TextSegment.is(seg)) {\n\t\t\t\tif (segmentIsRemoved(seg)) {\n\t\t\t\t\tsegments.push(`(${seg.text})`);\n\t\t\t\t} else {\n\t\t\t\t\tsegments.push(seg.text);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tassert.deepStrictEqual(segments, [\"G\", \"F\", \"E\", \"(D)\", \"(C)\", \"(B)\", \"(A)\", \"x\", \"0\"]);\n\t});\n});\n"]}
1
+ {"version":3,"file":"mergeTree.insertingWalk.spec.js","sourceRoot":"","sources":["../../src/test/mergeTree.insertingWalk.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { MergeTreeTextHelper } from \"../MergeTreeTextHelper.js\";\nimport { UniversalSequenceNumber } from \"../constants.js\";\nimport { MergeTree } from \"../mergeTree.js\";\nimport { walkAllChildSegments } from \"../mergeTreeNodeWalk.js\";\nimport { MergeBlock, MaxNodesInBlock, segmentIsRemoved } from \"../mergeTreeNodes.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport { makeRemoteClient, nodeOrdinalsHaveIntegrity } from \"./testUtils.js\";\n\ninterface ITestTreeFactory {\n\treadonly create: () => ITestData;\n\treadonly name: string;\n}\n\ninterface ITestData {\n\treadonly mergeTree: MergeTree;\n\treadonly textHelper: MergeTreeTextHelper;\n\treadonly initialText: string;\n\treadonly middle: number;\n\treadonly refSeq: number;\n}\n\nconst localClientId = 17;\nconst treeFactories: ITestTreeFactory[] = [\n\t{\n\t\tcreate: (): ITestData => {\n\t\t\tconst initialText = \"hello world\";\n\t\t\tconst mergeTree = new MergeTree();\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t0,\n\t\t\t\t[TextSegment.make(initialText)],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\tundefined,\n\t\t\t);\n\n\t\t\tmergeTree.startCollaboration(\n\t\t\t\tlocalClientId,\n\t\t\t\t/* minSeq: */ UniversalSequenceNumber,\n\t\t\t\t/* currentSeq: */ UniversalSequenceNumber,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinitialText,\n\t\t\t\tmergeTree,\n\t\t\t\tmiddle: Math.round(initialText.length / 2),\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\ttextHelper: new MergeTreeTextHelper(mergeTree),\n\t\t\t};\n\t\t},\n\t\tname: \"single segment tree\",\n\t},\n\t{\n\t\tcreate: (): ITestData => {\n\t\t\tlet initialText = \"0\";\n\t\t\tconst mergeTree = new MergeTree();\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t0,\n\t\t\t\t[TextSegment.make(initialText)],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tfor (let i = 1; i < MaxNodesInBlock - 1; i++) {\n\t\t\t\tconst text = i.toString();\n\t\t\t\tmergeTree.insertSegments(\n\t\t\t\t\tmergeTree.getLength(mergeTree.localPerspective),\n\t\t\t\t\t[TextSegment.make(text)],\n\t\t\t\t\tmergeTree.localPerspective,\n\t\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\tinitialText += text;\n\t\t\t}\n\n\t\t\tconst textHelper = new MergeTreeTextHelper(mergeTree);\n\t\t\tassert.equal(textHelper.getText(mergeTree.localPerspective), initialText);\n\n\t\t\tconst nodes: MergeBlock[] = [mergeTree.root];\n\t\t\twhile (nodes.length > 0) {\n\t\t\t\tconst node = nodes.pop()!;\n\t\t\t\tassert.equal(node.childCount, MaxNodesInBlock - 1);\n\t\t\t\tconst childrenBlocks = node.children\n\t\t\t\t\t.map((v) => v as MergeBlock)\n\t\t\t\t\t.filter((v) => v === undefined);\n\t\t\t\tnodes.push(...childrenBlocks);\n\t\t\t}\n\n\t\t\tmergeTree.startCollaboration(\n\t\t\t\tlocalClientId,\n\t\t\t\t/* minSeq: */ UniversalSequenceNumber,\n\t\t\t\t/* currentSeq: */ UniversalSequenceNumber,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tinitialText,\n\t\t\t\tmergeTree,\n\t\t\t\tmiddle: Math.round(MaxNodesInBlock / 2),\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\ttextHelper,\n\t\t\t};\n\t\t},\n\t\tname: \"Full single layer tree\",\n\t},\n\t{\n\t\tcreate: (): ITestData => {\n\t\t\tlet initialText = \"0\";\n\t\t\tconst mergeTree = new MergeTree();\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t0,\n\t\t\t\t[TextSegment.make(initialText)],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tfor (let i = 1; i < MaxNodesInBlock * 4; i++) {\n\t\t\t\tconst text = i.toString();\n\t\t\t\tmergeTree.insertSegments(\n\t\t\t\t\tmergeTree.getLength(mergeTree.localPerspective),\n\t\t\t\t\t[TextSegment.make(text)],\n\t\t\t\t\tmergeTree.localPerspective,\n\t\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t\tundefined,\n\t\t\t\t);\n\t\t\t\tinitialText += text;\n\t\t\t}\n\n\t\t\tconst remove = Math.round(initialText.length / 4);\n\t\t\t// remove from start\n\t\t\tmergeTree.markRangeRemoved(\n\t\t\t\t0,\n\t\t\t\tremove,\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\t{ clientId: localClientId, seq: UniversalSequenceNumber },\n\t\t\t\tundefined as never,\n\t\t\t);\n\t\t\tinitialText = initialText.slice(Math.max(0, remove));\n\n\t\t\t// remove from end\n\t\t\tmergeTree.markRangeRemoved(\n\t\t\t\tinitialText.length - remove,\n\t\t\t\tinitialText.length,\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\t{ clientId: localClientId, seq: UniversalSequenceNumber },\n\t\t\t\tundefined as never,\n\t\t\t);\n\t\t\tinitialText = initialText.slice(0, Math.max(0, initialText.length - remove));\n\n\t\t\tmergeTree.startCollaboration(\n\t\t\t\tlocalClientId,\n\t\t\t\t/* minSeq: */ UniversalSequenceNumber,\n\t\t\t\t/* currentSeq: */ UniversalSequenceNumber,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tinitialText,\n\t\t\t\tmergeTree,\n\t\t\t\tmiddle: Math.round(initialText.length / 2),\n\t\t\t\trefSeq: UniversalSequenceNumber,\n\t\t\t\ttextHelper: new MergeTreeTextHelper(mergeTree),\n\t\t\t};\n\t\t},\n\t\tname: \"Tree with remove segments\",\n\t},\n];\n\ndescribe(\"MergeTree.insertingWalk\", () => {\n\tfor (const tf of treeFactories) {\n\t\tdescribe(tf.name, () => {\n\t\t\tconst treeFactory = tf;\n\t\t\tlet testData: ITestData;\n\t\t\tbeforeEach(() => {\n\t\t\t\ttestData = treeFactory.create();\n\t\t\t\tassert(nodeOrdinalsHaveIntegrity(testData.mergeTree.root));\n\t\t\t});\n\t\t\tafterEach(() => {\n\t\t\t\tassert(nodeOrdinalsHaveIntegrity(testData.mergeTree.root));\n\t\t\t});\n\t\t\tdescribe(\"insertText\", () => {\n\t\t\t\tit(\"at beginning\", () => {\n\t\t\t\t\ttestData.mergeTree.insertSegments(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t[TextSegment.make(\"a\")],\n\t\t\t\t\t\ttestData.mergeTree.localPerspective,\n\t\t\t\t\t\ttestData.mergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttestData.mergeTree.getLength(testData.mergeTree.localPerspective),\n\t\t\t\t\t\ttestData.initialText.length + 1,\n\t\t\t\t\t);\n\t\t\t\t\tconst currentValue = testData.textHelper.getText(\n\t\t\t\t\t\ttestData.mergeTree.localPerspective,\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(currentValue.length, testData.initialText.length + 1);\n\t\t\t\t\tassert.equal(currentValue, `a${testData.initialText}`);\n\t\t\t\t});\n\n\t\t\t\tit(\"at end\", () => {\n\t\t\t\t\ttestData.mergeTree.insertSegments(\n\t\t\t\t\t\ttestData.initialText.length,\n\t\t\t\t\t\t[TextSegment.make(\"a\")],\n\t\t\t\t\t\ttestData.mergeTree.localPerspective,\n\t\t\t\t\t\ttestData.mergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttestData.mergeTree.getLength(testData.mergeTree.localPerspective),\n\t\t\t\t\t\ttestData.initialText.length + 1,\n\t\t\t\t\t);\n\t\t\t\t\tconst currentValue = testData.textHelper.getText(\n\t\t\t\t\t\ttestData.mergeTree.localPerspective,\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(currentValue.length, testData.initialText.length + 1);\n\t\t\t\t\tassert.equal(currentValue, `${testData.initialText}a`);\n\t\t\t\t});\n\n\t\t\t\tit(\"in middle\", () => {\n\t\t\t\t\ttestData.mergeTree.insertSegments(\n\t\t\t\t\t\ttestData.middle,\n\t\t\t\t\t\t[TextSegment.make(\"a\")],\n\t\t\t\t\t\ttestData.mergeTree.localPerspective,\n\t\t\t\t\t\ttestData.mergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t);\n\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\ttestData.mergeTree.getLength(testData.mergeTree.localPerspective),\n\t\t\t\t\t\ttestData.initialText.length + 1,\n\t\t\t\t\t);\n\t\t\t\t\tconst currentValue = testData.textHelper.getText(\n\t\t\t\t\t\ttestData.mergeTree.localPerspective,\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(currentValue.length, testData.initialText.length + 1);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t`${testData.initialText.slice(0, Math.max(0, testData.middle))}` +\n\t\t\t\t\t\t\t\"a\" +\n\t\t\t\t\t\t\t`${testData.initialText.slice(Math.max(0, testData.middle))}`,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\t}\n\n\tit(\"handles conflicts involving removed segments across block boundaries\", () => {\n\t\tlet initialText = \"0\";\n\t\tlet seq = 0;\n\t\tconst mergeTree = new MergeTree();\n\t\tmergeTree.insertSegments(\n\t\t\t0,\n\t\t\t[TextSegment.make(initialText)],\n\t\t\tmergeTree.localPerspective,\n\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\tundefined,\n\t\t);\n\t\tmergeTree.startCollaboration(localClientId, 0, seq);\n\t\tfor (let i = 1; i < MaxNodesInBlock; i++) {\n\t\t\tconst text = String.fromCodePoint(i + 64);\n\t\t\tmergeTree.insertSegments(\n\t\t\t\t0,\n\t\t\t\t[TextSegment.make(text)],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\tundefined,\n\t\t\t);\n\t\t\tinitialText += text;\n\t\t}\n\n\t\tconst textHelper = new MergeTreeTextHelper(mergeTree);\n\n\t\tassert.equal(mergeTree.root.childCount, 2);\n\t\tassert.equal(textHelper.getText(mergeTree.localPerspective), \"GFEDCBA0\");\n\t\t// Remove \"DCBA\"\n\t\tmergeTree.markRangeRemoved(\n\t\t\t3,\n\t\t\t7,\n\t\t\tmergeTree.localPerspective,\n\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\tundefined as never,\n\t\t);\n\t\tassert.equal(textHelper.getText(mergeTree.localPerspective), \"GFE0\");\n\t\t// Simulate another client inserting concurrently with the above operations. Because\n\t\t// all segments but the 0 are unacked, this insert should place the segment directly\n\t\t// before the 0. Prior to this regression test, an issue with `rightExcursion` in the\n\t\t// merge conflict logic instead caused the segment to be placed before the removed segments.\n\t\tconst remoteClient = makeRemoteClient({ clientId: localClientId + 1 });\n\t\tmergeTree.insertSegments(\n\t\t\t0,\n\t\t\t[TextSegment.make(\"x\")],\n\t\t\tremoteClient.perspectiveAt({ refSeq: 0 }),\n\t\t\tremoteClient.stampAt({ seq: ++seq }),\n\t\t\tundefined,\n\t\t);\n\n\t\tconst segments: string[] = [];\n\t\twalkAllChildSegments(mergeTree.root, (seg) => {\n\t\t\tif (TextSegment.is(seg)) {\n\t\t\t\tif (segmentIsRemoved(seg)) {\n\t\t\t\t\tsegments.push(`(${seg.text})`);\n\t\t\t\t} else {\n\t\t\t\t\tsegments.push(seg.text);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tassert.deepStrictEqual(segments, [\"G\", \"F\", \"E\", \"(D)\", \"(C)\", \"(B)\", \"(A)\", \"x\", \"0\"]);\n\t});\n\n\t// Inserting walk previously unnecessarily called `blockUpdate` for blocks even when no segment changes happened (e.g.\n\t// we called `ensureIntervalBoundary` but there was already a segment boundary at the position we wanted to ensure had one).\n\tit(\"avoids calling blockUpdate excessively\", () => {\n\t\tconst seq = 1;\n\t\tconst mergeTree = new MergeTree();\n\t\tmergeTree.startCollaboration(localClientId, 0, seq);\n\t\tfor (const char of [...\"hello world\"]) {\n\t\t\tmergeTree.insertSegments(\n\t\t\t\tmergeTree.getLength(mergeTree.localPerspective),\n\t\t\t\t[TextSegment.make(char)],\n\t\t\t\tmergeTree.localPerspective,\n\t\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\t\tundefined /* opArgs */,\n\t\t\t);\n\t\t}\n\n\t\tconst originalBlockUpdate: (block: MergeBlock) => void =\n\t\t\t// eslint-disable-next-line @typescript-eslint/dot-notation\n\t\t\t(mergeTree[\"blockUpdate\"] as (block: MergeBlock) => void).bind(mergeTree);\n\t\tconst blockUpdateCallLog: string[] = [];\n\t\t// eslint-disable-next-line @typescript-eslint/dot-notation\n\t\tmergeTree[\"blockUpdate\"] = (block: MergeBlock) => {\n\t\t\t// This is called in the middle of updating lots of merge-tree bookkeeping, so we don't want to do too much\n\t\t\t// advanced stuff here. However, walking the tree and concatenating all the text (ignoring other segment properties)\n\t\t\t// should be safe.\n\t\t\tlet text = \"\";\n\t\t\twalkAllChildSegments(block, (seg) => {\n\t\t\t\tif (TextSegment.is(seg)) {\n\t\t\t\t\ttext += seg.text;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\t\tblockUpdateCallLog.push(text);\n\t\t\toriginalBlockUpdate(block);\n\t\t};\n\n\t\tmergeTree.insertSegments(\n\t\t\t0,\n\t\t\t[TextSegment.make(\"Ot\")],\n\t\t\tmergeTree.localPerspective,\n\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\tundefined /* opArgs */,\n\t\t);\n\n\t\tassert.deepEqual(blockUpdateCallLog, [\"Othell\", \"Othello world\"]);\n\n\t\tblockUpdateCallLog.length = 0;\n\n\t\tmergeTree.markRangeRemoved(\n\t\t\t0,\n\t\t\t\"Othello world\".length,\n\t\t\tmergeTree.localPerspective,\n\t\t\tmergeTree.collabWindow.mintNextLocalOperationStamp(),\n\t\t\tundefined as never,\n\t\t);\n\n\t\t// The log ignores presence of segments. The important thing is that we only have one entry per block here.\n\t\tassert.deepEqual(blockUpdateCallLog, [\"Othell\", \"o world\", \"Othello world\"]);\n\t});\n});\n"]}