@y/y 14.0.0-rc.2 → 14.0.0-rc.21

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 (166) hide show
  1. package/README.md +36 -12
  2. package/dist/src/index.d.ts +24 -1
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/structs/AbstractStruct.d.ts +14 -17
  5. package/dist/src/structs/AbstractStruct.d.ts.map +1 -1
  6. package/dist/src/structs/GC.d.ts +9 -14
  7. package/dist/src/structs/GC.d.ts.map +1 -1
  8. package/dist/src/structs/Item.d.ts +569 -31
  9. package/dist/src/structs/Item.d.ts.map +1 -1
  10. package/dist/src/structs/Skip.d.ts +9 -11
  11. package/dist/src/structs/Skip.d.ts.map +1 -1
  12. package/dist/src/utils/BlockSet.d.ts +8 -7
  13. package/dist/src/utils/BlockSet.d.ts.map +1 -1
  14. package/dist/src/utils/Doc.d.ts +4 -9
  15. package/dist/src/utils/Doc.d.ts.map +1 -1
  16. package/dist/src/utils/ID.d.ts +0 -1
  17. package/dist/src/utils/ID.d.ts.map +1 -1
  18. package/dist/src/utils/RelativePosition.d.ts +2 -5
  19. package/dist/src/utils/RelativePosition.d.ts.map +1 -1
  20. package/dist/src/utils/Renderer.d.ts +144 -0
  21. package/dist/src/utils/Renderer.d.ts.map +1 -0
  22. package/dist/src/utils/Snapshot.d.ts +7 -11
  23. package/dist/src/utils/Snapshot.d.ts.map +1 -1
  24. package/dist/src/utils/StructStore.d.ts +45 -23
  25. package/dist/src/utils/StructStore.d.ts.map +1 -1
  26. package/dist/src/utils/Transaction.d.ts +11 -21
  27. package/dist/src/utils/Transaction.d.ts.map +1 -1
  28. package/dist/src/utils/UndoManager.d.ts +13 -14
  29. package/dist/src/utils/UndoManager.d.ts.map +1 -1
  30. package/dist/src/utils/UpdateDecoder.d.ts +1 -1
  31. package/dist/src/utils/UpdateDecoder.d.ts.map +1 -1
  32. package/dist/src/utils/UpdateEncoder.d.ts +0 -1
  33. package/dist/src/utils/UpdateEncoder.d.ts.map +1 -1
  34. package/dist/src/utils/YEvent.d.ts +22 -26
  35. package/dist/src/utils/YEvent.d.ts.map +1 -1
  36. package/dist/src/utils/content-helper.d.ts +2 -0
  37. package/dist/src/utils/content-helper.d.ts.map +1 -0
  38. package/dist/src/utils/delta-helpers.d.ts +2 -3
  39. package/dist/src/utils/delta-helpers.d.ts.map +1 -1
  40. package/dist/src/utils/encoding-helpers.d.ts +6 -0
  41. package/dist/src/utils/encoding-helpers.d.ts.map +1 -0
  42. package/dist/src/utils/encoding.d.ts +16 -18
  43. package/dist/src/utils/encoding.d.ts.map +1 -1
  44. package/dist/src/utils/ids.d.ts +331 -0
  45. package/dist/src/utils/ids.d.ts.map +1 -0
  46. package/dist/src/utils/isParentOf.d.ts +1 -2
  47. package/dist/src/utils/isParentOf.d.ts.map +1 -1
  48. package/dist/src/utils/logging.d.ts +0 -1
  49. package/dist/src/utils/logging.d.ts.map +1 -1
  50. package/dist/src/utils/meta.d.ts +15 -64
  51. package/dist/src/utils/meta.d.ts.map +1 -1
  52. package/dist/src/utils/renderer-helpers.d.ts +99 -0
  53. package/dist/src/utils/renderer-helpers.d.ts.map +1 -0
  54. package/dist/src/utils/schemas.d.ts +3 -0
  55. package/dist/src/utils/schemas.d.ts.map +1 -0
  56. package/dist/src/utils/transaction-helpers.d.ts +18 -0
  57. package/dist/src/utils/transaction-helpers.d.ts.map +1 -0
  58. package/dist/src/utils/updates.d.ts +19 -25
  59. package/dist/src/utils/updates.d.ts.map +1 -1
  60. package/dist/src/ytype.d.ts +144 -41
  61. package/dist/src/ytype.d.ts.map +1 -1
  62. package/global.d.ts +53 -0
  63. package/package.json +12 -16
  64. package/src/index.js +32 -124
  65. package/src/structs/AbstractStruct.js +21 -16
  66. package/src/structs/GC.js +15 -20
  67. package/src/structs/Item.js +992 -318
  68. package/src/structs/Skip.js +16 -19
  69. package/src/utils/BlockSet.js +20 -20
  70. package/src/utils/Doc.js +18 -29
  71. package/src/utils/ID.js +0 -2
  72. package/src/utils/RelativePosition.js +15 -25
  73. package/src/utils/{AttributionManager.js → Renderer.js} +42 -197
  74. package/src/utils/Snapshot.js +15 -37
  75. package/src/utils/StructStore.js +89 -227
  76. package/src/utils/Transaction.js +89 -321
  77. package/src/utils/UndoManager.js +157 -19
  78. package/src/utils/UpdateDecoder.js +2 -3
  79. package/src/utils/UpdateEncoder.js +0 -4
  80. package/src/utils/YEvent.js +20 -26
  81. package/src/utils/content-helper.js +0 -0
  82. package/src/utils/delta-helpers.js +21 -42
  83. package/src/utils/encoding-helpers.js +110 -0
  84. package/src/utils/encoding.js +197 -122
  85. package/src/utils/ids.js +1527 -0
  86. package/src/utils/isParentOf.js +2 -4
  87. package/src/utils/logging.js +0 -4
  88. package/src/utils/meta.js +57 -46
  89. package/src/utils/renderer-helpers.js +110 -0
  90. package/src/utils/schemas.js +3 -0
  91. package/src/utils/transaction-helpers.js +413 -0
  92. package/src/utils/updates.js +24 -146
  93. package/src/ytype.js +626 -255
  94. package/tests/testHelper.js +10 -12
  95. package/dist/src/internals.d.ts +0 -36
  96. package/dist/src/internals.d.ts.map +0 -1
  97. package/dist/src/structs/ContentAny.d.ts +0 -67
  98. package/dist/src/structs/ContentAny.d.ts.map +0 -1
  99. package/dist/src/structs/ContentBinary.d.ts +0 -64
  100. package/dist/src/structs/ContentBinary.d.ts.map +0 -1
  101. package/dist/src/structs/ContentDeleted.d.ts +0 -64
  102. package/dist/src/structs/ContentDeleted.d.ts.map +0 -1
  103. package/dist/src/structs/ContentDoc.d.ts +0 -72
  104. package/dist/src/structs/ContentDoc.d.ts.map +0 -1
  105. package/dist/src/structs/ContentEmbed.d.ts +0 -67
  106. package/dist/src/structs/ContentEmbed.d.ts.map +0 -1
  107. package/dist/src/structs/ContentFormat.d.ts +0 -69
  108. package/dist/src/structs/ContentFormat.d.ts.map +0 -1
  109. package/dist/src/structs/ContentJSON.d.ts +0 -70
  110. package/dist/src/structs/ContentJSON.d.ts.map +0 -1
  111. package/dist/src/structs/ContentString.d.ts +0 -70
  112. package/dist/src/structs/ContentString.d.ts.map +0 -1
  113. package/dist/src/structs/ContentType.d.ts +0 -77
  114. package/dist/src/structs/ContentType.d.ts.map +0 -1
  115. package/dist/src/utils/AttributionManager.d.ts +0 -238
  116. package/dist/src/utils/AttributionManager.d.ts.map +0 -1
  117. package/dist/src/utils/IdMap.d.ts +0 -164
  118. package/dist/src/utils/IdMap.d.ts.map +0 -1
  119. package/dist/src/utils/IdSet.d.ts +0 -163
  120. package/dist/src/utils/IdSet.d.ts.map +0 -1
  121. package/dist/tests/IdMap.tests.d.ts +0 -9
  122. package/dist/tests/IdMap.tests.d.ts.map +0 -1
  123. package/dist/tests/IdSet.tests.d.ts +0 -9
  124. package/dist/tests/IdSet.tests.d.ts.map +0 -1
  125. package/dist/tests/attribution.tests.d.ts +0 -9
  126. package/dist/tests/attribution.tests.d.ts.map +0 -1
  127. package/dist/tests/compatibility.tests.d.ts +0 -5
  128. package/dist/tests/compatibility.tests.d.ts.map +0 -1
  129. package/dist/tests/delta.tests.d.ts +0 -7
  130. package/dist/tests/delta.tests.d.ts.map +0 -1
  131. package/dist/tests/doc.tests.d.ts +0 -13
  132. package/dist/tests/doc.tests.d.ts.map +0 -1
  133. package/dist/tests/encoding.tests.d.ts +0 -5
  134. package/dist/tests/encoding.tests.d.ts.map +0 -1
  135. package/dist/tests/index.d.ts +0 -2
  136. package/dist/tests/index.d.ts.map +0 -1
  137. package/dist/tests/relativePositions.tests.d.ts +0 -11
  138. package/dist/tests/relativePositions.tests.d.ts.map +0 -1
  139. package/dist/tests/snapshot.tests.d.ts +0 -14
  140. package/dist/tests/snapshot.tests.d.ts.map +0 -1
  141. package/dist/tests/testHelper.d.ts +0 -171
  142. package/dist/tests/testHelper.d.ts.map +0 -1
  143. package/dist/tests/undo-redo.tests.d.ts +0 -27
  144. package/dist/tests/undo-redo.tests.d.ts.map +0 -1
  145. package/dist/tests/updates.tests.d.ts +0 -26
  146. package/dist/tests/updates.tests.d.ts.map +0 -1
  147. package/dist/tests/y-array.tests.d.ts +0 -43
  148. package/dist/tests/y-array.tests.d.ts.map +0 -1
  149. package/dist/tests/y-map.tests.d.ts +0 -42
  150. package/dist/tests/y-map.tests.d.ts.map +0 -1
  151. package/dist/tests/y-text.tests.d.ts +0 -49
  152. package/dist/tests/y-text.tests.d.ts.map +0 -1
  153. package/dist/tests/y-xml.tests.d.ts +0 -14
  154. package/dist/tests/y-xml.tests.d.ts.map +0 -1
  155. package/src/internals.js +0 -35
  156. package/src/structs/ContentAny.js +0 -115
  157. package/src/structs/ContentBinary.js +0 -93
  158. package/src/structs/ContentDeleted.js +0 -101
  159. package/src/structs/ContentDoc.js +0 -141
  160. package/src/structs/ContentEmbed.js +0 -98
  161. package/src/structs/ContentFormat.js +0 -105
  162. package/src/structs/ContentJSON.js +0 -119
  163. package/src/structs/ContentString.js +0 -113
  164. package/src/structs/ContentType.js +0 -152
  165. package/src/utils/IdMap.js +0 -673
  166. package/src/utils/IdSet.js +0 -825
@@ -1,825 +0,0 @@
1
- import {
2
- findIndexSS,
3
- getState,
4
- splitItem,
5
- iterateStructs,
6
- UpdateEncoderV2,
7
- IdMap,
8
- AttrRanges,
9
- AttrRange,
10
- Skip, AbstractStruct, IdSetDecoderV1, IdSetEncoderV1, IdSetDecoderV2, IdSetEncoderV2, Item, GC, StructStore, Transaction, ID // 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').ContentAttribute<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 != null && 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
- * @todo rename to excludeIdSet | excludeIdMap
447
- *
448
- * Remove all ranges from `exclude` from `ds`. The result is a fresh IdSet containing all ranges from `idSet` that are not
449
- * in `exclude`.
450
- *
451
- * @template {IdSet | IdMap<any>} Set
452
- * @param {Set} set
453
- * @param {IdSet | IdMap<any>} exclude
454
- * @return {Set}
455
- */
456
- export const _diffSet = (set, exclude) => {
457
- /**
458
- * @type {Set}
459
- */
460
- const res = /** @type {any } */ (set instanceof IdSet ? new IdSet() : new IdMap())
461
- const Ranges = set instanceof IdSet ? IdRanges : AttrRanges
462
- set.clients.forEach((_setRanges, client) => {
463
- /**
464
- * @type {Array<IdRange>}
465
- */
466
- let resRanges = []
467
- const _excludedRanges = exclude.clients.get(client)
468
- const setRanges = _setRanges.getIds()
469
- if (_excludedRanges == null) {
470
- resRanges = setRanges.slice()
471
- } else {
472
- const excludedRanges = _excludedRanges.getIds()
473
- let i = 0; let j = 0
474
- let currRange = setRanges[0]
475
- while (i < setRanges.length && j < excludedRanges.length) {
476
- const e = excludedRanges[j]
477
- if (currRange.clock + currRange.len <= e.clock) { // no overlapping, use next range item
478
- if (currRange.len > 0) resRanges.push(currRange)
479
- currRange = setRanges[++i]
480
- } else if (e.clock + e.len <= currRange.clock) { // no overlapping, use next excluded item
481
- j++
482
- } else if (e.clock <= currRange.clock) { // exclude laps into range (we already know that the ranges somehow collide)
483
- const newClock = e.clock + e.len
484
- const newLen = currRange.clock + currRange.len - newClock
485
- if (newLen > 0) {
486
- currRange = currRange.copyWith(newClock, newLen)
487
- j++
488
- } else {
489
- // this item is completely overwritten. len=0. We can jump to the next range
490
- currRange = setRanges[++i]
491
- }
492
- } else { // currRange.clock < e.clock -- range laps into exclude => adjust len
493
- // beginning can't be empty, add it to the result
494
- const nextLen = e.clock - currRange.clock
495
- resRanges.push(currRange.copyWith(currRange.clock, nextLen))
496
- // retain the remaining length after exclude in currRange
497
- currRange = currRange.copyWith(currRange.clock + e.len + nextLen, math.max(currRange.len - e.len - nextLen, 0))
498
- if (currRange.len === 0) currRange = setRanges[++i]
499
- else j++
500
- }
501
- }
502
- if (currRange != null) {
503
- resRanges.push(currRange)
504
- }
505
- i++
506
- while (i < setRanges.length) {
507
- resRanges.push(setRanges[i++])
508
- }
509
- }
510
- // @ts-ignore
511
- if (resRanges.length > 0) res.clients.set(client, /** @type {any} */ (new Ranges(resRanges)))
512
- })
513
- return res
514
- }
515
-
516
- /**
517
- * Remove all ranges from `exclude` from `idSet`. The result is a fresh IdSet containing all ranges from `idSet` that are not
518
- * in `exclude`.
519
- *
520
- * @type {(idSet: IdSet, exclude: IdSet|IdMap<any>) => IdSet}
521
- */
522
- export const diffIdSet = _diffSet
523
-
524
- /**
525
- * @template {IdSet | IdMap<any>} SetA
526
- * @template {IdSet | IdMap<any>} SetB
527
- * @param {SetA} setA
528
- * @param {SetB} setB
529
- * @return {SetA extends IdMap<infer A> ? (SetB extends IdMap<infer B> ? IdMap<A | B> : IdMap<A>) : IdSet}
530
- */
531
- export const _intersectSets = (setA, setB) => {
532
- /**
533
- * @type {IdMap<any> | IdSet}
534
- */
535
- const res = /** @type {any } */ (setA instanceof IdSet ? new IdSet() : new IdMap())
536
- const Ranges = setA instanceof IdSet ? IdRanges : AttrRanges
537
- setA.clients.forEach((_aRanges, client) => {
538
- /**
539
- * @type {Array<IdRange>}
540
- */
541
- const resRanges = []
542
- const _bRanges = setB.clients.get(client)
543
- const aRanges = _aRanges.getIds()
544
- if (_bRanges != null) {
545
- const bRanges = _bRanges.getIds()
546
- for (let a = 0, b = 0; a < aRanges.length && b < bRanges.length;) {
547
- const aRange = aRanges[a]
548
- const bRange = bRanges[b]
549
- // construct overlap
550
- const clock = math.max(aRange.clock, bRange.clock)
551
- const len = math.min(aRange.len - (clock - aRange.clock), bRange.len - (clock - bRange.clock))
552
- if (len > 0) {
553
- resRanges.push(aRange instanceof AttrRange
554
- ? new AttrRange(clock, len, /** @type {Array<any>} */ (aRange.attrs).concat(bRange.attrs))
555
- : new IdRange(clock, len)
556
- )
557
- }
558
- if (aRange.clock + aRange.len < bRange.clock + bRange.len) {
559
- a++
560
- } else {
561
- b++
562
- }
563
- }
564
- }
565
- // @ts-ignore
566
- if (resRanges.length > 0) res.clients.set(client, /** @type {any} */ (new Ranges(resRanges)))
567
- })
568
- return /** @type {any} */ (res)
569
- }
570
-
571
- export const intersectSets = _intersectSets
572
-
573
- /**
574
- * @param {IdSet} idSet
575
- * @param {number} client
576
- * @param {number} clock
577
- * @param {number} length
578
- *
579
- * @private
580
- * @function
581
- */
582
- export const addToIdSet = (idSet, client, clock, length) => {
583
- if (length === 0) return
584
- const idRanges = idSet.clients.get(client)
585
- if (idRanges) {
586
- idRanges.add(clock, length)
587
- } else {
588
- idSet.clients.set(client, new IdRanges([new IdRange(clock, length)]))
589
- }
590
- }
591
-
592
- /**
593
- * @param {IdSet} idSet
594
- * @param {AbstractStruct} struct
595
- *
596
- * @private
597
- * @function
598
- */
599
- export const addStructToIdSet = (idSet, struct) => addToIdSet(idSet, struct.id.client, struct.id.clock, struct.length)
600
-
601
- export const createIdSet = () => new IdSet()
602
-
603
- /**
604
- * @param {StructStore} ss
605
- * @return {IdSet}
606
- *
607
- * @private
608
- * @function
609
- */
610
- export const createDeleteSetFromStructStore = ss => {
611
- const ds = createIdSet()
612
- ss.clients.forEach((structs, client) => {
613
- /**
614
- * @type {Array<IdRange>}
615
- */
616
- const dsitems = []
617
- for (let i = 0; i < structs.length; i++) {
618
- const struct = structs[i]
619
- if (struct.deleted) {
620
- const clock = struct.id.clock
621
- let len = struct.length
622
- if (i + 1 < structs.length) {
623
- for (let next = structs[i + 1]; i + 1 < structs.length && next.deleted; next = structs[++i + 1]) {
624
- len += next.length
625
- }
626
- }
627
- dsitems.push(new IdRange(clock, len))
628
- }
629
- }
630
- if (dsitems.length > 0) {
631
- ds.clients.set(client, new IdRanges(dsitems))
632
- }
633
- })
634
- return ds
635
- }
636
-
637
- /**
638
- * @param {Array<GC | Item>} structs
639
- * @param {boolean} filterDeleted
640
- *
641
- */
642
- export const _createInsertSliceFromStructs = (structs, filterDeleted) => {
643
- /**
644
- * @type {Array<IdRange>}
645
- */
646
- const iditems = []
647
- for (let i = 0; i < structs.length; i++) {
648
- const struct = structs[i]
649
- if (!(filterDeleted && struct.deleted)) {
650
- const clock = struct.id.clock
651
- let len = struct.length
652
- if (i + 1 < structs.length) {
653
- // eslint-disable-next-line
654
- for (let next = structs[i + 1]; i + 1 < structs.length && !(filterDeleted && next.deleted); next = structs[++i + 1]) {
655
- len += next.length
656
- }
657
- }
658
- iditems.push(new IdRange(clock, len))
659
- }
660
- }
661
- return iditems
662
- }
663
-
664
- /**
665
- * @param {import('../internals.js').StructStore} ss
666
- * @param {boolean} filterDeleted
667
- */
668
- export const createInsertSetFromStructStore = (ss, filterDeleted) => {
669
- const idset = createIdSet()
670
- ss.clients.forEach((structs, client) => {
671
- const iditems = _createInsertSliceFromStructs(structs, filterDeleted)
672
- if (iditems.length !== 0) {
673
- idset.clients.set(client, new IdRanges(iditems))
674
- }
675
- })
676
- return idset
677
- }
678
-
679
- /**
680
- * @param {IdSetEncoderV1 | IdSetEncoderV2} encoder
681
- * @param {IdSet} idSet
682
- *
683
- * @private
684
- * @function
685
- */
686
- export const writeIdSet = (encoder, idSet) => {
687
- encoding.writeVarUint(encoder.restEncoder, idSet.clients.size)
688
- // Ensure that the delete set is written in a deterministic order
689
- array.from(idSet.clients.entries())
690
- .sort((a, b) => b[0] - a[0])
691
- .forEach(([client, _idRanges]) => {
692
- const idRanges = _idRanges.getIds()
693
- encoder.resetIdSetCurVal()
694
- encoding.writeVarUint(encoder.restEncoder, client)
695
- const len = idRanges.length
696
- encoding.writeVarUint(encoder.restEncoder, len)
697
- for (let i = 0; i < len; i++) {
698
- const item = idRanges[i]
699
- encoder.writeIdSetClock(item.clock)
700
- encoder.writeIdSetLen(item.len)
701
- }
702
- })
703
- }
704
-
705
- /**
706
- * @param {IdSetDecoderV1 | IdSetDecoderV2} decoder
707
- * @return {IdSet}
708
- *
709
- * @private
710
- * @function
711
- */
712
- export const readIdSet = decoder => {
713
- const ds = new IdSet()
714
- const numClients = decoding.readVarUint(decoder.restDecoder)
715
- for (let i = 0; i < numClients; i++) {
716
- decoder.resetDsCurVal()
717
- const client = decoding.readVarUint(decoder.restDecoder)
718
- const numberOfDeletes = decoding.readVarUint(decoder.restDecoder)
719
- if (numberOfDeletes > 0) {
720
- /**
721
- * @type {Array<IdRange>}
722
- */
723
- const dsRanges = []
724
- for (let i = 0; i < numberOfDeletes; i++) {
725
- dsRanges.push(new IdRange(decoder.readDsClock(), decoder.readDsLen()))
726
- }
727
- ds.clients.set(client, new IdRanges(dsRanges))
728
- }
729
- }
730
- return ds
731
- }
732
-
733
- /**
734
- * @todo YDecoder also contains references to String and other Decoders. Would make sense to exchange YDecoder.toUint8Array for YDecoder.DsToUint8Array()..
735
- */
736
-
737
- /**
738
- * @param {IdSetDecoderV1 | IdSetDecoderV2} decoder
739
- * @param {Transaction} transaction
740
- * @param {StructStore} store
741
- * @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.
742
- *
743
- * @private
744
- * @function
745
- */
746
- export const readAndApplyDeleteSet = (decoder, transaction, store) => {
747
- const unappliedDS = new IdSet()
748
- const numClients = decoding.readVarUint(decoder.restDecoder)
749
- for (let i = 0; i < numClients; i++) {
750
- decoder.resetDsCurVal()
751
- const client = decoding.readVarUint(decoder.restDecoder)
752
- const numberOfDeletes = decoding.readVarUint(decoder.restDecoder)
753
- const structs = store.clients.get(client) || []
754
- const state = getState(store, client)
755
- for (let i = 0; i < numberOfDeletes; i++) {
756
- const clock = decoder.readDsClock()
757
- const clockEnd = clock + decoder.readDsLen()
758
- if (clock < state) {
759
- if (state < clockEnd) {
760
- addToIdSet(unappliedDS, client, state, clockEnd - state)
761
- }
762
- let index = findIndexSS(structs, clock)
763
- /**
764
- * We can ignore the case of GC and Delete structs, because we are going to skip them
765
- * @type {Item | GC | Skip}
766
- */
767
- let struct = structs[index]
768
- // split the first item if necessary
769
- if (!struct.deleted && struct.id.clock < clock && struct instanceof Item) {
770
- // increment index, we now want to use the next struct
771
- structs.splice(++index, 0, splitItem(transaction, struct, clock - struct.id.clock))
772
- }
773
- while (index < structs.length) {
774
- // @ts-ignore
775
- struct = structs[index++]
776
- if (struct.id.clock < clockEnd) {
777
- if (!struct.deleted) {
778
- if (struct instanceof Item) {
779
- if (clockEnd < struct.id.clock + struct.length) {
780
- structs.splice(index, 0, splitItem(transaction, struct, clockEnd - struct.id.clock))
781
- }
782
- struct.delete(transaction)
783
- } else { // is a Skip - add range to unappliedDS
784
- const c = math.max(struct.id.clock, clock)
785
- unappliedDS.add(client, c, math.min(struct.length, clockEnd - c))
786
- }
787
- }
788
- } else {
789
- break
790
- }
791
- }
792
- } else {
793
- addToIdSet(unappliedDS, client, clock, clockEnd - clock)
794
- }
795
- }
796
- }
797
- if (unappliedDS.clients.size > 0) {
798
- const ds = new UpdateEncoderV2()
799
- encoding.writeVarUint(ds.restEncoder, 0) // encode 0 structs
800
- writeIdSet(ds, unappliedDS)
801
- return ds.toUint8Array()
802
- }
803
- return null
804
- }
805
-
806
- /**
807
- * @param {IdSet} ds1
808
- * @param {IdSet} ds2
809
- */
810
- export const equalIdSets = (ds1, ds2) => {
811
- if (ds1.clients.size !== ds2.clients.size) return false
812
- for (const [client, _deleteItems1] of ds1.clients.entries()) {
813
- const deleteItems1 = _deleteItems1.getIds()
814
- const deleteItems2 = ds2.clients.get(client)?.getIds()
815
- if (deleteItems2 === undefined || deleteItems1.length !== deleteItems2.length) return false
816
- for (let i = 0; i < deleteItems1.length; i++) {
817
- const di1 = deleteItems1[i]
818
- const di2 = deleteItems2[i]
819
- if (di1.clock !== di2.clock || di1.len !== di2.len) {
820
- return false
821
- }
822
- }
823
- }
824
- return true
825
- }