diff --git a/src/index.js b/src/index.js index 3daecee2..af555a23 100644 --- a/src/index.js +++ b/src/index.js @@ -72,5 +72,6 @@ export { tryGc, transact, AbstractConnector, - logType + logType, + mergeUpdates } from './internals.js' diff --git a/src/internals.js b/src/internals.js index 1984739b..5d32f0ad 100644 --- a/src/internals.js +++ b/src/internals.js @@ -15,6 +15,7 @@ export * from './utils/Snapshot.js' export * from './utils/StructStore.js' export * from './utils/Transaction.js' export * from './utils/UndoManager.js' +export * from './utils/updates.js' export * from './utils/YEvent.js' export * from './types/AbstractType.js' diff --git a/src/utils/updates.js b/src/utils/updates.js new file mode 100644 index 00000000..946ff9cb --- /dev/null +++ b/src/utils/updates.js @@ -0,0 +1,16 @@ + +/** + * @param {Array} updates + * @return {Uint8Array} + */ +export const mergeUpdates = updates => { + return updates[0] +} + +/** + * @param {Uint8Array} update + * @param {Uint8Array} sv + */ +export const diffUpdate = (update, sv) => { + return update +} diff --git a/tests/index.js b/tests/index.js index aec3ae5a..f8b453ed 100644 --- a/tests/index.js +++ b/tests/index.js @@ -8,6 +8,7 @@ import * as undoredo from './undo-redo.tests.js' import * as compatibility from './compatibility.tests.js' import * as doc from './doc.tests.js' import * as snapshot from './snapshot.tests.js' +import * as updates from './updates.tests.js' import { runTests } from 'lib0/testing.js' import { isBrowser, isNode } from 'lib0/environment.js' @@ -17,7 +18,7 @@ if (isBrowser) { log.createVConsole(document.body) } runTests({ - doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot + doc, map, array, text, xml, encoding, undoredo, compatibility, snapshot, updates }).then(success => { /* istanbul ignore next */ if (isNode) { diff --git a/tests/updates.tests.js b/tests/updates.tests.js new file mode 100644 index 00000000..70084273 --- /dev/null +++ b/tests/updates.tests.js @@ -0,0 +1,64 @@ +import * as t from 'lib0/testing.js' +import { init, compare } from './testHelper.js' // eslint-disable-line +import * as Y from '../src/index.js' + +/** + * @param {Array} users + */ +const fromUpdates = users => { + const updates = users.map(user => + Y.encodeStateAsUpdate(user) + ) + const ydoc = new Y.Doc() + Y.applyUpdate(ydoc, Y.mergeUpdates(updates)) + return ydoc +} + +/** + * @param {t.TestCase} tc + */ +export const testMergeUpdates = tc => { + const { users, array0, array1 } = init(tc, { users: 3 }) + + array0.insert(0, [1]) + array1.insert(0, [2]) + + const merged = fromUpdates(users) + compare(users) + t.compareArrays(array0.toArray(), merged.getArray('array').toArray()) +} + +/** + * @param {t.TestCase} tc + */ +export const testMergeUpdatesWrongOrder = tc => { + const ydoc = new Y.Doc() + const updates = /** @type {Array} */ ([]) + ydoc.on('update', update => { updates.push(update) }) + + const array = ydoc.getArray() + array.insert(0, [1]) + array.insert(0, [2]) + array.insert(0, [3]) + array.insert(0, [4]) + + const wrongOrder = Y.mergeUpdates([ + Y.mergeUpdates(updates.slice(2)), + Y.mergeUpdates(updates.slice(0, 2)) + ]) + const overlapping = Y.mergeUpdates([ + Y.mergeUpdates(updates.slice(2)), + Y.mergeUpdates(updates.slice(1, 3)), + updates[0] + ]) + const separated = Y.mergeUpdates([ + Y.mergeUpdates([updates[0], updates[2]]), + Y.mergeUpdates([updates[1], updates[3]]) + ]) + + ;[wrongOrder, overlapping, separated].forEach(updates => { + const merged = new Y.Doc() + Y.applyUpdate(merged, updates) + t.compareArrays(merged.getArray().toArray(), array.toArray()) + }) +}