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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +36 -12
  2. package/dist/src/index.d.ts +24 -1
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/structs/AbstractStruct.d.ts +14 -17
  5. package/dist/src/structs/AbstractStruct.d.ts.map +1 -1
  6. package/dist/src/structs/GC.d.ts +9 -14
  7. package/dist/src/structs/GC.d.ts.map +1 -1
  8. package/dist/src/structs/Item.d.ts +569 -31
  9. package/dist/src/structs/Item.d.ts.map +1 -1
  10. package/dist/src/structs/Skip.d.ts +9 -11
  11. package/dist/src/structs/Skip.d.ts.map +1 -1
  12. package/dist/src/utils/BlockSet.d.ts +8 -7
  13. package/dist/src/utils/BlockSet.d.ts.map +1 -1
  14. package/dist/src/utils/Doc.d.ts +4 -9
  15. package/dist/src/utils/Doc.d.ts.map +1 -1
  16. package/dist/src/utils/ID.d.ts +0 -1
  17. package/dist/src/utils/ID.d.ts.map +1 -1
  18. package/dist/src/utils/RelativePosition.d.ts +2 -5
  19. package/dist/src/utils/RelativePosition.d.ts.map +1 -1
  20. package/dist/src/utils/Renderer.d.ts +144 -0
  21. package/dist/src/utils/Renderer.d.ts.map +1 -0
  22. package/dist/src/utils/Snapshot.d.ts +7 -11
  23. package/dist/src/utils/Snapshot.d.ts.map +1 -1
  24. package/dist/src/utils/StructStore.d.ts +45 -23
  25. package/dist/src/utils/StructStore.d.ts.map +1 -1
  26. package/dist/src/utils/Transaction.d.ts +11 -21
  27. package/dist/src/utils/Transaction.d.ts.map +1 -1
  28. package/dist/src/utils/UndoManager.d.ts +13 -14
  29. package/dist/src/utils/UndoManager.d.ts.map +1 -1
  30. package/dist/src/utils/UpdateDecoder.d.ts +1 -1
  31. package/dist/src/utils/UpdateDecoder.d.ts.map +1 -1
  32. package/dist/src/utils/UpdateEncoder.d.ts +0 -1
  33. package/dist/src/utils/UpdateEncoder.d.ts.map +1 -1
  34. package/dist/src/utils/YEvent.d.ts +22 -26
  35. package/dist/src/utils/YEvent.d.ts.map +1 -1
  36. package/dist/src/utils/content-helper.d.ts +2 -0
  37. package/dist/src/utils/content-helper.d.ts.map +1 -0
  38. package/dist/src/utils/delta-helpers.d.ts +2 -3
  39. package/dist/src/utils/delta-helpers.d.ts.map +1 -1
  40. package/dist/src/utils/encoding-helpers.d.ts +6 -0
  41. package/dist/src/utils/encoding-helpers.d.ts.map +1 -0
  42. package/dist/src/utils/encoding.d.ts +16 -18
  43. package/dist/src/utils/encoding.d.ts.map +1 -1
  44. package/dist/src/utils/ids.d.ts +331 -0
  45. package/dist/src/utils/ids.d.ts.map +1 -0
  46. package/dist/src/utils/isParentOf.d.ts +1 -2
  47. package/dist/src/utils/isParentOf.d.ts.map +1 -1
  48. package/dist/src/utils/logging.d.ts +0 -1
  49. package/dist/src/utils/logging.d.ts.map +1 -1
  50. package/dist/src/utils/meta.d.ts +15 -64
  51. package/dist/src/utils/meta.d.ts.map +1 -1
  52. package/dist/src/utils/renderer-helpers.d.ts +99 -0
  53. package/dist/src/utils/renderer-helpers.d.ts.map +1 -0
  54. package/dist/src/utils/schemas.d.ts +3 -0
  55. package/dist/src/utils/schemas.d.ts.map +1 -0
  56. package/dist/src/utils/transaction-helpers.d.ts +18 -0
  57. package/dist/src/utils/transaction-helpers.d.ts.map +1 -0
  58. package/dist/src/utils/updates.d.ts +19 -25
  59. package/dist/src/utils/updates.d.ts.map +1 -1
  60. package/dist/src/ytype.d.ts +55 -24
  61. package/dist/src/ytype.d.ts.map +1 -1
  62. package/global.d.ts +53 -0
  63. package/package.json +12 -16
  64. package/src/index.js +32 -124
  65. package/src/structs/AbstractStruct.js +21 -16
  66. package/src/structs/GC.js +15 -20
  67. package/src/structs/Item.js +992 -318
  68. package/src/structs/Skip.js +16 -19
  69. package/src/utils/BlockSet.js +20 -20
  70. package/src/utils/Doc.js +15 -29
  71. package/src/utils/ID.js +0 -2
  72. package/src/utils/RelativePosition.js +15 -25
  73. package/src/utils/{AttributionManager.js → Renderer.js} +42 -197
  74. package/src/utils/Snapshot.js +15 -37
  75. package/src/utils/StructStore.js +89 -227
  76. package/src/utils/Transaction.js +63 -307
  77. package/src/utils/UndoManager.js +157 -19
  78. package/src/utils/UpdateDecoder.js +2 -3
  79. package/src/utils/UpdateEncoder.js +0 -4
  80. package/src/utils/YEvent.js +20 -26
  81. package/src/utils/content-helper.js +0 -0
  82. package/src/utils/delta-helpers.js +21 -42
  83. package/src/utils/encoding-helpers.js +110 -0
  84. package/src/utils/encoding.js +197 -122
  85. package/src/utils/ids.js +1527 -0
  86. package/src/utils/isParentOf.js +2 -4
  87. package/src/utils/logging.js +0 -4
  88. package/src/utils/meta.js +57 -46
  89. package/src/utils/renderer-helpers.js +110 -0
  90. package/src/utils/schemas.js +3 -0
  91. package/src/utils/transaction-helpers.js +413 -0
  92. package/src/utils/updates.js +24 -146
  93. package/src/ytype.js +325 -117
  94. package/tests/testHelper.js +10 -12
  95. package/dist/src/internals.d.ts +0 -36
  96. package/dist/src/internals.d.ts.map +0 -1
  97. package/dist/src/structs/ContentAny.d.ts +0 -67
  98. package/dist/src/structs/ContentAny.d.ts.map +0 -1
  99. package/dist/src/structs/ContentBinary.d.ts +0 -64
  100. package/dist/src/structs/ContentBinary.d.ts.map +0 -1
  101. package/dist/src/structs/ContentDeleted.d.ts +0 -64
  102. package/dist/src/structs/ContentDeleted.d.ts.map +0 -1
  103. package/dist/src/structs/ContentDoc.d.ts +0 -72
  104. package/dist/src/structs/ContentDoc.d.ts.map +0 -1
  105. package/dist/src/structs/ContentEmbed.d.ts +0 -67
  106. package/dist/src/structs/ContentEmbed.d.ts.map +0 -1
  107. package/dist/src/structs/ContentFormat.d.ts +0 -69
  108. package/dist/src/structs/ContentFormat.d.ts.map +0 -1
  109. package/dist/src/structs/ContentJSON.d.ts +0 -70
  110. package/dist/src/structs/ContentJSON.d.ts.map +0 -1
  111. package/dist/src/structs/ContentString.d.ts +0 -70
  112. package/dist/src/structs/ContentString.d.ts.map +0 -1
  113. package/dist/src/structs/ContentType.d.ts +0 -77
  114. package/dist/src/structs/ContentType.d.ts.map +0 -1
  115. package/dist/src/utils/AttributionManager.d.ts +0 -238
  116. package/dist/src/utils/AttributionManager.d.ts.map +0 -1
  117. package/dist/src/utils/IdMap.d.ts +0 -164
  118. package/dist/src/utils/IdMap.d.ts.map +0 -1
  119. package/dist/src/utils/IdSet.d.ts +0 -163
  120. package/dist/src/utils/IdSet.d.ts.map +0 -1
  121. package/dist/tests/IdMap.tests.d.ts +0 -9
  122. package/dist/tests/IdMap.tests.d.ts.map +0 -1
  123. package/dist/tests/IdSet.tests.d.ts +0 -9
  124. package/dist/tests/IdSet.tests.d.ts.map +0 -1
  125. package/dist/tests/attribution.tests.d.ts +0 -9
  126. package/dist/tests/attribution.tests.d.ts.map +0 -1
  127. package/dist/tests/compatibility.tests.d.ts +0 -5
  128. package/dist/tests/compatibility.tests.d.ts.map +0 -1
  129. package/dist/tests/delta.tests.d.ts +0 -7
  130. package/dist/tests/delta.tests.d.ts.map +0 -1
  131. package/dist/tests/doc.tests.d.ts +0 -13
  132. package/dist/tests/doc.tests.d.ts.map +0 -1
  133. package/dist/tests/encoding.tests.d.ts +0 -5
  134. package/dist/tests/encoding.tests.d.ts.map +0 -1
  135. package/dist/tests/index.d.ts +0 -2
  136. package/dist/tests/index.d.ts.map +0 -1
  137. package/dist/tests/relativePositions.tests.d.ts +0 -11
  138. package/dist/tests/relativePositions.tests.d.ts.map +0 -1
  139. package/dist/tests/snapshot.tests.d.ts +0 -14
  140. package/dist/tests/snapshot.tests.d.ts.map +0 -1
  141. package/dist/tests/testHelper.d.ts +0 -171
  142. package/dist/tests/testHelper.d.ts.map +0 -1
  143. package/dist/tests/undo-redo.tests.d.ts +0 -27
  144. package/dist/tests/undo-redo.tests.d.ts.map +0 -1
  145. package/dist/tests/updates.tests.d.ts +0 -26
  146. package/dist/tests/updates.tests.d.ts.map +0 -1
  147. package/dist/tests/y-array.tests.d.ts +0 -43
  148. package/dist/tests/y-array.tests.d.ts.map +0 -1
  149. package/dist/tests/y-map.tests.d.ts +0 -42
  150. package/dist/tests/y-map.tests.d.ts.map +0 -1
  151. package/dist/tests/y-text.tests.d.ts +0 -49
  152. package/dist/tests/y-text.tests.d.ts.map +0 -1
  153. package/dist/tests/y-xml.tests.d.ts +0 -14
  154. package/dist/tests/y-xml.tests.d.ts.map +0 -1
  155. package/src/internals.js +0 -35
  156. package/src/structs/ContentAny.js +0 -115
  157. package/src/structs/ContentBinary.js +0 -93
  158. package/src/structs/ContentDeleted.js +0 -101
  159. package/src/structs/ContentDoc.js +0 -141
  160. package/src/structs/ContentEmbed.js +0 -98
  161. package/src/structs/ContentFormat.js +0 -105
  162. package/src/structs/ContentJSON.js +0 -119
  163. package/src/structs/ContentString.js +0 -113
  164. package/src/structs/ContentType.js +0 -152
  165. package/src/utils/IdMap.js +0 -673
  166. package/src/utils/IdSet.js +0 -825
@@ -1,33 +1,20 @@
1
+ import * as error from 'lib0/error'
2
+ import * as binary from 'lib0/binary'
3
+ import * as env from 'lib0/environment'
4
+ import * as object from 'lib0/object'
5
+
6
+ import { AbstractStruct, addStructToIdSet } from '../structs/AbstractStruct.js'
7
+
8
+ import { ID, createID, compareIDs, findRootTypeKey } from '../utils/ID.js'
9
+ import { GC } from '../structs/GC.js'
10
+
1
11
  import {
2
- GC,
3
- getState,
4
- AbstractStruct,
5
12
  replaceStruct,
6
- addStruct,
7
- addToIdSet,
8
- findRootTypeKey,
9
- compareIDs,
10
- getItem,
11
13
  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, YType, Transaction, // eslint-disable-line
26
- } from '../internals.js'
14
+ addChangedTypeToTransaction
15
+ } from '../utils/transaction-helpers.js'
27
16
 
28
- import * as error from 'lib0/error'
29
- import * as binary from 'lib0/binary'
30
- import * as array from 'lib0/array'
17
+ const isDevMode = env.getVariable('node_env') === 'development'
31
18
 
32
19
  /**
33
20
  * @todo This should return several items
@@ -47,227 +34,15 @@ export const followRedone = (store, id) => {
47
34
  if (diff > 0) {
48
35
  nextID = createID(nextID.client, nextID.clock + diff)
49
36
  }
50
- item = getItem(store, nextID)
37
+ item = store.getItem(nextID)
51
38
  diff = nextID.clock - item.id.clock
52
39
  nextID = item.redone
53
- } while (nextID !== null && item instanceof Item)
40
+ } while (nextID !== null && item.isItem)
54
41
  return {
55
42
  item, diff
56
43
  }
57
44
  }
58
45
 
59
- /**
60
- * Make sure that neither item nor any of its parents is ever deleted.
61
- *
62
- * This property does not persist when storing it into a database or when
63
- * sending it to other peers
64
- *
65
- * @param {Item|null} item
66
- * @param {boolean} keep
67
- */
68
- export const keepItem = (item, keep) => {
69
- while (item !== null && item.keep !== keep) {
70
- item.keep = keep
71
- item = /** @type {YType} */ (item.parent)._item
72
- }
73
- }
74
-
75
- /**
76
- * Split leftItem into two items
77
- * @param {Transaction?} transaction
78
- * @param {Item} leftItem
79
- * @param {number} diff
80
- * @return {Item}
81
- *
82
- * @function
83
- * @private
84
- */
85
- export const splitItem = (transaction, leftItem, diff) => {
86
- // create rightItem
87
- const { client, clock } = leftItem.id
88
- const rightItem = new Item(
89
- createID(client, clock + diff),
90
- leftItem,
91
- createID(client, clock + diff - 1),
92
- leftItem.right,
93
- leftItem.rightOrigin,
94
- leftItem.parent,
95
- leftItem.parentSub,
96
- leftItem.content.splice(diff)
97
- )
98
- if (leftItem.deleted) {
99
- rightItem.markDeleted()
100
- }
101
- if (leftItem.keep) {
102
- rightItem.keep = true
103
- }
104
- if (leftItem.redone !== null) {
105
- rightItem.redone = createID(leftItem.redone.client, leftItem.redone.clock + diff)
106
- }
107
- if (transaction != null) {
108
- // update left (do not set leftItem.rightOrigin as it will lead to problems when syncing)
109
- leftItem.right = rightItem
110
- // update right
111
- if (rightItem.right !== null) {
112
- rightItem.right.left = rightItem
113
- }
114
- // right is more specific.
115
- transaction._mergeStructs.push(rightItem)
116
- // update parent._map
117
- if (rightItem.parentSub !== null && rightItem.right === null) {
118
- /** @type {YType} */ (rightItem.parent)._map.set(rightItem.parentSub, rightItem)
119
- }
120
- } else {
121
- rightItem.left = null
122
- rightItem.right = null
123
- }
124
- leftItem.length = diff
125
- return rightItem
126
- }
127
-
128
- /**
129
- * More generalized version of splitItem. Split leftStruct into two structs
130
- * @param {Transaction?} transaction
131
- * @param {AbstractStruct} leftStruct
132
- * @param {number} diff
133
- * @return {GC|Item}
134
- *
135
- * @function
136
- * @private
137
- */
138
- export const splitStruct = (transaction, leftStruct, diff) => {
139
- if (leftStruct instanceof Item) {
140
- return splitItem(transaction, leftStruct, diff)
141
- } else {
142
- const rightItem = leftStruct.splice(diff)
143
- transaction?._mergeStructs.push(rightItem)
144
- return rightItem
145
- }
146
- }
147
-
148
- /**
149
- * @param {Array<StackItem>} stack
150
- * @param {ID} id
151
- */
152
- const isDeletedByUndoStack = (stack, id) => array.some(stack, /** @param {StackItem} s */ s => s.deletes.hasId(id))
153
-
154
- /**
155
- * Redoes the effect of this operation.
156
- *
157
- * @param {Transaction} transaction The Yjs instance.
158
- * @param {Item} item
159
- * @param {Set<Item>} redoitems
160
- * @param {IdSet} itemsToDelete
161
- * @param {boolean} ignoreRemoteMapChanges
162
- * @param {import('../utils/UndoManager.js').UndoManager} um
163
- *
164
- * @return {Item|null}
165
- *
166
- * @private
167
- */
168
- export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) => {
169
- const doc = transaction.doc
170
- const store = doc.store
171
- const ownClientID = doc.clientID
172
- const redone = item.redone
173
- if (redone !== null) {
174
- return getItemCleanStart(transaction, redone)
175
- }
176
- let parentItem = /** @type {YType} */ (item.parent)._item
177
- /**
178
- * @type {Item|null}
179
- */
180
- let left = null
181
- /**
182
- * @type {Item|null}
183
- */
184
- let right
185
- // make sure that parent is redone
186
- if (parentItem !== null && parentItem.deleted === true) {
187
- // try to undo parent if it will be undone anyway
188
- if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) === null)) {
189
- return null
190
- }
191
- while (parentItem.redone !== null) {
192
- parentItem = getItemCleanStart(transaction, parentItem.redone)
193
- }
194
- }
195
- /**
196
- * @type {YType}
197
- */
198
- const parentType = /** @type {YType} */ (parentItem === null ? item.parent : /** @type {ContentType} */ (parentItem.content).type)
199
-
200
- if (item.parentSub === null) {
201
- // Is an array item. Insert at the old position
202
- left = item.left
203
- right = item
204
- // find next cloned_redo items
205
- while (left !== null) {
206
- /**
207
- * @type {Item|null}
208
- */
209
- let leftTrace = left
210
- // trace redone until parent matches
211
- while (leftTrace !== null && /** @type {YType} */ (leftTrace.parent)._item !== parentItem) {
212
- leftTrace = leftTrace.redone === null ? null : getItemCleanStart(transaction, leftTrace.redone)
213
- }
214
- if (leftTrace !== null && /** @type {YType} */ (leftTrace.parent)._item === parentItem) {
215
- left = leftTrace
216
- break
217
- }
218
- left = left.left
219
- }
220
- while (right !== null) {
221
- /**
222
- * @type {Item|null}
223
- */
224
- let rightTrace = right
225
- // trace redone until parent matches
226
- while (rightTrace !== null && /** @type {YType} */ (rightTrace.parent)._item !== parentItem) {
227
- rightTrace = rightTrace.redone === null ? null : getItemCleanStart(transaction, rightTrace.redone)
228
- }
229
- if (rightTrace !== null && /** @type {YType} */ (rightTrace.parent)._item === parentItem) {
230
- right = rightTrace
231
- break
232
- }
233
- right = right.right
234
- }
235
- } else {
236
- right = null
237
- if (item.right && !ignoreRemoteMapChanges) {
238
- left = item
239
- // Iterate right while right is in itemsToDelete
240
- // If it is intended to delete right while item is redone, we can expect that item should replace right.
241
- 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))) {
242
- left = left.right
243
- // follow redone
244
- while (left.redone) left = getItemCleanStart(transaction, left.redone)
245
- }
246
- if (left && left.right !== null) {
247
- // It is not possible to redo this item because it conflicts with a
248
- // change from another client
249
- return null
250
- }
251
- } else {
252
- left = parentType._map.get(item.parentSub) || null
253
- }
254
- }
255
- const nextClock = getState(store, ownClientID)
256
- const nextId = createID(ownClientID, nextClock)
257
- const redoneItem = new Item(
258
- nextId,
259
- left, left && left.lastId,
260
- right, right && right.id,
261
- parentType,
262
- item.parentSub,
263
- item.content.copy()
264
- )
265
- item.redone = nextId
266
- keepItem(redoneItem, true)
267
- redoneItem.integrate(transaction, 0)
268
- return redoneItem
269
- }
270
-
271
46
  /**
272
47
  * Abstract class that represents any content.
273
48
  */
@@ -386,56 +161,6 @@ export class Item extends AbstractStruct {
386
161
  this.info |= binary.BIT3
387
162
  }
388
163
 
389
- /**
390
- * Return the creator clientID of the missing op or define missing items and return null.
391
- *
392
- * @param {Transaction} transaction
393
- * @param {StructStore} store
394
- * @return {null | number}
395
- */
396
- getMissing (transaction, store) {
397
- if (this.origin && (this.origin.clock >= getState(store, this.origin.client) || store.skips.hasId(this.origin))) {
398
- return this.origin.client
399
- }
400
- if (this.rightOrigin && (this.rightOrigin.clock >= getState(store, this.rightOrigin.client) || store.skips.hasId(this.rightOrigin))) {
401
- return this.rightOrigin.client
402
- }
403
- if (this.parent && this.parent.constructor === ID && (this.parent.clock >= getState(store, this.parent.client) || store.skips.hasId(this.parent))) {
404
- return this.parent.client
405
- }
406
- // We have all missing ids, now find the items
407
- if (this.origin) {
408
- this.left = getItemCleanEnd(transaction, store, this.origin)
409
- this.origin = this.left.lastId
410
- }
411
- if (this.rightOrigin) {
412
- this.right = getItemCleanStart(transaction, this.rightOrigin)
413
- this.rightOrigin = this.right.id
414
- }
415
- if ((this.left && this.left.constructor === GC) || (this.right && this.right.constructor === GC)) {
416
- this.parent = null
417
- } else if (this.parent == null) {
418
- // only set parent if this shouldn't be garbage collected
419
- if (this.left && this.left.constructor === Item) {
420
- this.parent = this.left.parent
421
- this.parentSub = this.left.parentSub
422
- } else if (this.right && this.right.constructor === Item) {
423
- this.parent = this.right.parent
424
- this.parentSub = this.right.parentSub
425
- }
426
- } else if (this.parent.constructor === ID) {
427
- const parentItem = getItem(store, this.parent)
428
- if (parentItem.constructor === GC) {
429
- this.parent = null
430
- } else {
431
- this.parent = /** @type {ContentType} */ (parentItem.content).type
432
- }
433
- } else if (typeof this.parent === 'string') {
434
- this.parent = transaction.doc.get(this.parent)
435
- }
436
- return null
437
- }
438
-
439
164
  /**
440
165
  * @param {Transaction} transaction
441
166
  * @param {number} offset
@@ -497,9 +222,9 @@ export class Item extends AbstractStruct {
497
222
  // Since this is to the left of o, we can break here
498
223
  break
499
224
  } // else, o might be integrated before an item that this conflicts with. If so, we will find it in the next iterations
500
- } 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.
225
+ } else if (o.origin !== null && itemsBeforeOrigin.has(transaction.doc.store.getItem(o.origin))) { // use getItem instead of getItemCleanEnd because we don't want / need to split items.
501
226
  // case 2
502
- if (!conflictingItems.has(getItem(transaction.doc.store, o.origin))) {
227
+ if (!conflictingItems.has(transaction.doc.store.getItem(o.origin))) {
503
228
  left = o
504
229
  conflictingItems.clear()
505
230
  }
@@ -534,7 +259,7 @@ export class Item extends AbstractStruct {
534
259
  // set as current parent value if right === null and this is parentSub
535
260
  /** @type {YType} */ (this.parent)._map.set(this.parentSub, this)
536
261
  if (this.left !== null) {
537
- // this is the current attribute value of parent. delete right
262
+ // this is the current attribute value of parent. delete the previous value
538
263
  this.left.delete(transaction)
539
264
  }
540
265
  }
@@ -543,7 +268,7 @@ export class Item extends AbstractStruct {
543
268
  /** @type {YType} */ (this.parent)._length += this.length
544
269
  }
545
270
  addStructToIdSet(transaction.insertSet, this)
546
- addStruct(transaction.doc.store, this)
271
+ transaction.doc.store.add(this)
547
272
  this.content.integrate(transaction, this)
548
273
  // add parent to transaction.changed
549
274
  addChangedTypeToTransaction(transaction, /** @type {YType} */ (this.parent), this.parentSub)
@@ -646,7 +371,7 @@ export class Item extends AbstractStruct {
646
371
  parent._length -= this.length
647
372
  }
648
373
  this.markDeleted()
649
- addToIdSet(transaction.deleteSet, this.id.client, this.id.clock, this.length)
374
+ transaction.deleteSet.add(this.id.client, this.id.clock, this.length)
650
375
  addChangedTypeToTransaction(transaction, parent, this.parentSub)
651
376
  this.content.delete(transaction)
652
377
  }
@@ -668,6 +393,55 @@ export class Item extends AbstractStruct {
668
393
  }
669
394
  }
670
395
 
396
+ /**
397
+ * Split this into two items
398
+ * @param {Transaction?} transaction
399
+ * @param {number} diff
400
+ * @return {Item}
401
+ */
402
+ split (transaction, diff) {
403
+ // create rightItem
404
+ const { client, clock } = this.id
405
+ const rightItem = new Item(
406
+ createID(client, clock + diff),
407
+ this,
408
+ createID(client, clock + diff - 1),
409
+ this.right,
410
+ this.rightOrigin,
411
+ this.parent,
412
+ this.parentSub,
413
+ this.content.splice(diff)
414
+ )
415
+ if (this.deleted) {
416
+ rightItem.markDeleted()
417
+ }
418
+ if (this.keep) {
419
+ rightItem.keep = true
420
+ }
421
+ if (this.redone !== null) {
422
+ rightItem.redone = createID(this.redone.client, this.redone.clock + diff)
423
+ }
424
+ if (transaction != null) {
425
+ // update left (do not set leftItem.rightOrigin as it will lead to problems when syncing)
426
+ this.right = rightItem
427
+ // update right
428
+ if (rightItem.right !== null) {
429
+ rightItem.right.left = rightItem
430
+ }
431
+ // right is more specific.
432
+ transaction._mergeStructs.push(rightItem)
433
+ // update parent._map
434
+ if (rightItem.parentSub !== null && rightItem.right === null) {
435
+ /** @type {YType} */ (rightItem.parent)._map.set(rightItem.parentSub, rightItem)
436
+ }
437
+ } else {
438
+ rightItem.left = null
439
+ rightItem.right = null
440
+ }
441
+ this.length = diff
442
+ return rightItem
443
+ }
444
+
671
445
  /**
672
446
  * Transform the properties of this type to binary and write it to an
673
447
  * BinaryEncoder.
@@ -694,7 +468,7 @@ export class Item extends AbstractStruct {
694
468
  encoder.writeRightID(rightOrigin)
695
469
  }
696
470
  if (origin === null && rightOrigin === null) {
697
- const parent = /** @type {YType<any>} */ (this.parent)
471
+ const parent = /** @type {YType} */ (this.parent)
698
472
  if (parent._item !== undefined) {
699
473
  const parentItem = parent._item
700
474
  if (parentItem === null) {
@@ -722,32 +496,16 @@ export class Item extends AbstractStruct {
722
496
  }
723
497
  this.content.write(encoder, offset, offsetEnd)
724
498
  }
725
- }
726
499
 
727
- /**
728
- * @param {UpdateDecoderV1 | UpdateDecoderV2} decoder
729
- * @param {number} info
730
- */
731
- export const readItemContent = (decoder, info) => contentRefs[info & binary.BITS5](decoder)
500
+ get ref () {
501
+ return this.content.getRef()
502
+ }
503
+ }
732
504
 
733
505
  /**
734
- * A lookup map for reading Item content.
735
- *
736
- * @type {Array<function(UpdateDecoderV1 | UpdateDecoderV2):AbstractContent>}
506
+ * @type {true}
737
507
  */
738
- export const contentRefs = [
739
- () => { error.unexpectedCase() }, // GC is not ItemContent
740
- readContentDeleted, // 1
741
- readContentJSON, // 2
742
- readContentBinary, // 3
743
- readContentString, // 4
744
- readContentEmbed, // 5
745
- readContentFormat, // 6
746
- readContentType, // 7
747
- readContentAny, // 8
748
- readContentDoc, // 9
749
- () => { error.unexpectedCase() } // 10 - Skip is not ItemContent
750
- ]
508
+ Item.prototype.isItem = true
751
509
 
752
510
  /**
753
511
  * Do not implement this class!
@@ -834,10 +592,926 @@ export class AbstractContent {
834
592
  throw error.methodUnimplemented()
835
593
  }
836
594
 
595
+ /**
596
+ * @return {1|2|3|4|5|6|7|8|9}
597
+ */
598
+ getRef () {
599
+ throw error.methodUnimplemented()
600
+ }
601
+ }
602
+
603
+ export class ContentAny {
604
+ /**
605
+ * @param {Array<any>} arr
606
+ */
607
+ constructor (arr) {
608
+ /**
609
+ * @type {Array<any>}
610
+ */
611
+ this.arr = arr
612
+ isDevMode && object.deepFreeze(arr)
613
+ }
614
+
837
615
  /**
838
616
  * @return {number}
839
617
  */
618
+ getLength () {
619
+ return this.arr.length
620
+ }
621
+
622
+ /**
623
+ * @return {Array<any>}
624
+ */
625
+ getContent () {
626
+ return this.arr
627
+ }
628
+
629
+ /**
630
+ * @return {boolean}
631
+ */
632
+ isCountable () {
633
+ return true
634
+ }
635
+
636
+ /**
637
+ * @return {ContentAny}
638
+ */
639
+ copy () {
640
+ return new ContentAny(this.arr)
641
+ }
642
+
643
+ /**
644
+ * @param {number} offset
645
+ * @return {ContentAny}
646
+ */
647
+ splice (offset) {
648
+ const right = new ContentAny(this.arr.slice(offset))
649
+ this.arr = this.arr.slice(0, offset)
650
+ return right
651
+ }
652
+
653
+ /**
654
+ * @param {ContentAny} right
655
+ * @return {boolean}
656
+ */
657
+ mergeWith (right) {
658
+ this.arr = this.arr.concat(right.arr)
659
+ return true
660
+ }
661
+
662
+ /**
663
+ * @param {Transaction} _transaction
664
+ * @param {Item} _item
665
+ */
666
+ integrate (_transaction, _item) {}
667
+ /**
668
+ * @param {Transaction} _transaction
669
+ */
670
+ delete (_transaction) {}
671
+ /**
672
+ * @param {Transaction} _tr
673
+ */
674
+ gc (_tr) {}
675
+ /**
676
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
677
+ * @param {number} offset
678
+ * @param {number} offsetEnd
679
+ */
680
+ write (encoder, offset, offsetEnd) {
681
+ const end = this.arr.length - offsetEnd
682
+ encoder.writeLen(end - offset)
683
+ for (let i = offset; i < end; i++) {
684
+ const c = this.arr[i]
685
+ encoder.writeAny(c)
686
+ }
687
+ }
688
+
689
+ /**
690
+ * @return {8}
691
+ */
840
692
  getRef () {
693
+ return 8
694
+ }
695
+ }
696
+
697
+ export class ContentBinary {
698
+ /**
699
+ * @param {Uint8Array} content
700
+ */
701
+ constructor (content) {
702
+ this.content = content
703
+ }
704
+
705
+ /**
706
+ * @return {number}
707
+ */
708
+ getLength () {
709
+ return 1
710
+ }
711
+
712
+ /**
713
+ * @return {Array<any>}
714
+ */
715
+ getContent () {
716
+ return [this.content]
717
+ }
718
+
719
+ /**
720
+ * @return {boolean}
721
+ */
722
+ isCountable () {
723
+ return true
724
+ }
725
+
726
+ /**
727
+ * @return {ContentBinary}
728
+ */
729
+ copy () {
730
+ return new ContentBinary(this.content)
731
+ }
732
+
733
+ /**
734
+ * @param {number} _offset
735
+ * @return {ContentBinary}
736
+ */
737
+ splice (_offset) {
841
738
  throw error.methodUnimplemented()
842
739
  }
740
+
741
+ /**
742
+ * @param {ContentBinary} _right
743
+ * @return {boolean}
744
+ */
745
+ mergeWith (_right) {
746
+ return false
747
+ }
748
+
749
+ /**
750
+ * @param {Transaction} _transaction
751
+ * @param {Item} _item
752
+ */
753
+ integrate (_transaction, _item) {}
754
+ /**
755
+ * @param {Transaction} _transaction
756
+ */
757
+ delete (_transaction) {}
758
+ /**
759
+ * @param {Transaction} _tr
760
+ */
761
+ gc (_tr) {}
762
+ /**
763
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
764
+ * @param {number} _offset
765
+ * @param {number} _offsetEnd
766
+ */
767
+ write (encoder, _offset, _offsetEnd) {
768
+ encoder.writeBuf(this.content)
769
+ }
770
+
771
+ /**
772
+ * @return {3}
773
+ */
774
+ getRef () {
775
+ return 3
776
+ }
777
+ }
778
+
779
+ export class ContentDeleted {
780
+ /**
781
+ * @param {number} len
782
+ */
783
+ constructor (len) {
784
+ this.len = len
785
+ }
786
+
787
+ /**
788
+ * @return {number}
789
+ */
790
+ getLength () {
791
+ return this.len
792
+ }
793
+
794
+ /**
795
+ * @return {Array<any>}
796
+ */
797
+ getContent () {
798
+ return []
799
+ }
800
+
801
+ /**
802
+ * @return {boolean}
803
+ */
804
+ isCountable () {
805
+ return false
806
+ }
807
+
808
+ /**
809
+ * @return {ContentDeleted}
810
+ */
811
+ copy () {
812
+ return new ContentDeleted(this.len)
813
+ }
814
+
815
+ /**
816
+ * @param {number} offset
817
+ * @return {ContentDeleted}
818
+ */
819
+ splice (offset) {
820
+ const right = new ContentDeleted(this.len - offset)
821
+ this.len = offset
822
+ return right
823
+ }
824
+
825
+ /**
826
+ * @param {ContentDeleted} right
827
+ * @return {boolean}
828
+ */
829
+ mergeWith (right) {
830
+ this.len += right.len
831
+ return true
832
+ }
833
+
834
+ /**
835
+ * @param {Transaction} transaction
836
+ * @param {Item} item
837
+ */
838
+ integrate (transaction, item) {
839
+ transaction.deleteSet.add(item.id.client, item.id.clock, this.len)
840
+ item.markDeleted()
841
+ }
842
+
843
+ /**
844
+ * @param {Transaction} _transaction
845
+ */
846
+ delete (_transaction) {}
847
+ /**
848
+ * @param {Transaction} _tr
849
+ */
850
+ gc (_tr) {}
851
+ /**
852
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
853
+ * @param {number} offset
854
+ * @param {number} offsetEnd
855
+ */
856
+ write (encoder, offset, offsetEnd) {
857
+ encoder.writeLen(this.len - offset - offsetEnd)
858
+ }
859
+
860
+ /**
861
+ * @return {1}
862
+ */
863
+ getRef () {
864
+ return 1
865
+ }
866
+ }
867
+
868
+ /**
869
+ * @private
870
+ */
871
+ export class ContentDoc {
872
+ /**
873
+ * @param {string} guid
874
+ * @param {Object<string,any>} opts
875
+ */
876
+ constructor (guid, opts) {
877
+ /**
878
+ * @type {Doc?}
879
+ */
880
+ this.doc = null
881
+ this.guid = guid
882
+ this.opts = opts
883
+ }
884
+
885
+ /**
886
+ * @return {number}
887
+ */
888
+ getLength () {
889
+ return 1
890
+ }
891
+
892
+ /**
893
+ * @return {Array<any>}
894
+ */
895
+ getContent () {
896
+ return [this.doc]
897
+ }
898
+
899
+ /**
900
+ * @return {boolean}
901
+ */
902
+ isCountable () {
903
+ return true
904
+ }
905
+
906
+ /**
907
+ * @return {ContentDoc}
908
+ */
909
+ copy () {
910
+ return new ContentDoc(this.guid, this.opts)
911
+ }
912
+
913
+ /**
914
+ * @param {number} _offset
915
+ * @return {ContentDoc}
916
+ */
917
+ splice (_offset) {
918
+ throw error.methodUnimplemented()
919
+ }
920
+
921
+ /**
922
+ * @param {ContentDoc} _right
923
+ * @return {boolean}
924
+ */
925
+ mergeWith (_right) {
926
+ return false
927
+ }
928
+
929
+ /**
930
+ * @param {Transaction} transaction
931
+ * @param {Item} item
932
+ */
933
+ integrate (transaction, item) {
934
+ const opts = this.opts
935
+ if (this.doc == null) {
936
+ // we get the constructor from the existing doc to avoid import the doc module, leading to a
937
+ // circular dependency
938
+ this.doc = /** @type {Doc} */ (new /** @type {any} */ (transaction.doc.constructor)({ guid: this.guid, ...this.opts, shouldLoad: opts.shouldLoad || opts.autoLoad || false }))
939
+ }
940
+ this.doc._item = item
941
+ transaction.subdocsAdded.add(this.doc)
942
+ if (this.doc.shouldLoad) {
943
+ transaction.subdocsLoaded.add(this.doc)
944
+ }
945
+ }
946
+
947
+ /**
948
+ * @param {Transaction} transaction
949
+ */
950
+ delete (transaction) {
951
+ if (this.doc) {
952
+ if (transaction.subdocsAdded.has(this.doc)) {
953
+ transaction.subdocsAdded.delete(this.doc)
954
+ } else {
955
+ transaction.subdocsRemoved.add(this.doc)
956
+ }
957
+ }
958
+ }
959
+
960
+ /**
961
+ * @param {Transaction} _tr
962
+ */
963
+ gc (_tr) {}
964
+
965
+ /**
966
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
967
+ * @param {number} _offset
968
+ * @param {number} _offsetEnd
969
+ */
970
+ write (encoder, _offset, _offsetEnd) {
971
+ encoder.writeString(this.guid)
972
+ encoder.writeAny(this.opts)
973
+ }
974
+
975
+ /**
976
+ * @return {9}
977
+ */
978
+ getRef () {
979
+ return 9
980
+ }
981
+ }
982
+
983
+ /**
984
+ * @param {Doc} ydoc
985
+ */
986
+ export const createContentDocFromDoc = ydoc => {
987
+ /**
988
+ * @type {any}
989
+ */
990
+ const opts = {}
991
+ if (!ydoc.gc) {
992
+ opts.gc = false
993
+ }
994
+ if (ydoc.autoLoad) {
995
+ opts.autoLoad = true
996
+ }
997
+ if (ydoc.meta !== null) {
998
+ opts.meta = ydoc.meta
999
+ }
1000
+ const c = new ContentDoc(ydoc.guid, opts)
1001
+ c.doc = ydoc
1002
+ return c
1003
+ }
1004
+
1005
+ /**
1006
+ * @private
1007
+ */
1008
+ export class ContentEmbed {
1009
+ /**
1010
+ * @param {Object} embed
1011
+ */
1012
+ constructor (embed) {
1013
+ this.embed = embed
1014
+ }
1015
+
1016
+ /**
1017
+ * @return {number}
1018
+ */
1019
+ getLength () {
1020
+ return 1
1021
+ }
1022
+
1023
+ /**
1024
+ * @return {Array<any>}
1025
+ */
1026
+ getContent () {
1027
+ return [this.embed]
1028
+ }
1029
+
1030
+ /**
1031
+ * @return {boolean}
1032
+ */
1033
+ isCountable () {
1034
+ return true
1035
+ }
1036
+
1037
+ /**
1038
+ * @return {ContentEmbed}
1039
+ */
1040
+ copy () {
1041
+ return new ContentEmbed(this.embed)
1042
+ }
1043
+
1044
+ /**
1045
+ * @param {number} _offset
1046
+ * @return {ContentEmbed}
1047
+ */
1048
+ splice (_offset) {
1049
+ throw error.methodUnimplemented()
1050
+ }
1051
+
1052
+ /**
1053
+ * @param {ContentEmbed} _right
1054
+ * @return {boolean}
1055
+ */
1056
+ mergeWith (_right) {
1057
+ return false
1058
+ }
1059
+
1060
+ /**
1061
+ * @param {Transaction} _transaction
1062
+ * @param {Item} _item
1063
+ */
1064
+ integrate (_transaction, _item) {}
1065
+ /**
1066
+ * @param {Transaction} _transaction
1067
+ */
1068
+ delete (_transaction) {}
1069
+ /**
1070
+ * @param {Transaction} _tr
1071
+ */
1072
+ gc (_tr) {}
1073
+ /**
1074
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
1075
+ * @param {number} _offset
1076
+ * @param {number} _offsetEnd
1077
+ */
1078
+ write (encoder, _offset, _offsetEnd) {
1079
+ encoder.writeJSON(this.embed)
1080
+ }
1081
+
1082
+ /**
1083
+ * @return {5}
1084
+ */
1085
+ getRef () {
1086
+ return 5
1087
+ }
1088
+ }
1089
+
1090
+ /**
1091
+ * @private
1092
+ */
1093
+ export class ContentFormat {
1094
+ /**
1095
+ * @param {string} key
1096
+ * @param {Object} value
1097
+ */
1098
+ constructor (key, value) {
1099
+ this.key = key
1100
+ this.value = value
1101
+ }
1102
+
1103
+ /**
1104
+ * @return {number}
1105
+ */
1106
+ getLength () {
1107
+ return 1
1108
+ }
1109
+
1110
+ /**
1111
+ * @return {Array<any>}
1112
+ */
1113
+ getContent () {
1114
+ return []
1115
+ }
1116
+
1117
+ /**
1118
+ * @return {boolean}
1119
+ */
1120
+ isCountable () {
1121
+ return false
1122
+ }
1123
+
1124
+ /**
1125
+ * @return {ContentFormat}
1126
+ */
1127
+ copy () {
1128
+ return new ContentFormat(this.key, this.value)
1129
+ }
1130
+
1131
+ /**
1132
+ * @param {number} _offset
1133
+ * @return {ContentFormat}
1134
+ */
1135
+ splice (_offset) {
1136
+ throw error.methodUnimplemented()
1137
+ }
1138
+
1139
+ /**
1140
+ * @param {ContentFormat} _right
1141
+ * @return {boolean}
1142
+ */
1143
+ mergeWith (_right) {
1144
+ return false
1145
+ }
1146
+
1147
+ /**
1148
+ * @param {Transaction} _transaction
1149
+ * @param {Item} item
1150
+ */
1151
+ integrate (_transaction, item) {
1152
+ // @todo searchmarker are currently unsupported for rich text documents
1153
+ const p = /** @type {import('../ytype.js').YType<any>} */ (item.parent)
1154
+ p._searchMarker = null
1155
+ p._hasFormatting = true
1156
+ }
1157
+
1158
+ /**
1159
+ * @param {Transaction} _transaction
1160
+ */
1161
+ delete (_transaction) {}
1162
+ /**
1163
+ * @param {Transaction} _tr
1164
+ */
1165
+ gc (_tr) {}
1166
+ /**
1167
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
1168
+ * @param {number} _offset
1169
+ * @param {number} _offsetEnd
1170
+ */
1171
+ write (encoder, _offset, _offsetEnd) {
1172
+ encoder.writeKey(this.key)
1173
+ encoder.writeJSON(this.value)
1174
+ }
1175
+
1176
+ /**
1177
+ * @return {6}
1178
+ */
1179
+ getRef () {
1180
+ return 6
1181
+ }
1182
+ }
1183
+
1184
+ /**
1185
+ * @private
1186
+ */
1187
+ export class ContentJSON {
1188
+ /**
1189
+ * @param {Array<any>} arr
1190
+ */
1191
+ constructor (arr) {
1192
+ /**
1193
+ * @type {Array<any>}
1194
+ */
1195
+ this.arr = arr
1196
+ }
1197
+
1198
+ /**
1199
+ * @return {number}
1200
+ */
1201
+ getLength () {
1202
+ return this.arr.length
1203
+ }
1204
+
1205
+ /**
1206
+ * @return {Array<any>}
1207
+ */
1208
+ getContent () {
1209
+ return this.arr
1210
+ }
1211
+
1212
+ /**
1213
+ * @return {boolean}
1214
+ */
1215
+ isCountable () {
1216
+ return true
1217
+ }
1218
+
1219
+ /**
1220
+ * @return {ContentJSON}
1221
+ */
1222
+ copy () {
1223
+ return new ContentJSON(this.arr)
1224
+ }
1225
+
1226
+ /**
1227
+ * @param {number} offset
1228
+ * @return {ContentJSON}
1229
+ */
1230
+ splice (offset) {
1231
+ const right = new ContentJSON(this.arr.slice(offset))
1232
+ this.arr = this.arr.slice(0, offset)
1233
+ return right
1234
+ }
1235
+
1236
+ /**
1237
+ * @param {ContentJSON} right
1238
+ * @return {boolean}
1239
+ */
1240
+ mergeWith (right) {
1241
+ this.arr = this.arr.concat(right.arr)
1242
+ return true
1243
+ }
1244
+
1245
+ /**
1246
+ * @param {Transaction} _transaction
1247
+ * @param {Item} _item
1248
+ */
1249
+ integrate (_transaction, _item) {}
1250
+ /**
1251
+ * @param {Transaction} _transaction
1252
+ */
1253
+ delete (_transaction) {}
1254
+ /**
1255
+ * @param {Transaction} _tr
1256
+ */
1257
+ gc (_tr) {}
1258
+ /**
1259
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
1260
+ * @param {number} offset
1261
+ * @param {number} offsetEnd
1262
+ */
1263
+ write (encoder, offset, offsetEnd) {
1264
+ const end = this.arr.length - offsetEnd
1265
+ encoder.writeLen(end - offset)
1266
+ for (let i = offset; i < end; i++) {
1267
+ const c = this.arr[i]
1268
+ encoder.writeString(c === undefined ? 'undefined' : JSON.stringify(c))
1269
+ }
1270
+ }
1271
+
1272
+ /**
1273
+ * @return {2}
1274
+ */
1275
+ getRef () {
1276
+ return 2
1277
+ }
1278
+ }
1279
+
1280
+ /**
1281
+ * @private
1282
+ */
1283
+ export class ContentString {
1284
+ /**
1285
+ * @param {string} str
1286
+ */
1287
+ constructor (str) {
1288
+ /**
1289
+ * @type {string}
1290
+ */
1291
+ this.str = str
1292
+ }
1293
+
1294
+ /**
1295
+ * @return {number}
1296
+ */
1297
+ getLength () {
1298
+ return this.str.length
1299
+ }
1300
+
1301
+ /**
1302
+ * @return {Array<any>}
1303
+ */
1304
+ getContent () {
1305
+ return this.str.split('')
1306
+ }
1307
+
1308
+ /**
1309
+ * @return {boolean}
1310
+ */
1311
+ isCountable () {
1312
+ return true
1313
+ }
1314
+
1315
+ /**
1316
+ * @return {ContentString}
1317
+ */
1318
+ copy () {
1319
+ return new ContentString(this.str)
1320
+ }
1321
+
1322
+ /**
1323
+ * @param {number} offset
1324
+ * @return {ContentString}
1325
+ */
1326
+ splice (offset) {
1327
+ const right = new ContentString(this.str.slice(offset))
1328
+ this.str = this.str.slice(0, offset)
1329
+
1330
+ // Prevent encoding invalid documents because of splitting of surrogate pairs: https://github.com/yjs/yjs/issues/248
1331
+ const firstCharCode = this.str.charCodeAt(offset - 1)
1332
+ if (firstCharCode >= 0xD800 && firstCharCode <= 0xDBFF) {
1333
+ // Last character of the left split is the start of a surrogate utf16/ucs2 pair.
1334
+ // We don't support splitting of surrogate pairs because this may lead to invalid documents.
1335
+ // Replace the invalid character with a unicode replacement character (� / U+FFFD)
1336
+ this.str = this.str.slice(0, offset - 1) + '�'
1337
+ // replace right as well
1338
+ right.str = '�' + right.str.slice(1)
1339
+ }
1340
+ return right
1341
+ }
1342
+
1343
+ /**
1344
+ * @param {ContentString} right
1345
+ * @return {boolean}
1346
+ */
1347
+ mergeWith (right) {
1348
+ this.str += right.str
1349
+ return true
1350
+ }
1351
+
1352
+ /**
1353
+ * @param {Transaction} _transaction
1354
+ * @param {Item} _item
1355
+ */
1356
+ integrate (_transaction, _item) {}
1357
+ /**
1358
+ * @param {Transaction} _transaction
1359
+ */
1360
+ delete (_transaction) {}
1361
+ /**
1362
+ * @param {Transaction} _tr
1363
+ */
1364
+ gc (_tr) {}
1365
+ /**
1366
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
1367
+ * @param {number} offset
1368
+ * @param {number} offsetEnd
1369
+ */
1370
+ write (encoder, offset, offsetEnd) {
1371
+ encoder.writeString((offset === 0 && offsetEnd === 0) ? this.str : this.str.slice(offset, this.str.length - offsetEnd))
1372
+ }
1373
+
1374
+ /**
1375
+ * @return {4}
1376
+ */
1377
+ getRef () {
1378
+ return 4
1379
+ }
1380
+ }
1381
+
1382
+ export const YArrayRefID = 0
1383
+ export const YMapRefID = 1
1384
+ export const YTextRefID = 2
1385
+ export const YXmlElementRefID = 3
1386
+ export const YXmlFragmentRefID = 4
1387
+ export const YXmlHookRefID = 5
1388
+ export const YXmlTextRefID = 6
1389
+
1390
+ /**
1391
+ * @private
1392
+ */
1393
+ export class ContentType {
1394
+ /**
1395
+ * @param {import('../ytype.js').YType} type
1396
+ */
1397
+ constructor (type) {
1398
+ /**
1399
+ * @type {import('../ytype.js').YType}
1400
+ */
1401
+ this.type = type
1402
+ }
1403
+
1404
+ /**
1405
+ * @return {number}
1406
+ */
1407
+ getLength () {
1408
+ return 1
1409
+ }
1410
+
1411
+ /**
1412
+ * @return {Array<any>}
1413
+ */
1414
+ getContent () {
1415
+ return [this.type]
1416
+ }
1417
+
1418
+ /**
1419
+ * @return {boolean}
1420
+ */
1421
+ isCountable () {
1422
+ return true
1423
+ }
1424
+
1425
+ /**
1426
+ * @return {ContentType}
1427
+ */
1428
+ copy () {
1429
+ return new ContentType(this.type._copy())
1430
+ }
1431
+
1432
+ /**
1433
+ * @param {number} _offset
1434
+ * @return {ContentType}
1435
+ */
1436
+ splice (_offset) {
1437
+ throw error.methodUnimplemented()
1438
+ }
1439
+
1440
+ /**
1441
+ * @param {ContentType} _right
1442
+ * @return {boolean}
1443
+ */
1444
+ mergeWith (_right) {
1445
+ return false
1446
+ }
1447
+
1448
+ /**
1449
+ * @param {Transaction} transaction
1450
+ * @param {Item} item
1451
+ */
1452
+ integrate (transaction, item) {
1453
+ this.type._integrate(transaction.doc, item)
1454
+ }
1455
+
1456
+ /**
1457
+ * @param {Transaction} transaction
1458
+ */
1459
+ delete (transaction) {
1460
+ let item = this.type._start
1461
+ while (item !== null) {
1462
+ if (!item.deleted) {
1463
+ item.delete(transaction)
1464
+ } else if (!transaction.insertSet.hasId(item.id)) {
1465
+ // This will be gc'd later and we want to merge it if possible
1466
+ // We try to merge all deleted items after each transaction,
1467
+ // but we have no knowledge about that this needs to be merged
1468
+ // since it is not in transaction.ds. Hence we add it to transaction._mergeStructs
1469
+ transaction._mergeStructs.push(item)
1470
+ }
1471
+ item = item.right
1472
+ }
1473
+ this.type._map.forEach(item => {
1474
+ if (!item.deleted) {
1475
+ item.delete(transaction)
1476
+ } else if (!transaction.insertSet.hasId(item.id)) {
1477
+ // same as above
1478
+ transaction._mergeStructs.push(item)
1479
+ }
1480
+ })
1481
+ }
1482
+
1483
+ /**
1484
+ * @param {Transaction} tr
1485
+ */
1486
+ gc (tr) {
1487
+ let item = this.type._start
1488
+ while (item !== null) {
1489
+ item.gc(tr, true)
1490
+ item = item.right
1491
+ }
1492
+ this.type._start = null
1493
+ this.type._map.forEach(/** @param {Item | null} item */ (item) => {
1494
+ while (item !== null) {
1495
+ item.gc(tr, true)
1496
+ item = item.left
1497
+ }
1498
+ })
1499
+ this.type._map = new Map()
1500
+ }
1501
+
1502
+ /**
1503
+ * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
1504
+ * @param {number} _offset
1505
+ * @param {number} _offsetEnd
1506
+ */
1507
+ write (encoder, _offset, _offsetEnd) {
1508
+ this.type._write(encoder)
1509
+ }
1510
+
1511
+ /**
1512
+ * @return {7}
1513
+ */
1514
+ getRef () {
1515
+ return 7
1516
+ }
843
1517
  }