@y/y 14.0.0-16

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 (193) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +1406 -0
  3. package/dist/Skip-j0kX7pdq.js +12173 -0
  4. package/dist/Skip-j0kX7pdq.js.map +1 -0
  5. package/dist/Skip-wRT7BKFP.js +11877 -0
  6. package/dist/Skip-wRT7BKFP.js.map +1 -0
  7. package/dist/index-DyTeTfmj.js +163 -0
  8. package/dist/index-DyTeTfmj.js.map +1 -0
  9. package/dist/index-R7GxO-36.js +165 -0
  10. package/dist/index-R7GxO-36.js.map +1 -0
  11. package/dist/internals.cjs +286 -0
  12. package/dist/internals.cjs.map +1 -0
  13. package/dist/internals.mjs +25 -0
  14. package/dist/internals.mjs.map +1 -0
  15. package/dist/src/index.d.ts +2 -0
  16. package/dist/src/index.d.ts.map +1 -0
  17. package/dist/src/internals.d.ts +43 -0
  18. package/dist/src/internals.d.ts.map +1 -0
  19. package/dist/src/structs/AbstractStruct.d.ts +42 -0
  20. package/dist/src/structs/AbstractStruct.d.ts.map +1 -0
  21. package/dist/src/structs/ContentAny.d.ts +67 -0
  22. package/dist/src/structs/ContentAny.d.ts.map +1 -0
  23. package/dist/src/structs/ContentBinary.d.ts +64 -0
  24. package/dist/src/structs/ContentBinary.d.ts.map +1 -0
  25. package/dist/src/structs/ContentDeleted.d.ts +64 -0
  26. package/dist/src/structs/ContentDeleted.d.ts.map +1 -0
  27. package/dist/src/structs/ContentDoc.d.ts +72 -0
  28. package/dist/src/structs/ContentDoc.d.ts.map +1 -0
  29. package/dist/src/structs/ContentEmbed.d.ts +67 -0
  30. package/dist/src/structs/ContentEmbed.d.ts.map +1 -0
  31. package/dist/src/structs/ContentFormat.d.ts +69 -0
  32. package/dist/src/structs/ContentFormat.d.ts.map +1 -0
  33. package/dist/src/structs/ContentJSON.d.ts +70 -0
  34. package/dist/src/structs/ContentJSON.d.ts.map +1 -0
  35. package/dist/src/structs/ContentString.d.ts +70 -0
  36. package/dist/src/structs/ContentString.d.ts.map +1 -0
  37. package/dist/src/structs/ContentType.d.ts +83 -0
  38. package/dist/src/structs/ContentType.d.ts.map +1 -0
  39. package/dist/src/structs/GC.d.ts +31 -0
  40. package/dist/src/structs/GC.d.ts.map +1 -0
  41. package/dist/src/structs/Item.d.ts +212 -0
  42. package/dist/src/structs/Item.d.ts.map +1 -0
  43. package/dist/src/structs/Skip.d.ts +33 -0
  44. package/dist/src/structs/Skip.d.ts.map +1 -0
  45. package/dist/src/types/AbstractType.d.ts +239 -0
  46. package/dist/src/types/AbstractType.d.ts.map +1 -0
  47. package/dist/src/types/YArray.d.ts +128 -0
  48. package/dist/src/types/YArray.d.ts.map +1 -0
  49. package/dist/src/types/YMap.d.ts +112 -0
  50. package/dist/src/types/YMap.d.ts.map +1 -0
  51. package/dist/src/types/YText.d.ts +216 -0
  52. package/dist/src/types/YText.d.ts.map +1 -0
  53. package/dist/src/types/YXmlElement.d.ts +106 -0
  54. package/dist/src/types/YXmlElement.d.ts.map +1 -0
  55. package/dist/src/types/YXmlFragment.d.ts +143 -0
  56. package/dist/src/types/YXmlFragment.d.ts.map +1 -0
  57. package/dist/src/types/YXmlHook.d.ts +32 -0
  58. package/dist/src/types/YXmlHook.d.ts.map +1 -0
  59. package/dist/src/types/YXmlText.d.ts +34 -0
  60. package/dist/src/types/YXmlText.d.ts.map +1 -0
  61. package/dist/src/utils/AbstractConnector.d.ts +20 -0
  62. package/dist/src/utils/AbstractConnector.d.ts.map +1 -0
  63. package/dist/src/utils/AttributionManager.d.ts +224 -0
  64. package/dist/src/utils/AttributionManager.d.ts.map +1 -0
  65. package/dist/src/utils/Doc.d.ts +267 -0
  66. package/dist/src/utils/Doc.d.ts.map +1 -0
  67. package/dist/src/utils/EventHandler.d.ts +19 -0
  68. package/dist/src/utils/EventHandler.d.ts.map +1 -0
  69. package/dist/src/utils/ID.d.ts +26 -0
  70. package/dist/src/utils/ID.d.ts.map +1 -0
  71. package/dist/src/utils/IdMap.d.ts +161 -0
  72. package/dist/src/utils/IdMap.d.ts.map +1 -0
  73. package/dist/src/utils/IdSet.d.ts +163 -0
  74. package/dist/src/utils/IdSet.d.ts.map +1 -0
  75. package/dist/src/utils/RelativePosition.d.ts +91 -0
  76. package/dist/src/utils/RelativePosition.d.ts.map +1 -0
  77. package/dist/src/utils/Snapshot.d.ts +40 -0
  78. package/dist/src/utils/Snapshot.d.ts.map +1 -0
  79. package/dist/src/utils/StructSet.d.ts +27 -0
  80. package/dist/src/utils/StructSet.d.ts.map +1 -0
  81. package/dist/src/utils/StructStore.d.ts +41 -0
  82. package/dist/src/utils/StructStore.d.ts.map +1 -0
  83. package/dist/src/utils/Transaction.d.ts +136 -0
  84. package/dist/src/utils/Transaction.d.ts.map +1 -0
  85. package/dist/src/utils/UndoManager.d.ts +188 -0
  86. package/dist/src/utils/UndoManager.d.ts.map +1 -0
  87. package/dist/src/utils/UpdateDecoder.d.ts +167 -0
  88. package/dist/src/utils/UpdateDecoder.d.ts.map +1 -0
  89. package/dist/src/utils/UpdateEncoder.d.ts +164 -0
  90. package/dist/src/utils/UpdateEncoder.d.ts.map +1 -0
  91. package/dist/src/utils/YEvent.d.ts +120 -0
  92. package/dist/src/utils/YEvent.d.ts.map +1 -0
  93. package/dist/src/utils/delta-helpers.d.ts +6 -0
  94. package/dist/src/utils/delta-helpers.d.ts.map +1 -0
  95. package/dist/src/utils/encoding.d.ts +30 -0
  96. package/dist/src/utils/encoding.d.ts.map +1 -0
  97. package/dist/src/utils/isParentOf.d.ts +3 -0
  98. package/dist/src/utils/isParentOf.d.ts.map +1 -0
  99. package/dist/src/utils/logging.d.ts +3 -0
  100. package/dist/src/utils/logging.d.ts.map +1 -0
  101. package/dist/src/utils/types.d.ts +7 -0
  102. package/dist/src/utils/types.d.ts.map +1 -0
  103. package/dist/src/utils/updates.d.ts +89 -0
  104. package/dist/src/utils/updates.d.ts.map +1 -0
  105. package/dist/testHelper.cjs +780 -0
  106. package/dist/testHelper.cjs.map +1 -0
  107. package/dist/testHelper.mjs +617 -0
  108. package/dist/testHelper.mjs.map +1 -0
  109. package/dist/tests/IdMap.tests.d.ts +9 -0
  110. package/dist/tests/IdMap.tests.d.ts.map +1 -0
  111. package/dist/tests/IdSet.tests.d.ts +9 -0
  112. package/dist/tests/IdSet.tests.d.ts.map +1 -0
  113. package/dist/tests/attribution.tests.d.ts +8 -0
  114. package/dist/tests/attribution.tests.d.ts.map +1 -0
  115. package/dist/tests/compatibility.tests.d.ts +5 -0
  116. package/dist/tests/compatibility.tests.d.ts.map +1 -0
  117. package/dist/tests/delta.tests.d.ts +7 -0
  118. package/dist/tests/delta.tests.d.ts.map +1 -0
  119. package/dist/tests/doc.tests.d.ts +13 -0
  120. package/dist/tests/doc.tests.d.ts.map +1 -0
  121. package/dist/tests/encoding.tests.d.ts +5 -0
  122. package/dist/tests/encoding.tests.d.ts.map +1 -0
  123. package/dist/tests/index.d.ts +2 -0
  124. package/dist/tests/index.d.ts.map +1 -0
  125. package/dist/tests/relativePositions.tests.d.ts +11 -0
  126. package/dist/tests/relativePositions.tests.d.ts.map +1 -0
  127. package/dist/tests/snapshot.tests.d.ts +13 -0
  128. package/dist/tests/snapshot.tests.d.ts.map +1 -0
  129. package/dist/tests/testHelper.d.ts +167 -0
  130. package/dist/tests/testHelper.d.ts.map +1 -0
  131. package/dist/tests/undo-redo.tests.d.ts +27 -0
  132. package/dist/tests/undo-redo.tests.d.ts.map +1 -0
  133. package/dist/tests/updates.tests.d.ts +24 -0
  134. package/dist/tests/updates.tests.d.ts.map +1 -0
  135. package/dist/tests/y-array.tests.d.ts +45 -0
  136. package/dist/tests/y-array.tests.d.ts.map +1 -0
  137. package/dist/tests/y-map.tests.d.ts +45 -0
  138. package/dist/tests/y-map.tests.d.ts.map +1 -0
  139. package/dist/tests/y-text.tests.d.ts +49 -0
  140. package/dist/tests/y-text.tests.d.ts.map +1 -0
  141. package/dist/tests/y-xml.tests.d.ts +15 -0
  142. package/dist/tests/y-xml.tests.d.ts.map +1 -0
  143. package/dist/yjs.cjs +151 -0
  144. package/dist/yjs.cjs.map +1 -0
  145. package/dist/yjs.mjs +26 -0
  146. package/dist/yjs.mjs.map +1 -0
  147. package/package.json +101 -0
  148. package/src/index.js +153 -0
  149. package/src/internals.js +44 -0
  150. package/src/structs/AbstractStruct.js +59 -0
  151. package/src/structs/ContentAny.js +115 -0
  152. package/src/structs/ContentBinary.js +93 -0
  153. package/src/structs/ContentDeleted.js +101 -0
  154. package/src/structs/ContentDoc.js +141 -0
  155. package/src/structs/ContentEmbed.js +98 -0
  156. package/src/structs/ContentFormat.js +105 -0
  157. package/src/structs/ContentJSON.js +119 -0
  158. package/src/structs/ContentString.js +113 -0
  159. package/src/structs/ContentType.js +176 -0
  160. package/src/structs/GC.js +80 -0
  161. package/src/structs/Item.js +845 -0
  162. package/src/structs/Skip.js +75 -0
  163. package/src/types/AbstractType.js +1434 -0
  164. package/src/types/YArray.js +270 -0
  165. package/src/types/YMap.js +244 -0
  166. package/src/types/YText.js +934 -0
  167. package/src/types/YXmlElement.js +227 -0
  168. package/src/types/YXmlFragment.js +266 -0
  169. package/src/types/YXmlHook.js +68 -0
  170. package/src/types/YXmlText.js +66 -0
  171. package/src/utils/AbstractConnector.js +25 -0
  172. package/src/utils/AttributionManager.js +619 -0
  173. package/src/utils/Doc.js +372 -0
  174. package/src/utils/EventHandler.js +87 -0
  175. package/src/utils/ID.js +89 -0
  176. package/src/utils/IdMap.js +629 -0
  177. package/src/utils/IdSet.js +823 -0
  178. package/src/utils/RelativePosition.js +352 -0
  179. package/src/utils/Snapshot.js +220 -0
  180. package/src/utils/StructSet.js +137 -0
  181. package/src/utils/StructStore.js +289 -0
  182. package/src/utils/Transaction.js +489 -0
  183. package/src/utils/UndoManager.js +391 -0
  184. package/src/utils/UpdateDecoder.js +281 -0
  185. package/src/utils/UpdateEncoder.js +320 -0
  186. package/src/utils/YEvent.js +216 -0
  187. package/src/utils/delta-helpers.js +54 -0
  188. package/src/utils/encoding.js +623 -0
  189. package/src/utils/isParentOf.js +21 -0
  190. package/src/utils/logging.js +21 -0
  191. package/src/utils/types.js +28 -0
  192. package/src/utils/updates.js +715 -0
  193. package/tests/testHelper.js +600 -0
@@ -0,0 +1,617 @@
1
+ import * as t from 'lib0/testing';
2
+ import * as prng from 'lib0/prng';
3
+ import * as encoding from 'lib0/encoding';
4
+ import * as decoding from 'lib0/decoding';
5
+ import * as syncProtocol from '@y/protocols/sync';
6
+ import * as object from 'lib0/object';
7
+ import * as map from 'lib0/map';
8
+ import { Y } from './index-DyTeTfmj.js';
9
+ import * as math from 'lib0/math';
10
+ import * as list from 'lib0/list';
11
+ import * as delta from 'lib0/delta';
12
+ import { bb as diffUpdate, a$ as logUpdate, Q as applyUpdate, b4 as mergeUpdates, T as encodeStateAsUpdate, ba as diffUpdateV2, b0 as logUpdateV2, P as applyUpdateV2, b9 as mergeUpdatesV2, S as encodeStateAsUpdateV2, a7 as compareIDs, D as Doc, cs as YXmlElement, by as createIdMap, n as addToIdSet, p as createIdSet, bm as createAttributionItem, bv as encodeIdMap, bU as AbstractType, $ as encodeStateVector, v as equalIdSets, q as createDeleteSetFromStructStore, au as encodeSnapshot, az as snapshot, d4 as Item } from './Skip-wRT7BKFP.js';
13
+ export { ah as AbsolutePosition, bF as AbstractAttributionManager, A as AbstractConnector, cy as AbstractStruct, cf as Array, bl as Attribution, cN as ContentAny, cB as ContentBinary, cD as ContentDeleted, cF as ContentDoc, cH as ContentEmbed, cJ as ContentFormat, cL as ContentJSON, cP as ContentString, cZ as ContentType, bJ as DiffAttributionManager, cA as GC, a6 as ID, bt as IdMap, b as IdSet, ch as Map, ae as RelativePosition, d9 as Skip, ar as Snapshot, co as Text, aS as Transaction, bG as TwosetAttributionManager, aZ as UndoManager, U as UpdateDecoderV1, C as UpdateDecoderV2, F as UpdateEncoderV1, H as UpdateEncoderV2, cq as XmlFragment, cu as XmlHook, cw as XmlText, bh as YEvent, cl as cleanupYTextFormatting, y as cloneDoc, aq as compareRelativePositions, bf as convertUpdateFormatV1ToV2, bg as convertUpdateFormatV2ToV1, ap as createAbsolutePositionFromRelativePosition, bK as createAttributionManagerFromDiff, aC as createDocFromSnapshot, a8 as createID, bs as createIdMapFromIdSet, s as createInsertionSetFromStructStore, ag as createRelativePositionFromJSON, ak as createRelativePositionFromTypeIndex, ax as createSnapshot, bx as decodeIdMap, ao as decodeRelativePosition, aw as decodeSnapshot, av as decodeSnapshotV2, W as decodeStateVector, b1 as decodeUpdate, b2 as decodeUpdateV2, bN as diffDocsToDelta, bA as diffIdMap, j as diffIdSet, ay as emptySnapshot, am as encodeRelativePosition, at as encodeSnapshotV2, b6 as encodeStateVectorFromUpdate, b5 as encodeStateVectorFromUpdateV2, as as equalSnapshots, aK as findIndexSS, ab as findRootTypeKey, aM as getItem, aP as getItemCleanEnd, aO as getItemCleanStart, aH as getState, bS as getTypeChildren, bz as insertIntoIdMap, g as insertIntoIdSet, ac as isParentOf, i as iterateStructsByIdSet, ad as logType, br as mergeIdMaps, m as mergeIdSets, bI as noAttributionsManager, bd as obfuscateUpdate, be as obfuscateUpdateV2, bw as readIdMap, t as readIdSet, O as readUpdate, b8 as readUpdateIdRanges, b7 as readUpdateIdRangesV2, N as readUpdateV2, af as relativePositionToJSON, aE as snapshotContainsUpdate, aX as transact, aW as tryGc, bY as typeListToArraySnapshot, cd as typeMapGetAllSnapshot, cc as typeMapGetSnapshot } from './Skip-wRT7BKFP.js';
14
+ import 'lib0/function';
15
+ import 'lib0/binary';
16
+ import 'lib0/observable';
17
+ import 'lib0/array';
18
+ import 'lib0/traits';
19
+ import 'lib0/random';
20
+ import 'lib0/promise';
21
+ import 'lib0/buffer';
22
+ import 'lib0/error';
23
+ import 'lib0/set';
24
+ import 'lib0/logging';
25
+ import 'lib0/time';
26
+ import 'lib0/string';
27
+ import 'lib0/hash/rabin';
28
+ import 'lib0/iterator';
29
+ import 'lib0/environment';
30
+ import 'lib0/schema';
31
+
32
+ if (typeof window !== 'undefined') {
33
+ // @ts-ignore
34
+ window.Y = Y; // eslint-disable-line
35
+ }
36
+
37
+ /**
38
+ * @param {TestYInstance} y // publish message created by `y` to all other online clients
39
+ * @param {Uint8Array} m
40
+ */
41
+ const broadcastMessage = (y, m) => {
42
+ if (y.tc.onlineConns.has(y)) {
43
+ y.tc.onlineConns.forEach(remoteYInstance => {
44
+ if (remoteYInstance !== y) {
45
+ remoteYInstance._receive(m, y);
46
+ }
47
+ });
48
+ }
49
+ };
50
+
51
+ let useV2 = false;
52
+
53
+ const encV1 = {
54
+ encodeStateAsUpdate: encodeStateAsUpdate,
55
+ mergeUpdates: mergeUpdates,
56
+ applyUpdate: applyUpdate,
57
+ logUpdate: logUpdate,
58
+ updateEventName: /** @type {'update'} */ ('update'),
59
+ diffUpdate: diffUpdate
60
+ };
61
+
62
+ const encV2 = {
63
+ encodeStateAsUpdate: encodeStateAsUpdateV2,
64
+ mergeUpdates: mergeUpdatesV2,
65
+ applyUpdate: applyUpdateV2,
66
+ logUpdate: logUpdateV2,
67
+ updateEventName: /** @type {'updateV2'} */ ('updateV2'),
68
+ diffUpdate: diffUpdateV2
69
+ };
70
+
71
+ let enc = encV1;
72
+
73
+ const useV1Encoding = () => {
74
+ useV2 = false;
75
+ enc = encV1;
76
+ };
77
+
78
+ const useV2Encoding = () => {
79
+ console.error('sync protocol doesnt support v2 protocol yet, fallback to v1 encoding'); // @Todo
80
+ useV2 = false;
81
+ enc = encV1;
82
+ };
83
+
84
+ class TestYInstance extends Doc {
85
+ /**
86
+ * @param {TestConnector} testConnector
87
+ * @param {number} clientID
88
+ */
89
+ constructor (testConnector, clientID) {
90
+ super();
91
+ this.userID = clientID; // overwriting clientID
92
+ /**
93
+ * @type {TestConnector}
94
+ */
95
+ this.tc = testConnector;
96
+ /**
97
+ * @type {Map<TestYInstance, Array<Uint8Array>>}
98
+ */
99
+ this.receiving = new Map();
100
+ testConnector.allConns.add(this);
101
+ /**
102
+ * The list of received updates.
103
+ * We are going to merge them later using Y.mergeUpdates and check if the resulting document is correct.
104
+ * @type {Array<Uint8Array<ArrayBuffer>>}
105
+ */
106
+ this.updates = [];
107
+ // set up observe on local model
108
+ this.on(enc.updateEventName, (update, origin) => {
109
+ if (origin !== testConnector) {
110
+ const encoder = encoding.createEncoder();
111
+ syncProtocol.writeUpdate(encoder, update);
112
+ broadcastMessage(this, encoding.toUint8Array(encoder));
113
+ }
114
+ this.updates.push(update);
115
+ });
116
+ this.connect();
117
+ }
118
+
119
+ /**
120
+ * Disconnect from TestConnector.
121
+ */
122
+ disconnect () {
123
+ this.receiving = new Map();
124
+ this.tc.onlineConns.delete(this);
125
+ }
126
+
127
+ /**
128
+ * Append yourself to the list of known Y instances in testconnector.
129
+ * Also initiate sync with all clients.
130
+ */
131
+ connect () {
132
+ if (!this.tc.onlineConns.has(this)) {
133
+ this.tc.onlineConns.add(this);
134
+ const encoder = encoding.createEncoder();
135
+ syncProtocol.writeSyncStep1(encoder, this);
136
+ // publish SyncStep1
137
+ broadcastMessage(this, encoding.toUint8Array(encoder));
138
+ this.tc.onlineConns.forEach(remoteYInstance => {
139
+ if (remoteYInstance !== this) {
140
+ // remote instance sends instance to this instance
141
+ const encoder = encoding.createEncoder();
142
+ syncProtocol.writeSyncStep1(encoder, remoteYInstance);
143
+ this._receive(encoding.toUint8Array(encoder), remoteYInstance);
144
+ }
145
+ });
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Receive a message from another client. This message is only appended to the list of receiving messages.
151
+ * TestConnector decides when this client actually reads this message.
152
+ *
153
+ * @param {Uint8Array} message
154
+ * @param {TestYInstance} remoteClient
155
+ */
156
+ _receive (message, remoteClient) {
157
+ map.setIfUndefined(this.receiving, remoteClient, () => /** @type {Array<Uint8Array>} */ ([])).push(message);
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Keeps track of TestYInstances.
163
+ *
164
+ * The TestYInstances add/remove themselves from the list of connections maiained in this object.
165
+ * I think it makes sense. Deal with it.
166
+ */
167
+ class TestConnector {
168
+ /**
169
+ * @param {prng.PRNG} gen
170
+ */
171
+ constructor (gen) {
172
+ /**
173
+ * @type {Set<TestYInstance>}
174
+ */
175
+ this.allConns = new Set();
176
+ /**
177
+ * @type {Set<TestYInstance>}
178
+ */
179
+ this.onlineConns = new Set();
180
+ /**
181
+ * @type {prng.PRNG}
182
+ */
183
+ this.prng = gen;
184
+ }
185
+
186
+ /**
187
+ * Create a new Y instance and add it to the list of connections
188
+ * @param {number} clientID
189
+ */
190
+ createY (clientID) {
191
+ return new TestYInstance(this, clientID)
192
+ }
193
+
194
+ /**
195
+ * Choose random connection and flush a random message from a random sender.
196
+ *
197
+ * If this function was unable to flush a message, because there are no more messages to flush, it returns false. true otherwise.
198
+ * @return {boolean}
199
+ */
200
+ flushRandomMessage () {
201
+ const gen = this.prng;
202
+ const conns = Array.from(this.onlineConns).filter(conn => conn.receiving.size > 0);
203
+ if (conns.length > 0) {
204
+ const receiver = prng.oneOf(gen, conns);
205
+ const [sender, messages] = prng.oneOf(gen, Array.from(receiver.receiving));
206
+ const m = messages.shift();
207
+ if (messages.length === 0) {
208
+ receiver.receiving.delete(sender);
209
+ }
210
+ if (m === undefined) {
211
+ return this.flushRandomMessage()
212
+ }
213
+ const encoder = encoding.createEncoder();
214
+ // console.log('receive (' + sender.userID + '->' + receiver.userID + '):\n', syncProtocol.stringifySyncMessage(decoding.createDecoder(m), receiver))
215
+ // do not publish data created when this function is executed (could be ss2 or update message)
216
+ syncProtocol.readSyncMessage(decoding.createDecoder(m), encoder, receiver, receiver.tc);
217
+ if (encoding.length(encoder) > 0) {
218
+ // send reply message
219
+ sender._receive(encoding.toUint8Array(encoder), receiver);
220
+ }
221
+ return true
222
+ }
223
+ return false
224
+ }
225
+
226
+ /**
227
+ * @return {boolean} True iff this function actually flushed something
228
+ */
229
+ flushAllMessages () {
230
+ let didSomething = false;
231
+ while (this.flushRandomMessage()) {
232
+ didSomething = true;
233
+ }
234
+ return didSomething
235
+ }
236
+
237
+ reconnectAll () {
238
+ this.allConns.forEach(conn => conn.connect());
239
+ }
240
+
241
+ disconnectAll () {
242
+ this.allConns.forEach(conn => conn.disconnect());
243
+ }
244
+
245
+ syncAll () {
246
+ this.reconnectAll();
247
+ this.flushAllMessages();
248
+ }
249
+
250
+ /**
251
+ * @return {boolean} Whether it was possible to disconnect a random connection.
252
+ */
253
+ disconnectRandom () {
254
+ if (this.onlineConns.size === 0) {
255
+ return false
256
+ }
257
+ prng.oneOf(this.prng, Array.from(this.onlineConns)).disconnect();
258
+ return true
259
+ }
260
+
261
+ /**
262
+ * @return {boolean} Whether it was possible to reconnect a random connection.
263
+ */
264
+ reconnectRandom () {
265
+ /**
266
+ * @type {Array<TestYInstance>}
267
+ */
268
+ const reconnectable = [];
269
+ this.allConns.forEach(conn => {
270
+ if (!this.onlineConns.has(conn)) {
271
+ reconnectable.push(conn);
272
+ }
273
+ });
274
+ if (reconnectable.length === 0) {
275
+ return false
276
+ }
277
+ prng.oneOf(this.prng, reconnectable).connect();
278
+ return true
279
+ }
280
+ }
281
+
282
+ /**
283
+ * @template T
284
+ * @param {t.TestCase} tc
285
+ * @param {{users?:number}} conf
286
+ * @param {InitTestObjectCallback<T>} [initTestObject]
287
+ * @return {{testObjects:Array<any>,testConnector:TestConnector,users:Array<TestYInstance>,array0:Y.Array<any>,array1:Y.Array<any>,array2:Y.Array<any>,map0:Y.Map<any>,map1:Y.Map<any>,map2:Y.Map<any>,map3:Y.Map<any>,text0:Y.Text,text1:Y.Text,text2:Y.Text,xml0:Y.XmlElement,xml1:Y.XmlElement,xml2:Y.XmlElement}}
288
+ */
289
+ const init = (tc, { users = 5 } = {}, initTestObject) => {
290
+ /**
291
+ * @type {Object<string,any>}
292
+ */
293
+ const result = {
294
+ users: []
295
+ };
296
+ const gen = tc.prng;
297
+ // choose an encoding approach at random
298
+ if (prng.bool(gen)) {
299
+ useV2Encoding();
300
+ } else {
301
+ useV1Encoding();
302
+ }
303
+
304
+ const testConnector = new TestConnector(gen);
305
+ result.testConnector = testConnector;
306
+ for (let i = 0; i < users; i++) {
307
+ const y = testConnector.createY(i);
308
+ y.clientID = i;
309
+ result.users.push(y);
310
+ result['array' + i] = y.getArray('array');
311
+ result['map' + i] = y.getMap('map');
312
+ result['xml' + i] = y.get('xml', YXmlElement);
313
+ result['text' + i] = y.getText('text');
314
+ }
315
+ testConnector.syncAll();
316
+ result.testObjects = result.users.map(initTestObject || (() => null));
317
+ useV1Encoding();
318
+ return /** @type {any} */ (result)
319
+ };
320
+
321
+ /**
322
+ * @param {Y.IdSet} idSet1
323
+ * @param {Y.IdSet} idSet2
324
+ */
325
+ const compareIdSets = (idSet1, idSet2) => {
326
+ t.assert(idSet1.clients.size === idSet2.clients.size);
327
+ for (const [client, _items1] of idSet1.clients.entries()) {
328
+ const items1 = _items1.getIds();
329
+ const items2 = idSet2.clients.get(client)?.getIds();
330
+ t.assert(items2 !== undefined && items1.length === items2.length);
331
+ for (let i = 0; i < items1.length; i++) {
332
+ const di1 = items1[i];
333
+ const di2 = /** @type {Array<import('../src/utils/IdSet.js').IdRange>} */ (items2)[i];
334
+ t.assert(di1.clock === di2.clock && di1.len === di2.len);
335
+ }
336
+ }
337
+ return true
338
+ };
339
+
340
+ /**
341
+ * only use for testing
342
+ *
343
+ * @template T
344
+ * @param {Array<Y.Attribution<T>>} attrs
345
+ * @param {Y.Attribution<T>} attr
346
+ *
347
+ */
348
+ const _idmapAttrsHas = (attrs, attr) => {
349
+ const hash = attr.hash();
350
+ return attrs.find(a => a.hash() === hash)
351
+ };
352
+
353
+ /**
354
+ * only use for testing
355
+ *
356
+ * @template T
357
+ * @param {Array<Y.Attribution<T>>} a
358
+ * @param {Array<Y.Attribution<T>>} b
359
+ */
360
+ const _idmapAttrsEqual = (a, b) => a.length === b.length && a.every(v => _idmapAttrsHas(b, v));
361
+
362
+ /**
363
+ * Ensure that all attributes exist. Also create a copy and compare it to the original.
364
+ *
365
+ * @template T
366
+ * @param {Y.IdMap<T>} idmap
367
+ */
368
+ const validateIdMap = idmap => {
369
+ const copy = createIdMap();
370
+ idmap.clients.forEach((ranges, client) => {
371
+ ranges.getIds().forEach(range => {
372
+ range.attrs.forEach(attr => {
373
+ t.assert(idmap.attrs.has(attr));
374
+ t.assert(idmap.attrsH.get(attr.hash()) === attr);
375
+ copy.add(client, range.clock, range.len, range.attrs.slice());
376
+ });
377
+ });
378
+ t.assert(copy.clients.get(client)?.getIds().length === ranges.getIds().length);
379
+ });
380
+ t.assert(idmap.attrsH.size === idmap.attrs.size);
381
+ };
382
+
383
+ /**
384
+ * @template T
385
+ * @param {Y.IdMap<T>} idmap1
386
+ * @param {Y.IdMap<T>} idmap2
387
+ */
388
+ const compareIdmaps = (idmap1, idmap2) => {
389
+ t.assert(idmap1.clients.size === idmap2.clients.size);
390
+ for (const [client, _items1] of idmap1.clients.entries()) {
391
+ const items1 = _items1.getIds();
392
+ const items2 = idmap2.clients.get(client)?.getIds();
393
+ t.assert(items2 !== undefined && items1.length === items2.length);
394
+ for (let i = 0; i < items1.length; i++) {
395
+ const di1 = items1[i];
396
+ const di2 = /** @type {Array<import('../src/utils/IdMap.js').AttrRange<T>>} */ (items2)[i];
397
+ t.assert(di1.clock === di2.clock && di1.len === di2.len && _idmapAttrsEqual(di1.attrs, di2.attrs));
398
+ }
399
+ }
400
+ validateIdMap(idmap1);
401
+ validateIdMap(idmap2);
402
+ };
403
+
404
+ /**
405
+ * @param {prng.PRNG} gen
406
+ * @param {number} clients
407
+ * @param {number} clockRange (max clock - exclusive - by each client)
408
+ */
409
+ const createRandomIdSet = (gen, clients, clockRange) => {
410
+ const maxOpLen = 5;
411
+ const numOfOps = math.ceil((clients * clockRange) / maxOpLen);
412
+ const idset = createIdSet();
413
+ for (let i = 0; i < numOfOps; i++) {
414
+ const client = prng.uint32(gen, 0, clients - 1);
415
+ const clockStart = prng.uint32(gen, 0, clockRange);
416
+ const len = prng.uint32(gen, 0, clockRange - clockStart);
417
+ addToIdSet(idset, client, clockStart, len);
418
+ }
419
+ if (idset.clients.size === clients && clients > 1 && prng.bool(gen)) {
420
+ idset.clients.delete(prng.uint32(gen, 0, clients));
421
+ }
422
+ return idset
423
+ };
424
+
425
+ /**
426
+ * @template T
427
+ * @param {prng.PRNG} gen
428
+ * @param {number} clients
429
+ * @param {number} clockRange (max clock - exclusive - by each client)
430
+ * @param {Array<T>} attrChoices (max clock - exclusive - by each client)
431
+ * @return {Y.IdMap<T>}
432
+ */
433
+ const createRandomIdMap = (gen, clients, clockRange, attrChoices) => {
434
+ const maxOpLen = 5;
435
+ const numOfOps = math.ceil((clients * clockRange) / maxOpLen);
436
+ const idMap = createIdMap();
437
+ for (let i = 0; i < numOfOps; i++) {
438
+ const client = prng.uint32(gen, 0, clients - 1);
439
+ const clockStart = prng.uint32(gen, 0, clockRange);
440
+ const len = prng.uint32(gen, 0, clockRange - clockStart);
441
+ const attrs = [prng.oneOf(gen, attrChoices)];
442
+ // maybe add another attr
443
+ if (prng.bool(gen)) {
444
+ const a = prng.oneOf(gen, attrChoices);
445
+ if (attrs.find(attr => attr === a) == null) {
446
+ attrs.push(a);
447
+ }
448
+ }
449
+ idMap.add(client, clockStart, len, attrs.map(v => createAttributionItem('', v)));
450
+ }
451
+ t.info(`Created IdMap with ${numOfOps} ranges and ${attrChoices.length} different attributes. Encoded size: ${encodeIdMap(idMap).byteLength}`);
452
+ return idMap
453
+ };
454
+
455
+ /**
456
+ * 1. reconnect and flush all
457
+ * 2. user 0 gc
458
+ * 3. get type content
459
+ * 4. disconnect & reconnect all (so gc is propagated)
460
+ * 5. compare os, ds, ss
461
+ *
462
+ * @param {Array<TestYInstance>} users
463
+ */
464
+ const compare = users => {
465
+ users.forEach(u => u.connect());
466
+ while (users[0].tc.flushAllMessages()) {} // eslint-disable-line
467
+ // For each document, merge all received document updates with Y.mergeUpdates and create a new document which will be added to the list of "users"
468
+ // This ensures that mergeUpdates works correctly
469
+ const mergedDocs = users.map(user => {
470
+ const ydoc = new Doc();
471
+ enc.applyUpdate(ydoc, enc.mergeUpdates(user.updates));
472
+ return ydoc
473
+ });
474
+ users.push(.../** @type {any} */(mergedDocs));
475
+ const userArrayValues = users.map(u => u.getArray('array').toJSON());
476
+ const userMapValues = users.map(u => u.getMap('map').toJSON());
477
+ // @todo fix type error here
478
+ // @ts-ignore
479
+ const userXmlValues = users.map(u => /** @type {Y.XmlElement} */ (u.get('xml', YXmlElement)).toString());
480
+ const userTextValues = users.map(u => u.getText('text').getContentDeep());
481
+ for (const u of users) {
482
+ t.assert(u.store.pendingDs === null);
483
+ t.assert(u.store.pendingStructs === null);
484
+ }
485
+ // Test Array iterator
486
+ t.compare(users[0].getArray('array').toArray(), Array.from(users[0].getArray('array')));
487
+ // Test Map iterator
488
+ const ymapkeys = Array.from(users[0].getMap('map').keys());
489
+ t.assert(ymapkeys.length === Object.keys(userMapValues[0]).length);
490
+ ymapkeys.forEach(key => t.assert(object.hasProperty(userMapValues[0], key)));
491
+ /**
492
+ * @type {Object<string,any>}
493
+ */
494
+ const mapRes = {};
495
+ for (const [k, v] of users[0].getMap('map')) {
496
+ mapRes[k] = v instanceof AbstractType ? v.toJSON() : v;
497
+ }
498
+ t.compare(userMapValues[0], mapRes);
499
+ // Compare all users
500
+ for (let i = 0; i < users.length - 1; i++) {
501
+ t.compare(userArrayValues[i].length, users[i].getArray('array').length);
502
+ t.compare(userArrayValues[i], userArrayValues[i + 1]);
503
+ t.compare(userMapValues[i], userMapValues[i + 1]);
504
+ t.compare(userXmlValues[i], userXmlValues[i + 1]);
505
+ t.compare(list.toArray(userTextValues[i].children).map(a => (delta.$textOp.check(a) || delta.$insertOp.check(a)) ? a.insert.length : 0).reduce((a, b) => a + b, 0), users[i].getText('text').length);
506
+ t.compare(userTextValues[i], userTextValues[i + 1], '', (_constructor, a, b) => {
507
+ if (a instanceof AbstractType) {
508
+ t.compare(a.toJSON(), b.toJSON());
509
+ } else if (a !== b) {
510
+ t.fail('Deltas dont match');
511
+ }
512
+ return true
513
+ });
514
+ t.compare(encodeStateVector(users[i]), encodeStateVector(users[i + 1]));
515
+ equalIdSets(createDeleteSetFromStructStore(users[i].store), createDeleteSetFromStructStore(users[i + 1].store));
516
+ compareStructStores(users[i].store, users[i + 1].store);
517
+ t.compare(encodeSnapshot(snapshot(users[i])), encodeSnapshot(snapshot(users[i + 1])));
518
+ }
519
+ users.forEach(user => {
520
+ compareIdSets(user.store.ds, createDeleteSetFromStructStore(user.store));
521
+ });
522
+ users.map(u => u.destroy());
523
+ };
524
+
525
+ /**
526
+ * @param {Y.Item?} a
527
+ * @param {Y.Item?} b
528
+ * @return {boolean}
529
+ */
530
+ const compareItemIDs = (a, b) => a === b || (a !== null && b != null && compareIDs(a.id, b.id));
531
+
532
+ /**
533
+ * @param {import('../src/internals.js').StructStore} ss1
534
+ * @param {import('../src/internals.js').StructStore} ss2
535
+ */
536
+ const compareStructStores = (ss1, ss2) => {
537
+ t.assert(ss1.clients.size === ss2.clients.size);
538
+ for (const [client, structs1] of ss1.clients) {
539
+ const structs2 = /** @type {Array<Y.AbstractStruct>} */ (ss2.clients.get(client));
540
+ t.assert(structs2 !== undefined && structs1.length === structs2.length);
541
+ for (let i = 0; i < structs1.length; i++) {
542
+ const s1 = structs1[i];
543
+ const s2 = structs2[i];
544
+ // checks for abstract struct
545
+ if (
546
+ s1.constructor !== s2.constructor ||
547
+ !compareIDs(s1.id, s2.id) ||
548
+ s1.deleted !== s2.deleted ||
549
+ // @ts-ignore
550
+ s1.length !== s2.length
551
+ ) {
552
+ t.fail('Structs dont match');
553
+ }
554
+ if (s1 instanceof Item) {
555
+ if (
556
+ !(s2 instanceof Item) ||
557
+ !((s1.left === null && s2.left === null) || (s1.left !== null && s2.left !== null && compareIDs(s1.left.lastId, s2.left.lastId))) ||
558
+ !compareItemIDs(s1.right, s2.right) ||
559
+ !compareIDs(s1.origin, s2.origin) ||
560
+ !compareIDs(s1.rightOrigin, s2.rightOrigin) ||
561
+ s1.parentSub !== s2.parentSub
562
+ ) {
563
+ return t.fail('Items dont match')
564
+ }
565
+ // make sure that items are connected correctly
566
+ t.assert(s1.left === null || s1.left.right === s1);
567
+ t.assert(s1.right === null || s1.right.left === s1);
568
+ t.assert(s2.left === null || s2.left.right === s2);
569
+ t.assert(s2.right === null || s2.right.left === s2);
570
+ }
571
+ }
572
+ }
573
+ };
574
+
575
+ /**
576
+ * @template T
577
+ * @callback InitTestObjectCallback
578
+ * @param {TestYInstance} y
579
+ * @return {T}
580
+ */
581
+
582
+ /**
583
+ * @template T
584
+ * @param {t.TestCase} tc
585
+ * @param {Array<function(Y.Doc,prng.PRNG,T):void>} mods
586
+ * @param {number} iterations
587
+ * @param {InitTestObjectCallback<T>} [initTestObject]
588
+ */
589
+ const applyRandomTests = (tc, mods, iterations, initTestObject) => {
590
+ const gen = tc.prng;
591
+ const result = init(tc, { users: 5 }, initTestObject);
592
+ const { testConnector, users } = result;
593
+ for (let i = 0; i < iterations; i++) {
594
+ if (prng.int32(gen, 0, 100) <= 2) {
595
+ // 2% chance to disconnect/reconnect a random user
596
+ if (prng.bool(gen)) {
597
+ testConnector.disconnectRandom();
598
+ } else {
599
+ testConnector.reconnectRandom();
600
+ }
601
+ } else if (prng.int32(gen, 0, 100) <= 1) {
602
+ // 1% chance to flush all
603
+ testConnector.flushAllMessages();
604
+ } else if (prng.int32(gen, 0, 100) <= 50) {
605
+ // 50% chance to flush a random message
606
+ testConnector.flushRandomMessage();
607
+ }
608
+ const user = prng.int32(gen, 0, users.length - 1);
609
+ const test = prng.oneOf(gen, mods);
610
+ test(users[user], gen, result.testObjects[user]);
611
+ }
612
+ compare(users);
613
+ return result
614
+ };
615
+
616
+ export { AbstractType, Doc, Item, TestConnector, TestYInstance, YXmlElement as XmlElement, _idmapAttrsEqual, applyRandomTests, applyUpdate, applyUpdateV2, compare, compareIDs, compareIdSets, compareIdmaps, compareItemIDs, compareStructStores, createAttributionItem, createDeleteSetFromStructStore, createIdMap, createIdSet, createRandomIdMap, createRandomIdSet, diffUpdate, diffUpdateV2, enc, encV1, encV2, encodeIdMap, encodeSnapshot, encodeStateAsUpdate, encodeStateAsUpdateV2, encodeStateVector, equalIdSets, init, logUpdate, logUpdateV2, mergeUpdates, mergeUpdatesV2, snapshot, useV2, validateIdMap };
617
+ //# sourceMappingURL=testHelper.mjs.map