@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,1434 @@
1
+ import {
2
+ removeEventHandlerListener,
3
+ callEventHandlerListeners,
4
+ addEventHandlerListener,
5
+ createEventHandler,
6
+ getState,
7
+ isVisible,
8
+ ContentType,
9
+ createID,
10
+ ContentAny,
11
+ ContentFormat,
12
+ ContentBinary,
13
+ ContentJSON,
14
+ ContentDeleted,
15
+ ContentString,
16
+ ContentEmbed,
17
+ getItemCleanStart,
18
+ noAttributionsManager,
19
+ transact,
20
+ ItemTextListPosition,
21
+ insertText,
22
+ deleteText,
23
+ ContentDoc, UpdateEncoderV1, UpdateEncoderV2, Doc, Snapshot, Transaction, EventHandler, YEvent, Item, createAttributionFromAttributionItems, AbstractAttributionManager, YXmlElement, // eslint-disable-line
24
+ } from '../internals.js'
25
+
26
+ import * as delta from 'lib0/delta'
27
+ import * as array from 'lib0/array'
28
+ import * as map from 'lib0/map'
29
+ import * as iterator from 'lib0/iterator'
30
+ import * as error from 'lib0/error'
31
+ import * as math from 'lib0/math'
32
+ import * as log from 'lib0/logging'
33
+ import * as object from 'lib0/object'
34
+
35
+ /**
36
+ * @typedef {import('../utils/types.js').YType} YType_
37
+ */
38
+ /**
39
+ * @typedef {import('../utils/types.js').YValue} _YValue
40
+ */
41
+
42
+ /**
43
+ * https://docs.yjs.dev/getting-started/working-with-shared-types#caveats
44
+ */
45
+ export const warnPrematureAccess = () => { log.warn('Invalid access: Add Yjs type to a document before reading data.') }
46
+
47
+ const maxSearchMarker = 80
48
+
49
+ /**
50
+ * A unique timestamp that identifies each marker.
51
+ *
52
+ * Time is relative,.. this is more like an ever-increasing clock.
53
+ *
54
+ * @type {number}
55
+ */
56
+ let globalSearchMarkerTimestamp = 0
57
+
58
+ export class ArraySearchMarker {
59
+ /**
60
+ * @param {Item} p
61
+ * @param {number} index
62
+ */
63
+ constructor (p, index) {
64
+ p.marker = true
65
+ this.p = p
66
+ this.index = index
67
+ this.timestamp = globalSearchMarkerTimestamp++
68
+ }
69
+ }
70
+
71
+ /**
72
+ * @param {ArraySearchMarker} marker
73
+ */
74
+ const refreshMarkerTimestamp = marker => { marker.timestamp = globalSearchMarkerTimestamp++ }
75
+
76
+ /**
77
+ * This is rather complex so this function is the only thing that should overwrite a marker
78
+ *
79
+ * @param {ArraySearchMarker} marker
80
+ * @param {Item} p
81
+ * @param {number} index
82
+ */
83
+ const overwriteMarker = (marker, p, index) => {
84
+ marker.p.marker = false
85
+ marker.p = p
86
+ p.marker = true
87
+ marker.index = index
88
+ marker.timestamp = globalSearchMarkerTimestamp++
89
+ }
90
+
91
+ /**
92
+ * @param {Array<ArraySearchMarker>} searchMarker
93
+ * @param {Item} p
94
+ * @param {number} index
95
+ */
96
+ const markPosition = (searchMarker, p, index) => {
97
+ if (searchMarker.length >= maxSearchMarker) {
98
+ // override oldest marker (we don't want to create more objects)
99
+ const marker = searchMarker.reduce((a, b) => a.timestamp < b.timestamp ? a : b)
100
+ overwriteMarker(marker, p, index)
101
+ return marker
102
+ } else {
103
+ // create new marker
104
+ const pm = new ArraySearchMarker(p, index)
105
+ searchMarker.push(pm)
106
+ return pm
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Search marker help us to find positions in the associative array faster.
112
+ *
113
+ * They speed up the process of finding a position without much bookkeeping.
114
+ *
115
+ * A maximum of `maxSearchMarker` objects are created.
116
+ *
117
+ * This function always returns a refreshed marker (updated timestamp)
118
+ *
119
+ * @param {import('../utils/types.js').YType} yarray
120
+ * @param {number} index
121
+ */
122
+ export const findMarker = (yarray, index) => {
123
+ if (yarray._start === null || index === 0 || yarray._searchMarker === null) {
124
+ return null
125
+ }
126
+ const marker = yarray._searchMarker.length === 0 ? null : yarray._searchMarker.reduce((a, b) => math.abs(index - a.index) < math.abs(index - b.index) ? a : b)
127
+ let p = yarray._start
128
+ let pindex = 0
129
+ if (marker !== null) {
130
+ p = marker.p
131
+ pindex = marker.index
132
+ refreshMarkerTimestamp(marker) // we used it, we might need to use it again
133
+ }
134
+ // iterate to right if possible
135
+ while (p.right !== null && pindex < index) {
136
+ if (!p.deleted && p.countable) {
137
+ if (index < pindex + p.length) {
138
+ break
139
+ }
140
+ pindex += p.length
141
+ }
142
+ p = p.right
143
+ }
144
+ // iterate to left if necessary (might be that pindex > index)
145
+ while (p.left !== null && pindex > index) {
146
+ p = p.left
147
+ if (!p.deleted && p.countable) {
148
+ pindex -= p.length
149
+ }
150
+ }
151
+ // we want to make sure that p can't be merged with left, because that would screw up everything
152
+ // in that cas just return what we have (it is most likely the best marker anyway)
153
+ // iterate to left until p can't be merged with left
154
+ while (p.left !== null && p.left.id.client === p.id.client && p.left.id.clock + p.left.length === p.id.clock) {
155
+ p = p.left
156
+ if (!p.deleted && p.countable) {
157
+ pindex -= p.length
158
+ }
159
+ }
160
+
161
+ // @todo remove!
162
+ // assure position
163
+ // {
164
+ // let start = yarray._start
165
+ // let pos = 0
166
+ // while (start !== p) {
167
+ // if (!start.deleted && start.countable) {
168
+ // pos += start.length
169
+ // }
170
+ // start = /** @type {Item} */ (start.right)
171
+ // }
172
+ // if (pos !== pindex) {
173
+ // debugger
174
+ // throw new Error('Gotcha position fail!')
175
+ // }
176
+ // }
177
+ // if (marker) {
178
+ // if (window.lengths == null) {
179
+ // window.lengths = []
180
+ // window.getLengths = () => window.lengths.sort((a, b) => a - b)
181
+ // }
182
+ // window.lengths.push(marker.index - pindex)
183
+ // console.log('distance', marker.index - pindex, 'len', p && p.parent.length)
184
+ // }
185
+ if (marker !== null && math.abs(marker.index - pindex) < /** @type {any} */ (p.parent).length / maxSearchMarker) {
186
+ // adjust existing marker
187
+ overwriteMarker(marker, p, pindex)
188
+ return marker
189
+ } else {
190
+ // create new marker
191
+ return markPosition(yarray._searchMarker, p, pindex)
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Update markers when a change happened.
197
+ *
198
+ * This should be called before doing a deletion!
199
+ *
200
+ * @param {Array<ArraySearchMarker>} searchMarker
201
+ * @param {number} index
202
+ * @param {number} len If insertion, len is positive. If deletion, len is negative.
203
+ */
204
+ export const updateMarkerChanges = (searchMarker, index, len) => {
205
+ for (let i = searchMarker.length - 1; i >= 0; i--) {
206
+ const m = searchMarker[i]
207
+ if (len > 0) {
208
+ /**
209
+ * @type {Item|null}
210
+ */
211
+ let p = m.p
212
+ p.marker = false
213
+ // Ideally we just want to do a simple position comparison, but this will only work if
214
+ // search markers don't point to deleted items for formats.
215
+ // Iterate marker to prev undeleted countable position so we know what to do when updating a position
216
+ while (p && (p.deleted || !p.countable)) {
217
+ p = p.left
218
+ if (p && !p.deleted && p.countable) {
219
+ // adjust position. the loop should break now
220
+ m.index -= p.length
221
+ }
222
+ }
223
+ if (p === null || p.marker === true) {
224
+ // remove search marker if updated position is null or if position is already marked
225
+ searchMarker.splice(i, 1)
226
+ continue
227
+ }
228
+ m.p = p
229
+ p.marker = true
230
+ }
231
+ if (index < m.index || (len > 0 && index === m.index)) { // a simple index <= m.index check would actually suffice
232
+ m.index = math.max(index, m.index + len)
233
+ }
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Accumulate all (list) children of a type and return them as an Array.
239
+ *
240
+ * @param {import('../utils/types.js').YType} t
241
+ * @return {Array<Item>}
242
+ */
243
+ export const getTypeChildren = t => {
244
+ t.doc ?? warnPrematureAccess()
245
+ let s = t._start
246
+ const arr = []
247
+ while (s) {
248
+ arr.push(s)
249
+ s = s.right
250
+ }
251
+ return arr
252
+ }
253
+
254
+ /**
255
+ * Call event listeners with an event. This will also add an event to all
256
+ * parents (for `.observeDeep` handlers).
257
+ *
258
+ * @param {import('../utils/types.js').YType} type
259
+ * @param {Transaction} transaction
260
+ * @param {YEvent<any>} event
261
+ */
262
+ export const callTypeObservers = (type, transaction, event) => {
263
+ const changedType = type
264
+ const changedParentTypes = transaction.changedParentTypes
265
+ while (true) {
266
+ // @ts-ignore
267
+ map.setIfUndefined(changedParentTypes, type, () => []).push(event)
268
+ if (type._item === null) {
269
+ break
270
+ }
271
+ type = /** @type {import('../utils/types.js').YType} */ (type._item.parent)
272
+ }
273
+ callEventHandlerListeners(/** @type {any} */ (changedType._eH), event, transaction)
274
+ }
275
+
276
+ /**
277
+ * Abstract Yjs Type class
278
+ * @template {delta.Delta<any,any,any,any,any>} [EventDelta=any]
279
+ * @template {AbstractType<any,any>} [Self=any]
280
+ */
281
+ export class AbstractType {
282
+ constructor () {
283
+ /**
284
+ * @type {Item|null}
285
+ */
286
+ this._item = null
287
+ /**
288
+ * @type {Map<string,Item>}
289
+ */
290
+ this._map = new Map()
291
+ /**
292
+ * @type {Item|null}
293
+ */
294
+ this._start = null
295
+ /**
296
+ * @type {Doc|null}
297
+ */
298
+ this.doc = null
299
+ this._length = 0
300
+ /**
301
+ * Event handlers
302
+ * @type {EventHandler<YEvent<Self>,Transaction>}
303
+ */
304
+ this._eH = createEventHandler()
305
+ /**
306
+ * Deep event handlers
307
+ * @type {EventHandler<Array<YEvent<any>>,Transaction>}
308
+ */
309
+ this._dEH = createEventHandler()
310
+ /**
311
+ * @type {null | Array<ArraySearchMarker>}
312
+ */
313
+ this._searchMarker = null
314
+ /**
315
+ * @type {EventDelta?}
316
+ */
317
+ this._prelim = null
318
+ }
319
+
320
+ /**
321
+ * Returns a fresh delta that can be used to change this YType.
322
+ * @type {EventDelta}
323
+ */
324
+ get change () {
325
+ return /** @type {any} */ (delta.create())
326
+ }
327
+
328
+ /**
329
+ * @return {import('../utils/types.js').YType|null}
330
+ */
331
+ get parent () {
332
+ return /** @type {import('../utils/types.js').YType} */ (this._item ? this._item.parent : null)
333
+ }
334
+
335
+ /**
336
+ * Integrate this type into the Yjs instance.
337
+ *
338
+ * * Save this struct in the os
339
+ * * This type is sent to other client
340
+ * * Observer functions are fired
341
+ *
342
+ * @param {Doc} y The Yjs instance
343
+ * @param {Item|null} item
344
+ */
345
+ _integrate (y, item) {
346
+ this.doc = y
347
+ this._item = item
348
+ if (this._prelim) {
349
+ this.applyDelta(this._prelim)
350
+ this._prelim = null
351
+ }
352
+ }
353
+
354
+ /**
355
+ * @return {Self}
356
+ */
357
+ _copy () {
358
+ // @ts-ignore
359
+ return new this.constructor()
360
+ }
361
+
362
+ /**
363
+ * Makes a copy of this data type that can be included somewhere else.
364
+ *
365
+ * Note that the content is only readable _after_ it has been included somewhere in the Ydoc.
366
+ *
367
+ * @return {Self}
368
+ */
369
+ clone () {
370
+ // @todo remove this method from othern types by doing `_copy().apply(this.getContent())`
371
+ throw error.methodUnimplemented()
372
+ }
373
+
374
+ /**
375
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} _encoder
376
+ */
377
+ _write (_encoder) { }
378
+
379
+ /**
380
+ * The first non-deleted item
381
+ */
382
+ get _first () {
383
+ let n = this._start
384
+ while (n !== null && n.deleted) {
385
+ n = n.right
386
+ }
387
+ return n
388
+ }
389
+
390
+ /**
391
+ * Creates YEvent and calls all type observers.
392
+ * Must be implemented by each type.
393
+ *
394
+ * @param {Transaction} transaction
395
+ * @param {Set<null|string>} parentSubs Keys changed on this type. `null` if list was modified.
396
+ */
397
+ _callObserver (transaction, parentSubs) {
398
+ const event = new YEvent(/** @type {any} */ (this), transaction, parentSubs)
399
+ callTypeObservers(/** @type {any} */ (this), transaction, event)
400
+ if (!transaction.local && this._searchMarker) {
401
+ this._searchMarker.length = 0
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Observe all events that are created on this type.
407
+ *
408
+ * @template {(target: YEvent<Self>, tr: Transaction) => void} F
409
+ * @param {F} f Observer function
410
+ * @return {F}
411
+ */
412
+ observe (f) {
413
+ addEventHandlerListener(this._eH, f)
414
+ return f
415
+ }
416
+
417
+ /**
418
+ * Observe all events that are created by this type and its children.
419
+ *
420
+ * @template {function(Array<YEvent<any>>,Transaction):void} F
421
+ * @param {F} f Observer function
422
+ * @return {F}
423
+ */
424
+ observeDeep (f) {
425
+ addEventHandlerListener(this._dEH, f)
426
+ return f
427
+ }
428
+
429
+ /**
430
+ * Unregister an observer function.
431
+ *
432
+ * @param {(type:YEvent<Self>,tr:Transaction)=>void} f Observer function
433
+ */
434
+ unobserve (f) {
435
+ removeEventHandlerListener(this._eH, f)
436
+ }
437
+
438
+ /**
439
+ * Unregister an observer function.
440
+ *
441
+ * @param {function(Array<YEvent<any>>,Transaction):void} f Observer function
442
+ */
443
+ unobserveDeep (f) {
444
+ removeEventHandlerListener(this._dEH, f)
445
+ }
446
+
447
+ /**
448
+ * @abstract
449
+ * @return {any}
450
+ */
451
+ toJSON () {}
452
+
453
+ /**
454
+ * Render the difference to another ydoc (which can be empty) and highlight the differences with
455
+ * attributions.
456
+ *
457
+ * Note that deleted content that was not deleted in prevYdoc is rendered as an insertion with the
458
+ * attribution `{ isDeleted: true, .. }`.
459
+ *
460
+ * @template {boolean} [Deep=false]
461
+ *
462
+ * @param {AbstractAttributionManager} am
463
+ * @param {Object} [opts]
464
+ * @param {import('../utils/IdSet.js').IdSet?} [opts.itemsToRender]
465
+ * @param {boolean} [opts.retainInserts] - if true, retain rendered inserts with attributions
466
+ * @param {boolean} [opts.retainDeletes] - if true, retain rendered+attributed deletes only
467
+ * @param {import('../utils/IdSet.js').IdSet?} [opts.deletedItems] - used for computing prevItem in attributes
468
+ * @param {Map<import('../utils/types.js').YType,Set<string|null>>|null} [opts.modified] - set of types that should be rendered as modified children
469
+ * @param {Deep} [opts.deep] - render child types as delta
470
+ * @return {Deep extends true ? ToDeepEventDelta<EventDelta> : EventDelta} The Delta representation of this type.
471
+ *
472
+ * @public
473
+ */
474
+ getContent (am = noAttributionsManager, opts = {}) {
475
+ const { itemsToRender = null, retainInserts = false, retainDeletes = false, deletedItems = null, modified = null, deep = false } = opts
476
+ const renderAttrs = modified?.get(this) || null
477
+ const renderChildren = (modified == null || opts.modified.get(this)?.has(null))
478
+ /**
479
+ * @type {EventDelta extends delta.Delta<infer N,infer Attrs,infer Children,infer Text,any> ? delta.DeltaBuilder<N,Attrs,Children,Text,any> : never}
480
+ */
481
+ const d = /** @type {any} */ (delta.create(/** @type {any} */ (this).nodeName || null))
482
+ const optsAll = modified == null ? opts : object.assign({}, opts, { modified: null })
483
+ typeMapGetDelta(d, /** @type {any} */ (this), renderAttrs, am, deep, modified, deletedItems, itemsToRender, opts, optsAll)
484
+ if (renderChildren) {
485
+ /**
486
+ * @type {delta.FormattingAttributes}
487
+ */
488
+ let currentAttributes = {} // saves all current attributes for insert
489
+ let usingCurrentAttributes = false
490
+ /**
491
+ * @type {delta.FormattingAttributes}
492
+ */
493
+ let changedAttributes = {} // saves changed attributes for retain
494
+ let usingChangedAttributes = false
495
+ /**
496
+ * Logic for formatting attribute attribution
497
+ * Everything that comes after an formatting attribute is formatted by the user that created it.
498
+ * Two exceptions:
499
+ * - the user resets formatting to the previously known formatting that is not attributed
500
+ * - the user deletes a formatting attribute and hence restores the previously known formatting
501
+ * that is not attributed.
502
+ * @type {delta.FormattingAttributes}
503
+ */
504
+ const previousUnattributedAttributes = {} // contains previously known unattributed formatting
505
+ /**
506
+ * @type {delta.FormattingAttributes}
507
+ */
508
+ const previousAttributes = {} // The value before changes
509
+ /**
510
+ * @type {Array<import('../internals.js').AttributedContent<any>>}
511
+ */
512
+ const cs = []
513
+ for (let item = this._start; item !== null; cs.length = 0) {
514
+ if (itemsToRender != null) {
515
+ for (; item !== null && cs.length < 50; item = item.right) {
516
+ const rslice = itemsToRender.slice(item.id.client, item.id.clock, item.length)
517
+ let itemContent = rslice.length > 1 ? item.content.copy() : item.content
518
+ for (let ir = 0; ir < rslice.length; ir++) {
519
+ const idrange = rslice[ir]
520
+ const content = itemContent
521
+ if (ir !== rslice.length - 1) {
522
+ itemContent = itemContent.splice(idrange.len)
523
+ }
524
+ am.readContent(cs, item.id.client, idrange.clock, item.deleted, content, idrange.exists ? 2 : 0)
525
+ }
526
+ }
527
+ } else {
528
+ for (; item !== null && cs.length < 50; item = item.right) {
529
+ am.readContent(cs, item.id.client, item.id.clock, item.deleted, item.content, 1)
530
+ }
531
+ }
532
+ for (let i = 0; i < cs.length; i++) {
533
+ const c = cs[i]
534
+ // render (attributed) content even if it was deleted
535
+ const renderContent = c.render && (!c.deleted || c.attrs != null)
536
+ // content that was just deleted. It is not rendered as an insertion, because it doesn't
537
+ // have any attributes.
538
+ const renderDelete = c.render && c.deleted
539
+ // existing content that should be retained, only adding changed attributes
540
+ const retainContent = !c.render && (!c.deleted || c.attrs != null)
541
+ const attribution = (renderContent || c.content.constructor === ContentFormat) ? createAttributionFromAttributionItems(c.attrs, c.deleted) : null
542
+ switch (c.content.constructor) {
543
+ case ContentDeleted: {
544
+ if (renderDelete) d.delete(c.content.getLength())
545
+ break
546
+ }
547
+ case ContentString:
548
+ if (renderContent) {
549
+ d.usedAttributes = currentAttributes
550
+ usingCurrentAttributes = true
551
+ if (c.deleted ? retainDeletes : retainInserts) {
552
+ d.retain(/** @type {ContentString} */ (c.content).str.length, null, attribution ?? {})
553
+ } else {
554
+ d.insert(/** @type {ContentString} */ (c.content).str, null, attribution)
555
+ }
556
+ } else if (renderDelete) {
557
+ d.delete(c.content.getLength())
558
+ } else if (retainContent) {
559
+ d.usedAttributes = changedAttributes
560
+ usingChangedAttributes = true
561
+ d.retain(c.content.getLength())
562
+ }
563
+ break
564
+ case ContentEmbed:
565
+ case ContentAny:
566
+ case ContentJSON:
567
+ case ContentType:
568
+ case ContentBinary:
569
+ if (renderContent) {
570
+ d.usedAttributes = currentAttributes
571
+ usingCurrentAttributes = true
572
+ if (c.deleted ? retainDeletes : retainInserts) {
573
+ d.retain(c.content.getLength(), null, attribution ?? {})
574
+ } else if (deep && c.content.constructor === ContentType) {
575
+ d.insert([/** @type {any} */(c.content).type.getContent(am, optsAll)], null, attribution)
576
+ } else {
577
+ d.insert(c.content.getContent(), null, attribution)
578
+ }
579
+ } else if (renderDelete) {
580
+ d.delete(1)
581
+ } else if (retainContent) {
582
+ if (c.content.constructor === ContentType && modified?.has(/** @type {ContentType} */ (c.content).type)) {
583
+ // @todo use current transaction instead
584
+ d.modify(/** @type {any} */ (c.content).type.getContent(am, opts))
585
+ } else {
586
+ d.usedAttributes = changedAttributes
587
+ usingChangedAttributes = true
588
+ d.retain(1)
589
+ }
590
+ }
591
+ break
592
+ case ContentFormat: {
593
+ const { key, value } = /** @type {ContentFormat} */ (c.content)
594
+ const currAttrVal = currentAttributes[key] ?? null
595
+ if (attribution != null && (c.deleted || !object.hasProperty(previousUnattributedAttributes, key))) {
596
+ previousUnattributedAttributes[key] = c.deleted ? value : currAttrVal
597
+ }
598
+ // @todo write a function "updateCurrentAttributes" and "updateChangedAttributes"
599
+ // # Update Attributes
600
+ if (renderContent || renderDelete) {
601
+ // create fresh references
602
+ if (usingCurrentAttributes) {
603
+ currentAttributes = object.assign({}, currentAttributes)
604
+ usingCurrentAttributes = false
605
+ }
606
+ if (usingChangedAttributes) {
607
+ usingChangedAttributes = false
608
+ changedAttributes = object.assign({}, changedAttributes)
609
+ }
610
+ }
611
+ if (renderContent || renderDelete) {
612
+ if (c.deleted) {
613
+ // content was deleted, but is possibly attributed
614
+ if (!equalAttrs(value, currAttrVal)) { // do nothing if nothing changed
615
+ if (equalAttrs(currAttrVal, previousAttributes[key] ?? null) && changedAttributes[key] !== undefined) {
616
+ delete changedAttributes[key]
617
+ } else {
618
+ changedAttributes[key] = currAttrVal
619
+ }
620
+ // current attributes doesn't change
621
+ previousAttributes[key] = value
622
+ }
623
+ } else { // !c.deleted
624
+ // content was inserted, and is possibly attributed
625
+ if (equalAttrs(value, currAttrVal)) {
626
+ // item.delete(transaction)
627
+ } else if (equalAttrs(value, previousAttributes[key] ?? null)) {
628
+ delete changedAttributes[key]
629
+ } else {
630
+ changedAttributes[key] = value
631
+ }
632
+ if (value == null) {
633
+ delete currentAttributes[key]
634
+ } else {
635
+ currentAttributes[key] = value
636
+ }
637
+ }
638
+ } else if (retainContent && !c.deleted) {
639
+ // fresh reference to currentAttributes only
640
+ if (usingCurrentAttributes) {
641
+ currentAttributes = object.assign({}, currentAttributes)
642
+ usingCurrentAttributes = false
643
+ }
644
+ if (usingChangedAttributes && changedAttributes[key] !== undefined) {
645
+ usingChangedAttributes = false
646
+ changedAttributes = object.assign({}, changedAttributes)
647
+ }
648
+ if (value == null) {
649
+ delete currentAttributes[key]
650
+ } else {
651
+ currentAttributes[key] = value
652
+ }
653
+ delete changedAttributes[key]
654
+ previousAttributes[key] = value
655
+ }
656
+ // # Update Attributions
657
+ if (attribution != null || object.hasProperty(previousUnattributedAttributes, key)) {
658
+ /**
659
+ * @type {import('../utils/AttributionManager.js').Attribution}
660
+ */
661
+ const formattingAttribution = object.assign({}, d.usedAttribution)
662
+ const changedAttributedAttributes = /** @type {{ [key: string]: Array<any> }} */ (formattingAttribution.format = object.assign({}, formattingAttribution.format ?? {}))
663
+ if (attribution == null || equalAttrs(previousUnattributedAttributes[key], currentAttributes[key] ?? null)) {
664
+ // an unattributed formatting attribute was found or an attributed formatting
665
+ // attribute was found that resets to the previous status
666
+ delete changedAttributedAttributes[key]
667
+ delete previousUnattributedAttributes[key]
668
+ } else {
669
+ const by = changedAttributedAttributes[key] = (changedAttributedAttributes[key]?.slice() ?? [])
670
+ by.push(...((c.deleted ? attribution.delete : attribution.insert) ?? []))
671
+ const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt)
672
+ if (attributedAt) formattingAttribution.formatAt = attributedAt
673
+ }
674
+ if (object.isEmpty(changedAttributedAttributes)) {
675
+ d.useAttribution(null)
676
+ } else if (attribution != null) {
677
+ const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt)
678
+ if (attributedAt != null) formattingAttribution.formatAt = attributedAt
679
+ d.useAttribution(formattingAttribution)
680
+ }
681
+ }
682
+ break
683
+ }
684
+ }
685
+ }
686
+ }
687
+ }
688
+ return /** @type {any} */ (d.done(false))
689
+ }
690
+
691
+ /**
692
+ * Render the difference to another ydoc (which can be empty) and highlight the differences with
693
+ * attributions.
694
+ *
695
+ * @param {AbstractAttributionManager} am
696
+ * @return {ToDeepEventDelta<EventDelta>}
697
+ */
698
+ getContentDeep (am = noAttributionsManager) {
699
+ return /** @type {any} */ (this.getContent(am, { deep: true }))
700
+ }
701
+
702
+ /**
703
+ * Apply a {@link Delta} on this shared type.
704
+ *
705
+ * @param {delta.Delta<any,any,any,any,any>} d The changes to apply on this element.
706
+ * @param {AbstractAttributionManager} am
707
+ *
708
+ * @public
709
+ */
710
+ applyDelta (d, am = noAttributionsManager) {
711
+ if (this.doc == null) {
712
+ (this._prelim || (this._prelim = /** @type {any} */ (delta.create()))).apply(d)
713
+ } else {
714
+ // @todo this was moved here from ytext. Make this more generic
715
+ transact(this.doc, transaction => {
716
+ const currPos = new ItemTextListPosition(null, this._start, 0, new Map(), am)
717
+ for (const op of d.children) {
718
+ if (delta.$textOp.check(op)) {
719
+ insertText(transaction, /** @type {any} */ (this), currPos, op.insert, op.format || {})
720
+ } else if (delta.$insertOp.check(op)) {
721
+ for (let i = 0; i < op.insert.length; i++) {
722
+ let ins = op.insert[i]
723
+ if (delta.$deltaAny.check(ins)) {
724
+ if (ins.name != null) {
725
+ const t = new YXmlElement(ins.name)
726
+ t.applyDelta(ins)
727
+ ins = t
728
+ } else {
729
+ error.unexpectedCase()
730
+ }
731
+ }
732
+ insertText(transaction, /** @type {any} */ (this), currPos, ins, op.format || {})
733
+ }
734
+ } else if (delta.$retainOp.check(op)) {
735
+ currPos.formatText(transaction, /** @type {any} */ (this), op.retain, op.format || {})
736
+ } else if (delta.$deleteOp.check(op)) {
737
+ deleteText(transaction, currPos, op.delete)
738
+ } else if (delta.$modifyOp.check(op)) {
739
+ /** @type {ContentType} */ (currPos.right?.content).type.applyDelta(op.value)
740
+ currPos.formatText(transaction, /** @type {any} */ (this), 1, op.format || {})
741
+ } else {
742
+ error.unexpectedCase()
743
+ }
744
+ }
745
+ for (const op of d.attrs) {
746
+ if (delta.$insertOp.check(op)) {
747
+ typeMapSet(transaction, /** @type {any} */ (this), op.key, op.value)
748
+ } else if (delta.$deleteOp.check(op)) {
749
+ typeMapDelete(transaction, /** @type {any} */ (this), op.key)
750
+ } else {
751
+ const sub = typeMapGet(/** @type {any} */ (this), op.key)
752
+ if (!(sub instanceof AbstractType)) {
753
+ error.unexpectedCase()
754
+ }
755
+ sub.applyDelta(op.value)
756
+ }
757
+ }
758
+ })
759
+ }
760
+ }
761
+ }
762
+
763
+ /**
764
+ * @param {any} a
765
+ * @param {any} b
766
+ * @return {boolean}
767
+ */
768
+ export const equalAttrs = (a, b) => a === b || (typeof a === 'object' && typeof b === 'object' && a && b && object.equalFlat(a, b))
769
+
770
+ /**
771
+ * @template {delta.Delta<any,any,any,any,any>} D
772
+ * @typedef {D extends delta.Delta<infer N,infer Attrs,infer Cs,infer Text,any>
773
+ * ? delta.Delta<
774
+ * N,
775
+ * { [K in keyof Attrs]: TypeToDelta<Attrs[K]> },
776
+ * TypeToDelta<Cs>,
777
+ * Text
778
+ * >
779
+ * : D
780
+ * } ToDeepEventDelta
781
+ */
782
+
783
+ /**
784
+ * @template {any} T
785
+ * @typedef {(Extract<T,AbstractType<any>> extends AbstractType<infer D> ? (unknown extends D ? never : ToDeepEventDelta<D>) : never) | Exclude<T,AbstractType<any>>} TypeToDelta
786
+ */
787
+
788
+ /**
789
+ * @param {AbstractType<any>} type
790
+ * @param {number} start
791
+ * @param {number} end
792
+ * @return {Array<any>}
793
+ *
794
+ * @private
795
+ * @function
796
+ */
797
+ export const typeListSlice = (type, start, end) => {
798
+ type.doc ?? warnPrematureAccess()
799
+ if (start < 0) {
800
+ start = type._length + start
801
+ }
802
+ if (end < 0) {
803
+ end = type._length + end
804
+ }
805
+ let len = end - start
806
+ const cs = []
807
+ let n = type._start
808
+ while (n !== null && len > 0) {
809
+ if (n.countable && !n.deleted) {
810
+ const c = n.content.getContent()
811
+ if (c.length <= start) {
812
+ start -= c.length
813
+ } else {
814
+ for (let i = start; i < c.length && len > 0; i++) {
815
+ cs.push(c[i])
816
+ len--
817
+ }
818
+ start = 0
819
+ }
820
+ }
821
+ n = n.right
822
+ }
823
+ return cs
824
+ }
825
+
826
+ /**
827
+ * @param {import('../utils/types.js').YType} type
828
+ * @return {Array<any>}
829
+ *
830
+ * @private
831
+ * @function
832
+ */
833
+ export const typeListToArray = type => {
834
+ type.doc ?? warnPrematureAccess()
835
+ const cs = []
836
+ let n = type._start
837
+ while (n !== null) {
838
+ if (n.countable && !n.deleted) {
839
+ const c = n.content.getContent()
840
+ for (let i = 0; i < c.length; i++) {
841
+ cs.push(c[i])
842
+ }
843
+ }
844
+ n = n.right
845
+ }
846
+ return cs
847
+ }
848
+
849
+ /**
850
+ * @param {AbstractType<any>} type
851
+ * @param {Snapshot} snapshot
852
+ * @return {Array<any>}
853
+ *
854
+ * @private
855
+ * @function
856
+ */
857
+ export const typeListToArraySnapshot = (type, snapshot) => {
858
+ const cs = []
859
+ let n = type._start
860
+ while (n !== null) {
861
+ if (n.countable && isVisible(n, snapshot)) {
862
+ const c = n.content.getContent()
863
+ for (let i = 0; i < c.length; i++) {
864
+ cs.push(c[i])
865
+ }
866
+ }
867
+ n = n.right
868
+ }
869
+ return cs
870
+ }
871
+
872
+ /**
873
+ * Executes a provided function on once on every element of this YArray.
874
+ *
875
+ * @param {AbstractType<any>} type
876
+ * @param {function(any,number,any):void} f A function to execute on every element of this YArray.
877
+ *
878
+ * @private
879
+ * @function
880
+ */
881
+ export const typeListForEach = (type, f) => {
882
+ let index = 0
883
+ let n = type._start
884
+ type.doc ?? warnPrematureAccess()
885
+ while (n !== null) {
886
+ if (n.countable && !n.deleted) {
887
+ const c = n.content.getContent()
888
+ for (let i = 0; i < c.length; i++) {
889
+ f(c[i], index++, type)
890
+ }
891
+ }
892
+ n = n.right
893
+ }
894
+ }
895
+
896
+ /**
897
+ * @template C,R
898
+ * @param {AbstractType<any>} type
899
+ * @param {function(C,number,AbstractType<any>):R} f
900
+ * @return {Array<R>}
901
+ *
902
+ * @private
903
+ * @function
904
+ */
905
+ export const typeListMap = (type, f) => {
906
+ /**
907
+ * @type {Array<any>}
908
+ */
909
+ const result = []
910
+ typeListForEach(type, (c, i) => {
911
+ result.push(f(c, i, type))
912
+ })
913
+ return result
914
+ }
915
+
916
+ /**
917
+ * @param {AbstractType} type
918
+ * @return {IterableIterator<any>}
919
+ *
920
+ * @private
921
+ * @function
922
+ */
923
+ export const typeListCreateIterator = type => {
924
+ let n = type._start
925
+ /**
926
+ * @type {Array<any>|null}
927
+ */
928
+ let currentContent = null
929
+ let currentContentIndex = 0
930
+ return {
931
+ [Symbol.iterator] () {
932
+ return this
933
+ },
934
+ next: () => {
935
+ // find some content
936
+ if (currentContent === null) {
937
+ while (n !== null && n.deleted) {
938
+ n = n.right
939
+ }
940
+ // check if we reached the end, no need to check currentContent, because it does not exist
941
+ if (n === null) {
942
+ return {
943
+ done: true,
944
+ value: undefined
945
+ }
946
+ }
947
+ // we found n, so we can set currentContent
948
+ currentContent = n.content.getContent()
949
+ currentContentIndex = 0
950
+ n = n.right // we used the content of n, now iterate to next
951
+ }
952
+ const value = currentContent[currentContentIndex++]
953
+ // check if we need to empty currentContent
954
+ if (currentContent.length <= currentContentIndex) {
955
+ currentContent = null
956
+ }
957
+ return {
958
+ done: false,
959
+ value
960
+ }
961
+ }
962
+ }
963
+ }
964
+
965
+ /**
966
+ * Executes a provided function on once on every element of this YArray.
967
+ * Operates on a snapshotted state of the document.
968
+ *
969
+ * @param {AbstractType} type
970
+ * @param {function(any,number,AbstractType):void} f A function to execute on every element of this YArray.
971
+ * @param {Snapshot} snapshot
972
+ *
973
+ * @private
974
+ * @function
975
+ */
976
+ export const typeListForEachSnapshot = (type, f, snapshot) => {
977
+ let index = 0
978
+ let n = type._start
979
+ while (n !== null) {
980
+ if (n.countable && isVisible(n, snapshot)) {
981
+ const c = n.content.getContent()
982
+ for (let i = 0; i < c.length; i++) {
983
+ f(c[i], index++, type)
984
+ }
985
+ }
986
+ n = n.right
987
+ }
988
+ }
989
+
990
+ /**
991
+ * @param {import('../utils/types.js').YType} type
992
+ * @param {number} index
993
+ * @return {any}
994
+ *
995
+ * @private
996
+ * @function
997
+ */
998
+ export const typeListGet = (type, index) => {
999
+ type.doc ?? warnPrematureAccess()
1000
+ const marker = findMarker(type, index)
1001
+ let n = type._start
1002
+ if (marker !== null) {
1003
+ n = marker.p
1004
+ index -= marker.index
1005
+ }
1006
+ for (; n !== null; n = n.right) {
1007
+ if (!n.deleted && n.countable) {
1008
+ if (index < n.length) {
1009
+ return n.content.getContent()[index]
1010
+ }
1011
+ index -= n.length
1012
+ }
1013
+ }
1014
+ }
1015
+
1016
+ /**
1017
+ * @param {Transaction} transaction
1018
+ * @param {YType_} parent
1019
+ * @param {Item?} referenceItem
1020
+ * @param {Array<_YValue>} content
1021
+ *
1022
+ * @private
1023
+ * @function
1024
+ */
1025
+ export const typeListInsertGenericsAfter = (transaction, parent, referenceItem, content) => {
1026
+ let left = referenceItem
1027
+ const doc = transaction.doc
1028
+ const ownClientId = doc.clientID
1029
+ const store = doc.store
1030
+ const right = referenceItem === null ? parent._start : referenceItem.right
1031
+ /**
1032
+ * @type {Array<Object|Array<any>|number|null>}
1033
+ */
1034
+ let jsonContent = []
1035
+ const packJsonContent = () => {
1036
+ if (jsonContent.length > 0) {
1037
+ left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentAny(jsonContent))
1038
+ left.integrate(transaction, 0)
1039
+ jsonContent = []
1040
+ }
1041
+ }
1042
+ content.forEach(c => {
1043
+ if (c === null) {
1044
+ jsonContent.push(c)
1045
+ } else {
1046
+ switch (c.constructor) {
1047
+ case Number:
1048
+ case Object:
1049
+ case undefined:
1050
+ case Boolean:
1051
+ case Array:
1052
+ case String:
1053
+ case BigInt:
1054
+ case Date:
1055
+ jsonContent.push(c)
1056
+ break
1057
+ default:
1058
+ packJsonContent()
1059
+ switch (c.constructor) {
1060
+ case Uint8Array:
1061
+ case ArrayBuffer:
1062
+ left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentBinary(new Uint8Array(/** @type {Uint8Array} */ (c))))
1063
+ left.integrate(transaction, 0)
1064
+ break
1065
+ case Doc:
1066
+ left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentDoc(/** @type {Doc} */ (c)))
1067
+ left.integrate(transaction, 0)
1068
+ break
1069
+ default:
1070
+ if (c instanceof AbstractType) {
1071
+ left = new Item(createID(ownClientId, getState(store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, new ContentType(/** @type {any} */ (c)))
1072
+ left.integrate(transaction, 0)
1073
+ } else {
1074
+ throw new Error('Unexpected content type in insert operation')
1075
+ }
1076
+ }
1077
+ }
1078
+ }
1079
+ })
1080
+ packJsonContent()
1081
+ }
1082
+
1083
+ const lengthExceeded = () => error.create('Length exceeded!')
1084
+
1085
+ /**
1086
+ * @param {Transaction} transaction
1087
+ * @param {YType_} parent
1088
+ * @param {number} index
1089
+ * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
1090
+ *
1091
+ * @private
1092
+ * @function
1093
+ */
1094
+ export const typeListInsertGenerics = (transaction, parent, index, content) => {
1095
+ if (index > parent._length) {
1096
+ throw lengthExceeded()
1097
+ }
1098
+ if (index === 0) {
1099
+ if (parent._searchMarker) {
1100
+ updateMarkerChanges(parent._searchMarker, index, content.length)
1101
+ }
1102
+ return typeListInsertGenericsAfter(transaction, parent, null, content)
1103
+ }
1104
+ const startIndex = index
1105
+ const marker = findMarker(parent, index)
1106
+ let n = parent._start
1107
+ if (marker !== null) {
1108
+ n = marker.p
1109
+ index -= marker.index
1110
+ // we need to iterate one to the left so that the algorithm works
1111
+ if (index === 0) {
1112
+ // @todo refactor this as it actually doesn't consider formats
1113
+ n = n.prev // important! get the left undeleted item so that we can actually decrease index
1114
+ index += (n && n.countable && !n.deleted) ? n.length : 0
1115
+ }
1116
+ }
1117
+ for (; n !== null; n = n.right) {
1118
+ if (!n.deleted && n.countable) {
1119
+ if (index <= n.length) {
1120
+ if (index < n.length) {
1121
+ // insert in-between
1122
+ getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index))
1123
+ }
1124
+ break
1125
+ }
1126
+ index -= n.length
1127
+ }
1128
+ }
1129
+ if (parent._searchMarker) {
1130
+ updateMarkerChanges(parent._searchMarker, startIndex, content.length)
1131
+ }
1132
+ return typeListInsertGenericsAfter(transaction, parent, n, content)
1133
+ }
1134
+
1135
+ /**
1136
+ * Pushing content is special as we generally want to push after the last item. So we don't have to update
1137
+ * the search marker.
1138
+ *
1139
+ * @param {Transaction} transaction
1140
+ * @param {YType_} parent
1141
+ * @param {Array<Object<string,any>|Array<any>|number|null|string|Uint8Array>} content
1142
+ *
1143
+ * @private
1144
+ * @function
1145
+ */
1146
+ export const typeListPushGenerics = (transaction, parent, content) => {
1147
+ // Use the marker with the highest index and iterate to the right.
1148
+ const marker = (parent._searchMarker || []).reduce((maxMarker, currMarker) => currMarker.index > maxMarker.index ? currMarker : maxMarker, { index: 0, p: parent._start })
1149
+ let n = marker.p
1150
+ if (n) {
1151
+ while (n.right) {
1152
+ n = n.right
1153
+ }
1154
+ }
1155
+ return typeListInsertGenericsAfter(transaction, parent, n, content)
1156
+ }
1157
+
1158
+ /**
1159
+ * @param {Transaction} transaction
1160
+ * @param {import('../utils/types.js').YType} parent
1161
+ * @param {number} index
1162
+ * @param {number} length
1163
+ *
1164
+ * @private
1165
+ * @function
1166
+ */
1167
+ export const typeListDelete = (transaction, parent, index, length) => {
1168
+ if (length === 0) { return }
1169
+ const startIndex = index
1170
+ const startLength = length
1171
+ const marker = findMarker(parent, index)
1172
+ let n = parent._start
1173
+ if (marker !== null) {
1174
+ n = marker.p
1175
+ index -= marker.index
1176
+ }
1177
+ // compute the first item to be deleted
1178
+ for (; n !== null && index > 0; n = n.right) {
1179
+ if (!n.deleted && n.countable) {
1180
+ if (index < n.length) {
1181
+ getItemCleanStart(transaction, createID(n.id.client, n.id.clock + index))
1182
+ }
1183
+ index -= n.length
1184
+ }
1185
+ }
1186
+ // delete all items until done
1187
+ while (length > 0 && n !== null) {
1188
+ if (!n.deleted) {
1189
+ if (length < n.length) {
1190
+ getItemCleanStart(transaction, createID(n.id.client, n.id.clock + length))
1191
+ }
1192
+ n.delete(transaction)
1193
+ length -= n.length
1194
+ }
1195
+ n = n.right
1196
+ }
1197
+ if (length > 0) {
1198
+ throw lengthExceeded()
1199
+ }
1200
+ if (parent._searchMarker) {
1201
+ updateMarkerChanges(parent._searchMarker, startIndex, -startLength + length /* in case we remove the above exception */)
1202
+ }
1203
+ }
1204
+
1205
+ /**
1206
+ * @param {Transaction} transaction
1207
+ * @param {YType_} parent
1208
+ * @param {string} key
1209
+ *
1210
+ * @private
1211
+ * @function
1212
+ */
1213
+ export const typeMapDelete = (transaction, parent, key) => {
1214
+ const c = parent._map.get(key)
1215
+ if (c !== undefined) {
1216
+ c.delete(transaction)
1217
+ }
1218
+ }
1219
+
1220
+ /**
1221
+ * @param {Transaction} transaction
1222
+ * @param {AbstractType} parent
1223
+ * @param {string} key
1224
+ * @param {_YValue} value
1225
+ *
1226
+ * @private
1227
+ * @function
1228
+ */
1229
+ export const typeMapSet = (transaction, parent, key, value) => {
1230
+ const left = parent._map.get(key) || null
1231
+ const doc = transaction.doc
1232
+ const ownClientId = doc.clientID
1233
+ let content
1234
+ if (value == null) {
1235
+ content = new ContentAny([value])
1236
+ } else {
1237
+ switch (value.constructor) {
1238
+ case Number:
1239
+ case Object:
1240
+ case Boolean:
1241
+ case Array:
1242
+ case String:
1243
+ case Date:
1244
+ case BigInt:
1245
+ content = new ContentAny([value])
1246
+ break
1247
+ case Uint8Array:
1248
+ content = new ContentBinary(/** @type {Uint8Array} */ (value))
1249
+ break
1250
+ case Doc:
1251
+ content = new ContentDoc(/** @type {Doc} */ (value))
1252
+ break
1253
+ default:
1254
+ if (value instanceof AbstractType) {
1255
+ content = new ContentType(/** @type {any} */ (value))
1256
+ } else {
1257
+ throw new Error('Unexpected content type')
1258
+ }
1259
+ }
1260
+ }
1261
+ new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, null, null, parent, key, content).integrate(transaction, 0)
1262
+ }
1263
+
1264
+ /**
1265
+ * @param {AbstractType<any,any>} parent
1266
+ * @param {string} key
1267
+ * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
1268
+ *
1269
+ * @private
1270
+ * @function
1271
+ */
1272
+ export const typeMapGet = (parent, key) => {
1273
+ parent.doc ?? warnPrematureAccess()
1274
+ const val = parent._map.get(key)
1275
+ return val !== undefined && !val.deleted ? val.content.getContent()[val.length - 1] : undefined
1276
+ }
1277
+
1278
+ /**
1279
+ * @param {AbstractType<any>} parent
1280
+ * @return {Object<string,Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined>}
1281
+ *
1282
+ * @private
1283
+ * @function
1284
+ */
1285
+ export const typeMapGetAll = (parent) => {
1286
+ /**
1287
+ * @type {Object<string,any>}
1288
+ */
1289
+ const res = {}
1290
+ parent.doc ?? warnPrematureAccess()
1291
+ parent._map.forEach((value, key) => {
1292
+ if (!value.deleted) {
1293
+ res[key] = value.content.getContent()[value.length - 1]
1294
+ }
1295
+ })
1296
+ return res
1297
+ }
1298
+
1299
+ /**
1300
+ * @todo move this to getContent/getDelta
1301
+ *
1302
+ * Render the difference to another ydoc (which can be empty) and highlight the differences with
1303
+ * attributions.
1304
+ *
1305
+ * Note that deleted content that was not deleted in prevYdoc is rendered as an insertion with the
1306
+ * attribution `{ isDeleted: true, .. }`.
1307
+ *
1308
+ * @template {delta.DeltaBuilder<any,any,any,any>} TypeDelta
1309
+ * @param {TypeDelta} d
1310
+ * @param {YType_} parent
1311
+ * @param {Set<string|null>?} attrsToRender
1312
+ * @param {import('../internals.js').AbstractAttributionManager} am
1313
+ * @param {boolean} deep
1314
+ * @param {Set<import('../utils/types.js').YType>|Map<import('../utils/types.js').YType,any>|null} [modified] - set of types that should be rendered as modified children
1315
+ * @param {import('../utils/IdSet.js').IdSet?} [deletedItems]
1316
+ * @param {import('../utils/IdSet.js').IdSet?} [itemsToRender]
1317
+ * @param {any} [opts]
1318
+ * @param {any} [optsAll]
1319
+ *
1320
+ * @private
1321
+ * @function
1322
+ */
1323
+ export const typeMapGetDelta = (d, parent, attrsToRender, am, deep, modified, deletedItems, itemsToRender, opts, optsAll) => {
1324
+ // @todo support modified ops!
1325
+ /**
1326
+ * @param {Item} item
1327
+ * @param {string} key
1328
+ */
1329
+ const renderAttrs = (item, key) => {
1330
+ /**
1331
+ * @type {Array<import('../internals.js').AttributedContent<any>>}
1332
+ */
1333
+ const cs = []
1334
+ am.readContent(cs, item.id.client, item.id.clock, item.deleted, item.content, 1)
1335
+ const { deleted, attrs, content } = cs[cs.length - 1]
1336
+ const attribution = createAttributionFromAttributionItems(attrs, deleted)
1337
+ let c = array.last(content.getContent())
1338
+ if (deleted) {
1339
+ if (itemsToRender == null || itemsToRender.hasId(item.lastId)) {
1340
+ d.unset(key, attribution, c)
1341
+ }
1342
+ } else if (deep && c instanceof AbstractType && modified?.has(c)) {
1343
+ d.update(key, c.getContent(am, opts))
1344
+ } else {
1345
+ // find prev content
1346
+ let prevContentItem = item
1347
+ // this algorithm is problematic. should check all previous content using am.readcontent
1348
+ for (; prevContentItem.left !== null && deletedItems?.hasId(prevContentItem.left.lastId); prevContentItem = prevContentItem.left) {
1349
+ // nop
1350
+ }
1351
+ const prevValue = (prevContentItem !== item && itemsToRender?.hasId(prevContentItem.lastId)) ? array.last(prevContentItem.content.getContent()) : undefined
1352
+ if (deep && c instanceof AbstractType) {
1353
+ c = /** @type {any} */(c).getContent(am, optsAll)
1354
+ }
1355
+ d.set(key, c, attribution, prevValue)
1356
+ }
1357
+ }
1358
+ if (attrsToRender == null) {
1359
+ parent._map.forEach(renderAttrs)
1360
+ } else {
1361
+ attrsToRender.forEach(key => key != null && renderAttrs(/** @type {Item} */ (parent._map.get(key)), key))
1362
+ }
1363
+ }
1364
+
1365
+ /**
1366
+ * @param {AbstractType<any>} parent
1367
+ * @param {string} key
1368
+ * @return {boolean}
1369
+ *
1370
+ * @private
1371
+ * @function
1372
+ */
1373
+ export const typeMapHas = (parent, key) => {
1374
+ parent.doc ?? warnPrematureAccess()
1375
+ const val = parent._map.get(key)
1376
+ return val !== undefined && !val.deleted
1377
+ }
1378
+
1379
+ /**
1380
+ * @param {AbstractType<any>} parent
1381
+ * @param {string} key
1382
+ * @param {Snapshot} snapshot
1383
+ * @return {Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined}
1384
+ *
1385
+ * @private
1386
+ * @function
1387
+ */
1388
+ export const typeMapGetSnapshot = (parent, key, snapshot) => {
1389
+ let v = parent._map.get(key) || null
1390
+ while (v !== null && (!snapshot.sv.has(v.id.client) || v.id.clock >= (snapshot.sv.get(v.id.client) || 0))) {
1391
+ v = v.left
1392
+ }
1393
+ return v !== null && isVisible(v, snapshot) ? v.content.getContent()[v.length - 1] : undefined
1394
+ }
1395
+
1396
+ /**
1397
+ * @param {AbstractType<any>} parent
1398
+ * @param {Snapshot} snapshot
1399
+ * @return {Object<string,Object<string,any>|number|null|Array<any>|string|Uint8Array|AbstractType<any>|undefined>}
1400
+ *
1401
+ * @private
1402
+ * @function
1403
+ */
1404
+ export const typeMapGetAllSnapshot = (parent, snapshot) => {
1405
+ /**
1406
+ * @type {Object<string,any>}
1407
+ */
1408
+ const res = {}
1409
+ parent._map.forEach((value, key) => {
1410
+ /**
1411
+ * @type {Item|null}
1412
+ */
1413
+ let v = value
1414
+ while (v !== null && (!snapshot.sv.has(v.id.client) || v.id.clock >= (snapshot.sv.get(v.id.client) || 0))) {
1415
+ v = v.left
1416
+ }
1417
+ if (v !== null && isVisible(v, snapshot)) {
1418
+ res[key] = v.content.getContent()[v.length - 1]
1419
+ }
1420
+ })
1421
+ return res
1422
+ }
1423
+
1424
+ /**
1425
+ * @param {AbstractType<any> & { _map: Map<string, Item> }} type
1426
+ * @return {IterableIterator<Array<any>>}
1427
+ *
1428
+ * @private
1429
+ * @function
1430
+ */
1431
+ export const createMapIterator = type => {
1432
+ type.doc ?? warnPrematureAccess()
1433
+ return iterator.iteratorFilter(type._map.entries(), /** @param {any} entry */ entry => !entry[1].deleted)
1434
+ }