@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,845 @@
1
+ import {
2
+ GC,
3
+ getState,
4
+ AbstractStruct,
5
+ replaceStruct,
6
+ addStruct,
7
+ addToIdSet,
8
+ findRootTypeKey,
9
+ compareIDs,
10
+ getItem,
11
+ getItemCleanEnd,
12
+ getItemCleanStart,
13
+ readContentDeleted,
14
+ readContentBinary,
15
+ readContentJSON,
16
+ readContentAny,
17
+ readContentString,
18
+ readContentEmbed,
19
+ readContentDoc,
20
+ createID,
21
+ readContentFormat,
22
+ readContentType,
23
+ addChangedTypeToTransaction,
24
+ addStructToIdSet,
25
+ IdSet, StackItem, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, ContentType, ContentDeleted, StructStore, ID, AbstractType, Transaction, // eslint-disable-line
26
+ } from '../internals.js'
27
+
28
+ import * as error from 'lib0/error'
29
+ import * as binary from 'lib0/binary'
30
+ import * as array from 'lib0/array'
31
+
32
+ /**
33
+ * @typedef {import('../utils/types.js').YType} YType__
34
+ */
35
+
36
+ /**
37
+ * @todo This should return several items
38
+ *
39
+ * @param {StructStore} store
40
+ * @param {ID} id
41
+ * @return {{item:Item, diff:number}}
42
+ */
43
+ export const followRedone = (store, id) => {
44
+ /**
45
+ * @type {ID|null}
46
+ */
47
+ let nextID = id
48
+ let diff = 0
49
+ let item
50
+ do {
51
+ if (diff > 0) {
52
+ nextID = createID(nextID.client, nextID.clock + diff)
53
+ }
54
+ item = getItem(store, nextID)
55
+ diff = nextID.clock - item.id.clock
56
+ nextID = item.redone
57
+ } while (nextID !== null && item instanceof Item)
58
+ return {
59
+ item, diff
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Make sure that neither item nor any of its parents is ever deleted.
65
+ *
66
+ * This property does not persist when storing it into a database or when
67
+ * sending it to other peers
68
+ *
69
+ * @param {Item|null} item
70
+ * @param {boolean} keep
71
+ */
72
+ export const keepItem = (item, keep) => {
73
+ while (item !== null && item.keep !== keep) {
74
+ item.keep = keep
75
+ item = /** @type {YType__} */ (item.parent)._item
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Split leftItem into two items
81
+ * @param {Transaction?} transaction
82
+ * @param {Item} leftItem
83
+ * @param {number} diff
84
+ * @return {Item}
85
+ *
86
+ * @function
87
+ * @private
88
+ */
89
+ export const splitItem = (transaction, leftItem, diff) => {
90
+ // create rightItem
91
+ const { client, clock } = leftItem.id
92
+ const rightItem = new Item(
93
+ createID(client, clock + diff),
94
+ leftItem,
95
+ createID(client, clock + diff - 1),
96
+ leftItem.right,
97
+ leftItem.rightOrigin,
98
+ leftItem.parent,
99
+ leftItem.parentSub,
100
+ leftItem.content.splice(diff)
101
+ )
102
+ if (leftItem.deleted) {
103
+ rightItem.markDeleted()
104
+ }
105
+ if (leftItem.keep) {
106
+ rightItem.keep = true
107
+ }
108
+ if (leftItem.redone !== null) {
109
+ rightItem.redone = createID(leftItem.redone.client, leftItem.redone.clock + diff)
110
+ }
111
+ if (transaction != null) {
112
+ // update left (do not set leftItem.rightOrigin as it will lead to problems when syncing)
113
+ leftItem.right = rightItem
114
+ // update right
115
+ if (rightItem.right !== null) {
116
+ rightItem.right.left = rightItem
117
+ }
118
+ // right is more specific.
119
+ transaction._mergeStructs.push(rightItem)
120
+ // update parent._map
121
+ if (rightItem.parentSub !== null && rightItem.right === null) {
122
+ /** @type {YType__} */ (rightItem.parent)._map.set(rightItem.parentSub, rightItem)
123
+ }
124
+ } else {
125
+ rightItem.left = null
126
+ rightItem.right = null
127
+ }
128
+ leftItem.length = diff
129
+ return rightItem
130
+ }
131
+
132
+ /**
133
+ * More generalized version of splitItem. Split leftStruct into two structs
134
+ * @param {Transaction?} transaction
135
+ * @param {AbstractStruct} leftStruct
136
+ * @param {number} diff
137
+ * @return {GC|Item}
138
+ *
139
+ * @function
140
+ * @private
141
+ */
142
+ export const splitStruct = (transaction, leftStruct, diff) => {
143
+ if (leftStruct instanceof Item) {
144
+ return splitItem(transaction, leftStruct, diff)
145
+ } else {
146
+ const rightItem = leftStruct.splice(diff)
147
+ transaction?._mergeStructs.push(rightItem)
148
+ return rightItem
149
+ }
150
+ }
151
+
152
+ /**
153
+ * @param {Array<StackItem>} stack
154
+ * @param {ID} id
155
+ */
156
+ const isDeletedByUndoStack = (stack, id) => array.some(stack, /** @param {StackItem} s */ s => s.deletions.hasId(id))
157
+
158
+ /**
159
+ * Redoes the effect of this operation.
160
+ *
161
+ * @param {Transaction} transaction The Yjs instance.
162
+ * @param {Item} item
163
+ * @param {Set<Item>} redoitems
164
+ * @param {IdSet} itemsToDelete
165
+ * @param {boolean} ignoreRemoteMapChanges
166
+ * @param {import('../utils/UndoManager.js').UndoManager} um
167
+ *
168
+ * @return {Item|null}
169
+ *
170
+ * @private
171
+ */
172
+ export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) => {
173
+ const doc = transaction.doc
174
+ const store = doc.store
175
+ const ownClientID = doc.clientID
176
+ const redone = item.redone
177
+ if (redone !== null) {
178
+ return getItemCleanStart(transaction, redone)
179
+ }
180
+ let parentItem = /** @type {YType__} */ (item.parent)._item
181
+ /**
182
+ * @type {Item|null}
183
+ */
184
+ let left = null
185
+ /**
186
+ * @type {Item|null}
187
+ */
188
+ let right
189
+ // make sure that parent is redone
190
+ if (parentItem !== null && parentItem.deleted === true) {
191
+ // try to undo parent if it will be undone anyway
192
+ if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) === null)) {
193
+ return null
194
+ }
195
+ while (parentItem.redone !== null) {
196
+ parentItem = getItemCleanStart(transaction, parentItem.redone)
197
+ }
198
+ }
199
+ /**
200
+ * @type {YType__}
201
+ */
202
+ const parentType = /** @type {YType__} */ (parentItem === null ? item.parent : /** @type {ContentType} */ (parentItem.content).type)
203
+
204
+ if (item.parentSub === null) {
205
+ // Is an array item. Insert at the old position
206
+ left = item.left
207
+ right = item
208
+ // find next cloned_redo items
209
+ while (left !== null) {
210
+ /**
211
+ * @type {Item|null}
212
+ */
213
+ let leftTrace = left
214
+ // trace redone until parent matches
215
+ while (leftTrace !== null && /** @type {YType__} */ (leftTrace.parent)._item !== parentItem) {
216
+ leftTrace = leftTrace.redone === null ? null : getItemCleanStart(transaction, leftTrace.redone)
217
+ }
218
+ if (leftTrace !== null && /** @type {YType__} */ (leftTrace.parent)._item === parentItem) {
219
+ left = leftTrace
220
+ break
221
+ }
222
+ left = left.left
223
+ }
224
+ while (right !== null) {
225
+ /**
226
+ * @type {Item|null}
227
+ */
228
+ let rightTrace = right
229
+ // trace redone until parent matches
230
+ while (rightTrace !== null && /** @type {YType__} */ (rightTrace.parent)._item !== parentItem) {
231
+ rightTrace = rightTrace.redone === null ? null : getItemCleanStart(transaction, rightTrace.redone)
232
+ }
233
+ if (rightTrace !== null && /** @type {YType__} */ (rightTrace.parent)._item === parentItem) {
234
+ right = rightTrace
235
+ break
236
+ }
237
+ right = right.right
238
+ }
239
+ } else {
240
+ right = null
241
+ if (item.right && !ignoreRemoteMapChanges) {
242
+ left = item
243
+ // Iterate right while right is in itemsToDelete
244
+ // If it is intended to delete right while item is redone, we can expect that item should replace right.
245
+ while (left !== null && left.right !== null && (left.right.redone || itemsToDelete.hasId(left.right.id) || isDeletedByUndoStack(um.undoStack, left.right.id) || isDeletedByUndoStack(um.redoStack, left.right.id))) {
246
+ left = left.right
247
+ // follow redone
248
+ while (left.redone) left = getItemCleanStart(transaction, left.redone)
249
+ }
250
+ if (left && left.right !== null) {
251
+ // It is not possible to redo this item because it conflicts with a
252
+ // change from another client
253
+ return null
254
+ }
255
+ } else {
256
+ left = parentType._map.get(item.parentSub) || null
257
+ }
258
+ }
259
+ const nextClock = getState(store, ownClientID)
260
+ const nextId = createID(ownClientID, nextClock)
261
+ const redoneItem = new Item(
262
+ nextId,
263
+ left, left && left.lastId,
264
+ right, right && right.id,
265
+ parentType,
266
+ item.parentSub,
267
+ item.content.copy()
268
+ )
269
+ item.redone = nextId
270
+ keepItem(redoneItem, true)
271
+ redoneItem.integrate(transaction, 0)
272
+ return redoneItem
273
+ }
274
+
275
+ /**
276
+ * Abstract class that represents any content.
277
+ */
278
+ export class Item extends AbstractStruct {
279
+ /**
280
+ * @param {ID} id
281
+ * @param {Item | null} left
282
+ * @param {ID | null} origin
283
+ * @param {Item | null} right
284
+ * @param {ID | null} rightOrigin
285
+ * @param {AbstractType<any,any>|ID|null} parent Is a type if integrated, is null if it is possible to copy parent from left or right, is ID before integration to search for it.
286
+ * @param {string | null} parentSub
287
+ * @param {AbstractContent} content
288
+ */
289
+ constructor (id, left, origin, right, rightOrigin, parent, parentSub, content) {
290
+ super(id, content.getLength())
291
+ /**
292
+ * The item that was originally to the left of this item.
293
+ * @type {ID | null}
294
+ */
295
+ this.origin = origin
296
+ /**
297
+ * The item that is currently to the left of this item.
298
+ * @type {Item | null}
299
+ */
300
+ this.left = left
301
+ /**
302
+ * The item that is currently to the right of this item.
303
+ * @type {Item | null}
304
+ */
305
+ this.right = right
306
+ /**
307
+ * The item that was originally to the right of this item.
308
+ * @type {ID | null}
309
+ */
310
+ this.rightOrigin = rightOrigin
311
+ /**
312
+ * @type {AbstractType<any,any>|ID|null}
313
+ */
314
+ this.parent = parent
315
+ /**
316
+ * If the parent refers to this item with some kind of key (e.g. YMap, the
317
+ * key is specified here. The key is then used to refer to the list in which
318
+ * to insert this item. If `parentSub = null` type._start is the list in
319
+ * which to insert to. Otherwise it is `parent._map`.
320
+ * @type {String | null}
321
+ */
322
+ this.parentSub = parentSub
323
+ /**
324
+ * If this type's effect is redone this type refers to the type that undid
325
+ * this operation.
326
+ * @type {ID | null}
327
+ */
328
+ this.redone = null
329
+ /**
330
+ * @type {AbstractContent}
331
+ */
332
+ this.content = content
333
+ /**
334
+ * bit1: keep
335
+ * bit2: countable
336
+ * bit3: deleted
337
+ * bit4: mark - mark node as fast-search-marker
338
+ * @type {number} byte
339
+ */
340
+ this.info = this.content.isCountable() ? binary.BIT2 : 0
341
+ }
342
+
343
+ /**
344
+ * This is used to mark the item as an indexed fast-search marker
345
+ *
346
+ * @type {boolean}
347
+ */
348
+ set marker (isMarked) {
349
+ if (((this.info & binary.BIT4) > 0) !== isMarked) {
350
+ this.info ^= binary.BIT4
351
+ }
352
+ }
353
+
354
+ get marker () {
355
+ return (this.info & binary.BIT4) > 0
356
+ }
357
+
358
+ /**
359
+ * If true, do not garbage collect this Item.
360
+ */
361
+ get keep () {
362
+ return (this.info & binary.BIT1) > 0
363
+ }
364
+
365
+ set keep (doKeep) {
366
+ if (this.keep !== doKeep) {
367
+ this.info ^= binary.BIT1
368
+ }
369
+ }
370
+
371
+ get countable () {
372
+ return (this.info & binary.BIT2) > 0
373
+ }
374
+
375
+ /**
376
+ * Whether this item was deleted or not.
377
+ * @type {Boolean}
378
+ */
379
+ get deleted () {
380
+ return (this.info & binary.BIT3) > 0
381
+ }
382
+
383
+ set deleted (doDelete) {
384
+ if (this.deleted !== doDelete) {
385
+ this.info ^= binary.BIT3
386
+ }
387
+ }
388
+
389
+ markDeleted () {
390
+ this.info |= binary.BIT3
391
+ }
392
+
393
+ /**
394
+ * Return the creator clientID of the missing op or define missing items and return null.
395
+ *
396
+ * @param {Transaction} transaction
397
+ * @param {StructStore} store
398
+ * @return {null | number}
399
+ */
400
+ getMissing (transaction, store) {
401
+ if (this.origin && (this.origin.clock >= getState(store, this.origin.client) || store.skips.hasId(this.origin))) {
402
+ return this.origin.client
403
+ }
404
+ if (this.rightOrigin && (this.rightOrigin.clock >= getState(store, this.rightOrigin.client) || store.skips.hasId(this.rightOrigin))) {
405
+ return this.rightOrigin.client
406
+ }
407
+ if (this.parent && this.parent.constructor === ID && (this.parent.clock >= getState(store, this.parent.client) || store.skips.hasId(this.parent))) {
408
+ return this.parent.client
409
+ }
410
+ // We have all missing ids, now find the items
411
+ if (this.origin) {
412
+ this.left = getItemCleanEnd(transaction, store, this.origin)
413
+ this.origin = this.left.lastId
414
+ }
415
+ if (this.rightOrigin) {
416
+ this.right = getItemCleanStart(transaction, this.rightOrigin)
417
+ this.rightOrigin = this.right.id
418
+ }
419
+ if ((this.left && this.left.constructor === GC) || (this.right && this.right.constructor === GC)) {
420
+ this.parent = null
421
+ } else if (!this.parent) {
422
+ // only set parent if this shouldn't be garbage collected
423
+ if (this.left && this.left.constructor === Item) {
424
+ this.parent = this.left.parent
425
+ this.parentSub = this.left.parentSub
426
+ } else if (this.right && this.right.constructor === Item) {
427
+ this.parent = this.right.parent
428
+ this.parentSub = this.right.parentSub
429
+ }
430
+ } else if (this.parent.constructor === ID) {
431
+ const parentItem = getItem(store, this.parent)
432
+ if (parentItem.constructor === GC) {
433
+ this.parent = null
434
+ } else {
435
+ this.parent = /** @type {ContentType} */ (parentItem.content).type
436
+ }
437
+ }
438
+ return null
439
+ }
440
+
441
+ /**
442
+ * @param {Transaction} transaction
443
+ * @param {number} offset
444
+ */
445
+ integrate (transaction, offset) {
446
+ if (offset > 0) {
447
+ this.id.clock += offset
448
+ this.left = getItemCleanEnd(transaction, transaction.doc.store, createID(this.id.client, this.id.clock - 1))
449
+ this.origin = this.left.lastId
450
+ this.content = this.content.splice(offset)
451
+ this.length -= offset
452
+ }
453
+
454
+ if (this.parent) {
455
+ if ((!this.left && (!this.right || this.right.left !== null)) || (this.left && this.left.right !== this.right)) {
456
+ /**
457
+ * @type {Item|null}
458
+ */
459
+ let left = this.left
460
+
461
+ /**
462
+ * @type {Item|null}
463
+ */
464
+ let o
465
+ // set o to the first conflicting item
466
+ if (left !== null) {
467
+ o = left.right
468
+ } else if (this.parentSub !== null) {
469
+ o = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null
470
+ while (o !== null && o.left !== null) {
471
+ o = o.left
472
+ }
473
+ } else {
474
+ o = /** @type {AbstractType<any>} */ (this.parent)._start
475
+ }
476
+ // TODO: use something like DeleteSet here (a tree implementation would be best)
477
+ // @todo use global set definitions
478
+ /**
479
+ * @type {Set<Item>}
480
+ */
481
+ const conflictingItems = new Set()
482
+ /**
483
+ * @type {Set<Item>}
484
+ */
485
+ const itemsBeforeOrigin = new Set()
486
+ // Let c in conflictingItems, b in itemsBeforeOrigin
487
+ // ***{origin}bbbb{this}{c,b}{c,b}{o}***
488
+ // Note that conflictingItems is a subset of itemsBeforeOrigin
489
+ while (o !== null && o !== this.right) {
490
+ itemsBeforeOrigin.add(o)
491
+ conflictingItems.add(o)
492
+ if (compareIDs(this.origin, o.origin)) {
493
+ // case 1
494
+ if (o.id.client < this.id.client) {
495
+ left = o
496
+ conflictingItems.clear()
497
+ } else if (compareIDs(this.rightOrigin, o.rightOrigin)) {
498
+ // this and o are conflicting and point to the same integration points. The id decides which item comes first.
499
+ // Since this is to the left of o, we can break here
500
+ break
501
+ } // else, o might be integrated before an item that this conflicts with. If so, we will find it in the next iterations
502
+ } else if (o.origin !== null && itemsBeforeOrigin.has(getItem(transaction.doc.store, o.origin))) { // use getItem instead of getItemCleanEnd because we don't want / need to split items.
503
+ // case 2
504
+ if (!conflictingItems.has(getItem(transaction.doc.store, o.origin))) {
505
+ left = o
506
+ conflictingItems.clear()
507
+ }
508
+ } else {
509
+ break
510
+ }
511
+ o = o.right
512
+ }
513
+ this.left = left
514
+ }
515
+ // reconnect left/right + update parent map/start if necessary
516
+ if (this.left !== null) {
517
+ const right = this.left.right
518
+ this.right = right
519
+ this.left.right = this
520
+ } else {
521
+ let r
522
+ if (this.parentSub !== null) {
523
+ r = /** @type {AbstractType<any>} */ (this.parent)._map.get(this.parentSub) || null
524
+ while (r !== null && r.left !== null) {
525
+ r = r.left
526
+ }
527
+ } else {
528
+ r = /** @type {AbstractType<any>} */ (this.parent)._start
529
+ ;/** @type {AbstractType<any>} */ (this.parent)._start = this
530
+ }
531
+ this.right = r
532
+ }
533
+ if (this.right !== null) {
534
+ this.right.left = this
535
+ } else if (this.parentSub !== null) {
536
+ // set as current parent value if right === null and this is parentSub
537
+ /** @type {AbstractType<any>} */ (this.parent)._map.set(this.parentSub, this)
538
+ if (this.left !== null) {
539
+ // this is the current attribute value of parent. delete right
540
+ this.left.delete(transaction)
541
+ }
542
+ }
543
+ // adjust length of parent
544
+ if (this.parentSub === null && this.countable && !this.deleted) {
545
+ /** @type {AbstractType<any>} */ (this.parent)._length += this.length
546
+ }
547
+ addStructToIdSet(transaction.insertSet, this)
548
+ addStruct(transaction.doc.store, this)
549
+ this.content.integrate(transaction, this)
550
+ // add parent to transaction.changed
551
+ addChangedTypeToTransaction(transaction, /** @type {import('../utils/types.js').YType} */ (this.parent), this.parentSub)
552
+ if ((/** @type {AbstractType<any>} */ (this.parent)._item !== null && /** @type {AbstractType<any>} */ (this.parent)._item.deleted) || (this.parentSub !== null && this.right !== null)) {
553
+ // delete if parent is deleted or if this is not the current attribute value of parent
554
+ this.delete(transaction)
555
+ }
556
+ } else {
557
+ // parent is not defined. Integrate GC struct instead
558
+ new GC(this.id, this.length).integrate(transaction, 0)
559
+ }
560
+ }
561
+
562
+ /**
563
+ * Returns the next non-deleted item
564
+ */
565
+ get next () {
566
+ let n = this.right
567
+ while (n !== null && n.deleted) {
568
+ n = n.right
569
+ }
570
+ return n
571
+ }
572
+
573
+ /**
574
+ * Returns the previous non-deleted item
575
+ */
576
+ get prev () {
577
+ let n = this.left
578
+ while (n !== null && n.deleted) {
579
+ n = n.left
580
+ }
581
+ return n
582
+ }
583
+
584
+ /**
585
+ * Computes the last content address of this Item.
586
+ */
587
+ get lastId () {
588
+ // allocating ids is pretty costly because of the amount of ids created, so we try to reuse whenever possible
589
+ return this.length === 1 ? this.id : createID(this.id.client, this.id.clock + this.length - 1)
590
+ }
591
+
592
+ /**
593
+ * Try to merge two items
594
+ *
595
+ * @param {Item} right
596
+ * @return {boolean}
597
+ */
598
+ mergeWith (right) {
599
+ if (
600
+ this.constructor === right.constructor &&
601
+ compareIDs(right.origin, this.lastId) &&
602
+ this.right === right &&
603
+ compareIDs(this.rightOrigin, right.rightOrigin) &&
604
+ this.id.client === right.id.client &&
605
+ this.id.clock + this.length === right.id.clock &&
606
+ this.deleted === right.deleted &&
607
+ this.redone === null &&
608
+ right.redone === null &&
609
+ this.content.constructor === right.content.constructor &&
610
+ this.content.mergeWith(right.content)
611
+ ) {
612
+ const searchMarker = /** @type {AbstractType<any>} */ (this.parent)._searchMarker
613
+ if (searchMarker) {
614
+ searchMarker.forEach(marker => {
615
+ if (marker.p === right) {
616
+ // right is going to be "forgotten" so we need to update the marker
617
+ marker.p = this
618
+ // adjust marker index
619
+ if (!this.deleted && this.countable) {
620
+ marker.index -= this.length
621
+ }
622
+ }
623
+ })
624
+ }
625
+ if (right.keep) {
626
+ this.keep = true
627
+ }
628
+ this.right = right.right
629
+ if (this.right !== null) {
630
+ this.right.left = this
631
+ }
632
+ this.length += right.length
633
+ return true
634
+ }
635
+ return false
636
+ }
637
+
638
+ /**
639
+ * Mark this Item as deleted.
640
+ *
641
+ * @param {Transaction} transaction
642
+ */
643
+ delete (transaction) {
644
+ if (!this.deleted) {
645
+ const parent = /** @type {import('../utils/types.js').YType} */ (this.parent)
646
+ // adjust the length of parent
647
+ if (this.countable && this.parentSub === null) {
648
+ parent._length -= this.length
649
+ }
650
+ this.markDeleted()
651
+ addToIdSet(transaction.deleteSet, this.id.client, this.id.clock, this.length)
652
+ addChangedTypeToTransaction(transaction, parent, this.parentSub)
653
+ this.content.delete(transaction)
654
+ }
655
+ }
656
+
657
+ /**
658
+ * @param {Transaction} tr
659
+ * @param {boolean} parentGCd
660
+ */
661
+ gc (tr, parentGCd) {
662
+ if (!this.deleted) {
663
+ throw error.unexpectedCase()
664
+ }
665
+ this.content.gc(tr)
666
+ if (parentGCd) {
667
+ replaceStruct(tr, this, new GC(this.id, this.length))
668
+ } else {
669
+ this.content = new ContentDeleted(this.length)
670
+ }
671
+ }
672
+
673
+ /**
674
+ * Transform the properties of this type to binary and write it to an
675
+ * BinaryEncoder.
676
+ *
677
+ * This is called when this Item is sent to a remote peer.
678
+ *
679
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder The encoder to write data to.
680
+ * @param {number} offset
681
+ * @param {number} offsetEnd
682
+ */
683
+ write (encoder, offset, offsetEnd) {
684
+ const origin = offset > 0 ? createID(this.id.client, this.id.clock + offset - 1) : this.origin
685
+ const rightOrigin = this.rightOrigin
686
+ const parentSub = this.parentSub
687
+ const info = (this.content.getRef() & binary.BITS5) |
688
+ (origin === null ? 0 : binary.BIT8) | // origin is defined
689
+ (rightOrigin === null ? 0 : binary.BIT7) | // right origin is defined
690
+ (parentSub === null ? 0 : binary.BIT6) // parentSub is non-null
691
+ encoder.writeInfo(info)
692
+ if (origin !== null) {
693
+ encoder.writeLeftID(origin)
694
+ }
695
+ if (rightOrigin !== null) {
696
+ encoder.writeRightID(rightOrigin)
697
+ }
698
+ if (origin === null && rightOrigin === null) {
699
+ const parent = /** @type {AbstractType<any>} */ (this.parent)
700
+ if (parent._item !== undefined) {
701
+ const parentItem = parent._item
702
+ if (parentItem === null) {
703
+ // parent type on y._map
704
+ // find the correct key
705
+ const ykey = findRootTypeKey(parent)
706
+ encoder.writeParentInfo(true) // write parentYKey
707
+ encoder.writeString(ykey)
708
+ } else {
709
+ encoder.writeParentInfo(false) // write parent id
710
+ encoder.writeLeftID(parentItem.id)
711
+ }
712
+ } else if (parent.constructor === String) { // this edge case was added by differential updates
713
+ encoder.writeParentInfo(true) // write parentYKey
714
+ encoder.writeString(parent)
715
+ } else if (parent.constructor === ID) {
716
+ encoder.writeParentInfo(false) // write parent id
717
+ encoder.writeLeftID(parent)
718
+ } else {
719
+ error.unexpectedCase()
720
+ }
721
+ if (parentSub !== null) {
722
+ encoder.writeString(parentSub)
723
+ }
724
+ }
725
+ this.content.write(encoder, offset, offsetEnd)
726
+ }
727
+ }
728
+
729
+ /**
730
+ * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
731
+ * @param {number} info
732
+ */
733
+ export const readItemContent = (decoder, info) => contentRefs[info & binary.BITS5](decoder)
734
+
735
+ /**
736
+ * A lookup map for reading Item content.
737
+ *
738
+ * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractContent>}
739
+ */
740
+ export const contentRefs = [
741
+ () => { error.unexpectedCase() }, // GC is not ItemContent
742
+ readContentDeleted, // 1
743
+ readContentJSON, // 2
744
+ readContentBinary, // 3
745
+ readContentString, // 4
746
+ readContentEmbed, // 5
747
+ readContentFormat, // 6
748
+ readContentType, // 7
749
+ readContentAny, // 8
750
+ readContentDoc, // 9
751
+ () => { error.unexpectedCase() } // 10 - Skip is not ItemContent
752
+ ]
753
+
754
+ /**
755
+ * Do not implement this class!
756
+ */
757
+ export class AbstractContent {
758
+ /**
759
+ * @return {number}
760
+ */
761
+ getLength () {
762
+ throw error.methodUnimplemented()
763
+ }
764
+
765
+ /**
766
+ * @return {Array<any>}
767
+ */
768
+ getContent () {
769
+ throw error.methodUnimplemented()
770
+ }
771
+
772
+ /**
773
+ * Should return false if this Item is some kind of meta information
774
+ * (e.g. format information).
775
+ *
776
+ * * Whether this Item should be addressable via `yarray.get(i)`
777
+ * * Whether this Item should be counted when computing yarray.length
778
+ *
779
+ * @return {boolean}
780
+ */
781
+ isCountable () {
782
+ throw error.methodUnimplemented()
783
+ }
784
+
785
+ /**
786
+ * @return {AbstractContent}
787
+ */
788
+ copy () {
789
+ throw error.methodUnimplemented()
790
+ }
791
+
792
+ /**
793
+ * @param {number} _offset
794
+ * @return {AbstractContent}
795
+ */
796
+ splice (_offset) {
797
+ throw error.methodUnimplemented()
798
+ }
799
+
800
+ /**
801
+ * @param {AbstractContent} _right
802
+ * @return {boolean}
803
+ */
804
+ mergeWith (_right) {
805
+ throw error.methodUnimplemented()
806
+ }
807
+
808
+ /**
809
+ * @param {Transaction} _transaction
810
+ * @param {Item} _item
811
+ */
812
+ integrate (_transaction, _item) {
813
+ throw error.methodUnimplemented()
814
+ }
815
+
816
+ /**
817
+ * @param {Transaction} _transaction
818
+ */
819
+ delete (_transaction) {
820
+ throw error.methodUnimplemented()
821
+ }
822
+
823
+ /**
824
+ * @param {Transaction} _transaction
825
+ */
826
+ gc (_transaction) {
827
+ throw error.methodUnimplemented()
828
+ }
829
+
830
+ /**
831
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} _encoder
832
+ * @param {number} _offset
833
+ * @param {number} _offsetEnd
834
+ */
835
+ write (_encoder, _offset, _offsetEnd) {
836
+ throw error.methodUnimplemented()
837
+ }
838
+
839
+ /**
840
+ * @return {number}
841
+ */
842
+ getRef () {
843
+ throw error.methodUnimplemented()
844
+ }
845
+ }