@y/y 14.0.0-16 → 14.0.0-17

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 (68) hide show
  1. package/dist/{index-DyTeTfmj.js → index-BV-j5wdP.js} +2 -2
  2. package/dist/{index-R7GxO-36.js.map → index-BV-j5wdP.js.map} +1 -1
  3. package/dist/{internals.mjs → internals.js} +1 -1
  4. package/dist/internals.js.map +1 -0
  5. package/dist/{testHelper.mjs → testHelper.js} +2 -2
  6. package/dist/testHelper.js.map +1 -0
  7. package/dist/{yjs.mjs → yjs.js} +2 -2
  8. package/dist/yjs.js.map +1 -0
  9. package/package.json +8 -17
  10. package/dist/Skip-j0kX7pdq.js +0 -12173
  11. package/dist/Skip-j0kX7pdq.js.map +0 -1
  12. package/dist/index-DyTeTfmj.js.map +0 -1
  13. package/dist/index-R7GxO-36.js +0 -165
  14. package/dist/internals.cjs +0 -286
  15. package/dist/internals.cjs.map +0 -1
  16. package/dist/internals.mjs.map +0 -1
  17. package/dist/testHelper.cjs +0 -780
  18. package/dist/testHelper.cjs.map +0 -1
  19. package/dist/testHelper.mjs.map +0 -1
  20. package/dist/yjs.cjs +0 -151
  21. package/dist/yjs.cjs.map +0 -1
  22. package/dist/yjs.mjs.map +0 -1
  23. package/src/index.js +0 -153
  24. package/src/internals.js +0 -44
  25. package/src/structs/AbstractStruct.js +0 -59
  26. package/src/structs/ContentAny.js +0 -115
  27. package/src/structs/ContentBinary.js +0 -93
  28. package/src/structs/ContentDeleted.js +0 -101
  29. package/src/structs/ContentDoc.js +0 -141
  30. package/src/structs/ContentEmbed.js +0 -98
  31. package/src/structs/ContentFormat.js +0 -105
  32. package/src/structs/ContentJSON.js +0 -119
  33. package/src/structs/ContentString.js +0 -113
  34. package/src/structs/ContentType.js +0 -176
  35. package/src/structs/GC.js +0 -80
  36. package/src/structs/Item.js +0 -845
  37. package/src/structs/Skip.js +0 -75
  38. package/src/types/AbstractType.js +0 -1434
  39. package/src/types/YArray.js +0 -270
  40. package/src/types/YMap.js +0 -244
  41. package/src/types/YText.js +0 -934
  42. package/src/types/YXmlElement.js +0 -227
  43. package/src/types/YXmlFragment.js +0 -266
  44. package/src/types/YXmlHook.js +0 -68
  45. package/src/types/YXmlText.js +0 -66
  46. package/src/utils/AbstractConnector.js +0 -25
  47. package/src/utils/AttributionManager.js +0 -619
  48. package/src/utils/Doc.js +0 -372
  49. package/src/utils/EventHandler.js +0 -87
  50. package/src/utils/ID.js +0 -89
  51. package/src/utils/IdMap.js +0 -629
  52. package/src/utils/IdSet.js +0 -823
  53. package/src/utils/RelativePosition.js +0 -352
  54. package/src/utils/Snapshot.js +0 -220
  55. package/src/utils/StructSet.js +0 -137
  56. package/src/utils/StructStore.js +0 -289
  57. package/src/utils/Transaction.js +0 -489
  58. package/src/utils/UndoManager.js +0 -391
  59. package/src/utils/UpdateDecoder.js +0 -281
  60. package/src/utils/UpdateEncoder.js +0 -320
  61. package/src/utils/YEvent.js +0 -216
  62. package/src/utils/delta-helpers.js +0 -54
  63. package/src/utils/encoding.js +0 -623
  64. package/src/utils/isParentOf.js +0 -21
  65. package/src/utils/logging.js +0 -21
  66. package/src/utils/types.js +0 -28
  67. package/src/utils/updates.js +0 -715
  68. package/tests/testHelper.js +0 -600
@@ -1,489 +0,0 @@
1
- import {
2
- getState,
3
- writeStructsFromTransaction,
4
- writeIdSet,
5
- getStateVector,
6
- findIndexSS,
7
- callEventHandlerListeners,
8
- createIdSet,
9
- Item,
10
- generateNewClientId,
11
- createID,
12
- cleanupYTextAfterTransaction,
13
- IdSet, UpdateEncoderV1, UpdateEncoderV2, GC, StructStore, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line
14
- } from '../internals.js'
15
-
16
- import * as error from 'lib0/error'
17
- import * as map from 'lib0/map'
18
- import * as math from 'lib0/math'
19
- import * as set from 'lib0/set'
20
- import * as logging from 'lib0/logging'
21
- import { callAll } from 'lib0/function'
22
-
23
- /**
24
- * A transaction is created for every change on the Yjs model. It is possible
25
- * to bundle changes on the Yjs model in a single transaction to
26
- * minimize the number on messages sent and the number of observer calls.
27
- * If possible the user of this library should bundle as many changes as
28
- * possible. Here is an example to illustrate the advantages of bundling:
29
- *
30
- * @example
31
- * const ydoc = new Y.Doc()
32
- * const map = ydoc.getMap('map')
33
- * // Log content when change is triggered
34
- * map.observe(() => {
35
- * console.log('change triggered')
36
- * })
37
- * // Each change on the map type triggers a log message:
38
- * map.set('a', 0) // => "change triggered"
39
- * map.set('b', 0) // => "change triggered"
40
- * // When put in a transaction, it will trigger the log after the transaction:
41
- * ydoc.transact(() => {
42
- * map.set('a', 1)
43
- * map.set('b', 1)
44
- * }) // => "change triggered"
45
- *
46
- * @public
47
- */
48
- export class Transaction {
49
- /**
50
- * @param {Doc} doc
51
- * @param {any} origin
52
- * @param {boolean} local
53
- */
54
- constructor (doc, origin, local) {
55
- /**
56
- * The Yjs instance.
57
- * @type {Doc}
58
- */
59
- this.doc = doc
60
- /**
61
- * Describes the set of deleted items by ids
62
- */
63
- this.deleteSet = createIdSet()
64
- /**
65
- * Describes the set of items that are cleaned up / deleted by ids. It is a subset of
66
- * this.deleteSet
67
- */
68
- this.cleanUps = createIdSet()
69
- /**
70
- * Describes the set of inserted items by ids
71
- */
72
- this.insertSet = createIdSet()
73
- /**
74
- * Holds the state before the transaction started.
75
- * @type {Map<Number,Number>?}
76
- */
77
- this._beforeState = null
78
- /**
79
- * Holds the state after the transaction.
80
- * @type {Map<Number,Number>?}
81
- */
82
- this._afterState = null
83
- /**
84
- * All types that were directly modified (property added or child
85
- * inserted/deleted). New types are not included in this Set.
86
- * Maps from type to parentSubs (`item.parentSub = null` for YArray)
87
- * @type {Map<import('../utils/types.js').YType,Set<String|null>>}
88
- */
89
- this.changed = new Map()
90
- /**
91
- * Stores the events for the types that observe also child elements.
92
- * It is mainly used by `observeDeep`.
93
- * @type {Map<import('../utils/types.js').YType,Array<YEvent<any>>>}
94
- */
95
- this.changedParentTypes = new Map()
96
- /**
97
- * @type {Array<AbstractStruct>}
98
- */
99
- this._mergeStructs = []
100
- /**
101
- * @type {any}
102
- */
103
- this.origin = origin
104
- /**
105
- * Stores meta information on the transaction
106
- * @type {Map<any,any>}
107
- */
108
- this.meta = new Map()
109
- /**
110
- * Whether this change originates from this doc.
111
- * @type {boolean}
112
- */
113
- this.local = local
114
- /**
115
- * @type {Set<Doc>}
116
- */
117
- this.subdocsAdded = new Set()
118
- /**
119
- * @type {Set<Doc>}
120
- */
121
- this.subdocsRemoved = new Set()
122
- /**
123
- * @type {Set<Doc>}
124
- */
125
- this.subdocsLoaded = new Set()
126
- /**
127
- * @type {boolean}
128
- */
129
- this._needFormattingCleanup = false
130
- this._done = false
131
- }
132
-
133
- /**
134
- * Holds the state before the transaction started.
135
- *
136
- * @deprecated
137
- * @type {Map<Number,Number>}
138
- */
139
- get beforeState () {
140
- if (this._beforeState == null) {
141
- const sv = getStateVector(this.doc.store)
142
- this.insertSet.clients.forEach((ranges, client) => {
143
- sv.set(client, ranges.getIds()[0].clock)
144
- })
145
- this._beforeState = sv
146
- }
147
- return this._beforeState
148
- }
149
-
150
- /**
151
- * Holds the state after the transaction.
152
- *
153
- * @deprecated
154
- * @type {Map<Number,Number>}
155
- */
156
- get afterState () {
157
- if (!this._done) error.unexpectedCase()
158
- if (this._afterState == null) {
159
- const sv = getStateVector(this.doc.store)
160
- this.insertSet.clients.forEach((_ranges, client) => {
161
- const ranges = _ranges.getIds()
162
- const d = ranges[ranges.length - 1]
163
- sv.set(client, d.clock + d.len)
164
- })
165
- this._afterState = sv
166
- }
167
- return this._afterState
168
- }
169
- }
170
-
171
- /**
172
- * @param {UpdateEncoderV1 | UpdateEncoderV2} encoder
173
- * @param {Transaction} transaction
174
- * @return {boolean} Whether data was written.
175
- */
176
- export const writeUpdateMessageFromTransaction = (encoder, transaction) => {
177
- if (transaction.deleteSet.clients.size === 0 && transaction.insertSet.clients.size === 0) {
178
- return false
179
- }
180
- writeStructsFromTransaction(encoder, transaction)
181
- writeIdSet(encoder, transaction.deleteSet)
182
- return true
183
- }
184
-
185
- /**
186
- * @param {Transaction} transaction
187
- *
188
- * @private
189
- * @function
190
- */
191
- export const nextID = transaction => {
192
- const y = transaction.doc
193
- return createID(y.clientID, getState(y.store, y.clientID))
194
- }
195
-
196
- /**
197
- * If `type.parent` was added in current transaction, `type` technically
198
- * did not change, it was just added and we should not fire events for `type`.
199
- *
200
- * @param {Transaction} transaction
201
- * @param {import('../utils/types.js').YType} type
202
- * @param {string|null} parentSub
203
- */
204
- export const addChangedTypeToTransaction = (transaction, type, parentSub) => {
205
- const item = type._item
206
- if (item === null || (!item.deleted && !transaction.insertSet.hasId(item.id))) {
207
- map.setIfUndefined(transaction.changed, type, set.create).add(parentSub)
208
- }
209
- }
210
-
211
- /**
212
- * @param {Array<AbstractStruct>} structs
213
- * @param {number} pos
214
- * @return {number} # of merged structs
215
- */
216
- const tryToMergeWithLefts = (structs, pos) => {
217
- let right = structs[pos]
218
- let left = structs[pos - 1]
219
- let i = pos
220
- for (; i > 0; right = left, left = structs[--i - 1]) {
221
- if (left.deleted === right.deleted && left.constructor === right.constructor) {
222
- if (left.mergeWith(right)) {
223
- if (right instanceof Item && right.parentSub !== null && /** @type {AbstractType<any>} */ (right.parent)._map.get(right.parentSub) === right) {
224
- /** @type {AbstractType<any>} */ (right.parent)._map.set(right.parentSub, /** @type {Item} */ (left))
225
- }
226
- continue
227
- }
228
- }
229
- break
230
- }
231
- const merged = pos - i
232
- if (merged) {
233
- // remove all merged structs from the array
234
- structs.splice(pos + 1 - merged, merged)
235
- }
236
- return merged
237
- }
238
-
239
- /**
240
- * @param {Transaction} tr
241
- * @param {IdSet} ds
242
- * @param {function(Item):boolean} gcFilter
243
- */
244
- const tryGcDeleteSet = (tr, ds, gcFilter) => {
245
- for (const [client, _deleteItems] of ds.clients.entries()) {
246
- const deleteItems = _deleteItems.getIds()
247
- const structs = /** @type {Array<GC|Item>} */ (tr.doc.store.clients.get(client))
248
- for (let di = deleteItems.length - 1; di >= 0; di--) {
249
- const deleteItem = deleteItems[di]
250
- const endDeleteItemClock = deleteItem.clock + deleteItem.len
251
- for (
252
- let si = findIndexSS(structs, deleteItem.clock), struct = structs[si];
253
- si < structs.length && struct.id.clock < endDeleteItemClock;
254
- struct = structs[++si]
255
- ) {
256
- const struct = structs[si]
257
- if (deleteItem.clock + deleteItem.len <= struct.id.clock) {
258
- break
259
- }
260
- if (struct instanceof Item && struct.deleted && !struct.keep && gcFilter(struct)) {
261
- struct.gc(tr, false)
262
- }
263
- }
264
- }
265
- }
266
- }
267
-
268
- /**
269
- * @param {IdSet} ds
270
- * @param {StructStore} store
271
- */
272
- const tryMerge = (ds, store) => {
273
- // try to merge deleted / gc'd items
274
- // merge from right to left for better efficiency and so we don't miss any merge targets
275
- ds.clients.forEach((_deleteItems, client) => {
276
- const deleteItems = _deleteItems.getIds()
277
- const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
278
- for (let di = deleteItems.length - 1; di >= 0; di--) {
279
- const deleteItem = deleteItems[di]
280
- // start with merging the item next to the last deleted item
281
- const mostRightIndexToCheck = math.min(structs.length - 1, 1 + findIndexSS(structs, deleteItem.clock + deleteItem.len - 1))
282
- for (
283
- let si = mostRightIndexToCheck, struct = structs[si];
284
- si > 0 && struct.id.clock >= deleteItem.clock;
285
- struct = structs[si]
286
- ) {
287
- si -= 1 + tryToMergeWithLefts(structs, si)
288
- }
289
- }
290
- })
291
- }
292
-
293
- /**
294
- * @param {Transaction} tr
295
- * @param {IdSet} idset
296
- * @param {function(Item):boolean} gcFilter
297
- */
298
- export const tryGc = (tr, idset, gcFilter) => {
299
- tryGcDeleteSet(tr, idset, gcFilter)
300
- tryMerge(idset, tr.doc.store)
301
- }
302
-
303
- /**
304
- * @param {Array<Transaction>} transactionCleanups
305
- * @param {number} i
306
- */
307
- const cleanupTransactions = (transactionCleanups, i) => {
308
- if (i < transactionCleanups.length) {
309
- const transaction = transactionCleanups[i]
310
- transaction._done = true
311
- const doc = transaction.doc
312
- const store = doc.store
313
- const ds = transaction.deleteSet
314
- const mergeStructs = transaction._mergeStructs
315
- // insertIntoIdSet(store.ds, ds)
316
- try {
317
- doc.emit('beforeObserverCalls', [transaction, doc])
318
- /**
319
- * An array of event callbacks.
320
- *
321
- * Each callback is called even if the other ones throw errors.
322
- *
323
- * @type {Array<function():void>}
324
- */
325
- const fs = []
326
- // observe events on changed types
327
- transaction.changed.forEach((subs, itemtype) =>
328
- fs.push(() => {
329
- if (itemtype._item === null || !itemtype._item.deleted) {
330
- itemtype._callObserver(transaction, subs)
331
- }
332
- })
333
- )
334
- fs.push(() => {
335
- // deep observe events
336
- transaction.changedParentTypes.forEach((events, type) => {
337
- // We need to think about the possibility that the user transforms the
338
- // Y.Doc in the event.
339
- if (type._dEH.l.length > 0 && (type._item === null || !type._item.deleted)) {
340
- events = events
341
- .filter(event =>
342
- event.target._item === null || !event.target._item.deleted
343
- )
344
- events
345
- .forEach(event => {
346
- event.currentTarget = type
347
- // path is relative to the current target
348
- event._path = null
349
- })
350
- // sort events by path length so that top-level events are fired first.
351
- events
352
- .sort((event1, event2) => event1.path.length - event2.path.length)
353
- // We don't need to check for events.length
354
- // because we know it has at least one element
355
- callEventHandlerListeners(type._dEH, events, transaction)
356
- }
357
- })
358
- })
359
- fs.push(() => doc.emit('afterTransaction', [transaction, doc]))
360
- callAll(fs, [])
361
- if (transaction._needFormattingCleanup && doc.cleanupFormatting) {
362
- cleanupYTextAfterTransaction(transaction)
363
- }
364
- } finally {
365
- // Replace deleted items with ItemDeleted / GC.
366
- // This is where content is actually remove from the Yjs Doc.
367
- if (doc.gc) {
368
- tryGcDeleteSet(transaction, ds, doc.gcFilter)
369
- }
370
- tryMerge(ds, store)
371
-
372
- // on all affected store.clients props, try to merge
373
- transaction.insertSet.clients.forEach((ids, client) => {
374
- const firstClock = ids.getIds()[0].clock
375
- const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
376
- // we iterate from right to left so we can safely remove entries
377
- const firstChangePos = math.max(findIndexSS(structs, firstClock), 1)
378
- for (let i = structs.length - 1; i >= firstChangePos;) {
379
- i -= 1 + tryToMergeWithLefts(structs, i)
380
- }
381
- })
382
- // try to merge mergeStructs
383
- // @todo: it makes more sense to transform mergeStructs to a DS, sort it, and merge from right to left
384
- // but at the moment DS does not handle duplicates
385
- for (let i = mergeStructs.length - 1; i >= 0; i--) {
386
- const { client, clock } = mergeStructs[i].id
387
- const structs = /** @type {Array<GC|Item>} */ (store.clients.get(client))
388
- const replacedStructPos = findIndexSS(structs, clock)
389
- if (replacedStructPos + 1 < structs.length) {
390
- if (tryToMergeWithLefts(structs, replacedStructPos + 1) > 1) {
391
- continue // no need to perform next check, both are already merged
392
- }
393
- }
394
- if (replacedStructPos > 0) {
395
- tryToMergeWithLefts(structs, replacedStructPos)
396
- }
397
- }
398
- if (!transaction.local && transaction.insertSet.clients.has(doc.clientID)) {
399
- logging.print(logging.ORANGE, logging.BOLD, '[yjs] ', logging.UNBOLD, logging.RED, 'Changed the client-id because another client seems to be using it.')
400
- doc.clientID = generateNewClientId()
401
- }
402
- // @todo Merge all the transactions into one and provide send the data as a single update message
403
- doc.emit('afterTransactionCleanup', [transaction, doc])
404
- if (doc._observers.has('update')) {
405
- const encoder = new UpdateEncoderV1()
406
- const hasContent = writeUpdateMessageFromTransaction(encoder, transaction)
407
- if (hasContent) {
408
- doc.emit('update', [encoder.toUint8Array(), transaction.origin, doc, transaction])
409
- }
410
- }
411
- if (doc._observers.has('updateV2')) {
412
- const encoder = new UpdateEncoderV2()
413
- const hasContent = writeUpdateMessageFromTransaction(encoder, transaction)
414
- if (hasContent) {
415
- doc.emit('updateV2', [encoder.toUint8Array(), transaction.origin, doc, transaction])
416
- }
417
- }
418
- const { subdocsAdded, subdocsLoaded, subdocsRemoved } = transaction
419
- if (subdocsAdded.size > 0 || subdocsRemoved.size > 0 || subdocsLoaded.size > 0) {
420
- subdocsAdded.forEach(subdoc => {
421
- subdoc.clientID = doc.clientID
422
- if (subdoc.collectionid == null) {
423
- subdoc.collectionid = doc.collectionid
424
- }
425
- doc.subdocs.add(subdoc)
426
- })
427
- subdocsRemoved.forEach(subdoc => doc.subdocs.delete(subdoc))
428
- doc.emit('subdocs', [{ loaded: subdocsLoaded, added: subdocsAdded, removed: subdocsRemoved }, doc, transaction])
429
- subdocsRemoved.forEach(subdoc => subdoc.destroy())
430
- }
431
-
432
- if (transactionCleanups.length <= i + 1) {
433
- doc._transactionCleanups = []
434
- doc.emit('afterAllTransactions', [doc, transactionCleanups])
435
- } else {
436
- cleanupTransactions(transactionCleanups, i + 1)
437
- }
438
- }
439
- }
440
- }
441
-
442
- /**
443
- * Implements the functionality of `y.transact(()=>{..})`
444
- *
445
- * @template T
446
- * @param {Doc} doc
447
- * @param {function(Transaction):T} f
448
- * @param {any} [origin=true]
449
- * @return {T}
450
- *
451
- * @function
452
- */
453
- export const transact = (doc, f, origin = null, local = true) => {
454
- const transactionCleanups = doc._transactionCleanups
455
- let initialCall = false
456
- /**
457
- * @type {any}
458
- */
459
- let result = null
460
- if (doc._transaction === null) {
461
- initialCall = true
462
- doc._transaction = new Transaction(doc, origin, local)
463
- transactionCleanups.push(doc._transaction)
464
- if (transactionCleanups.length === 1) {
465
- doc.emit('beforeAllTransactions', [doc])
466
- }
467
- doc.emit('beforeTransaction', [doc._transaction, doc])
468
- }
469
- try {
470
- result = f(doc._transaction)
471
- } finally {
472
- if (initialCall) {
473
- const finishCleanup = doc._transaction === transactionCleanups[0]
474
- doc._transaction = null
475
- if (finishCleanup) {
476
- // The first transaction ended, now process observer calls.
477
- // Observer call may create new transactions for which we need to call the observers and do cleanup.
478
- // We don't want to nest these calls, so we execute these calls one after
479
- // another.
480
- // Also we need to ensure that all cleanups are called, even if the
481
- // observes throw errors.
482
- // This file is full of hacky try {} finally {} blocks to ensure that an
483
- // event can throw errors and also that the cleanup is called.
484
- cleanupTransactions(transactionCleanups, 0)
485
- }
486
- }
487
- }
488
- return result
489
- }