@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,673 +0,0 @@
1
- import {
2
- _diffSet,
3
- findIndexInIdRanges,
4
- findRangeStartInIdRanges,
5
- _deleteRangeFromIdSet,
6
- IdSetDecoderV1, IdSetDecoderV2, IdSetEncoderV1, IdSetEncoderV2, IdSet, ID, // eslint-disable-line
7
- _insertIntoIdSet,
8
- _intersectSets,
9
- createIdSet,
10
- IdRanges
11
- } from '../internals.js'
12
-
13
- import * as array from 'lib0/array'
14
- import * as map from 'lib0/map'
15
- import * as encoding from 'lib0/encoding'
16
- import * as decoding from 'lib0/decoding'
17
- import * as buf from 'lib0/buffer'
18
- import * as rabin from 'lib0/hash/rabin'
19
-
20
- /**
21
- * @todo rename this to `Attribute`
22
- * @template V
23
- */
24
- export class ContentAttribute {
25
- /**
26
- * @param {string} name
27
- * @param {V} val
28
- */
29
- constructor (name, val) {
30
- this.name = name
31
- this.val = val
32
- }
33
-
34
- hash () {
35
- const encoder = encoding.createEncoder()
36
- encoding.writeVarString(encoder, this.name)
37
- encoding.writeAny(encoder, /** @type {any} */ (this.val))
38
- return buf.toBase64(rabin.fingerprint(rabin.StandardIrreducible128, encoding.toUint8Array(encoder)))
39
- }
40
- }
41
-
42
- /**
43
- * @template V
44
- * @param {string} name
45
- * @param {V} val
46
- * @return {ContentAttribute<V>}
47
- */
48
- export const createContentAttribute = (name, val) => new ContentAttribute(name, val)
49
-
50
- /**
51
- * @template T
52
- * @param {Array<T>} attrs
53
- * @param {T} attr
54
- *
55
- */
56
- const idmapAttrsHas = (attrs, attr) => attrs.find(a => a === attr)
57
-
58
- /**
59
- * @template T
60
- * @param {Array<T>} a
61
- * @param {Array<T>} b
62
- */
63
- export const idmapAttrsEqual = (a, b) => a.length === b.length && a.every(v => idmapAttrsHas(b, v))
64
-
65
- /**
66
- * @template T
67
- * @param {Array<T>} a
68
- * @param {Array<T>} b
69
- */
70
- const idmapAttrRangeJoin = (a, b) => a.concat(b.filter(attr => !idmapAttrsHas(a, attr)))
71
-
72
- /**
73
- * @template Attrs
74
- */
75
- export class AttrRange {
76
- /**
77
- * @param {number} clock
78
- * @param {number} len
79
- * @param {Array<ContentAttribute<Attrs>>} attrs
80
- */
81
- constructor (clock, len, attrs) {
82
- /**
83
- * @readonly
84
- */
85
- this.clock = clock
86
- /**
87
- * @readonly
88
- */
89
- this.len = len
90
- /**
91
- * @readonly
92
- */
93
- this.attrs = attrs
94
- }
95
-
96
- /**
97
- * @param {number} clock
98
- * @param {number} len
99
- */
100
- copyWith (clock, len) {
101
- return new AttrRange(clock, len, this.attrs)
102
- }
103
- }
104
-
105
- /**
106
- * @template Attrs
107
- * @typedef {{ clock: number, len: number, attrs: Array<ContentAttribute<Attrs>>? }} MaybeAttrRange
108
- */
109
-
110
- /**
111
- * @template Attrs
112
- *
113
- * @param {number} clock
114
- * @param {number} len
115
- * @param {Array<ContentAttribute<Attrs>>?} attrs
116
- * @return {MaybeAttrRange<Attrs>}
117
- */
118
- export const createMaybeAttrRange = (clock, len, attrs) => new AttrRange(clock, len, /** @type {any} */ (attrs))
119
-
120
- /**
121
- * Whenever this is instantiated, it must receive a fresh array of ops, not something copied.
122
- *
123
- * @template Attrs
124
- */
125
- export class AttrRanges {
126
- /**
127
- * @param {Array<AttrRange<Attrs>>} ids
128
- */
129
- constructor (ids) {
130
- this.sorted = false
131
- /**
132
- * @private
133
- */
134
- this._ids = ids
135
- }
136
-
137
- copy () {
138
- return new AttrRanges(this._ids.slice())
139
- }
140
-
141
- /**
142
- * @param {number} clock
143
- * @param {number} length
144
- * @param {Array<ContentAttribute<Attrs>>} attrs
145
- */
146
- add (clock, length, attrs) {
147
- if (length === 0) return
148
- this.sorted = false
149
- this._ids.push(new AttrRange(clock, length, attrs))
150
- }
151
-
152
- /**
153
- * Return the list of id ranges, sorted and merged.
154
- */
155
- getIds () {
156
- const ids = this._ids
157
- if (!this.sorted) {
158
- this.sorted = true
159
- ids.sort((a, b) => a.clock - b.clock)
160
- /**
161
- * algorithm thoughts:
162
- * - sort (by clock AND by length), bigger length is to the right (or not, we can't make
163
- * assumptions abouth length after long length has been split)
164
- * -- maybe better: sort by clock+length. Then split items from right to left. This way, items are always
165
- * in the right order. But I also need to swap if left items is smaller after split
166
- * --- thought: there is no way to go around swapping. Unless, for each item from left to
167
- * right, when I have to split because one of the look-ahead items is overlapping, i split
168
- * it and merge the attributes into the following ones (that I also need to split). Best is
169
- * probably left to right with lookahead.
170
- * - left to right, split overlapping items so that we can make the assumption that either an
171
- * item is overlapping with the next 1-on-1 or it is not overlapping at all (when splitting,
172
- * we can already incorporate the attributes)
173
- * -- better: for each item, go left to right and add own attributes to overlapping items.
174
- * Split them if necessary. After split, i must insert the retainer at a valid position.
175
- * - merge items if neighbor has same attributes
176
- */
177
- for (let i = 0; i < ids.length - 1;) {
178
- const range = ids[i]
179
- const nextRange = ids[i + 1]
180
- // find out how to split range. it must match with next range.
181
- // 1) we have space. Split if necessary.
182
- // 2) concat attributes in range to the next range. Split range and splice the remainder at
183
- // the correct position.
184
- if (range.clock < nextRange.clock) { // might need to split range
185
- if (range.clock + range.len > nextRange.clock) {
186
- // is overlapping
187
- const diff = nextRange.clock - range.clock
188
- ids[i] = new AttrRange(range.clock, diff, range.attrs)
189
- ids.splice(i + 1, 0, new AttrRange(nextRange.clock, range.len - diff, range.attrs))
190
- }
191
- i++
192
- continue
193
- }
194
- // now we know that range.clock === nextRange.clock
195
- // merge range with nextRange
196
- const largerRange = range.len > nextRange.len ? range : nextRange
197
- const smallerLen = range.len < nextRange.len ? range.len : nextRange.len
198
- ids[i] = new AttrRange(range.clock, smallerLen, idmapAttrRangeJoin(range.attrs, nextRange.attrs))
199
- if (range.len === nextRange.len) {
200
- ids.splice(i + 1, 1)
201
- } else {
202
- ids[i + 1] = new AttrRange(range.clock + smallerLen, largerRange.len - smallerLen, largerRange.attrs)
203
- array.bubblesortItem(ids, i + 1, (a, b) => a.clock - b.clock)
204
- }
205
- if (smallerLen === 0) i++
206
- }
207
- while (ids.length > 0 && ids[0].len === 0) {
208
- ids.splice(0, 1)
209
- }
210
- // merge items without filtering or splicing the array.
211
- // i is the current pointer
212
- // j refers to the current insert position for the pointed item
213
- // try to merge dels[i] into dels[j-1] or set dels[j]=dels[i]
214
- let i, j
215
- for (i = 1, j = 1; i < ids.length; i++) {
216
- const left = ids[j - 1]
217
- const right = ids[i]
218
- if (left.clock + left.len === right.clock && idmapAttrsEqual(left.attrs, right.attrs)) {
219
- ids[j - 1] = new AttrRange(left.clock, left.len + right.len, left.attrs)
220
- } else if (right.len !== 0) {
221
- if (j < i) {
222
- ids[j] = right
223
- }
224
- j++
225
- }
226
- }
227
- ids.length = ids.length === 0 ? 0 : (ids[j - 1].len === 0 ? j - 1 : j)
228
- }
229
- return ids
230
- }
231
- }
232
-
233
- /**
234
- * Merge multiple idmaps. Ensures that there are no redundant attribution definitions (two
235
- * Attributions that describe the same thing).
236
- *
237
- * @template T
238
- * @param {Array<IdMap<T>>} ams
239
- * @return {IdMap<T>} A fresh IdSet
240
- */
241
- export const mergeIdMaps = ams => {
242
- /**
243
- * Maps attribution to the attribution of the merged idmap.
244
- *
245
- * @type {Map<ContentAttribute<any>,ContentAttribute<any>>}
246
- */
247
- const attrMapper = new Map()
248
- const merged = createIdMap()
249
- for (let amsI = 0; amsI < ams.length; amsI++) {
250
- ams[amsI].clients.forEach((rangesLeft, client) => {
251
- if (!merged.clients.has(client)) {
252
- // Write all missing keys from current set and all following.
253
- // If merged already contains `client` current ds has already been added.
254
- let ids = rangesLeft.getIds().slice()
255
- for (let i = amsI + 1; i < ams.length; i++) {
256
- const nextIds = ams[i].clients.get(client)
257
- if (nextIds) {
258
- array.appendTo(ids, nextIds.getIds())
259
- }
260
- }
261
- ids = ids.map(id => new AttrRange(id.clock, id.len, id.attrs.map(attr =>
262
- map.setIfUndefined(attrMapper, attr, () =>
263
- _ensureAttrs(merged, [attr])[0]
264
- )
265
- )))
266
- merged.clients.set(client, new AttrRanges(ids))
267
- }
268
- })
269
- }
270
- return merged
271
- }
272
-
273
- /**
274
- * @param {IdSet} idset
275
- * @param {Array<ContentAttribute<any>>} attrs
276
- */
277
- export const createIdMapFromIdSet = (idset, attrs) => {
278
- const idmap = createIdMap()
279
- // map attrs to idmap
280
- attrs = _ensureAttrs(idmap, attrs)
281
- // filter out duplicates
282
- /**
283
- * @type {Array<ContentAttribute<any>>}
284
- */
285
- const checkedAttrs = []
286
- attrs.forEach(attr => {
287
- if (!idmapAttrsHas(checkedAttrs, attr)) {
288
- checkedAttrs.push(attr)
289
- }
290
- })
291
- idset.clients.forEach((ranges, client) => {
292
- const attrRanges = new AttrRanges(ranges.getIds().map(range => new AttrRange(range.clock, range.len, checkedAttrs)))
293
- attrRanges.sorted = true // is sorted because idset is sorted
294
- idmap.clients.set(client, attrRanges)
295
- })
296
- return idmap
297
- }
298
-
299
- /**
300
- * Create an IdSet from an IdMap by stripping the attributes.
301
- *
302
- * @param {IdMap<any>} idmap
303
- * @return {IdSet}
304
- */
305
- export const createIdSetFromIdMap = idmap => {
306
- const idset = createIdSet()
307
- idmap.clients.forEach((ranges, client) => {
308
- const idRanges = new IdRanges([])
309
- ranges.getIds().forEach(range => idRanges.add(range.clock, range.len))
310
- idset.clients.set(client, idRanges)
311
- })
312
- return idset
313
- }
314
-
315
- /**
316
- * @template Attrs
317
- */
318
- export class IdMap {
319
- constructor () {
320
- /**
321
- * @type {Map<number,AttrRanges<Attrs>>}
322
- */
323
- this.clients = new Map()
324
- /**
325
- * @type {Map<string, ContentAttribute<Attrs>>}
326
- */
327
- this.attrsH = new Map()
328
- /**
329
- * @type {Set<ContentAttribute<Attrs>>}
330
- */
331
- this.attrs = new Set()
332
- }
333
-
334
- /**
335
- * @param {(attrRange:AttrRange<Attrs>, client:number) => void} f
336
- */
337
- forEach (f) {
338
- this.clients.forEach((ranges, client) => {
339
- ranges.getIds().forEach((range) => {
340
- f(range, client)
341
- })
342
- })
343
- }
344
-
345
- isEmpty () {
346
- return this.clients.size === 0
347
- }
348
-
349
- /**
350
- * @param {ID} id
351
- * @return {boolean}
352
- */
353
- hasId (id) {
354
- return this.has(id.client, id.clock)
355
- }
356
-
357
- /**
358
- * @param {number} client
359
- * @param {number} clock
360
- * @return {boolean}
361
- */
362
- has (client, clock) {
363
- const dr = this.clients.get(client)
364
- if (dr) {
365
- return findIndexInIdRanges(dr.getIds(), clock) !== null
366
- }
367
- return false
368
- }
369
-
370
- /**
371
- * Return attributions for a slice of ids.
372
- *
373
- * @param {ID} id
374
- * @param {number} len
375
- * @return {Array<MaybeAttrRange<Attrs>>}
376
- */
377
- sliceId (id, len) {
378
- return this.slice(id.client, id.clock, len)
379
- }
380
-
381
- /**
382
- * Return attributions for a slice of ids.
383
- *
384
- * @param {number} client
385
- * @param {number} clock
386
- * @param {number} len
387
- * @return {Array<MaybeAttrRange<Attrs>>}
388
- */
389
- slice (client, clock, len) {
390
- const dr = this.clients.get(client)
391
- /**
392
- * @type {Array<MaybeAttrRange<Attrs>>}
393
- */
394
- const res = []
395
- if (dr) {
396
- /**
397
- * @type {Array<AttrRange<Attrs>>}
398
- */
399
- const ranges = dr.getIds()
400
- let index = findRangeStartInIdRanges(ranges, clock)
401
- if (index !== null) {
402
- let prev = null
403
- while (index < ranges.length) {
404
- let r = ranges[index]
405
- if (r.clock < clock) {
406
- r = new AttrRange(clock, r.len - (clock - r.clock), r.attrs)
407
- }
408
- if (r.clock + r.len > clock + len) {
409
- r = new AttrRange(r.clock, clock + len - r.clock, r.attrs)
410
- }
411
- if (r.len <= 0) break
412
- const prevEnd = prev != null ? prev.clock + prev.len : clock
413
- if (prevEnd < r.clock) {
414
- res.push(createMaybeAttrRange(prevEnd, r.clock - prevEnd, null))
415
- }
416
- prev = r
417
- res.push(r)
418
- index++
419
- }
420
- }
421
- }
422
- if (res.length > 0) {
423
- const last = res[res.length - 1]
424
- const end = last.clock + last.len
425
- if (end < clock + len) {
426
- res.push(createMaybeAttrRange(end, clock + len - end, null))
427
- }
428
- } else {
429
- res.push(createMaybeAttrRange(clock, len, null))
430
- }
431
- return res
432
- }
433
-
434
- /**
435
- * @param {number} client
436
- * @param {number} clock
437
- * @param {number} len
438
- * @param {Array<ContentAttribute<Attrs>>} attrs
439
- */
440
- add (client, clock, len, attrs) {
441
- if (len === 0) return
442
- attrs = _ensureAttrs(this, attrs)
443
- const ranges = this.clients.get(client)
444
- if (ranges == null) {
445
- this.clients.set(client, new AttrRanges([new AttrRange(clock, len, attrs)]))
446
- } else {
447
- ranges.add(clock, len, attrs)
448
- }
449
- }
450
-
451
- /**
452
- * @param {number} client
453
- * @param {number} clock
454
- * @param {number} len
455
- */
456
- delete (client, clock, len) {
457
- _deleteRangeFromIdSet(this, client, clock, len)
458
- }
459
- }
460
-
461
- /**
462
- * Efficiently encodes IdMap to a binary form. Ensures that information is de-duplicated when
463
- * written. Attribute.names are referenced by id. Attributes themselfs are also referenced by id.
464
- *
465
- * @template Attr
466
- * @param {IdSetEncoderV1 | IdSetEncoderV2} encoder
467
- * @param {IdMap<Attr>} idmap
468
- *
469
- * @private
470
- * @function
471
- */
472
- export const writeIdMap = (encoder, idmap) => {
473
- encoding.writeVarUint(encoder.restEncoder, idmap.clients.size)
474
- let lastWrittenClientId = 0
475
- /**
476
- * @type {Map<ContentAttribute<Attr>, number>}
477
- */
478
- const visitedAttributions = map.create()
479
- /**
480
- * @type {Map<string, number>}
481
- */
482
- const visitedAttrNames = map.create()
483
- // Ensure that the ids are written in a deterministic order (smaller clientids first)
484
- array.from(idmap.clients.entries())
485
- .sort((a, b) => a[0] - b[0])
486
- .forEach(([client, _idRanges]) => {
487
- const attrRanges = _idRanges.getIds()
488
- encoder.resetIdSetCurVal()
489
- const diff = client - lastWrittenClientId
490
- encoding.writeVarUint(encoder.restEncoder, diff)
491
- lastWrittenClientId = client
492
- const len = attrRanges.length
493
- encoding.writeVarUint(encoder.restEncoder, len)
494
- for (let i = 0; i < len; i++) {
495
- const item = attrRanges[i]
496
- const attrs = item.attrs
497
- const attrLen = attrs.length
498
- encoder.writeIdSetClock(item.clock)
499
- encoder.writeIdSetLen(item.len)
500
- encoding.writeVarUint(encoder.restEncoder, attrLen)
501
- for (let j = 0; j < attrLen; j++) {
502
- const attr = attrs[j]
503
- const attrId = visitedAttributions.get(attr)
504
- if (attrId != null) {
505
- encoding.writeVarUint(encoder.restEncoder, attrId)
506
- } else {
507
- const newAttrId = visitedAttributions.size
508
- visitedAttributions.set(attr, newAttrId)
509
- encoding.writeVarUint(encoder.restEncoder, newAttrId)
510
- const attrNameId = visitedAttrNames.get(attr.name)
511
- // write attr.name
512
- if (attrNameId != null) {
513
- encoding.writeVarUint(encoder.restEncoder, attrNameId)
514
- } else {
515
- const newAttrNameId = visitedAttrNames.size
516
- encoding.writeVarUint(encoder.restEncoder, newAttrNameId)
517
- encoding.writeVarString(encoder.restEncoder, attr.name)
518
- visitedAttrNames.set(attr.name, newAttrNameId)
519
- }
520
- encoding.writeAny(encoder.restEncoder, /** @type {any} */ (attr.val))
521
- }
522
- }
523
- }
524
- })
525
- }
526
-
527
- /**
528
- * @param {IdMap<any>} idmap
529
- */
530
- export const encodeIdMap = idmap => {
531
- const encoder = new IdSetEncoderV2()
532
- writeIdMap(encoder, idmap)
533
- return encoder.toUint8Array()
534
- }
535
-
536
- /**
537
- * @param {IdSetDecoderV1 | IdSetDecoderV2} decoder
538
- * @return {IdMap<any>}
539
- *
540
- * @private
541
- * @function
542
- */
543
- export const readIdMap = decoder => {
544
- const idmap = new IdMap()
545
- const numClients = decoding.readVarUint(decoder.restDecoder)
546
- /**
547
- * @type {Array<ContentAttribute<any>>}
548
- */
549
- const visitedAttributions = []
550
- /**
551
- * @type {Array<string>}
552
- */
553
- const visitedAttrNames = []
554
- let lastClientId = 0
555
- for (let i = 0; i < numClients; i++) {
556
- decoder.resetDsCurVal()
557
- const client = lastClientId + decoding.readVarUint(decoder.restDecoder)
558
- lastClientId = client
559
- const numberOfDeletes = decoding.readVarUint(decoder.restDecoder)
560
- /**
561
- * @type {Array<AttrRange<any>>}
562
- */
563
- const attrRanges = []
564
- for (let i = 0; i < numberOfDeletes; i++) {
565
- const rangeClock = decoder.readDsClock()
566
- const rangeLen = decoder.readDsLen()
567
- /**
568
- * @type {Array<ContentAttribute<any>>}
569
- */
570
- const attrs = []
571
- const attrsLen = decoding.readVarUint(decoder.restDecoder)
572
- for (let j = 0; j < attrsLen; j++) {
573
- const attrId = decoding.readVarUint(decoder.restDecoder)
574
- if (attrId >= visitedAttributions.length) {
575
- // attrId not known yet
576
- const attrNameId = decoding.readVarUint(decoder.restDecoder)
577
- if (attrNameId >= visitedAttrNames.length) {
578
- visitedAttrNames.push(decoding.readVarString(decoder.restDecoder))
579
- }
580
- visitedAttributions.push(new ContentAttribute(visitedAttrNames[attrNameId], decoding.readAny(decoder.restDecoder)))
581
- }
582
- attrs.push(visitedAttributions[attrId])
583
- }
584
- attrRanges.push(new AttrRange(rangeClock, rangeLen, attrs))
585
- }
586
- idmap.clients.set(client, new AttrRanges(attrRanges))
587
- }
588
- visitedAttributions.forEach(attr => {
589
- idmap.attrs.add(attr)
590
- idmap.attrsH.set(attr.hash(), attr)
591
- })
592
- return idmap
593
- }
594
-
595
- /**
596
- * @param {Uint8Array} data
597
- * @return {IdMap<any>}
598
- */
599
- export const decodeIdMap = data => readIdMap(new IdSetDecoderV2(decoding.createDecoder(data)))
600
-
601
- /**
602
- * @template Attrs
603
- * @param {IdMap<Attrs>} idmap
604
- * @param {Array<ContentAttribute<Attrs>>} attrs
605
- * @return {Array<ContentAttribute<Attrs>>}
606
- */
607
- const _ensureAttrs = (idmap, attrs) => attrs.map(attr =>
608
- idmap.attrs.has(attr)
609
- ? attr
610
- : map.setIfUndefined(idmap.attrsH, attr.hash(), () => {
611
- idmap.attrs.add(attr)
612
- return attr
613
- }))
614
-
615
- export const createIdMap = () => new IdMap()
616
-
617
- /**
618
- * @template T
619
- * @param {IdMap<T>} dest
620
- * @param {IdMap<T>} src
621
- */
622
- export const insertIntoIdMap = _insertIntoIdSet
623
-
624
- /**
625
- * Remove all ranges from `exclude` from `ds`. The result is a fresh IdMap containing all ranges from `idSet` that are not
626
- * in `exclude`.
627
- *
628
- * @template {IdMap<any>} ISet
629
- * @param {ISet} set
630
- * @param {IdSet | IdMap<any>} exclude
631
- * @return {ISet}
632
- */
633
- export const diffIdMap = (set, exclude) => {
634
- const diffed = _diffSet(set, exclude)
635
- diffed.attrs = set.attrs
636
- diffed.attrsH = set.attrsH
637
- return diffed
638
- }
639
-
640
- export const intersectMaps = _intersectSets
641
-
642
- /**
643
- * Filter attributes in an IdMap based on a predicate function.
644
- * Returns a new IdMap containing idranges that match the predicate.
645
- *
646
- * @template Attrs
647
- * @param {IdMap<Attrs>} idmap
648
- * @param {(attr: Array<ContentAttribute<Attrs>>) => boolean} predicate
649
- * @return {IdMap<Attrs>}
650
- */
651
- export const filterIdMap = (idmap, predicate) => {
652
- const filtered = createIdMap()
653
- idmap.clients.forEach((ranges, client) => {
654
- /**
655
- * @type {Array<AttrRange<Attrs>>}
656
- */
657
- const attrRanges = []
658
- ranges.getIds().forEach((range) => {
659
- if (predicate(range.attrs)) {
660
- const rangeCpy = range.copyWith(range.clock, range.len)
661
- attrRanges.push(rangeCpy)
662
- rangeCpy.attrs.forEach(attr => {
663
- filtered.attrs.add(attr)
664
- filtered.attrsH.set(attr.hash(), attr)
665
- })
666
- }
667
- })
668
- if (attrRanges.length > 0) {
669
- filtered.clients.set(client, new AttrRanges(attrRanges))
670
- }
671
- })
672
- return filtered
673
- }