@fluidframework/sequence 2.0.0-rc.2.0.2 → 2.0.0-rc.3.0.1

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 (313) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/api-report/sequence.api.md +32 -32
  4. package/beta.d.ts +11 -0
  5. package/dist/{localValues.d.ts → IntervalCollectionValues.d.ts} +13 -12
  6. package/dist/IntervalCollectionValues.d.ts.map +1 -0
  7. package/dist/{localValues.js → IntervalCollectionValues.js} +6 -6
  8. package/dist/IntervalCollectionValues.js.map +1 -0
  9. package/dist/beta.d.ts +12 -0
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +10 -10
  13. package/dist/index.js.map +1 -1
  14. package/dist/intervalCollection.d.ts +10 -10
  15. package/dist/intervalCollection.d.ts.map +1 -1
  16. package/dist/intervalCollection.js +103 -99
  17. package/dist/intervalCollection.js.map +1 -1
  18. package/dist/{defaultMap.d.ts → intervalCollectionMap.d.ts} +11 -44
  19. package/dist/intervalCollectionMap.d.ts.map +1 -0
  20. package/dist/{defaultMap.js → intervalCollectionMap.js} +15 -70
  21. package/dist/intervalCollectionMap.js.map +1 -0
  22. package/dist/{defaultMapInterfaces.d.ts → intervalCollectionMapInterfaces.d.ts} +17 -16
  23. package/dist/intervalCollectionMapInterfaces.d.ts.map +1 -0
  24. package/dist/{defaultMapInterfaces.js → intervalCollectionMapInterfaces.js} +1 -1
  25. package/dist/intervalCollectionMapInterfaces.js.map +1 -0
  26. package/dist/intervalIndex/endpointInRangeIndex.d.ts +1 -1
  27. package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
  28. package/dist/intervalIndex/endpointInRangeIndex.js +3 -3
  29. package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -1
  30. package/dist/intervalIndex/endpointIndex.d.ts +1 -1
  31. package/dist/intervalIndex/endpointIndex.d.ts.map +1 -1
  32. package/dist/intervalIndex/endpointIndex.js +3 -3
  33. package/dist/intervalIndex/endpointIndex.js.map +1 -1
  34. package/dist/intervalIndex/idIntervalIndex.d.ts.map +1 -1
  35. package/dist/intervalIndex/idIntervalIndex.js +3 -3
  36. package/dist/intervalIndex/idIntervalIndex.js.map +1 -1
  37. package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +3 -3
  38. package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
  39. package/dist/intervalIndex/overlappingIntervalsIndex.js +2 -3
  40. package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  41. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
  42. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +6 -6
  43. package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  44. package/dist/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
  45. package/dist/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
  46. package/dist/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
  47. package/dist/intervalIndex/startpointInRangeIndex.d.ts +1 -1
  48. package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
  49. package/dist/intervalIndex/startpointInRangeIndex.js +3 -3
  50. package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -1
  51. package/dist/intervalTree.d.ts +1 -1
  52. package/dist/intervalTree.d.ts.map +1 -1
  53. package/dist/intervalTree.js +2 -2
  54. package/dist/intervalTree.js.map +1 -1
  55. package/dist/intervals/interval.d.ts +1 -1
  56. package/dist/intervals/interval.d.ts.map +1 -1
  57. package/dist/intervals/interval.js +10 -10
  58. package/dist/intervals/interval.js.map +1 -1
  59. package/dist/intervals/intervalUtils.d.ts +1 -1
  60. package/dist/intervals/intervalUtils.d.ts.map +1 -1
  61. package/dist/intervals/intervalUtils.js +5 -5
  62. package/dist/intervals/intervalUtils.js.map +1 -1
  63. package/dist/intervals/sequenceInterval.d.ts +1 -1
  64. package/dist/intervals/sequenceInterval.d.ts.map +1 -1
  65. package/dist/intervals/sequenceInterval.js +34 -34
  66. package/dist/intervals/sequenceInterval.js.map +1 -1
  67. package/dist/legacy.d.ts +61 -0
  68. package/dist/packageVersion.d.ts +1 -1
  69. package/dist/packageVersion.js +1 -1
  70. package/dist/packageVersion.js.map +1 -1
  71. package/dist/public.d.ts +12 -0
  72. package/dist/revertibles.d.ts +2 -2
  73. package/dist/revertibles.d.ts.map +1 -1
  74. package/dist/revertibles.js +34 -34
  75. package/dist/revertibles.js.map +1 -1
  76. package/dist/sequence.d.ts +7 -6
  77. package/dist/sequence.d.ts.map +1 -1
  78. package/dist/sequence.js +34 -34
  79. package/dist/sequence.js.map +1 -1
  80. package/dist/sequenceDeltaEvent.d.ts +1 -1
  81. package/dist/sequenceDeltaEvent.d.ts.map +1 -1
  82. package/dist/sequenceDeltaEvent.js +4 -4
  83. package/dist/sequenceDeltaEvent.js.map +1 -1
  84. package/dist/sequenceFactory.d.ts +1 -1
  85. package/dist/sequenceFactory.d.ts.map +1 -1
  86. package/dist/sequenceFactory.js +3 -3
  87. package/dist/sequenceFactory.js.map +1 -1
  88. package/dist/sharedIntervalCollection.d.ts +4 -3
  89. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  90. package/dist/sharedIntervalCollection.js +5 -5
  91. package/dist/sharedIntervalCollection.js.map +1 -1
  92. package/dist/sharedSequence.d.ts +3 -2
  93. package/dist/sharedSequence.d.ts.map +1 -1
  94. package/dist/sharedSequence.js +4 -4
  95. package/dist/sharedSequence.js.map +1 -1
  96. package/dist/sharedString.d.ts +2 -2
  97. package/dist/sharedString.d.ts.map +1 -1
  98. package/dist/sharedString.js +9 -9
  99. package/dist/sharedString.js.map +1 -1
  100. package/internal.d.ts +11 -0
  101. package/legacy.d.ts +11 -0
  102. package/lib/{localValues.d.ts → IntervalCollectionValues.d.ts} +13 -12
  103. package/lib/IntervalCollectionValues.d.ts.map +1 -0
  104. package/lib/{localValues.js → IntervalCollectionValues.js} +3 -3
  105. package/lib/IntervalCollectionValues.js.map +1 -0
  106. package/lib/beta.d.ts +12 -0
  107. package/lib/index.d.ts +2 -2
  108. package/lib/index.d.ts.map +1 -1
  109. package/lib/index.js +1 -1
  110. package/lib/index.js.map +1 -1
  111. package/lib/intervalCollection.d.ts +10 -10
  112. package/lib/intervalCollection.d.ts.map +1 -1
  113. package/lib/intervalCollection.js +8 -4
  114. package/lib/intervalCollection.js.map +1 -1
  115. package/lib/{defaultMap.d.ts → intervalCollectionMap.d.ts} +11 -44
  116. package/lib/intervalCollectionMap.d.ts.map +1 -0
  117. package/lib/{defaultMap.js → intervalCollectionMap.js} +8 -63
  118. package/lib/intervalCollectionMap.js.map +1 -0
  119. package/lib/{defaultMapInterfaces.d.ts → intervalCollectionMapInterfaces.d.ts} +17 -16
  120. package/lib/intervalCollectionMapInterfaces.d.ts.map +1 -0
  121. package/lib/{defaultMapInterfaces.js → intervalCollectionMapInterfaces.js} +1 -1
  122. package/lib/intervalCollectionMapInterfaces.js.map +1 -0
  123. package/lib/intervalIndex/endpointInRangeIndex.d.ts +1 -1
  124. package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
  125. package/lib/intervalIndex/endpointInRangeIndex.js +1 -1
  126. package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -1
  127. package/lib/intervalIndex/endpointIndex.d.ts +1 -1
  128. package/lib/intervalIndex/endpointIndex.d.ts.map +1 -1
  129. package/lib/intervalIndex/endpointIndex.js +1 -1
  130. package/lib/intervalIndex/endpointIndex.js.map +1 -1
  131. package/lib/intervalIndex/idIntervalIndex.d.ts.map +1 -1
  132. package/lib/intervalIndex/idIntervalIndex.js +1 -1
  133. package/lib/intervalIndex/idIntervalIndex.js.map +1 -1
  134. package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +3 -3
  135. package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
  136. package/lib/intervalIndex/overlappingIntervalsIndex.js +2 -3
  137. package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
  138. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
  139. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +2 -2
  140. package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
  141. package/lib/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
  142. package/lib/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
  143. package/lib/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
  144. package/lib/intervalIndex/startpointInRangeIndex.d.ts +1 -1
  145. package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
  146. package/lib/intervalIndex/startpointInRangeIndex.js +1 -1
  147. package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -1
  148. package/lib/intervalTree.d.ts +1 -1
  149. package/lib/intervalTree.d.ts.map +1 -1
  150. package/lib/intervalTree.js +1 -1
  151. package/lib/intervalTree.js.map +1 -1
  152. package/lib/intervals/interval.d.ts +1 -1
  153. package/lib/intervals/interval.d.ts.map +1 -1
  154. package/lib/intervals/interval.js +3 -3
  155. package/lib/intervals/interval.js.map +1 -1
  156. package/lib/intervals/intervalUtils.d.ts +1 -1
  157. package/lib/intervals/intervalUtils.d.ts.map +1 -1
  158. package/lib/intervals/intervalUtils.js +1 -1
  159. package/lib/intervals/intervalUtils.js.map +1 -1
  160. package/lib/intervals/sequenceInterval.d.ts +1 -1
  161. package/lib/intervals/sequenceInterval.d.ts.map +1 -1
  162. package/lib/intervals/sequenceInterval.js +3 -3
  163. package/lib/intervals/sequenceInterval.js.map +1 -1
  164. package/lib/legacy.d.ts +61 -0
  165. package/lib/packageVersion.d.ts +1 -1
  166. package/lib/packageVersion.js +1 -1
  167. package/lib/packageVersion.js.map +1 -1
  168. package/lib/public.d.ts +12 -0
  169. package/lib/revertibles.d.ts +2 -2
  170. package/lib/revertibles.d.ts.map +1 -1
  171. package/lib/revertibles.js +3 -4
  172. package/lib/revertibles.js.map +1 -1
  173. package/lib/sequence.d.ts +7 -6
  174. package/lib/sequence.d.ts.map +1 -1
  175. package/lib/sequence.js +11 -12
  176. package/lib/sequence.js.map +1 -1
  177. package/lib/sequenceDeltaEvent.d.ts +1 -1
  178. package/lib/sequenceDeltaEvent.d.ts.map +1 -1
  179. package/lib/sequenceDeltaEvent.js +3 -4
  180. package/lib/sequenceDeltaEvent.js.map +1 -1
  181. package/lib/sequenceFactory.d.ts +1 -1
  182. package/lib/sequenceFactory.d.ts.map +1 -1
  183. package/lib/sequenceFactory.js +1 -1
  184. package/lib/sequenceFactory.js.map +1 -1
  185. package/lib/sharedIntervalCollection.d.ts +4 -3
  186. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  187. package/lib/sharedIntervalCollection.js +4 -4
  188. package/lib/sharedIntervalCollection.js.map +1 -1
  189. package/lib/sharedSequence.d.ts +3 -2
  190. package/lib/sharedSequence.d.ts.map +1 -1
  191. package/lib/sharedSequence.js +2 -2
  192. package/lib/sharedSequence.js.map +1 -1
  193. package/lib/sharedString.d.ts +2 -2
  194. package/lib/sharedString.d.ts.map +1 -1
  195. package/lib/sharedString.js +1 -1
  196. package/lib/sharedString.js.map +1 -1
  197. package/package.json +41 -58
  198. package/src/{localValues.ts → IntervalCollectionValues.ts} +26 -18
  199. package/src/index.ts +2 -2
  200. package/src/intervalCollection.ts +46 -47
  201. package/src/{defaultMap.ts → intervalCollectionMap.ts} +42 -105
  202. package/src/{defaultMapInterfaces.ts → intervalCollectionMapInterfaces.ts} +26 -16
  203. package/src/intervalIndex/endpointInRangeIndex.ts +4 -1
  204. package/src/intervalIndex/endpointIndex.ts +4 -1
  205. package/src/intervalIndex/idIntervalIndex.ts +4 -2
  206. package/src/intervalIndex/overlappingIntervalsIndex.ts +8 -5
  207. package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +6 -3
  208. package/src/intervalIndex/sequenceIntervalIndexes.ts +3 -1
  209. package/src/intervalIndex/startpointInRangeIndex.ts +4 -1
  210. package/src/intervalTree.ts +4 -3
  211. package/src/intervals/interval.ts +6 -3
  212. package/src/intervals/intervalUtils.ts +4 -2
  213. package/src/intervals/sequenceInterval.ts +5 -3
  214. package/src/packageVersion.ts +1 -1
  215. package/src/revertibles.ts +10 -10
  216. package/src/sequence.ts +24 -31
  217. package/src/sequenceDeltaEvent.ts +3 -4
  218. package/src/sequenceFactory.ts +4 -3
  219. package/src/sharedIntervalCollection.ts +12 -18
  220. package/src/sharedSequence.ts +9 -6
  221. package/src/sharedString.ts +4 -3
  222. package/api-extractor-cjs.json +0 -8
  223. package/dist/defaultMap.d.ts.map +0 -1
  224. package/dist/defaultMap.js.map +0 -1
  225. package/dist/defaultMapInterfaces.d.ts.map +0 -1
  226. package/dist/defaultMapInterfaces.js.map +0 -1
  227. package/dist/localValues.d.ts.map +0 -1
  228. package/dist/localValues.js.map +0 -1
  229. package/dist/sequence-alpha.d.ts +0 -1432
  230. package/dist/sequence-beta.d.ts +0 -246
  231. package/dist/sequence-public.d.ts +0 -246
  232. package/dist/sequence-untrimmed.d.ts +0 -1820
  233. package/lib/defaultMap.d.ts.map +0 -1
  234. package/lib/defaultMap.js.map +0 -1
  235. package/lib/defaultMapInterfaces.d.ts.map +0 -1
  236. package/lib/defaultMapInterfaces.js.map +0 -1
  237. package/lib/localValues.d.ts.map +0 -1
  238. package/lib/localValues.js.map +0 -1
  239. package/lib/sequence-alpha.d.ts +0 -1432
  240. package/lib/sequence-beta.d.ts +0 -246
  241. package/lib/sequence-public.d.ts +0 -246
  242. package/lib/sequence-untrimmed.d.ts +0 -1820
  243. package/lib/test/collections.intervalTree.js +0 -73
  244. package/lib/test/collections.intervalTree.js.map +0 -1
  245. package/lib/test/createSnapshotFiles.js +0 -15
  246. package/lib/test/createSnapshotFiles.js.map +0 -1
  247. package/lib/test/dirname.cjs +0 -16
  248. package/lib/test/dirname.cjs.map +0 -1
  249. package/lib/test/endpointInRangeIndex.spec.js +0 -182
  250. package/lib/test/endpointInRangeIndex.spec.js.map +0 -1
  251. package/lib/test/fuzz/fuzzUtils.js +0 -250
  252. package/lib/test/fuzz/fuzzUtils.js.map +0 -1
  253. package/lib/test/fuzz/intervalCollection.fuzz.spec.js +0 -200
  254. package/lib/test/fuzz/intervalCollection.fuzz.spec.js.map +0 -1
  255. package/lib/test/fuzz/intervalRevertibles.fuzz.spec.js +0 -129
  256. package/lib/test/fuzz/intervalRevertibles.fuzz.spec.js.map +0 -1
  257. package/lib/test/fuzz/sharedString.fuzz.spec.js +0 -91
  258. package/lib/test/fuzz/sharedString.fuzz.spec.js.map +0 -1
  259. package/lib/test/generateSharedStrings.js +0 -138
  260. package/lib/test/generateSharedStrings.js.map +0 -1
  261. package/lib/test/intervalCollection.detached.spec.js +0 -126
  262. package/lib/test/intervalCollection.detached.spec.js.map +0 -1
  263. package/lib/test/intervalCollection.events.spec.js +0 -491
  264. package/lib/test/intervalCollection.events.spec.js.map +0 -1
  265. package/lib/test/intervalCollection.perf.spec.js +0 -88
  266. package/lib/test/intervalCollection.perf.spec.js.map +0 -1
  267. package/lib/test/intervalCollection.snapshot.spec.js +0 -171
  268. package/lib/test/intervalCollection.snapshot.spec.js.map +0 -1
  269. package/lib/test/intervalCollection.spec.js +0 -1660
  270. package/lib/test/intervalCollection.spec.js.map +0 -1
  271. package/lib/test/intervalIndexTestUtils.js +0 -49
  272. package/lib/test/intervalIndexTestUtils.js.map +0 -1
  273. package/lib/test/intervalRebasing.spec.js +0 -589
  274. package/lib/test/intervalRebasing.spec.js.map +0 -1
  275. package/lib/test/intervalStashedOps.spec.js +0 -142
  276. package/lib/test/intervalStashedOps.spec.js.map +0 -1
  277. package/lib/test/intervalTestUtils.js +0 -81
  278. package/lib/test/intervalTestUtils.js.map +0 -1
  279. package/lib/test/marshalling.spec.js +0 -55
  280. package/lib/test/marshalling.spec.js.map +0 -1
  281. package/lib/test/memory/sharedSequence.spec.js +0 -82
  282. package/lib/test/memory/sharedSequence.spec.js.map +0 -1
  283. package/lib/test/memory/sharedString.spec.js +0 -134
  284. package/lib/test/memory/sharedString.spec.js.map +0 -1
  285. package/lib/test/overlappingSequenceIntervalsIndex.spec.js +0 -348
  286. package/lib/test/overlappingSequenceIntervalsIndex.spec.js.map +0 -1
  287. package/lib/test/partialLoad.spec.js +0 -211
  288. package/lib/test/partialLoad.spec.js.map +0 -1
  289. package/lib/test/rebasing.spec.js +0 -81
  290. package/lib/test/rebasing.spec.js.map +0 -1
  291. package/lib/test/reentrancy.spec.js +0 -174
  292. package/lib/test/reentrancy.spec.js.map +0 -1
  293. package/lib/test/revertibles.spec.js +0 -971
  294. package/lib/test/revertibles.spec.js.map +0 -1
  295. package/lib/test/sequenceDeltaEvent.spec.js +0 -2144
  296. package/lib/test/sequenceDeltaEvent.spec.js.map +0 -1
  297. package/lib/test/sharedIntervalCollection.spec.js +0 -159
  298. package/lib/test/sharedIntervalCollection.spec.js.map +0 -1
  299. package/lib/test/sharedString.spec.js +0 -532
  300. package/lib/test/sharedString.spec.js.map +0 -1
  301. package/lib/test/snapshotEmptyProps.spec.js +0 -45
  302. package/lib/test/snapshotEmptyProps.spec.js.map +0 -1
  303. package/lib/test/snapshotVersion.spec.js +0 -149
  304. package/lib/test/snapshotVersion.spec.js.map +0 -1
  305. package/lib/test/startpointInRangeIndex.spec.js +0 -182
  306. package/lib/test/startpointInRangeIndex.spec.js.map +0 -1
  307. package/lib/test/subSequence.spec.js +0 -92
  308. package/lib/test/subSequence.spec.js.map +0 -1
  309. package/lib/test/types/validateSequencePrevious.generated.js +0 -162
  310. package/lib/test/types/validateSequencePrevious.generated.js.map +0 -1
  311. package/lib/test/v1IntervalCollectionHelpers.js +0 -93
  312. package/lib/test/v1IntervalCollectionHelpers.js.map +0 -1
  313. /package/{dist → lib}/tsdoc-metadata.json +0 -0
@@ -1,2144 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { strict as assert } from "assert";
6
- import { isNullOrUndefined } from "util";
7
- import { createAnnotateRangeOp, createInsertSegmentOp, createRemoveRangeOp, TextSegment, } from "@fluidframework/merge-tree";
8
- // eslint-disable-next-line import/no-internal-modules
9
- import { TestClient } from "@fluidframework/merge-tree/test";
10
- import { SequenceDeltaEvent } from "../sequenceDeltaEvent.js";
11
- describe("non-collab", () => {
12
- const userId = "localUser";
13
- let client;
14
- describe("insert", () => {
15
- before(() => {
16
- client = new TestClient();
17
- client.startOrUpdateCollaboration(userId);
18
- });
19
- const initialText = "done";
20
- const beginningText = "What's ";
21
- const middleText = " is";
22
- const endText = " done";
23
- it("initially", () => {
24
- insertText(0, initialText);
25
- });
26
- it("in the beginning", () => {
27
- insertText(0, beginningText);
28
- });
29
- it("in the end", () => {
30
- insertText(client.getLength(), endText);
31
- });
32
- it("in the middle", () => {
33
- insertText(initialText.length + beginningText.length, middleText);
34
- });
35
- function insertText(offset, text) {
36
- let deltaArgs;
37
- client.on("delta", (opArgs, delta) => {
38
- deltaArgs = delta;
39
- });
40
- const op = client.insertTextLocal(offset, text);
41
- assert(deltaArgs);
42
- assert.equal(deltaArgs.deltaSegments.length, 1);
43
- assert(op);
44
- const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
45
- assert(event.isLocal);
46
- assert.equal(event.ranges.length, 1);
47
- assert.equal(event.first.position, offset);
48
- assert.equal(event.first.segment.cachedLength, text.length);
49
- assert.equal(event.last.position + event.last.segment.cachedLength, offset + text.length);
50
- const segment = event.first.segment;
51
- assert.equal(segment.text, text);
52
- }
53
- });
54
- describe("remove", () => {
55
- before(() => {
56
- client = new TestClient();
57
- client.insertTextLocal(0, "All is well!");
58
- client.startOrUpdateCollaboration(userId);
59
- });
60
- it("from the middle", () => {
61
- removeText(3, 7);
62
- });
63
- it("from the beginning", () => {
64
- removeText(0, 3);
65
- });
66
- it("from the end", () => {
67
- removeText(4, 5);
68
- });
69
- it("all", () => {
70
- removeText(0, client.getLength());
71
- });
72
- function removeText(start, end) {
73
- let deltaArgs;
74
- client.on("delta", (opArgs, delta) => {
75
- deltaArgs = delta;
76
- });
77
- const op = client.removeRangeLocal(start, end);
78
- assert(deltaArgs);
79
- assert.equal(deltaArgs.deltaSegments.length, 1);
80
- assert(op);
81
- const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
82
- assert(event.isLocal);
83
- assert.equal(event.ranges.length, 1);
84
- assert.equal(event.first.position, start);
85
- assert.equal(event.first.segment.cachedLength, end - start);
86
- assert.equal(event.last.position + event.last.segment.cachedLength, end);
87
- }
88
- });
89
- describe("annotate", () => {
90
- before(() => {
91
- client = new TestClient();
92
- client.insertTextLocal(0, "All is well!");
93
- client.startOrUpdateCollaboration(userId);
94
- });
95
- it("add property over separate range", () => {
96
- annotateText(0, 3, { foo1: "bar1" }, [
97
- { offset: 0, numChar: 3, props: { foo1: "bar1" }, propDeltas: { foo1: null } },
98
- ]);
99
- annotateText(3, 7, { foo2: "bar2" }, [
100
- { offset: 3, numChar: 4, props: { foo2: "bar2" }, propDeltas: { foo2: null } },
101
- ]);
102
- annotateText(7, client.getLength(), { foo3: "bar3" }, [
103
- { offset: 7, numChar: 5, props: { foo3: "bar3" }, propDeltas: { foo3: null } },
104
- ]);
105
- });
106
- it("add property over overlapping runs", () => {
107
- annotateText(2, 10, { foo: "bar" }, [
108
- {
109
- offset: 2,
110
- numChar: 1,
111
- props: { foo: "bar", foo1: "bar1" },
112
- propDeltas: { foo: null },
113
- },
114
- {
115
- offset: 3,
116
- numChar: 4,
117
- props: { foo: "bar", foo2: "bar2" },
118
- propDeltas: { foo: null },
119
- },
120
- {
121
- offset: 7,
122
- numChar: 3,
123
- props: { foo: "bar", foo3: "bar3" },
124
- propDeltas: { foo: null },
125
- },
126
- ]);
127
- });
128
- it("nullify all properties", () => {
129
- annotateText(2, 10, { foo: undefined }, [
130
- {
131
- offset: 2,
132
- numChar: 1,
133
- props: { foo: undefined, foo1: "bar1" },
134
- propDeltas: { foo: "bar" },
135
- },
136
- {
137
- offset: 3,
138
- numChar: 4,
139
- props: { foo: undefined, foo2: "bar2" },
140
- propDeltas: { foo: "bar" },
141
- },
142
- {
143
- offset: 7,
144
- numChar: 3,
145
- props: { foo: undefined, foo3: "bar3" },
146
- propDeltas: { foo: "bar" },
147
- },
148
- ]);
149
- annotateText(2, 3, { foo1: undefined }, [
150
- {
151
- offset: 2,
152
- numChar: 1,
153
- props: { foo: undefined, foo1: undefined },
154
- propDeltas: { foo1: "bar1" },
155
- },
156
- ]);
157
- annotateText(3, 7, { foo2: undefined }, [
158
- {
159
- offset: 3,
160
- numChar: 4,
161
- props: { foo: undefined, foo2: undefined },
162
- propDeltas: { foo2: "bar2" },
163
- },
164
- ]);
165
- annotateText(7, 10, { foo3: undefined }, [
166
- {
167
- offset: 7,
168
- numChar: 3,
169
- props: { foo: undefined, foo3: undefined },
170
- propDeltas: { foo3: "bar3" },
171
- },
172
- ]);
173
- });
174
- function annotateText(start, end, newProps, expected) {
175
- let deltaArgs;
176
- client.on("delta", (opArgs, delta) => {
177
- deltaArgs = delta;
178
- });
179
- const op = client.annotateRangeLocal(start, end, newProps);
180
- assert(deltaArgs);
181
- assert.equal(deltaArgs.deltaSegments.length, expected.length);
182
- assert(op);
183
- const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
184
- assert(event.isLocal);
185
- assert.equal(event.first.position, start);
186
- assert.equal(event.last.position + event.last.segment.cachedLength, end);
187
- assert.equal(event.ranges.length, expected.length);
188
- for (let i = 0; i < expected.length; i = i + 1) {
189
- assert.equal(event.ranges[i].position, expected[i].offset);
190
- assert.equal(event.ranges[i].segment.cachedLength, expected[i].numChar);
191
- assert.equal(Object.keys(event.ranges[i].segment.properties ?? {}).length, Object.keys(expected[i].props).length);
192
- for (const key of Object.keys(event.ranges[i].segment.properties ?? {})) {
193
- assert.equal(event.ranges[i].segment.properties?.[key], expected[i].props[key]);
194
- }
195
- if (expected[i].propDeltas !== undefined) {
196
- assert.equal(Object.keys(event.ranges[i].propertyDeltas).length, Object.keys(expected[i].propDeltas ?? {}).length);
197
- for (const key of Object.keys(event.ranges[i].propertyDeltas)) {
198
- assert.equal(event.ranges[i].propertyDeltas[key], expected[i].propDeltas?.[key]);
199
- }
200
- }
201
- else {
202
- assert(event.ranges[i].propertyDeltas === undefined);
203
- }
204
- }
205
- }
206
- });
207
- });
208
- describe("collab", () => {
209
- const localUserId = "localUser";
210
- const remoteUserId = "remoteUser";
211
- let client;
212
- describe("insert", () => {
213
- beforeEach(() => {
214
- client = new TestClient();
215
- client.insertTextLocal(0, "The fox jumps over the dog");
216
- client.startOrUpdateCollaboration(localUserId);
217
- });
218
- it("separate regions, local before remote", () => {
219
- const localInsertPos = 4; // before "brown"
220
- const localInsertText = "quick brown ";
221
- const remoteInsertPos = client.getLength() - 3; // before "dog"
222
- const remoteInsertText = "lazy ";
223
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
224
- let event;
225
- client.on("delta", (clientArgs, mergeTreeArgs) => {
226
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
227
- });
228
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
229
- client.applyMsg(localInsertMessage);
230
- assert(event);
231
- assert(event.isLocal);
232
- assert.equal(event.first.position, localInsertPos);
233
- assert.equal(event.last.position, localInsertPos);
234
- assert.equal(event.first.segment.cachedLength, localInsertText.length);
235
- assert.equal(event.last.segment.cachedLength, localInsertText.length);
236
- assert.equal(event.ranges.length, 1);
237
- const segment1 = event.first.segment;
238
- assert.equal(segment1.text, localInsertText);
239
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
240
- remoteUserId);
241
- client.applyMsg(remoteInsertMessage);
242
- assert(!event.isLocal);
243
- assert.equal(event.first.position, remoteInsertPos + localInsertText.length);
244
- assert.equal(event.last.position, remoteInsertPos + localInsertText.length);
245
- assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
246
- assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
247
- assert.equal(event.ranges.length, 1);
248
- const segment2 = event.first.segment;
249
- assert.equal(segment2.text, remoteInsertText);
250
- });
251
- it("separate regions, remote before local", () => {
252
- const localInsertPos = client.getLength() - 3; // before "dog"
253
- const localInsertText = "lazy ";
254
- const remoteInsertPos = 4; // before "fox"
255
- const remoteInsertText = "quick brown ";
256
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
257
- let event;
258
- client.on("delta", (clientArgs, mergeTreeArgs) => {
259
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
260
- });
261
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 2, currentSeqNumber);
262
- assert(event);
263
- assert(event.isLocal);
264
- assert.equal(event.first.position, localInsertPos);
265
- assert.equal(event.last.position, localInsertPos);
266
- assert.equal(event.first.segment.cachedLength, localInsertText.length);
267
- assert.equal(event.last.segment.cachedLength, localInsertText.length);
268
- assert.equal(event.ranges.length, 1);
269
- const segment1 = event.first.segment;
270
- assert.equal(segment1.text, localInsertText);
271
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
272
- remoteUserId);
273
- client.applyMsg(remoteInsertMessage);
274
- client.applyMsg(localInsertMessage);
275
- assert(!event.isLocal);
276
- assert.equal(event.first.position, remoteInsertPos);
277
- assert.equal(event.last.position, remoteInsertPos);
278
- assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
279
- assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
280
- assert.equal(event.ranges.length, 1);
281
- const segment2 = event.first.segment;
282
- assert.equal(segment2.text, remoteInsertText);
283
- });
284
- it("at same position, local before remote", () => {
285
- const localInsertPos = 4; // before "fox"
286
- const localInsertText = "brown ";
287
- const remoteInsertPos = 4; // before "fox"
288
- const remoteInsertText = "quick ";
289
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
290
- let event;
291
- client.on("delta", (clientArgs, mergeTreeArgs) => {
292
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
293
- });
294
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
295
- client.applyMsg(localInsertMessage);
296
- assert(event);
297
- assert(event.isLocal);
298
- assert.equal(event.first.position, localInsertPos);
299
- assert.equal(event.last.position, localInsertPos);
300
- assert.equal(event.first.segment.cachedLength, localInsertText.length);
301
- assert.equal(event.last.segment.cachedLength, localInsertText.length);
302
- assert.equal(event.ranges.length, 1);
303
- const segment1 = event.first.segment;
304
- assert.equal(segment1.text, localInsertText);
305
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 2, currentSeqNumber, // refseq
306
- remoteUserId);
307
- client.applyMsg(remoteInsertMessage);
308
- assert(!event.isLocal);
309
- assert.equal(event.first.position, remoteInsertPos);
310
- assert.equal(event.last.position, remoteInsertPos);
311
- assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
312
- assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
313
- assert.equal(event.ranges.length, 1);
314
- assert.equal(event.first.position, remoteInsertPos);
315
- const segment2 = event.first.segment;
316
- assert.equal(segment2.text, remoteInsertText);
317
- });
318
- it("at same position, remote before local", () => {
319
- const localInsertPos = 4; // before "fox"
320
- const localInsertText = "quick ";
321
- const remoteInsertPos = 4; // before "fox"
322
- const remoteInsertText = "brown ";
323
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
324
- let event;
325
- client.on("delta", (clientArgs, mergeTreeArgs) => {
326
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
327
- });
328
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 2, currentSeqNumber);
329
- assert(event);
330
- assert(event.isLocal);
331
- assert.equal(event.ranges.length, 1);
332
- assert.equal(event.first.position, localInsertPos);
333
- assert.equal(event.last.position, localInsertPos);
334
- assert.equal(event.first.segment.cachedLength, localInsertText.length);
335
- assert.equal(event.last.segment.cachedLength, localInsertText.length);
336
- const segment1 = event.first.segment;
337
- assert.equal(segment1.text, localInsertText);
338
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseq
339
- remoteUserId);
340
- client.applyMsg(remoteInsertMessage);
341
- client.applyMsg(localInsertMessage);
342
- assert(!event.isLocal);
343
- assert.equal(event.ranges.length, 1);
344
- assert.equal(event.first.position, remoteInsertPos + localInsertText.length);
345
- assert.equal(event.last.position, remoteInsertPos + localInsertText.length);
346
- assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
347
- assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
348
- const segment2 = event.first.segment;
349
- assert.equal(segment2.text, remoteInsertText);
350
- });
351
- it("overlapping regions, local before remote", () => {
352
- const localInsertPos = 4; // before "fox"
353
- const localInsertText = "quick brown ";
354
- const remoteInsertPos = 3; // before "fox"
355
- const remoteInsertText = " legendary";
356
- // output: The legendary quick brown fox jumps over the dog
357
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
358
- let event;
359
- client.on("delta", (clientArgs, mergeTreeArgs) => {
360
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
361
- });
362
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
363
- client.applyMsg(localInsertMessage);
364
- assert(event);
365
- assert(event.isLocal);
366
- assert.equal(event.first.position, localInsertPos);
367
- assert.equal(event.last.position, localInsertPos);
368
- assert.equal(event.first.segment.cachedLength, localInsertText.length);
369
- assert.equal(event.last.segment.cachedLength, localInsertText.length);
370
- assert.equal(event.ranges.length, 1);
371
- const segment1 = event.first.segment;
372
- assert.equal(segment1.text, localInsertText);
373
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 2, currentSeqNumber, // refseq
374
- remoteUserId);
375
- client.applyMsg(remoteInsertMessage);
376
- assert(!event.isLocal);
377
- assert.equal(event.first.position, remoteInsertPos);
378
- assert.equal(event.last.position, remoteInsertPos);
379
- assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
380
- assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
381
- assert.equal(event.ranges.length, 1);
382
- const segment2 = event.first.segment;
383
- assert.equal(segment2.text, remoteInsertText);
384
- });
385
- it("overlapping regions, remote before local", () => {
386
- const localInsertPos = 3; // before "fox"
387
- const localInsertText = " legendary";
388
- const remoteInsertPos = 4; // before "fox"
389
- const remoteInsertText = "quick brown ";
390
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
391
- let event;
392
- client.on("delta", (clientArgs, mergeTreeArgs) => {
393
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
394
- });
395
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 2, currentSeqNumber);
396
- assert(event);
397
- assert(event.isLocal);
398
- assert.equal(event.first.position, localInsertPos);
399
- assert.equal(event.last.position, localInsertPos);
400
- assert.equal(event.first.segment.cachedLength, localInsertText.length);
401
- assert.equal(event.last.segment.cachedLength, localInsertText.length);
402
- assert.equal(event.ranges.length, 1);
403
- const segment1 = event.first.segment;
404
- assert.equal(segment1.text, localInsertText);
405
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseq
406
- remoteUserId);
407
- client.applyMsg(remoteInsertMessage);
408
- client.applyMsg(localInsertMessage);
409
- assert(!event.isLocal);
410
- assert.equal(event.first.position, remoteInsertPos + localInsertText.length);
411
- assert.equal(event.last.position, remoteInsertPos + localInsertText.length);
412
- assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
413
- assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
414
- assert.equal(event.ranges.length, 1);
415
- const segment2 = event.first.segment;
416
- assert.equal(segment2.text, remoteInsertText);
417
- });
418
- it("overlapping regions, multiple inserts: local, remote, remoteAfterLocal", () => {
419
- const localInsertPos = 4; // before "fox"
420
- const localInsertText = "brown ";
421
- const remoteInsertPos1 = 4; // before "fox", and before local update
422
- const remoteInsertText1 = "quick ";
423
- // before "fox", but after local update
424
- const remoteInsertPos2 = client.getLength() - 3 + localInsertText.length + remoteInsertText1.length;
425
- const remoteInsertText2 = "lazy ";
426
- // output: The quick brown fox jumps over the lazy dog
427
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
428
- let event;
429
- client.on("delta", (clientArgs, mergeTreeArgs) => {
430
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
431
- });
432
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
433
- client.applyMsg(localInsertMessage);
434
- assert(event);
435
- assert(event.isLocal);
436
- assert.equal(event.first.position, localInsertPos);
437
- assert.equal(event.last.position, localInsertPos);
438
- assert.equal(event.first.segment.cachedLength, localInsertText.length);
439
- assert.equal(event.last.segment.cachedLength, localInsertText.length);
440
- assert.equal(event.ranges.length, 1);
441
- const segment1 = event.first.segment;
442
- assert.equal(segment1.text, localInsertText);
443
- const remoteInsertMessage1 = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos1, new TextSegment(remoteInsertText1)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
444
- remoteUserId);
445
- client.applyMsg(remoteInsertMessage1);
446
- assert(!event.isLocal);
447
- assert.equal(event.first.position, remoteInsertPos1);
448
- assert.equal(event.last.position, remoteInsertPos1);
449
- assert.equal(event.first.segment.cachedLength, remoteInsertText1.length);
450
- assert.equal(event.last.segment.cachedLength, remoteInsertText1.length);
451
- assert.equal(event.ranges.length, 1);
452
- const segment2 = event.first.segment;
453
- assert.equal(segment2.text, remoteInsertText1);
454
- const remoteInsertMessage2 = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos2, new TextSegment(remoteInsertText2)), currentSeqNumber + 3, currentSeqNumber + 1, // refseqnum
455
- remoteUserId);
456
- client.applyMsg(remoteInsertMessage2);
457
- assert(!event.isLocal);
458
- assert.equal(event.first.position, remoteInsertPos2);
459
- assert.equal(event.last.position, remoteInsertPos2);
460
- assert.equal(event.first.segment.cachedLength, remoteInsertText2.length);
461
- assert.equal(event.last.segment.cachedLength, remoteInsertText2.length);
462
- assert.equal(event.ranges.length, 1);
463
- const segment3 = event.first.segment;
464
- assert.equal(segment3.text, remoteInsertText2);
465
- });
466
- it("overlapping regions, multiple inserts: remote, local, localAfterRemote", () => {
467
- const localInsertPos1 = 4; // before "fox"
468
- const localInsertText1 = "quick ";
469
- const remoteInsertPos = 4; // before "fox", and before local update
470
- const remoteInsertText = "brown ";
471
- // before "dog", after local update
472
- const localInsertPos2 = client.getLength() - 3 + remoteInsertText.length + localInsertText1.length;
473
- const localInsertText2 = "lazy ";
474
- // output: The quick brown fox jumps over the lazy dog
475
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
476
- let event;
477
- client.on("delta", (clientArgs, mergeTreeArgs) => {
478
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
479
- });
480
- const localInsertMessage1 = client.makeOpMessage(client.insertTextLocal(localInsertPos1, localInsertText1), currentSeqNumber + 2, currentSeqNumber);
481
- assert(event);
482
- assert(event.isLocal);
483
- assert.equal(event.first.position, localInsertPos1);
484
- assert.equal(event.last.position, localInsertPos1);
485
- assert.equal(event.first.segment.cachedLength, localInsertText1.length);
486
- assert.equal(event.last.segment.cachedLength, localInsertText1.length);
487
- assert.equal(event.ranges.length, 1);
488
- const segment1 = event.first.segment;
489
- assert.equal(segment1.text, localInsertText1);
490
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
491
- remoteUserId);
492
- client.applyMsg(remoteInsertMessage);
493
- client.applyMsg(localInsertMessage1);
494
- assert(!event.isLocal);
495
- assert.equal(event.first.position, remoteInsertPos + localInsertText1.length);
496
- assert.equal(event.last.position, remoteInsertPos + localInsertText1.length);
497
- assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
498
- assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
499
- assert.equal(event.ranges.length, 1);
500
- const segment2 = event.first.segment;
501
- assert.equal(segment2.text, remoteInsertText);
502
- const localInsertMessage2 = client.makeOpMessage(client.insertTextLocal(localInsertPos2, localInsertText2), currentSeqNumber + 3, currentSeqNumber + 1);
503
- client.applyMsg(localInsertMessage2);
504
- assert(event.isLocal);
505
- assert.equal(event.first.position, localInsertPos2);
506
- assert.equal(event.last.position, localInsertPos2);
507
- assert.equal(event.first.segment.cachedLength, localInsertText2.length);
508
- assert.equal(event.last.segment.cachedLength, localInsertText2.length);
509
- assert.equal(event.ranges.length, 1);
510
- const segment3 = event.first.segment;
511
- assert.equal(segment3.text, localInsertText2);
512
- });
513
- });
514
- describe("delete", () => {
515
- beforeEach(() => {
516
- client = new TestClient();
517
- client.insertTextLocal(0, "The quick brown fox jumps over the lazy dog");
518
- client.startOrUpdateCollaboration(localUserId);
519
- });
520
- it("separate regions, local before remote", () => {
521
- const localRemovePosStart = 4; // "quick "
522
- const localRemovePosEnd = localRemovePosStart + 6;
523
- const remoteRemovePosStart = client.getLength() - 8; // "lazy "
524
- const remoteRemovePosEnd = remoteRemovePosStart + 5;
525
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
526
- let event;
527
- client.on("delta", (clientArgs, mergeTreeArgs) => {
528
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
529
- });
530
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
531
- client.applyMsg(localRemoveMessage);
532
- assert(event);
533
- assert(event.isLocal);
534
- assert.equal(event.first.position, localRemovePosStart);
535
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
536
- assert.equal(event.ranges.length, 1);
537
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
538
- const segment1 = event.first.segment;
539
- assert.equal(segment1.text, "quick ");
540
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
541
- remoteUserId);
542
- client.applyMsg(remoteRemoveMessage);
543
- assert(!event.isLocal);
544
- assert.equal(event.first.position, remoteRemovePosStart - localRemovePosEnd + localRemovePosStart);
545
- assert.equal(event.last.position + event.last.segment.cachedLength, remoteRemovePosEnd - localRemovePosEnd + localRemovePosStart);
546
- assert.equal(event.ranges.length, 1);
547
- assert.equal(event.first.segment.cachedLength, remoteRemovePosEnd - remoteRemovePosStart);
548
- const segment2 = event.first.segment;
549
- assert.equal(segment2.text, "lazy ");
550
- });
551
- it("separate regions, remote before local", () => {
552
- const localRemovePosStart = 4; // "quick "
553
- const localRemovePosEnd = localRemovePosStart + 6;
554
- const remoteRemovePosStart = client.getLength() - 8; // "lazy "
555
- const remoteRemovePosEnd = remoteRemovePosStart + 5;
556
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
557
- let event;
558
- client.on("delta", (clientArgs, mergeTreeArgs) => {
559
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
560
- });
561
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
562
- assert(event);
563
- assert(event.isLocal);
564
- assert.equal(event.first.position, localRemovePosStart);
565
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
566
- assert.equal(event.ranges.length, 1);
567
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
568
- const segment1 = event.first.segment;
569
- assert.equal(segment1.text, "quick ");
570
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
571
- remoteUserId);
572
- client.applyMsg(remoteRemoveMessage);
573
- client.applyMsg(localRemoveMessage);
574
- assert(!event.isLocal);
575
- assert.equal(event.first.position, remoteRemovePosStart - localRemovePosEnd + localRemovePosStart);
576
- assert.equal(event.last.position + event.last.segment.cachedLength, remoteRemovePosEnd - localRemovePosEnd + localRemovePosStart);
577
- assert.equal(event.ranges.length, 1);
578
- assert.equal(event.first.segment.cachedLength, remoteRemovePosEnd - remoteRemovePosStart);
579
- const segment2 = event.first.segment;
580
- assert.equal(segment2.text, "lazy ");
581
- });
582
- it("overlapping regions, same range, local before remote", () => {
583
- const localRemovePosStart = 4; // "quick brown "
584
- const localRemovePosEnd = localRemovePosStart + 12;
585
- const remoteRemovePosStart = 4; // "quick brown "
586
- const remoteRemovePosEnd = remoteRemovePosStart + 12;
587
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
588
- const events = [];
589
- client.on("delta", (clientArgs, mergeTreeArgs) => {
590
- events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
591
- });
592
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
593
- client.applyMsg(localRemoveMessage);
594
- assert.equal(events.length, 1);
595
- const [event] = events;
596
- assert(event.isLocal);
597
- assert.equal(event.first.position, localRemovePosStart);
598
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
599
- assert.equal(event.ranges.length, 1);
600
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
601
- const segment = event.first.segment;
602
- assert.equal(segment.text, "quick brown ");
603
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
604
- remoteUserId);
605
- client.applyMsg(remoteRemoveMessage);
606
- // No new event should be emitted since the delta is empty.
607
- assert.equal(events.length, 1);
608
- });
609
- it("overlapping regions, same range, remote before local", () => {
610
- const localRemovePosStart = 4; // "quick brown "
611
- const localRemovePosEnd = localRemovePosStart + 12;
612
- const remoteRemovePosStart = 4; // "quick brown "
613
- const remoteRemovePosEnd = remoteRemovePosStart + 12;
614
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
615
- const events = [];
616
- client.on("delta", (clientArgs, mergeTreeArgs) => {
617
- events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
618
- });
619
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
620
- assert.equal(events.length, 1);
621
- const [event] = events;
622
- assert(event.isLocal);
623
- assert.equal(event.first.position, localRemovePosStart);
624
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
625
- assert.equal(event.ranges.length, 1);
626
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
627
- const segment = event.first.segment;
628
- assert.equal(segment.text, "quick brown ");
629
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
630
- remoteUserId);
631
- client.applyMsg(remoteRemoveMessage);
632
- client.applyMsg(localRemoveMessage);
633
- // No new event should be emitted since the delta is empty.
634
- assert.equal(events.length, 1);
635
- });
636
- it("overlapping regions, local shadows remote, local before remote", () => {
637
- const localRemovePosStart = 4; // "quick brown "
638
- const localRemovePosEnd = localRemovePosStart + 12;
639
- const remoteRemovePosStart = 10; // "brown"
640
- const remoteRemovePosEnd = remoteRemovePosStart + 5;
641
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
642
- const events = [];
643
- client.on("delta", (clientArgs, mergeTreeArgs) => {
644
- events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
645
- });
646
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
647
- client.applyMsg(localRemoveMessage);
648
- assert.equal(events.length, 1);
649
- const [event] = events;
650
- assert(event.isLocal);
651
- assert.equal(event.first.position, localRemovePosStart);
652
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
653
- assert.equal(event.ranges.length, 1);
654
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
655
- const segment = event.first.segment;
656
- assert.equal(segment.text, "quick brown ");
657
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
658
- remoteUserId);
659
- client.applyMsg(remoteRemoveMessage);
660
- // No new event should be emitted since the delta is empty.
661
- assert.equal(events.length, 1);
662
- });
663
- it("overlapping regions, local shadows remote, remote before local", () => {
664
- const localRemovePosStart = 4; // "quick brown "
665
- const localRemovePosEnd = localRemovePosStart + 12;
666
- const remoteRemovePosStart = 10; // "brown"
667
- const remoteRemovePosEnd = remoteRemovePosStart + 5;
668
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
669
- const events = [];
670
- client.on("delta", (clientArgs, mergeTreeArgs) => {
671
- events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
672
- });
673
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
674
- assert.equal(events.length, 1);
675
- const [event] = events;
676
- assert(event.isLocal);
677
- assert.equal(event.first.position, localRemovePosStart);
678
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
679
- assert.equal(event.ranges.length, 1);
680
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
681
- const segment = event.first.segment;
682
- assert.equal(segment.text, "quick brown ");
683
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
684
- remoteUserId);
685
- client.applyMsg(remoteRemoveMessage);
686
- client.applyMsg(localRemoveMessage);
687
- // No new event should be emitted since the delta is empty.
688
- assert.equal(events.length, 1);
689
- });
690
- it("overlapping regions, local range precedes remote range, local before remote", () => {
691
- // space after "quick" is the overlap
692
- const localRemovePosStart = 4; // "quick "
693
- const localRemovePosEnd = localRemovePosStart + 6;
694
- const remoteRemovePosStart = 9; // " brown "
695
- const remoteRemovePosEnd = remoteRemovePosStart + 7;
696
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
697
- let event;
698
- client.on("delta", (clientArgs, mergeTreeArgs) => {
699
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
700
- });
701
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
702
- client.applyMsg(localRemoveMessage);
703
- assert(event);
704
- assert(event.isLocal);
705
- assert.equal(event.first.position, localRemovePosStart);
706
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
707
- assert.equal(event.ranges.length, 1);
708
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
709
- const segment1 = event.first.segment;
710
- assert.equal(segment1.text, "quick ");
711
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
712
- remoteUserId);
713
- client.applyMsg(remoteRemoveMessage);
714
- // start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
715
- // 1 is for overlapping character
716
- const start = 4;
717
- // end = 4 + 7 - 1
718
- const end = 10;
719
- assert(!event.isLocal);
720
- assert.equal(event.first.position, start);
721
- assert.equal(event.last.position + event.last.segment.cachedLength, end);
722
- assert.equal(event.ranges.length, 1);
723
- assert.equal(event.first.segment.cachedLength, end - start);
724
- const segment2 = event.first.segment;
725
- assert.equal(segment2.text, "brown ");
726
- });
727
- it("overlapping regions, local range precedes remote range, remote before local", () => {
728
- // space after "quick" is the overlap
729
- const localRemovePosStart = 4; // "quick "
730
- const localRemovePosEnd = localRemovePosStart + 6;
731
- const remoteRemovePosStart = 9; // " brown "
732
- const remoteRemovePosEnd = remoteRemovePosStart + 7;
733
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
734
- let event;
735
- client.on("delta", (clientArgs, mergeTreeArgs) => {
736
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
737
- });
738
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
739
- assert(event);
740
- assert(event.isLocal);
741
- assert.equal(event.first.position, localRemovePosStart);
742
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
743
- assert.equal(event.ranges.length, 1);
744
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
745
- const segment1 = event.first.segment;
746
- assert.equal(segment1.text, "quick ");
747
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
748
- remoteUserId);
749
- client.applyMsg(remoteRemoveMessage);
750
- client.applyMsg(localRemoveMessage);
751
- // start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
752
- // 1 is for overlapping character
753
- const start = 4;
754
- // end = 4 + 7 - 1
755
- const end = 10;
756
- assert(!event.isLocal);
757
- assert.equal(event.first.position, start);
758
- assert.equal(event.last.position + event.last.segment.cachedLength, end);
759
- assert.equal(event.ranges.length, 1);
760
- assert.equal(event.first.segment.cachedLength, end - start);
761
- const segment2 = event.first.segment;
762
- assert.equal(segment2.text, "brown ");
763
- });
764
- it("overlapping regions, remote range precedes local range, local before remote", () => {
765
- // space after "quick" is the overlap
766
- const localRemovePosStart = 9; // " brown "
767
- const localRemovePosEnd = localRemovePosStart + 7;
768
- const remoteRemovePosStart = 4; // "quick "
769
- const remoteRemovePosEnd = remoteRemovePosStart + 6;
770
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
771
- let event;
772
- client.on("delta", (clientArgs, mergeTreeArgs) => {
773
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
774
- });
775
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
776
- client.applyMsg(localRemoveMessage);
777
- assert(event);
778
- assert(event.isLocal);
779
- assert.equal(event.first.position, localRemovePosStart);
780
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
781
- assert.equal(event.ranges.length, 1);
782
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
783
- const segment1 = event.first.segment;
784
- assert.equal(segment1.text, " brown ");
785
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
786
- remoteUserId);
787
- client.applyMsg(remoteRemoveMessage);
788
- // start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
789
- // 1 is for overlapping character
790
- const start = 4;
791
- // end = 4 + 6 - 1
792
- const end = 9;
793
- assert(!event.isLocal);
794
- assert.equal(event.first.position, start);
795
- assert.equal(event.last.position + event.last.segment.cachedLength, end);
796
- assert.equal(event.ranges.length, 1);
797
- assert.equal(event.first.segment.cachedLength, end - start);
798
- const segment2 = event.first.segment;
799
- assert.equal(segment2.text, "quick");
800
- });
801
- it("overlapping regions, remote range precedes local range, remote before local", () => {
802
- // space after "quick" is the overlap
803
- const localRemovePosStart = 9; // " brown "
804
- const localRemovePosEnd = localRemovePosStart + 7;
805
- const remoteRemovePosStart = 4; // "quick "
806
- const remoteRemovePosEnd = remoteRemovePosStart + 6;
807
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
808
- let event;
809
- client.on("delta", (clientArgs, mergeTreeArgs) => {
810
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
811
- });
812
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
813
- assert(event);
814
- assert(event.isLocal);
815
- assert.equal(event.first.position, localRemovePosStart);
816
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
817
- assert.equal(event.ranges.length, 1);
818
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
819
- const segment1 = event.first.segment;
820
- assert.equal(segment1.text, " brown ");
821
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
822
- remoteUserId);
823
- client.applyMsg(remoteRemoveMessage);
824
- client.applyMsg(localRemoveMessage);
825
- // start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
826
- // 1 is for overlapping character
827
- const start = 4;
828
- // end = 4 + 6 - 1
829
- const end = 9;
830
- assert(!event.isLocal);
831
- assert.equal(event.first.position, start);
832
- assert.equal(event.last.position + event.last.segment.cachedLength, end);
833
- assert.equal(event.ranges.length, 1);
834
- assert.equal(event.first.segment.cachedLength, end - start);
835
- const segment2 = event.first.segment;
836
- assert.equal(segment2.text, "quick");
837
- });
838
- it("overlapping regions, remote shadows local, local before remote", () => {
839
- const localRemovePosStart = 10; // "brown"
840
- const localRemovePosEnd = localRemovePosStart + 5;
841
- const remoteRemovePosStart = 4; // "quick brown "
842
- const remoteRemovePosEnd = remoteRemovePosStart + 12;
843
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
844
- let event;
845
- client.on("delta", (clientArgs, mergeTreeArgs) => {
846
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
847
- });
848
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
849
- client.applyMsg(localRemoveMessage);
850
- assert(event);
851
- assert(event.isLocal);
852
- assert.equal(event.first.position, localRemovePosStart);
853
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
854
- assert.equal(event.ranges.length, 1);
855
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
856
- const segment1 = event.first.segment;
857
- assert.equal(segment1.text, "brown");
858
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
859
- remoteUserId);
860
- client.applyMsg(remoteRemoveMessage);
861
- assert(!event.isLocal);
862
- assert.equal(event.ranges.length, 2);
863
- assert.equal(event.first.position, remoteRemovePosStart);
864
- // -1 is for split
865
- assert.equal(event.first.segment.cachedLength, "quick ".length);
866
- const segment2 = event.first.segment;
867
- assert.equal(segment2.text, "quick ");
868
- assert.equal(event.ranges[1].position, remoteRemovePosStart);
869
- // -1 is for split
870
- assert.equal(event.ranges[1].segment.cachedLength, " ".length);
871
- const segment3 = event.ranges[1].segment;
872
- assert.equal(segment3.text, " ");
873
- });
874
- it("overlapping regions, remote shadows local, remote before local", () => {
875
- const localRemovePosStart = 10; // "brown"
876
- const localRemovePosEnd = localRemovePosStart + 5;
877
- const remoteRemovePosStart = 4; // "quick brown "
878
- const remoteRemovePosEnd = remoteRemovePosStart + 12;
879
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
880
- let event;
881
- client.on("delta", (clientArgs, mergeTreeArgs) => {
882
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
883
- });
884
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
885
- assert(event);
886
- assert(event.isLocal);
887
- assert.equal(event.first.position, localRemovePosStart);
888
- assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
889
- assert.equal(event.ranges.length, 1);
890
- assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
891
- const segment1 = event.first.segment;
892
- assert.equal(segment1.text, "brown");
893
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
894
- remoteUserId);
895
- client.applyMsg(remoteRemoveMessage);
896
- client.applyMsg(localRemoveMessage);
897
- assert(!event.isLocal);
898
- assert.equal(event.ranges.length, 2);
899
- assert.equal(event.first.position, remoteRemovePosStart);
900
- // -1 is for split
901
- assert.equal(event.first.segment.cachedLength, "quick ".length);
902
- const segment2 = event.first.segment;
903
- assert.equal(segment2.text, "quick ");
904
- assert.equal(event.ranges[1].position, remoteRemovePosStart);
905
- // -1 is for split
906
- assert.equal(event.ranges[1].segment.cachedLength, " ".length);
907
- const segment3 = event.ranges[1].segment;
908
- assert.equal(segment3.text, " ");
909
- });
910
- });
911
- describe("annotate", () => {
912
- beforeEach(() => {
913
- client = new TestClient();
914
- client.insertTextLocal(0, "Habits change into character");
915
- client.startOrUpdateCollaboration(localUserId);
916
- });
917
- it("same range, same property, local before remote", () => {
918
- const localPosStart = 7; // "change"
919
- const localPosEnd = localPosStart + 6;
920
- const remotePosStart = 7; // "change"
921
- const remotePosEnd = remotePosStart + 6;
922
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
923
- let event;
924
- client.on("delta", (clientArgs, mergeTreeArgs) => {
925
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
926
- });
927
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 1, currentSeqNumber);
928
- client.applyMsg(localMessage);
929
- assert(event);
930
- verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
931
- {
932
- numChar: localPosEnd - localPosStart,
933
- offset: localPosStart,
934
- propDeltas: { foo: null },
935
- props: { foo: "bar" },
936
- text: "change",
937
- },
938
- ]);
939
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bar" }), currentSeqNumber + 2, currentSeqNumber, // refseq
940
- remoteUserId);
941
- client.applyMsg(remoteMessage);
942
- verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
943
- {
944
- numChar: remotePosEnd - remotePosStart,
945
- offset: remotePosStart,
946
- propDeltas: { foo: "bar" },
947
- props: { foo: "bar" },
948
- text: "change",
949
- },
950
- ]);
951
- });
952
- it("same range, same property, remote before local", () => {
953
- const localPosStart = 7; // "change"
954
- const localPosEnd = localPosStart + 6;
955
- const remotePosStart = 7; // "change"
956
- const remotePosEnd = remotePosStart + 6;
957
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
958
- let event;
959
- client.on("delta", (clientArgs, mergeTreeArgs) => {
960
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
961
- });
962
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 2, currentSeqNumber);
963
- assert(event);
964
- verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
965
- {
966
- numChar: localPosEnd - localPosStart,
967
- offset: localPosStart,
968
- propDeltas: { foo: null },
969
- props: { foo: "bar" },
970
- text: "change",
971
- },
972
- ]);
973
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bar" }), currentSeqNumber + 1, currentSeqNumber, // refseq
974
- remoteUserId);
975
- client.applyMsg(remoteMessage);
976
- verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
977
- {
978
- numChar: remotePosEnd - remotePosStart,
979
- offset: remotePosStart,
980
- props: { foo: "bar" },
981
- text: "change",
982
- },
983
- ]);
984
- client.applyMsg(localMessage);
985
- });
986
- it("same range, same property, different value, local before remote", () => {
987
- const localPosStart = 7; // "change"
988
- const localPosEnd = localPosStart + 6;
989
- const remotePosStart = 7; // "change"
990
- const remotePosEnd = remotePosStart + 6;
991
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
992
- let event;
993
- client.on("delta", (clientArgs, mergeTreeArgs) => {
994
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
995
- });
996
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 1, currentSeqNumber);
997
- client.applyMsg(localMessage);
998
- assert(event);
999
- verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
1000
- {
1001
- numChar: localPosEnd - localPosStart,
1002
- offset: localPosStart,
1003
- propDeltas: { foo: null },
1004
- props: { foo: "bar" },
1005
- text: "change",
1006
- },
1007
- ]);
1008
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bardash" }), currentSeqNumber + 2, currentSeqNumber, // refseq
1009
- remoteUserId);
1010
- client.applyMsg(remoteMessage);
1011
- verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
1012
- {
1013
- numChar: remotePosEnd - remotePosStart,
1014
- offset: remotePosStart,
1015
- propDeltas: { foo: "bar" },
1016
- props: { foo: "bardash" },
1017
- text: "change",
1018
- },
1019
- ]);
1020
- });
1021
- it("same range, same property, different value, remote before local", () => {
1022
- const localPosStart = 7; // "change"
1023
- const localPosEnd = localPosStart + 6;
1024
- const remotePosStart = 7; // "change"
1025
- const remotePosEnd = remotePosStart + 6;
1026
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1027
- let event;
1028
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1029
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1030
- });
1031
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 2, currentSeqNumber);
1032
- assert(event);
1033
- verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
1034
- {
1035
- numChar: localPosEnd - localPosStart,
1036
- offset: localPosStart,
1037
- propDeltas: { foo: null },
1038
- props: { foo: "bar" },
1039
- text: "change",
1040
- },
1041
- ]);
1042
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bardash" }), currentSeqNumber + 1, currentSeqNumber, // refseq
1043
- remoteUserId);
1044
- client.applyMsg(remoteMessage);
1045
- client.applyMsg(localMessage);
1046
- verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
1047
- {
1048
- numChar: remotePosEnd - remotePosStart,
1049
- offset: remotePosStart,
1050
- props: { foo: "bar" },
1051
- text: "change",
1052
- },
1053
- ]);
1054
- });
1055
- it("same range, different properties, local before remote", () => {
1056
- const localPosStart = 7; // "change"
1057
- const localPosEnd = localPosStart + 6;
1058
- const remotePosStart = 7; // "change"
1059
- const remotePosEnd = remotePosStart + 6;
1060
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1061
- let event;
1062
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1063
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1064
- });
1065
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo1: "bar1" }), currentSeqNumber + 1, currentSeqNumber);
1066
- client.applyMsg(localMessage);
1067
- assert(event);
1068
- verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
1069
- {
1070
- numChar: localPosEnd - localPosStart,
1071
- offset: localPosStart,
1072
- propDeltas: { foo1: null },
1073
- props: { foo1: "bar1" },
1074
- text: "change",
1075
- },
1076
- ]);
1077
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo2: "bar2" }), currentSeqNumber + 2, currentSeqNumber, // refseq
1078
- remoteUserId);
1079
- client.applyMsg(remoteMessage);
1080
- verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
1081
- {
1082
- numChar: remotePosEnd - remotePosStart,
1083
- offset: remotePosStart,
1084
- propDeltas: { foo2: null },
1085
- props: { foo1: "bar1", foo2: "bar2" },
1086
- text: "change",
1087
- },
1088
- ]);
1089
- });
1090
- it("same range, different properties, remote before local", () => {
1091
- const localPosStart = 7; // "change"
1092
- const localPosEnd = localPosStart + 6;
1093
- const remotePosStart = 7; // "change"
1094
- const remotePosEnd = remotePosStart + 6;
1095
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1096
- let event;
1097
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1098
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1099
- });
1100
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo1: "bar1" }), currentSeqNumber + 2, currentSeqNumber);
1101
- assert(event);
1102
- verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
1103
- {
1104
- numChar: localPosEnd - localPosStart,
1105
- offset: localPosStart,
1106
- propDeltas: { foo1: null },
1107
- props: { foo1: "bar1" },
1108
- text: "change",
1109
- },
1110
- ]);
1111
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo2: "bar2" }), currentSeqNumber + 1, currentSeqNumber, // refseq
1112
- remoteUserId);
1113
- client.applyMsg(remoteMessage);
1114
- verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
1115
- {
1116
- numChar: remotePosEnd - remotePosStart,
1117
- offset: remotePosStart,
1118
- propDeltas: { foo2: null },
1119
- props: { foo1: "bar1", foo2: "bar2" },
1120
- text: "change",
1121
- },
1122
- ]);
1123
- client.applyMsg(localMessage);
1124
- });
1125
- it("overlapping ranges, same properties, different values", () => {
1126
- // initialize as following:
1127
- // - second word has property foo1=bar1
1128
- // - third word has property foo2=bar2
1129
- // - fourth word has property foo3=bar3
1130
- initialize();
1131
- // apply remote operation that has seen "initialize" seqnum as following:
1132
- // - apply foo=bar on whole line
1133
- step1(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq);
1134
- // apply local operation that has seen "step1" seqnum as following:
1135
- // - change foo=bar1 for [firstWordStart, secondWordEnd)
1136
- step2(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq);
1137
- // apply remote operation that has not seen "step2" seqnum as following:
1138
- // - change foo=bar2 for [thirdWordStart, fourthWordEnd)
1139
- step3(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq - 1);
1140
- // apply local operation that has seen "step3" seqnum as following:
1141
- // - change foo=bar3 for [secondWordStart, fourthWordEnd)
1142
- step4(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq);
1143
- });
1144
- const firstWordStart = 0; // "Habits"
1145
- const secondWordStart = 7; // "change"
1146
- const secondWordEnd = 13;
1147
- const thirdWordStart = 14; // "into"
1148
- const thirdWordEnd = 18;
1149
- const fourthWordStart = 19; // "character"
1150
- const fourthWordEnd = 28;
1151
- function initialize() {
1152
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1153
- let event;
1154
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1155
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1156
- });
1157
- const localMessage1 = client.makeOpMessage(client.annotateRangeLocal(secondWordStart, secondWordEnd, { foo1: "bar1" }), currentSeqNumber + 1, currentSeqNumber);
1158
- client.applyMsg(localMessage1);
1159
- assert(event);
1160
- verifyEventForAnnotate(event, true, secondWordStart, secondWordEnd, [
1161
- {
1162
- numChar: secondWordEnd - secondWordStart,
1163
- offset: secondWordStart,
1164
- propDeltas: { foo1: null },
1165
- props: { foo1: "bar1" },
1166
- text: "change",
1167
- },
1168
- ]);
1169
- const localMessage2 = client.makeOpMessage(client.annotateRangeLocal(fourthWordStart, fourthWordEnd, { foo3: "bar3" }), currentSeqNumber + 2, currentSeqNumber + 1);
1170
- client.applyMsg(localMessage2);
1171
- verifyEventForAnnotate(event, true, fourthWordStart, fourthWordEnd, [
1172
- {
1173
- numChar: fourthWordEnd - fourthWordStart,
1174
- offset: fourthWordStart,
1175
- propDeltas: { foo3: null },
1176
- props: { foo3: "bar3" },
1177
- text: "character",
1178
- },
1179
- ]);
1180
- const remoteMessage1 = client.makeOpMessage(createAnnotateRangeOp(thirdWordStart, thirdWordEnd, { foo2: "bar2" }), currentSeqNumber + 3, currentSeqNumber, // refseq
1181
- remoteUserId);
1182
- client.applyMsg(remoteMessage1);
1183
- verifyEventForAnnotate(event, false, thirdWordStart, thirdWordEnd, [
1184
- {
1185
- numChar: thirdWordEnd - thirdWordStart,
1186
- offset: thirdWordStart,
1187
- propDeltas: { foo2: null },
1188
- props: { foo2: "bar2" },
1189
- text: "into",
1190
- },
1191
- ]);
1192
- }
1193
- function step1(seqnum, refseqnum) {
1194
- let event;
1195
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1196
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1197
- });
1198
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(firstWordStart, fourthWordEnd, { foo: "bar" }), seqnum, refseqnum, remoteUserId);
1199
- client.applyMsg(remoteMessage);
1200
- assert(event);
1201
- verifyEventForAnnotate(event, false, firstWordStart, fourthWordEnd, [
1202
- {
1203
- numChar: secondWordStart - firstWordStart,
1204
- offset: firstWordStart,
1205
- propDeltas: { foo: null },
1206
- props: { foo: "bar" },
1207
- text: "Habits ",
1208
- },
1209
- {
1210
- numChar: secondWordEnd - secondWordStart,
1211
- offset: secondWordStart,
1212
- propDeltas: { foo: null },
1213
- props: { foo: "bar", foo1: "bar1" },
1214
- text: "change",
1215
- },
1216
- {
1217
- numChar: thirdWordStart - secondWordEnd,
1218
- offset: secondWordEnd,
1219
- propDeltas: { foo: null },
1220
- props: { foo: "bar" },
1221
- text: " ",
1222
- },
1223
- {
1224
- numChar: thirdWordEnd - thirdWordStart,
1225
- offset: thirdWordStart,
1226
- propDeltas: { foo: null },
1227
- props: { foo: "bar", foo2: "bar2" },
1228
- text: "into",
1229
- },
1230
- {
1231
- numChar: fourthWordStart - thirdWordEnd,
1232
- offset: thirdWordEnd,
1233
- propDeltas: { foo: null },
1234
- props: { foo: "bar" },
1235
- text: " ",
1236
- },
1237
- {
1238
- numChar: fourthWordEnd - fourthWordStart,
1239
- offset: fourthWordStart,
1240
- propDeltas: { foo: null },
1241
- props: { foo: "bar", foo3: "bar3" },
1242
- text: "character",
1243
- },
1244
- ]);
1245
- }
1246
- function step2(seqnum, refseqnum) {
1247
- let event;
1248
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1249
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1250
- });
1251
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(firstWordStart, secondWordEnd, { foo: "bar1" }), seqnum, refseqnum);
1252
- client.applyMsg(localMessage);
1253
- assert(event);
1254
- verifyEventForAnnotate(event, true, firstWordStart, secondWordEnd, [
1255
- {
1256
- numChar: secondWordStart - firstWordStart,
1257
- offset: firstWordStart,
1258
- propDeltas: { foo: "bar" },
1259
- props: { foo: "bar1" },
1260
- text: "Habits ",
1261
- },
1262
- {
1263
- numChar: secondWordEnd - secondWordStart,
1264
- offset: secondWordStart,
1265
- propDeltas: { foo: "bar" },
1266
- props: { foo: "bar1", foo1: "bar1" },
1267
- text: "change",
1268
- },
1269
- ]);
1270
- }
1271
- function step3(seqnum, refseqnum) {
1272
- let event;
1273
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1274
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1275
- });
1276
- const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(thirdWordStart, fourthWordEnd, { foo: "bar2" }), seqnum, refseqnum, remoteUserId);
1277
- client.applyMsg(remoteMessage);
1278
- assert(event);
1279
- verifyEventForAnnotate(event, false, thirdWordStart, fourthWordEnd, [
1280
- {
1281
- numChar: thirdWordEnd - thirdWordStart,
1282
- offset: thirdWordStart,
1283
- propDeltas: { foo: "bar" },
1284
- props: { foo: "bar2", foo2: "bar2" },
1285
- text: "into",
1286
- },
1287
- {
1288
- numChar: fourthWordStart - thirdWordEnd,
1289
- offset: thirdWordEnd,
1290
- propDeltas: { foo: "bar" },
1291
- props: { foo: "bar2" },
1292
- text: " ",
1293
- },
1294
- {
1295
- numChar: fourthWordEnd - fourthWordStart,
1296
- offset: fourthWordStart,
1297
- propDeltas: { foo: "bar" },
1298
- props: { foo: "bar2", foo3: "bar3" },
1299
- text: "character",
1300
- },
1301
- ]);
1302
- }
1303
- function step4(seqnum, refseqnum) {
1304
- let event;
1305
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1306
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1307
- });
1308
- const localMessage = client.makeOpMessage(client.annotateRangeLocal(secondWordStart, fourthWordEnd, { foo: "bar3" }), seqnum, refseqnum);
1309
- client.applyMsg(localMessage);
1310
- assert(event);
1311
- verifyEventForAnnotate(event, true, secondWordStart, fourthWordEnd, [
1312
- {
1313
- numChar: secondWordEnd - secondWordStart,
1314
- offset: secondWordStart,
1315
- propDeltas: { foo: "bar1" },
1316
- props: { foo: "bar3", foo1: "bar1" },
1317
- text: "change",
1318
- },
1319
- {
1320
- numChar: thirdWordStart - secondWordEnd,
1321
- offset: secondWordEnd,
1322
- propDeltas: { foo: "bar" },
1323
- props: { foo: "bar3" },
1324
- text: " ",
1325
- },
1326
- {
1327
- numChar: thirdWordEnd - thirdWordStart,
1328
- offset: thirdWordStart,
1329
- propDeltas: { foo: "bar2" },
1330
- props: { foo: "bar3", foo2: "bar2" },
1331
- text: "into",
1332
- },
1333
- {
1334
- numChar: fourthWordStart - thirdWordEnd,
1335
- offset: thirdWordEnd,
1336
- propDeltas: { foo: "bar2" },
1337
- props: { foo: "bar3" },
1338
- text: " ",
1339
- },
1340
- {
1341
- numChar: fourthWordEnd - fourthWordStart,
1342
- offset: fourthWordStart,
1343
- propDeltas: { foo: "bar2" },
1344
- props: { foo: "bar3", foo3: "bar3" },
1345
- text: "character",
1346
- },
1347
- ]);
1348
- }
1349
- function verifyEventForAnnotate(event, isLocal, start, end, expected) {
1350
- assert(event.isLocal === isLocal);
1351
- assert.equal(event.first.position, start);
1352
- assert.equal(event.last.position + event.last.segment.cachedLength, end);
1353
- assert.equal(event.ranges.length, expected.length);
1354
- for (let i = 0; i < expected.length; i = i + 1) {
1355
- assert.equal(event.ranges[i].position, expected[i].offset);
1356
- assert.equal(event.ranges[i].segment.cachedLength, expected[i].numChar);
1357
- assert.equal(Object.keys(event.ranges[i].segment.properties ?? {}).length, Object.keys(expected[i].props).length);
1358
- for (const key of Object.keys(event.ranges[i].segment.properties ?? {})) {
1359
- assert.equal(event.ranges[i].segment.properties?.[key], expected[i].props[key]);
1360
- }
1361
- if (expected[i].propDeltas !== undefined) {
1362
- assert.equal(Object.keys(event.ranges[i].propertyDeltas).length, Object.keys(expected[i].propDeltas ?? {}).length);
1363
- for (const key of Object.keys(event.ranges[i].propertyDeltas)) {
1364
- assert.equal(event.ranges[i].propertyDeltas[key], expected[i].propDeltas?.[key]);
1365
- }
1366
- }
1367
- else {
1368
- assert(isNullOrUndefined(event.ranges[i].propertyDeltas) ||
1369
- Object.keys(event.ranges[i].propertyDeltas).length === 0);
1370
- }
1371
- if (expected[i].text !== undefined) {
1372
- const segment = event.ranges[i].segment;
1373
- assert.equal(segment.text, expected[i].text);
1374
- }
1375
- }
1376
- }
1377
- });
1378
- describe("combination", () => {
1379
- beforeEach(() => {
1380
- client = new TestClient();
1381
- client.insertTextLocal(0, "The brown fox jumps over the lazy dog");
1382
- client.startOrUpdateCollaboration(localUserId);
1383
- });
1384
- it("insertPos before deleteRange, insertLocal deleteRemote, local before remote", () => {
1385
- const insertPos = 4; // before "brown"
1386
- const insertText = "quick ";
1387
- const deleteRangeStart = 29; // "lazy "
1388
- const deleteRangeEnd = 34;
1389
- const output = "The quick brown fox jumps over the dog";
1390
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1391
- let event;
1392
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1393
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1394
- });
1395
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
1396
- client.applyMsg(localInsertMessage);
1397
- assert(event);
1398
- assert(event.isLocal);
1399
- assert.equal(event.first.position, insertPos);
1400
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1401
- assert.equal(event.ranges.length, 1);
1402
- assert.equal(event.first.segment.cachedLength, insertText.length);
1403
- const segment1 = event.first.segment;
1404
- assert.equal(segment1.text, insertText);
1405
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
1406
- remoteUserId);
1407
- client.applyMsg(remoteRemoveMessage);
1408
- assert(!event.isLocal);
1409
- assert.equal(event.first.position, deleteRangeStart + insertText.length);
1410
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
1411
- assert.equal(event.ranges.length, 1);
1412
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1413
- const segment2 = event.first.segment;
1414
- assert.equal(segment2.text, "lazy ");
1415
- assert.equal(client.getText(), output);
1416
- });
1417
- it("insertPos before deleteRange, insertLocal deleteRemote, remote before local", () => {
1418
- const insertPos = 4; // before "brown"
1419
- const insertText = "quick ";
1420
- const deleteRangeStart = 29; // "lazy "
1421
- const deleteRangeEnd = 34;
1422
- const output = "The quick brown fox jumps over the dog";
1423
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1424
- let event;
1425
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1426
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1427
- });
1428
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
1429
- assert(event);
1430
- assert(event.isLocal);
1431
- assert.equal(event.first.position, insertPos);
1432
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1433
- assert.equal(event.ranges.length, 1);
1434
- assert.equal(event.first.segment.cachedLength, insertText.length);
1435
- const segment1 = event.first.segment;
1436
- assert.equal(segment1.text, insertText);
1437
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
1438
- remoteUserId);
1439
- client.applyMsg(remoteRemoveMessage);
1440
- assert(!event.isLocal);
1441
- assert.equal(event.first.position, deleteRangeStart + insertText.length);
1442
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
1443
- assert.equal(event.ranges.length, 1);
1444
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1445
- const segment2 = event.first.segment;
1446
- assert.equal(segment2.text, "lazy ");
1447
- client.applyMsg(localInsertMessage);
1448
- assert.equal(client.getText(), output);
1449
- });
1450
- it("insertPos before deleteRange, deleteLocal insertRemote, local before remote", () => {
1451
- const insertPos = 4; // before "brown"
1452
- const insertText = "quick ";
1453
- const deleteRangeStart = 29; // "lazy "
1454
- const deleteRangeEnd = 34;
1455
- const output = "The quick brown fox jumps over the dog";
1456
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1457
- let event;
1458
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1459
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1460
- });
1461
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
1462
- client.applyMsg(localRemoveMessage);
1463
- assert(event);
1464
- assert(event.isLocal);
1465
- assert.equal(event.first.position, deleteRangeStart);
1466
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1467
- assert.equal(event.ranges.length, 1);
1468
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1469
- const segment1 = event.first.segment;
1470
- assert.equal(segment1.text, "lazy ");
1471
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
1472
- remoteUserId);
1473
- client.applyMsg(remoteInsertMessage);
1474
- assert(!event.isLocal);
1475
- assert.equal(event.first.position, insertPos);
1476
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1477
- assert.equal(event.ranges.length, 1);
1478
- assert.equal(event.first.segment.cachedLength, insertText.length);
1479
- const segment2 = event.first.segment;
1480
- assert.equal(segment2.text, insertText);
1481
- assert.equal(client.getText(), output);
1482
- });
1483
- it("insertPos before deleteRange, deleteLocal insertRemote, remote before local", () => {
1484
- const insertPos = 4; // before "brown"
1485
- const insertText = "quick ";
1486
- const deleteRangeStart = 29; // "lazy "
1487
- const deleteRangeEnd = 34;
1488
- const output = "The quick brown fox jumps over the dog";
1489
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1490
- let event;
1491
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1492
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1493
- });
1494
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
1495
- assert(event);
1496
- assert(event.isLocal);
1497
- assert.equal(event.first.position, deleteRangeStart);
1498
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1499
- assert.equal(event.ranges.length, 1);
1500
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1501
- const segment1 = event.first.segment;
1502
- assert.equal(segment1.text, "lazy ");
1503
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
1504
- remoteUserId);
1505
- client.applyMsg(remoteInsertMessage);
1506
- assert(!event.isLocal);
1507
- assert.equal(event.first.position, insertPos);
1508
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1509
- assert.equal(event.ranges.length, 1);
1510
- assert.equal(event.first.segment.cachedLength, insertText.length);
1511
- const segment2 = event.first.segment;
1512
- assert.equal(segment2.text, insertText);
1513
- client.applyMsg(localRemoveMessage);
1514
- assert.equal(client.getText(), output);
1515
- });
1516
- it("insertPos after deleteRange, insertLocal deleteRemote, local before remote", () => {
1517
- const insertPos = 29; // before "lazy"
1518
- const insertText = "black ";
1519
- const deleteRangeStart = 4; // "brown "
1520
- const deleteRangeEnd = 10;
1521
- const output = "The fox jumps over the black lazy dog";
1522
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1523
- let event;
1524
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1525
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1526
- });
1527
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
1528
- client.applyMsg(localInsertMessage);
1529
- assert(event);
1530
- assert(event.isLocal);
1531
- assert.equal(event.first.position, insertPos);
1532
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1533
- assert.equal(event.ranges.length, 1);
1534
- assert.equal(event.first.segment.cachedLength, insertText.length);
1535
- const segment1 = event.first.segment;
1536
- assert.equal(segment1.text, insertText);
1537
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
1538
- remoteUserId);
1539
- client.applyMsg(remoteRemoveMessage);
1540
- assert(!event.isLocal);
1541
- assert.equal(event.first.position, deleteRangeStart);
1542
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1543
- assert.equal(event.ranges.length, 1);
1544
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1545
- const segment2 = event.first.segment;
1546
- assert.equal(segment2.text, "brown ");
1547
- assert.equal(client.getText(), output);
1548
- });
1549
- it("insertPos after deleteRange, insertLocal deleteRemote, remote before local", () => {
1550
- const insertPos = 29; // before "lazy"
1551
- const insertText = "black ";
1552
- const deleteRangeStart = 4; // "brown "
1553
- const deleteRangeEnd = 10;
1554
- const output = "The fox jumps over the black lazy dog";
1555
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1556
- let event;
1557
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1558
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1559
- });
1560
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
1561
- assert(event);
1562
- assert(event.isLocal);
1563
- assert.equal(event.first.position, insertPos);
1564
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1565
- assert.equal(event.ranges.length, 1);
1566
- assert.equal(event.first.segment.cachedLength, insertText.length);
1567
- const segment1 = event.first.segment;
1568
- assert.equal(segment1.text, insertText);
1569
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
1570
- remoteUserId);
1571
- client.applyMsg(remoteRemoveMessage);
1572
- assert(!event.isLocal);
1573
- assert.equal(event.first.position, deleteRangeStart);
1574
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1575
- assert.equal(event.ranges.length, 1);
1576
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1577
- const segment2 = event.first.segment;
1578
- assert.equal(segment2.text, "brown ");
1579
- client.applyMsg(localInsertMessage);
1580
- assert.equal(client.getText(), output);
1581
- });
1582
- it("insertPos after deleteRange, deleteLocal insertRemote, local before remote", () => {
1583
- const insertPos = 29; // before "lazy"
1584
- const insertText = "black ";
1585
- const deleteRangeStart = 4; // "brown "
1586
- const deleteRangeEnd = 10;
1587
- const output = "The fox jumps over the black lazy dog";
1588
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1589
- let event;
1590
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1591
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1592
- });
1593
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
1594
- client.applyMsg(localRemoveMessage);
1595
- assert(event);
1596
- assert(event.isLocal);
1597
- assert.equal(event.first.position, deleteRangeStart);
1598
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1599
- assert.equal(event.ranges.length, 1);
1600
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1601
- const segment1 = event.first.segment;
1602
- assert.equal(segment1.text, "brown ");
1603
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
1604
- remoteUserId);
1605
- client.applyMsg(remoteInsertMessage);
1606
- assert(!event.isLocal);
1607
- assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
1608
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos - (deleteRangeEnd - deleteRangeStart) + insertText.length);
1609
- assert.equal(event.ranges.length, 1);
1610
- assert.equal(event.first.segment.cachedLength, insertText.length);
1611
- const segment2 = event.first.segment;
1612
- assert.equal(segment2.text, insertText);
1613
- assert.equal(client.getText(), output);
1614
- });
1615
- it("insertPos after deleteRange, deleteLocal insertRemote, remote before local", () => {
1616
- const insertPos = 29; // before "lazy"
1617
- const insertText = "black ";
1618
- const deleteRangeStart = 4; // "brown "
1619
- const deleteRangeEnd = 10;
1620
- const output = "The fox jumps over the black lazy dog";
1621
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1622
- let event;
1623
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1624
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1625
- });
1626
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
1627
- assert(event);
1628
- assert(event.isLocal);
1629
- assert.equal(event.first.position, deleteRangeStart);
1630
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1631
- assert.equal(event.ranges.length, 1);
1632
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1633
- const segment1 = event.first.segment;
1634
- assert.equal(segment1.text, "brown ");
1635
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
1636
- remoteUserId);
1637
- client.applyMsg(remoteInsertMessage);
1638
- assert(!event.isLocal);
1639
- assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
1640
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos - (deleteRangeEnd - deleteRangeStart) + insertText.length);
1641
- assert.equal(event.ranges.length, 1);
1642
- assert.equal(event.first.segment.cachedLength, insertText.length);
1643
- const segment2 = event.first.segment;
1644
- assert.equal(segment2.text, insertText);
1645
- client.applyMsg(localRemoveMessage);
1646
- assert.equal(client.getText(), output);
1647
- });
1648
- it("insertPos is deleteRangeStart, insertLocal deleteRemote, local before remote", () => {
1649
- const insertPos = 29; // before "lazy"
1650
- const insertText = "black ";
1651
- const deleteRangeStart = 29; // "lazy "
1652
- const deleteRangeEnd = 34;
1653
- const output = "The brown fox jumps over the black dog";
1654
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1655
- let event;
1656
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1657
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1658
- });
1659
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
1660
- client.applyMsg(localInsertMessage);
1661
- assert(event);
1662
- assert(event.isLocal);
1663
- assert.equal(event.first.position, insertPos);
1664
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1665
- assert.equal(event.ranges.length, 1);
1666
- assert.equal(event.first.segment.cachedLength, insertText.length);
1667
- const segment1 = event.first.segment;
1668
- assert.equal(segment1.text, insertText);
1669
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
1670
- remoteUserId);
1671
- client.applyMsg(remoteRemoveMessage);
1672
- assert(!event.isLocal);
1673
- assert.equal(event.first.position, deleteRangeStart + insertText.length);
1674
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
1675
- assert.equal(event.ranges.length, 1);
1676
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1677
- const segment2 = event.first.segment;
1678
- assert.equal(segment2.text, "lazy ");
1679
- assert.equal(client.getText(), output);
1680
- });
1681
- it("insertPos is deleteRangeStart, insertLocal deleteRemote, remote before local", () => {
1682
- const insertPos = 29; // before "lazy"
1683
- const insertText = "black ";
1684
- const deleteRangeStart = 29; // "lazy "
1685
- const deleteRangeEnd = 34;
1686
- const output = "The brown fox jumps over the black dog";
1687
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1688
- let event;
1689
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1690
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1691
- });
1692
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
1693
- assert(event);
1694
- assert(event.isLocal);
1695
- assert.equal(event.first.position, insertPos);
1696
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1697
- assert.equal(event.ranges.length, 1);
1698
- assert.equal(event.first.segment.cachedLength, insertText.length);
1699
- const segment1 = event.first.segment;
1700
- assert.equal(segment1.text, insertText);
1701
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
1702
- remoteUserId);
1703
- client.applyMsg(remoteRemoveMessage);
1704
- assert(!event.isLocal);
1705
- assert.equal(event.first.position, deleteRangeStart + insertText.length);
1706
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
1707
- assert.equal(event.ranges.length, 1);
1708
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1709
- const segment2 = event.first.segment;
1710
- assert.equal(segment2.text, "lazy ");
1711
- client.applyMsg(localInsertMessage);
1712
- assert.equal(client.getText(), output);
1713
- });
1714
- it("insertPos is deleteRangeStart, deleteLocal insertRemote, local before remote", () => {
1715
- const insertPos = 29; // before "lazy"
1716
- const insertText = "black ";
1717
- const deleteRangeStart = 29; // "lazy "
1718
- const deleteRangeEnd = 34;
1719
- const output = "The brown fox jumps over the black dog";
1720
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1721
- let event;
1722
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1723
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1724
- });
1725
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
1726
- client.applyMsg(localRemoveMessage);
1727
- assert(event);
1728
- assert(event.isLocal);
1729
- assert.equal(event.first.position, deleteRangeStart);
1730
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1731
- assert.equal(event.ranges.length, 1);
1732
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1733
- const segment1 = event.first.segment;
1734
- assert.equal(segment1.text, "lazy ");
1735
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
1736
- remoteUserId);
1737
- client.applyMsg(remoteInsertMessage);
1738
- assert(!event.isLocal);
1739
- assert.equal(event.first.position, insertPos);
1740
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1741
- assert.equal(event.ranges.length, 1);
1742
- assert.equal(event.first.segment.cachedLength, insertText.length);
1743
- const segment2 = event.first.segment;
1744
- assert.equal(segment2.text, insertText);
1745
- assert.equal(client.getText(), output);
1746
- });
1747
- it("insertPos is deleteRangeStart, deleteLocal insertRemote, remote before local", () => {
1748
- const insertPos = 29; // before "lazy"
1749
- const insertText = "black ";
1750
- const deleteRangeStart = 29; // "lazy "
1751
- const deleteRangeEnd = 34;
1752
- const output = "The brown fox jumps over the black dog";
1753
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1754
- let event;
1755
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1756
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1757
- });
1758
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
1759
- assert(event);
1760
- assert(event.isLocal);
1761
- assert.equal(event.first.position, deleteRangeStart);
1762
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1763
- assert.equal(event.ranges.length, 1);
1764
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1765
- const segment1 = event.first.segment;
1766
- assert.equal(segment1.text, "lazy ");
1767
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
1768
- remoteUserId);
1769
- client.applyMsg(remoteInsertMessage);
1770
- assert(!event.isLocal);
1771
- assert.equal(event.first.position, insertPos);
1772
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1773
- assert.equal(event.ranges.length, 1);
1774
- assert.equal(event.first.segment.cachedLength, insertText.length);
1775
- const segment2 = event.first.segment;
1776
- assert.equal(segment2.text, insertText);
1777
- client.applyMsg(localRemoveMessage);
1778
- assert.equal(client.getText(), output);
1779
- });
1780
- it("insertPos is deleteRangeEnd, insertLocal deleteRemote, local before remote", () => {
1781
- const insertPos = 34; // after "lazy"
1782
- const insertText = "black ";
1783
- const deleteRangeStart = 29; // "lazy "
1784
- const deleteRangeEnd = 34;
1785
- const output = "The brown fox jumps over the black dog";
1786
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1787
- let event;
1788
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1789
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1790
- });
1791
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
1792
- client.applyMsg(localInsertMessage);
1793
- assert(event);
1794
- assert(event.isLocal);
1795
- assert.equal(event.first.position, insertPos);
1796
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1797
- assert.equal(event.ranges.length, 1);
1798
- assert.equal(event.first.segment.cachedLength, insertText.length);
1799
- const segment1 = event.first.segment;
1800
- assert.equal(segment1.text, insertText);
1801
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
1802
- remoteUserId);
1803
- client.applyMsg(remoteRemoveMessage);
1804
- assert(!event.isLocal);
1805
- assert.equal(event.first.position, deleteRangeStart);
1806
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1807
- assert.equal(event.ranges.length, 1);
1808
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1809
- const segment2 = event.first.segment;
1810
- assert.equal(segment2.text, "lazy ");
1811
- assert.equal(client.getText(), output);
1812
- });
1813
- it("insertPos is deleteRangeEnd, insertLocal deleteRemote, remote before local", () => {
1814
- const insertPos = 34; // after "lazy"
1815
- const insertText = "black ";
1816
- const deleteRangeStart = 29; // "lazy "
1817
- const deleteRangeEnd = 34;
1818
- const output = "The brown fox jumps over the black dog";
1819
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1820
- let event;
1821
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1822
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1823
- });
1824
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
1825
- assert(event);
1826
- assert(event.isLocal);
1827
- assert.equal(event.first.position, insertPos);
1828
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1829
- assert.equal(event.ranges.length, 1);
1830
- assert.equal(event.first.segment.cachedLength, insertText.length);
1831
- const segment1 = event.first.segment;
1832
- assert.equal(segment1.text, insertText);
1833
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
1834
- remoteUserId);
1835
- client.applyMsg(remoteRemoveMessage);
1836
- assert(!event.isLocal);
1837
- assert.equal(event.first.position, deleteRangeStart);
1838
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1839
- assert.equal(event.ranges.length, 1);
1840
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1841
- const segment2 = event.first.segment;
1842
- assert.equal(segment2.text, "lazy ");
1843
- client.applyMsg(localInsertMessage);
1844
- assert.equal(client.getText(), output);
1845
- });
1846
- it("insertPos is deleteRangeEnd, deleteLocal insertRemote, local before remote", () => {
1847
- const insertPos = 34; // after "lazy"
1848
- const insertText = "black ";
1849
- const deleteRangeStart = 29; // "lazy "
1850
- const deleteRangeEnd = 34;
1851
- const output = "The brown fox jumps over the black dog";
1852
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1853
- let event;
1854
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1855
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1856
- });
1857
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
1858
- assert(event);
1859
- assert(event.isLocal);
1860
- assert.equal(event.first.position, deleteRangeStart);
1861
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1862
- assert.equal(event.ranges.length, 1);
1863
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1864
- const segment1 = event.first.segment;
1865
- assert.equal(segment1.text, "lazy ");
1866
- client.applyMsg(localRemoveMessage);
1867
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
1868
- remoteUserId);
1869
- client.applyMsg(remoteInsertMessage);
1870
- assert(!event.isLocal);
1871
- assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
1872
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length - (deleteRangeEnd - deleteRangeStart));
1873
- assert.equal(event.ranges.length, 1);
1874
- assert.equal(event.first.segment.cachedLength, insertText.length);
1875
- const segment2 = event.first.segment;
1876
- assert.equal(segment2.text, insertText);
1877
- assert.equal(client.getText(), output);
1878
- });
1879
- it("insertPos is deleteRangeEnd, deleteLocal insertRemote, remote before local", () => {
1880
- const insertPos = 34; // after "lazy"
1881
- const insertText = "black ";
1882
- const deleteRangeStart = 29; // "lazy "
1883
- const deleteRangeEnd = 34;
1884
- const output = "The brown fox jumps over the black dog";
1885
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1886
- let event;
1887
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1888
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1889
- });
1890
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
1891
- assert(event);
1892
- assert(event.isLocal);
1893
- assert.equal(event.first.position, deleteRangeStart);
1894
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
1895
- assert.equal(event.ranges.length, 1);
1896
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
1897
- const segment1 = event.first.segment;
1898
- assert.equal(segment1.text, "lazy ");
1899
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
1900
- remoteUserId);
1901
- client.applyMsg(remoteInsertMessage);
1902
- assert(!event.isLocal);
1903
- assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
1904
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length - (deleteRangeEnd - deleteRangeStart));
1905
- assert.equal(event.ranges.length, 1);
1906
- assert.equal(event.first.segment.cachedLength, insertText.length);
1907
- const segment2 = event.first.segment;
1908
- assert.equal(segment2.text, insertText);
1909
- client.applyMsg(localRemoveMessage);
1910
- assert.equal(client.getText(), output);
1911
- });
1912
- it("insertPos is deleteRangeStart, insertLocal deleteRemote, local before remote", () => {
1913
- const insertPos = 10; // before "fox"
1914
- const insertText = "black wolf ";
1915
- const deleteRangeStart = 4; // "brown fox "
1916
- const deleteRangeEnd = 14;
1917
- const output = "The black wolf jumps over the lazy dog";
1918
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1919
- let event;
1920
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1921
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1922
- });
1923
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
1924
- client.applyMsg(localInsertMessage);
1925
- assert(event);
1926
- assert(event.isLocal);
1927
- assert.equal(event.first.position, insertPos);
1928
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1929
- assert.equal(event.ranges.length, 1);
1930
- assert.equal(event.first.segment.cachedLength, insertText.length);
1931
- const segment1 = event.first.segment;
1932
- assert.equal(segment1.text, insertText);
1933
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
1934
- remoteUserId);
1935
- client.applyMsg(remoteRemoveMessage);
1936
- const expectedRangeStart1 = deleteRangeStart;
1937
- const expectedRangeEnd1 = expectedRangeStart1 + "brown ".length;
1938
- // merge tree internal: "brown " is deleted and then end is calculated
1939
- const expectedRangeStart2 = deleteRangeStart + insertText.length;
1940
- const expectedRangeEnd2 = expectedRangeStart2 + "fox ".length;
1941
- assert(!event.isLocal);
1942
- assert.equal(event.first.position, expectedRangeStart1);
1943
- assert.equal(event.last.position + event.last.segment.cachedLength, expectedRangeEnd2);
1944
- assert.equal(event.ranges.length, 2);
1945
- assert.equal(event.first.segment.cachedLength, expectedRangeEnd1 - expectedRangeStart1);
1946
- const segment2 = event.first.segment;
1947
- assert.equal(segment2.text, "brown ");
1948
- assert.equal(event.ranges[1].position, expectedRangeStart2);
1949
- assert.equal(event.ranges[1].segment.cachedLength, expectedRangeEnd2 - expectedRangeStart2);
1950
- const segment3 = event.ranges[1].segment;
1951
- assert.equal(segment3.text, "fox ");
1952
- assert.equal(client.getText(), output);
1953
- });
1954
- it("insertPos is deleteRangeStart, insertLocal deleteRemote, remote before local", () => {
1955
- const insertPos = 10; // before "fox"
1956
- const insertText = "black wolf ";
1957
- const deleteRangeStart = 4; // "brown fox "
1958
- const deleteRangeEnd = 14;
1959
- const output = "The black wolf jumps over the lazy dog";
1960
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
1961
- let event;
1962
- client.on("delta", (clientArgs, mergeTreeArgs) => {
1963
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
1964
- });
1965
- const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
1966
- assert(event);
1967
- assert(event.isLocal);
1968
- assert.equal(event.first.position, insertPos);
1969
- assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
1970
- assert.equal(event.ranges.length, 1);
1971
- assert.equal(event.first.segment.cachedLength, insertText.length);
1972
- const segment1 = event.first.segment;
1973
- assert.equal(segment1.text, insertText);
1974
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
1975
- remoteUserId);
1976
- client.applyMsg(remoteRemoveMessage);
1977
- const expectedRangeStart1 = deleteRangeStart;
1978
- const expectedRangeEnd1 = expectedRangeStart1 + "brown ".length;
1979
- // merge tree internal: "brown " is deleted and then end is calculated
1980
- const expectedRangeStart2 = deleteRangeStart + insertText.length;
1981
- const expectedRangeEnd2 = expectedRangeStart2 + "fox ".length;
1982
- assert(!event.isLocal);
1983
- assert.equal(event.first.position, expectedRangeStart1);
1984
- assert.equal(event.last.position + event.last.segment.cachedLength, expectedRangeEnd2);
1985
- assert.equal(event.ranges.length, 2);
1986
- assert.equal(event.first.segment.cachedLength, expectedRangeEnd1 - expectedRangeStart1);
1987
- const segment2 = event.first.segment;
1988
- assert.equal(segment2.text, "brown ");
1989
- assert.equal(event.ranges[1].position, expectedRangeStart2);
1990
- assert.equal(event.ranges[1].segment.cachedLength, expectedRangeEnd2 - expectedRangeStart2);
1991
- const segment3 = event.ranges[1].segment;
1992
- assert.equal(segment3.text, "fox ");
1993
- client.applyMsg(localInsertMessage);
1994
- assert.equal(client.getText(), output);
1995
- });
1996
- it("insertPos is deleteRangeStart, deleteLocal insertRemote, local before remote", () => {
1997
- const insertPos = 10; // before "fox"
1998
- const insertText = "black wolf ";
1999
- const deleteRangeStart = 4; // "brown fox "
2000
- const deleteRangeEnd = 14;
2001
- const output = "The black wolf jumps over the lazy dog";
2002
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
2003
- let event;
2004
- client.on("delta", (clientArgs, mergeTreeArgs) => {
2005
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
2006
- });
2007
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
2008
- client.applyMsg(localRemoveMessage);
2009
- assert(event);
2010
- assert(event.isLocal);
2011
- assert.equal(event.first.position, deleteRangeStart);
2012
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
2013
- assert.equal(event.ranges.length, 1);
2014
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
2015
- const segment1 = event.first.segment;
2016
- assert.equal(segment1.text, "brown fox ");
2017
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
2018
- remoteUserId);
2019
- client.applyMsg(remoteInsertMessage);
2020
- assert(!event.isLocal);
2021
- assert.equal(event.first.position, deleteRangeStart);
2022
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeStart + insertText.length);
2023
- assert.equal(event.ranges.length, 1);
2024
- assert.equal(event.first.segment.cachedLength, insertText.length);
2025
- const segment2 = event.first.segment;
2026
- assert.equal(segment2.text, insertText);
2027
- assert.equal(client.getText(), output);
2028
- });
2029
- it("insertPos is deleteRangeStart, deleteLocal insertRemote, remote before local", () => {
2030
- const insertPos = 10; // before "fox"
2031
- const insertText = "black wolf ";
2032
- const deleteRangeStart = 4; // "brown fox "
2033
- const deleteRangeEnd = 14;
2034
- const output = "The black wolf jumps over the lazy dog";
2035
- const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
2036
- let event;
2037
- client.on("delta", (clientArgs, mergeTreeArgs) => {
2038
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
2039
- });
2040
- const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
2041
- assert(event);
2042
- assert(event.isLocal);
2043
- assert.equal(event.first.position, deleteRangeStart);
2044
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
2045
- assert.equal(event.ranges.length, 1);
2046
- assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
2047
- const segment1 = event.first.segment;
2048
- assert.equal(segment1.text, "brown fox ");
2049
- const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
2050
- remoteUserId);
2051
- client.applyMsg(remoteInsertMessage);
2052
- assert(!event.isLocal);
2053
- assert.equal(event.first.position, deleteRangeStart);
2054
- assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeStart + insertText.length);
2055
- assert.equal(event.ranges.length, 1);
2056
- assert.equal(event.first.segment.cachedLength, insertText.length);
2057
- const segment2 = event.first.segment;
2058
- assert.equal(segment2.text, insertText);
2059
- client.applyMsg(localRemoveMessage);
2060
- assert.equal(client.getText(), output);
2061
- });
2062
- });
2063
- });
2064
- describe("SequenceDeltaEvent", () => {
2065
- const localUserLongId = "localUser";
2066
- let client;
2067
- beforeEach(() => {
2068
- client = new TestClient();
2069
- client.startOrUpdateCollaboration(localUserLongId);
2070
- });
2071
- describe(".ranges", () => {
2072
- it("single segment", () => {
2073
- const insertText = "text";
2074
- let deltaArgs;
2075
- client.on("delta", (opArgs, delta) => {
2076
- deltaArgs = delta;
2077
- });
2078
- const op = client.insertTextLocal(0, insertText);
2079
- assert(deltaArgs);
2080
- assert.equal(deltaArgs.deltaSegments.length, 1);
2081
- assert(op);
2082
- const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
2083
- assert(event.isLocal);
2084
- assert.equal(event.ranges.length, 1);
2085
- assert.equal(event.first.position, 0);
2086
- assert.equal(event.first.segment.cachedLength, insertText.length);
2087
- assert.equal(event.last.position + event.last.segment.cachedLength, insertText.length);
2088
- });
2089
- it("multiple continuous segments", () => {
2090
- const insertText = "text";
2091
- const segmentCount = 5;
2092
- for (let i = 0; i < segmentCount + 2; i = i + 1) {
2093
- client.insertTextLocal(0, insertText);
2094
- }
2095
- let deltaArgs;
2096
- client.on("delta", (opArgs, delta) => {
2097
- deltaArgs = delta;
2098
- });
2099
- const op = client.annotateRangeLocal(insertText.length, client.getLength() - insertText.length, {
2100
- foo: "bar",
2101
- });
2102
- assert(deltaArgs);
2103
- assert.equal(deltaArgs.deltaSegments.length, segmentCount);
2104
- assert(op);
2105
- const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
2106
- assert(event.isLocal);
2107
- assert.equal(event.ranges.length, segmentCount);
2108
- assert.equal(event.first.position, insertText.length);
2109
- for (let i = 0; i < segmentCount; i = i + 1) {
2110
- assert.equal(event.ranges[i].position, (i + 1) * insertText.length);
2111
- assert.equal(event.ranges[i].segment.cachedLength, insertText.length);
2112
- assert.equal(event.ranges[i].propertyDeltas.foo, null);
2113
- }
2114
- assert.equal(event.last.position + event.last.segment.cachedLength, client.getLength() - insertText.length);
2115
- });
2116
- it("multiple noncontinuous segments", () => {
2117
- const textCount = 4;
2118
- const segmentCount = 5;
2119
- for (let i = 0; i < segmentCount; i = i + 1) {
2120
- const op = client.insertTextLocal(0, `${i}`.repeat(textCount));
2121
- client.applyMsg(client.makeOpMessage(op, client.mergeTree.collabWindow.currentSeq + 1));
2122
- }
2123
- const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(0, client.getLength()), client.mergeTree.collabWindow.currentSeq + 1);
2124
- remoteRemoveMessage.clientSequenceNumber = 0;
2125
- remoteRemoveMessage.clientId = "remote user";
2126
- for (let i = 0; i < segmentCount; i = i + 1) {
2127
- client.insertTextLocal(i * 2 * textCount, "b".repeat(textCount));
2128
- }
2129
- let event;
2130
- client.on("delta", (clientArgs, mergeTreeArgs) => {
2131
- event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
2132
- });
2133
- client.applyMsg(remoteRemoveMessage);
2134
- assert(event);
2135
- assert(!event.isLocal);
2136
- assert.equal(event.ranges.length, segmentCount);
2137
- for (let i = 0; i < segmentCount; i = i + 1) {
2138
- assert.equal(event.ranges[i].position, (i + 1) * textCount);
2139
- assert.equal(event.ranges[i].segment.cachedLength, textCount);
2140
- }
2141
- });
2142
- });
2143
- });
2144
- //# sourceMappingURL=sequenceDeltaEvent.spec.js.map