@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,823 @@
1
+ import {
2
+ findIndexSS,
3
+ getState,
4
+ splitItem,
5
+ iterateStructs,
6
+ UpdateEncoderV2,
7
+ IdMap,
8
+ AttrRanges,
9
+ AttrRange,
10
+ Skip, AbstractStruct, DSDecoderV1, IdSetEncoderV1, DSDecoderV2, IdSetEncoderV2, Item, GC, StructStore, Transaction, ID, AttributionItem, // eslint-disable-line
11
+ } from '../internals.js'
12
+
13
+ import * as array from 'lib0/array'
14
+ import * as math from 'lib0/math'
15
+ import * as encoding from 'lib0/encoding'
16
+ import * as decoding from 'lib0/decoding'
17
+ import * as traits from 'lib0/traits'
18
+
19
+ export class IdRange {
20
+ /**
21
+ * @param {number} clock
22
+ * @param {number} len
23
+ */
24
+ constructor (clock, len) {
25
+ /**
26
+ * @type {number}
27
+ */
28
+ this.clock = clock
29
+ /**
30
+ * @type {number}
31
+ */
32
+ this.len = len
33
+ }
34
+
35
+ /**
36
+ * @param {number} clock
37
+ * @param {number} len
38
+ */
39
+ copyWith (clock, len) {
40
+ return new IdRange(clock, len)
41
+ }
42
+
43
+ /**
44
+ * Helper method making this compatible with IdMap.
45
+ *
46
+ * @return {Array<import('./IdMap.js').AttributionItem<any>>}
47
+ */
48
+ get attrs () {
49
+ return []
50
+ }
51
+ }
52
+
53
+ export class MaybeIdRange {
54
+ /**
55
+ * @param {number} clock
56
+ * @param {number} len
57
+ * @param {boolean} exists
58
+ */
59
+ constructor (clock, len, exists) {
60
+ /**
61
+ * @type {number}
62
+ */
63
+ this.clock = clock
64
+ /**
65
+ * @type {number}
66
+ */
67
+ this.len = len
68
+ /**
69
+ * @type {boolean}
70
+ */
71
+ this.exists = exists
72
+ }
73
+ }
74
+
75
+ /**
76
+ * @param {number} clock
77
+ * @param {number} len
78
+ * @param {boolean} exists
79
+ * @return {MaybeIdRange}
80
+ */
81
+ export const createMaybeIdRange = (clock, len, exists) => new MaybeIdRange(clock, len, exists)
82
+
83
+ export class IdRanges {
84
+ /**
85
+ * @param {Array<IdRange>} ids
86
+ */
87
+ constructor (ids) {
88
+ this.sorted = false
89
+ /**
90
+ * A typical use-case for IdSet is to append data. We heavily optimize this case by allowing the
91
+ * last item to be mutated ef it isn't used currently.
92
+ * This flag is true if the last item was exposed to the outside.
93
+ */
94
+ this._lastIsUsed = false
95
+ /**
96
+ * @private
97
+ */
98
+ this._ids = ids
99
+ }
100
+
101
+ copy () {
102
+ return new IdRanges(this._ids.slice())
103
+ }
104
+
105
+ /**
106
+ * @param {number} clock
107
+ * @param {number} length
108
+ */
109
+ add (clock, length) {
110
+ const last = this._ids[this._ids.length - 1]
111
+ if (last.clock + last.len === clock) {
112
+ if (this._lastIsUsed) {
113
+ this._ids[this._ids.length - 1] = new IdRange(last.clock, last.len + length)
114
+ this._lastIsUsed = false
115
+ } else {
116
+ this._ids[this._ids.length - 1].len += length
117
+ }
118
+ } else {
119
+ this.sorted = false
120
+ this._ids.push(new IdRange(clock, length))
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Return the list of immutable id ranges, sorted and merged.
126
+ */
127
+ getIds () {
128
+ const ids = this._ids
129
+ this._lastIsUsed = true
130
+ if (!this.sorted) {
131
+ this.sorted = true
132
+ ids.sort((a, b) => a.clock - b.clock)
133
+ // merge items without filtering or splicing the array
134
+ // i is the current pointer
135
+ // j refers to the current insert position for the pointed item
136
+ // try to merge dels[i] into dels[j-1] or set dels[j]=dels[i]
137
+ let i, j
138
+ for (i = 1, j = 1; i < ids.length; i++) {
139
+ const left = ids[j - 1]
140
+ const right = ids[i]
141
+ if (left.clock + left.len >= right.clock) {
142
+ const r = right.clock + right.len - left.clock
143
+ if (left.len < r) {
144
+ ids[j - 1] = new IdRange(left.clock, r)
145
+ }
146
+ } else if (left.len === 0) {
147
+ ids[j - 1] = right
148
+ } else {
149
+ if (j < i) {
150
+ ids[j] = right
151
+ }
152
+ j++
153
+ }
154
+ }
155
+ ids.length = ids[j - 1].len === 0 ? j - 1 : j
156
+ }
157
+ return ids
158
+ }
159
+ }
160
+
161
+ /**
162
+ * @implements {traits.EqualityTrait}
163
+ */
164
+ export class IdSet {
165
+ constructor () {
166
+ /**
167
+ * @type {Map<number,IdRanges>}
168
+ */
169
+ this.clients = new Map()
170
+ }
171
+
172
+ isEmpty () {
173
+ return this.clients.size === 0
174
+ }
175
+
176
+ /**
177
+ * @param {(idrange:IdRange, client:number) => void} f
178
+ */
179
+ forEach (f) {
180
+ this.clients.forEach((ranges, client) => {
181
+ ranges.getIds().forEach((range) => {
182
+ f(range, client)
183
+ })
184
+ })
185
+ }
186
+
187
+ /**
188
+ * @param {ID} id
189
+ * @return {boolean}
190
+ */
191
+ hasId (id) {
192
+ return this.has(id.client, id.clock)
193
+ }
194
+
195
+ /**
196
+ * @param {number} client
197
+ * @param {number} clock
198
+ */
199
+ has (client, clock) {
200
+ const dr = this.clients.get(client)
201
+ if (dr) {
202
+ return findIndexInIdRanges(dr.getIds(), clock) !== null
203
+ }
204
+ return false
205
+ }
206
+
207
+ /**
208
+ * Return slices of ids that exist in this idset.
209
+ *
210
+ * @param {number} client
211
+ * @param {number} clock
212
+ * @param {number} len
213
+ * @return {Array<MaybeIdRange>}
214
+ */
215
+ slice (client, clock, len) {
216
+ const dr = this.clients.get(client)
217
+ /**
218
+ * @type {Array<MaybeIdRange>}
219
+ */
220
+ const res = []
221
+ if (dr) {
222
+ /**
223
+ * @type {Array<IdRange>}
224
+ */
225
+ const ranges = dr.getIds()
226
+ let index = findRangeStartInIdRanges(ranges, clock)
227
+ if (index !== null) {
228
+ let prev = null
229
+ while (index < ranges.length) {
230
+ let r = ranges[index]
231
+ if (r.clock < clock) {
232
+ r = new IdRange(clock, r.len - (clock - r.clock))
233
+ }
234
+ if (r.clock + r.len > clock + len) {
235
+ r = new IdRange(r.clock, clock + len - r.clock)
236
+ }
237
+ if (r.len <= 0) break
238
+ const prevEnd = prev != null ? prev.clock + prev.len : clock
239
+ if (prevEnd < r.clock) {
240
+ res.push(createMaybeIdRange(prevEnd, r.clock - prevEnd, false))
241
+ }
242
+ prev = r
243
+ res.push(createMaybeIdRange(r.clock, r.len, true))
244
+ index++
245
+ }
246
+ }
247
+ }
248
+ if (res.length > 0) {
249
+ const last = res[res.length - 1]
250
+ const end = last.clock + last.len
251
+ if (end < clock + len) {
252
+ res.push(createMaybeIdRange(end, clock + len - end, false))
253
+ }
254
+ } else {
255
+ res.push(createMaybeIdRange(clock, len, false))
256
+ }
257
+ return res
258
+ }
259
+
260
+ /**
261
+ * @param {number} client
262
+ * @param {number} clock
263
+ * @param {number} len
264
+ */
265
+ add (client, clock, len) {
266
+ addToIdSet(this, client, clock, len)
267
+ }
268
+
269
+ /**
270
+ * @param {number} client
271
+ * @param {number} clock
272
+ * @param {number} len
273
+ */
274
+ delete (client, clock, len) {
275
+ _deleteRangeFromIdSet(this, client, clock, len)
276
+ }
277
+
278
+ /**
279
+ * @param {any} other
280
+ */
281
+ [traits.EqualityTraitSymbol] (other) {
282
+ return equalIdSets(this, other)
283
+ }
284
+ }
285
+
286
+ /**
287
+ * @param {IdSet | IdMap<any>} set
288
+ * @param {number} client
289
+ * @param {number} clock
290
+ * @param {number} len
291
+ */
292
+ export const _deleteRangeFromIdSet = (set, client, clock, len) => {
293
+ const dr = set.clients.get(client)
294
+ if (dr && len > 0) {
295
+ const ids = dr.getIds()
296
+ let index = findRangeStartInIdRanges(ids, clock)
297
+ if (index != null) {
298
+ for (let r = ids[index]; index < ids.length && r.clock < clock + len; r = ids[++index]) {
299
+ if (r.clock < clock) {
300
+ ids[index] = r.copyWith(r.clock, clock - r.clock)
301
+ if (clock + len < r.clock + r.len) {
302
+ ids.splice(index + 1, 0, r.copyWith(clock + len, r.clock + r.len - clock - len))
303
+ }
304
+ } else if (clock + len < r.clock + r.len) {
305
+ // need to retain end
306
+ ids[index] = r.copyWith(clock + len, r.clock + r.len - clock - len)
307
+ } else if (ids.length === 1) {
308
+ set.clients.delete(client)
309
+ return
310
+ } else {
311
+ ids.splice(index--, 1)
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Iterate over all structs that are mentioned by the IdSet.
320
+ *
321
+ * @param {Transaction} transaction
322
+ * @param {IdSet} ds
323
+ * @param {function(GC|Item):void} f
324
+ *
325
+ * @function
326
+ */
327
+ export const iterateStructsByIdSet = (transaction, ds, f) =>
328
+ ds.clients.forEach((idRanges, clientid) => {
329
+ const ranges = idRanges.getIds()
330
+ const structs = /** @type {Array<GC|Item>} */ (transaction.doc.store.clients.get(clientid))
331
+ if (structs != null) {
332
+ for (let i = 0; i < ranges.length; i++) {
333
+ const del = ranges[i]
334
+ iterateStructs(transaction, structs, del.clock, del.len, f)
335
+ }
336
+ }
337
+ })
338
+
339
+ /**
340
+ * @param {Array<IdRange>} dis
341
+ * @param {number} clock
342
+ * @return {number|null}
343
+ *
344
+ * @private
345
+ * @function
346
+ */
347
+ export const findIndexInIdRanges = (dis, clock) => {
348
+ let left = 0
349
+ let right = dis.length - 1
350
+ while (left <= right) {
351
+ const midindex = math.floor((left + right) / 2)
352
+ const mid = dis[midindex]
353
+ const midclock = mid.clock
354
+ if (midclock <= clock) {
355
+ if (clock < midclock + mid.len) {
356
+ return midindex
357
+ }
358
+ left = midindex + 1
359
+ } else {
360
+ right = midindex - 1
361
+ }
362
+ }
363
+ return null
364
+ }
365
+
366
+ /**
367
+ * Find the first range that contains clock or comes after clock.
368
+ *
369
+ * @param {Array<IdRange>} dis
370
+ * @param {number} clock
371
+ * @return {number|null}
372
+ *
373
+ * @private
374
+ * @function
375
+ */
376
+ export const findRangeStartInIdRanges = (dis, clock) => {
377
+ let left = 0
378
+ let right = dis.length - 1
379
+ while (left <= right) {
380
+ const midindex = math.floor((left + right) / 2)
381
+ const mid = dis[midindex]
382
+ const midclock = mid.clock
383
+ if (midclock <= clock) {
384
+ if (clock < midclock + mid.len) {
385
+ return midindex
386
+ }
387
+ left = midindex + 1
388
+ } else {
389
+ right = midindex - 1
390
+ }
391
+ }
392
+ return left < dis.length ? left : null
393
+ }
394
+
395
+ /**
396
+ * @param {Array<IdSet>} idSets
397
+ * @return {IdSet} A fresh IdSet
398
+ */
399
+ export const mergeIdSets = idSets => {
400
+ const merged = new IdSet()
401
+ for (let dssI = 0; dssI < idSets.length; dssI++) {
402
+ idSets[dssI].clients.forEach((rangesLeft, client) => {
403
+ if (!merged.clients.has(client)) {
404
+ // Write all missing keys from current ds and all following.
405
+ // If merged already contains `client` current ds has already been added.
406
+ const ids = rangesLeft.getIds().slice()
407
+ for (let i = dssI + 1; i < idSets.length; i++) {
408
+ const nextIds = idSets[i].clients.get(client)
409
+ if (nextIds) {
410
+ array.appendTo(ids, nextIds.getIds())
411
+ }
412
+ }
413
+ merged.clients.set(client, new IdRanges(ids))
414
+ }
415
+ })
416
+ }
417
+ return merged
418
+ }
419
+
420
+ /**
421
+ * @template {IdSet | IdMap<any>} S
422
+ * @param {S} dest
423
+ * @param {S} src
424
+ */
425
+ export const _insertIntoIdSet = (dest, src) => {
426
+ src.clients.forEach((srcRanges, client) => {
427
+ const targetRanges = dest.clients.get(client)
428
+ if (targetRanges) {
429
+ array.appendTo(targetRanges.getIds(), srcRanges.getIds())
430
+ targetRanges.sorted = false
431
+ } else {
432
+ const res = srcRanges.copy()
433
+ res.sorted = true
434
+ dest.clients.set(client, /** @type {any} */ (res))
435
+ }
436
+ })
437
+ }
438
+
439
+ /**
440
+ * @param {IdSet} dest
441
+ * @param {IdSet} src
442
+ */
443
+ export const insertIntoIdSet = _insertIntoIdSet
444
+
445
+ /**
446
+ * Remove all ranges from `exclude` from `ds`. The result is a fresh IdSet containing all ranges from `idSet` that are not
447
+ * in `exclude`.
448
+ *
449
+ * @template {IdSet | IdMap<any>} Set
450
+ * @param {Set} set
451
+ * @param {IdSet | IdMap<any>} exclude
452
+ * @return {Set}
453
+ */
454
+ export const _diffSet = (set, exclude) => {
455
+ /**
456
+ * @type {Set}
457
+ */
458
+ const res = /** @type {any } */ (set instanceof IdSet ? new IdSet() : new IdMap())
459
+ const Ranges = set instanceof IdSet ? IdRanges : AttrRanges
460
+ set.clients.forEach((_setRanges, client) => {
461
+ /**
462
+ * @type {Array<IdRange>}
463
+ */
464
+ let resRanges = []
465
+ const _excludedRanges = exclude.clients.get(client)
466
+ const setRanges = _setRanges.getIds()
467
+ if (_excludedRanges == null) {
468
+ resRanges = setRanges.slice()
469
+ } else {
470
+ const excludedRanges = _excludedRanges.getIds()
471
+ let i = 0; let j = 0
472
+ let currRange = setRanges[0]
473
+ while (i < setRanges.length && j < excludedRanges.length) {
474
+ const e = excludedRanges[j]
475
+ if (currRange.clock + currRange.len <= e.clock) { // no overlapping, use next range item
476
+ if (currRange.len > 0) resRanges.push(currRange)
477
+ currRange = setRanges[++i]
478
+ } else if (e.clock + e.len <= currRange.clock) { // no overlapping, use next excluded item
479
+ j++
480
+ } else if (e.clock <= currRange.clock) { // exclude laps into range (we already know that the ranges somehow collide)
481
+ const newClock = e.clock + e.len
482
+ const newLen = currRange.clock + currRange.len - newClock
483
+ if (newLen > 0) {
484
+ currRange = currRange.copyWith(newClock, newLen)
485
+ j++
486
+ } else {
487
+ // this item is completely overwritten. len=0. We can jump to the next range
488
+ currRange = setRanges[++i]
489
+ }
490
+ } else { // currRange.clock < e.clock -- range laps into exclude => adjust len
491
+ // beginning can't be empty, add it to the result
492
+ const nextLen = e.clock - currRange.clock
493
+ resRanges.push(currRange.copyWith(currRange.clock, nextLen))
494
+ // retain the remaining length after exclude in currRange
495
+ currRange = currRange.copyWith(currRange.clock + e.len + nextLen, math.max(currRange.len - e.len - nextLen, 0))
496
+ if (currRange.len === 0) currRange = setRanges[++i]
497
+ else j++
498
+ }
499
+ }
500
+ if (currRange != null) {
501
+ resRanges.push(currRange)
502
+ }
503
+ i++
504
+ while (i < setRanges.length) {
505
+ resRanges.push(setRanges[i++])
506
+ }
507
+ }
508
+ // @ts-ignore
509
+ if (resRanges.length > 0) res.clients.set(client, /** @type {any} */ (new Ranges(resRanges)))
510
+ })
511
+ return res
512
+ }
513
+
514
+ /**
515
+ * Remove all ranges from `exclude` from `idSet`. The result is a fresh IdSet containing all ranges from `idSet` that are not
516
+ * in `exclude`.
517
+ *
518
+ * @type {(idSet: IdSet, exclude: IdSet|IdMap<any>) => IdSet}
519
+ */
520
+ export const diffIdSet = _diffSet
521
+
522
+ /**
523
+ * @template {IdSet | IdMap<any>} SetA
524
+ * @template {IdSet | IdMap<any>} SetB
525
+ * @param {SetA} setA
526
+ * @param {SetB} setB
527
+ * @return {SetA extends IdMap<infer A> ? (SetB extends IdMap<infer B> ? IdMap<A | B> : IdMap<A>) : IdSet}
528
+ */
529
+ export const _intersectSets = (setA, setB) => {
530
+ /**
531
+ * @type {IdMap<any> | IdSet}
532
+ */
533
+ const res = /** @type {any } */ (setA instanceof IdSet ? new IdSet() : new IdMap())
534
+ const Ranges = setA instanceof IdSet ? IdRanges : AttrRanges
535
+ setA.clients.forEach((_aRanges, client) => {
536
+ /**
537
+ * @type {Array<IdRange>}
538
+ */
539
+ const resRanges = []
540
+ const _bRanges = setB.clients.get(client)
541
+ const aRanges = _aRanges.getIds()
542
+ if (_bRanges != null) {
543
+ const bRanges = _bRanges.getIds()
544
+ for (let a = 0, b = 0; a < aRanges.length && b < bRanges.length;) {
545
+ const aRange = aRanges[a]
546
+ const bRange = bRanges[b]
547
+ // construct overlap
548
+ const clock = math.max(aRange.clock, bRange.clock)
549
+ const len = math.min(aRange.len - (clock - aRange.clock), bRange.len - (clock - bRange.clock))
550
+ if (len > 0) {
551
+ resRanges.push(aRange instanceof AttrRange
552
+ ? new AttrRange(clock, len, /** @type {Array<AttributionItem<any>>} */ (aRange.attrs).concat(bRange.attrs))
553
+ : new IdRange(clock, len)
554
+ )
555
+ }
556
+ if (aRange.clock + aRange.len < bRange.clock + bRange.len) {
557
+ a++
558
+ } else {
559
+ b++
560
+ }
561
+ }
562
+ }
563
+ // @ts-ignore
564
+ if (resRanges.length > 0) res.clients.set(client, /** @type {any} */ (new Ranges(resRanges)))
565
+ })
566
+ return /** @type {any} */ (res)
567
+ }
568
+
569
+ export const intersectSets = _intersectSets
570
+
571
+ /**
572
+ * @param {IdSet} idSet
573
+ * @param {number} client
574
+ * @param {number} clock
575
+ * @param {number} length
576
+ *
577
+ * @private
578
+ * @function
579
+ */
580
+ export const addToIdSet = (idSet, client, clock, length) => {
581
+ if (length === 0) return
582
+ const idRanges = idSet.clients.get(client)
583
+ if (idRanges) {
584
+ idRanges.add(clock, length)
585
+ } else {
586
+ idSet.clients.set(client, new IdRanges([new IdRange(clock, length)]))
587
+ }
588
+ }
589
+
590
+ /**
591
+ * @param {IdSet} idSet
592
+ * @param {AbstractStruct} struct
593
+ *
594
+ * @private
595
+ * @function
596
+ */
597
+ export const addStructToIdSet = (idSet, struct) => addToIdSet(idSet, struct.id.client, struct.id.clock, struct.length)
598
+
599
+ export const createIdSet = () => new IdSet()
600
+
601
+ /**
602
+ * @param {StructStore} ss
603
+ * @return {IdSet}
604
+ *
605
+ * @private
606
+ * @function
607
+ */
608
+ export const createDeleteSetFromStructStore = ss => {
609
+ const ds = createIdSet()
610
+ ss.clients.forEach((structs, client) => {
611
+ /**
612
+ * @type {Array<IdRange>}
613
+ */
614
+ const dsitems = []
615
+ for (let i = 0; i < structs.length; i++) {
616
+ const struct = structs[i]
617
+ if (struct.deleted) {
618
+ const clock = struct.id.clock
619
+ let len = struct.length
620
+ if (i + 1 < structs.length) {
621
+ for (let next = structs[i + 1]; i + 1 < structs.length && next.deleted; next = structs[++i + 1]) {
622
+ len += next.length
623
+ }
624
+ }
625
+ dsitems.push(new IdRange(clock, len))
626
+ }
627
+ }
628
+ if (dsitems.length > 0) {
629
+ ds.clients.set(client, new IdRanges(dsitems))
630
+ }
631
+ })
632
+ return ds
633
+ }
634
+
635
+ /**
636
+ * @param {Array<GC | Item>} structs
637
+ * @param {boolean} filterDeleted
638
+ *
639
+ */
640
+ export const _createInsertSliceFromStructs = (structs, filterDeleted) => {
641
+ /**
642
+ * @type {Array<IdRange>}
643
+ */
644
+ const iditems = []
645
+ for (let i = 0; i < structs.length; i++) {
646
+ const struct = structs[i]
647
+ if (!(filterDeleted && struct.deleted)) {
648
+ const clock = struct.id.clock
649
+ let len = struct.length
650
+ if (i + 1 < structs.length) {
651
+ // eslint-disable-next-line
652
+ for (let next = structs[i + 1]; i + 1 < structs.length && !(filterDeleted && next.deleted); next = structs[++i + 1]) {
653
+ len += next.length
654
+ }
655
+ }
656
+ iditems.push(new IdRange(clock, len))
657
+ }
658
+ }
659
+ return iditems
660
+ }
661
+
662
+ /**
663
+ * @param {import('../internals.js').StructStore} ss
664
+ * @param {boolean} filterDeleted
665
+ */
666
+ export const createInsertSetFromStructStore = (ss, filterDeleted) => {
667
+ const idset = createIdSet()
668
+ ss.clients.forEach((structs, client) => {
669
+ const iditems = _createInsertSliceFromStructs(structs, filterDeleted)
670
+ if (iditems.length !== 0) {
671
+ idset.clients.set(client, new IdRanges(iditems))
672
+ }
673
+ })
674
+ return idset
675
+ }
676
+
677
+ /**
678
+ * @param {IdSetEncoderV1 | IdSetEncoderV2} encoder
679
+ * @param {IdSet} idSet
680
+ *
681
+ * @private
682
+ * @function
683
+ */
684
+ export const writeIdSet = (encoder, idSet) => {
685
+ encoding.writeVarUint(encoder.restEncoder, idSet.clients.size)
686
+ // Ensure that the delete set is written in a deterministic order
687
+ array.from(idSet.clients.entries())
688
+ .sort((a, b) => b[0] - a[0])
689
+ .forEach(([client, _idRanges]) => {
690
+ const idRanges = _idRanges.getIds()
691
+ encoder.resetIdSetCurVal()
692
+ encoding.writeVarUint(encoder.restEncoder, client)
693
+ const len = idRanges.length
694
+ encoding.writeVarUint(encoder.restEncoder, len)
695
+ for (let i = 0; i < len; i++) {
696
+ const item = idRanges[i]
697
+ encoder.writeIdSetClock(item.clock)
698
+ encoder.writeIdSetLen(item.len)
699
+ }
700
+ })
701
+ }
702
+
703
+ /**
704
+ * @param {DSDecoderV1 | DSDecoderV2} decoder
705
+ * @return {IdSet}
706
+ *
707
+ * @private
708
+ * @function
709
+ */
710
+ export const readIdSet = decoder => {
711
+ const ds = new IdSet()
712
+ const numClients = decoding.readVarUint(decoder.restDecoder)
713
+ for (let i = 0; i < numClients; i++) {
714
+ decoder.resetDsCurVal()
715
+ const client = decoding.readVarUint(decoder.restDecoder)
716
+ const numberOfDeletes = decoding.readVarUint(decoder.restDecoder)
717
+ if (numberOfDeletes > 0) {
718
+ /**
719
+ * @type {Array<IdRange>}
720
+ */
721
+ const dsRanges = []
722
+ for (let i = 0; i < numberOfDeletes; i++) {
723
+ dsRanges.push(new IdRange(decoder.readDsClock(), decoder.readDsLen()))
724
+ }
725
+ ds.clients.set(client, new IdRanges(dsRanges))
726
+ }
727
+ }
728
+ return ds
729
+ }
730
+
731
+ /**
732
+ * @todo YDecoder also contains references to String and other Decoders. Would make sense to exchange YDecoder.toUint8Array for YDecoder.DsToUint8Array()..
733
+ */
734
+
735
+ /**
736
+ * @param {DSDecoderV1 | DSDecoderV2} decoder
737
+ * @param {Transaction} transaction
738
+ * @param {StructStore} store
739
+ * @return {Uint8Array<ArrayBuffer>|null} Returns a v2 update containing all deletes that couldn't be applied yet; or null if all deletes were applied successfully.
740
+ *
741
+ * @private
742
+ * @function
743
+ */
744
+ export const readAndApplyDeleteSet = (decoder, transaction, store) => {
745
+ const unappliedDS = new IdSet()
746
+ const numClients = decoding.readVarUint(decoder.restDecoder)
747
+ for (let i = 0; i < numClients; i++) {
748
+ decoder.resetDsCurVal()
749
+ const client = decoding.readVarUint(decoder.restDecoder)
750
+ const numberOfDeletes = decoding.readVarUint(decoder.restDecoder)
751
+ const structs = store.clients.get(client) || []
752
+ const state = getState(store, client)
753
+ for (let i = 0; i < numberOfDeletes; i++) {
754
+ const clock = decoder.readDsClock()
755
+ const clockEnd = clock + decoder.readDsLen()
756
+ if (clock < state) {
757
+ if (state < clockEnd) {
758
+ addToIdSet(unappliedDS, client, state, clockEnd - state)
759
+ }
760
+ let index = findIndexSS(structs, clock)
761
+ /**
762
+ * We can ignore the case of GC and Delete structs, because we are going to skip them
763
+ * @type {Item | GC | Skip}
764
+ */
765
+ let struct = structs[index]
766
+ // split the first item if necessary
767
+ if (!struct.deleted && struct.id.clock < clock && struct instanceof Item) {
768
+ // increment index, we now want to use the next struct
769
+ structs.splice(++index, 0, splitItem(transaction, struct, clock - struct.id.clock))
770
+ }
771
+ while (index < structs.length) {
772
+ // @ts-ignore
773
+ struct = structs[index++]
774
+ if (struct.id.clock < clockEnd) {
775
+ if (!struct.deleted) {
776
+ if (struct instanceof Item) {
777
+ if (clockEnd < struct.id.clock + struct.length) {
778
+ structs.splice(index, 0, splitItem(transaction, struct, clockEnd - struct.id.clock))
779
+ }
780
+ struct.delete(transaction)
781
+ } else { // is a Skip - add range to unappliedDS
782
+ const c = math.max(struct.id.clock, clock)
783
+ unappliedDS.add(client, c, math.min(struct.length, clockEnd - c))
784
+ }
785
+ }
786
+ } else {
787
+ break
788
+ }
789
+ }
790
+ } else {
791
+ addToIdSet(unappliedDS, client, clock, clockEnd - clock)
792
+ }
793
+ }
794
+ }
795
+ if (unappliedDS.clients.size > 0) {
796
+ const ds = new UpdateEncoderV2()
797
+ encoding.writeVarUint(ds.restEncoder, 0) // encode 0 structs
798
+ writeIdSet(ds, unappliedDS)
799
+ return ds.toUint8Array()
800
+ }
801
+ return null
802
+ }
803
+
804
+ /**
805
+ * @param {IdSet} ds1
806
+ * @param {IdSet} ds2
807
+ */
808
+ export const equalIdSets = (ds1, ds2) => {
809
+ if (ds1.clients.size !== ds2.clients.size) return false
810
+ for (const [client, _deleteItems1] of ds1.clients.entries()) {
811
+ const deleteItems1 = _deleteItems1.getIds()
812
+ const deleteItems2 = ds2.clients.get(client)?.getIds()
813
+ if (deleteItems2 === undefined || deleteItems1.length !== deleteItems2.length) return false
814
+ for (let i = 0; i < deleteItems1.length; i++) {
815
+ const di1 = deleteItems1[i]
816
+ const di2 = deleteItems2[i]
817
+ if (di1.clock !== di2.clock || di1.len !== di2.len) {
818
+ return false
819
+ }
820
+ }
821
+ }
822
+ return true
823
+ }