mirror of
https://github.com/yjs/yjs.git
synced 2025-12-16 11:47:46 +01:00
implement diffDocsToDelta
This commit is contained in:
@@ -120,7 +120,8 @@ export {
|
|||||||
mergeIdMaps,
|
mergeIdMaps,
|
||||||
readIdMap,
|
readIdMap,
|
||||||
readIdSet,
|
readIdSet,
|
||||||
decodeIdMap
|
decodeIdMap,
|
||||||
|
diffDocsToDelta
|
||||||
} from './internals.js'
|
} from './internals.js'
|
||||||
|
|
||||||
const glo = /** @type {any} */ (typeof globalThis !== 'undefined'
|
const glo = /** @type {any} */ (typeof globalThis !== 'undefined'
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export * from './utils/YEvent.js'
|
|||||||
export * from './utils/StructSet.js'
|
export * from './utils/StructSet.js'
|
||||||
export * from './utils/IdMap.js'
|
export * from './utils/IdMap.js'
|
||||||
export * from './utils/AttributionManager.js'
|
export * from './utils/AttributionManager.js'
|
||||||
|
export * from './utils/delta-helpers.js'
|
||||||
|
|
||||||
export * from './types/AbstractType.js'
|
export * from './types/AbstractType.js'
|
||||||
export * from './types/YArray.js'
|
export * from './types/YArray.js'
|
||||||
|
|||||||
@@ -1351,7 +1351,7 @@ export const typeMapGetDelta = (d, parent, attrsToRender, am, deep, modified, de
|
|||||||
if (attrsToRender == null) {
|
if (attrsToRender == null) {
|
||||||
parent._map.forEach(renderAttrs)
|
parent._map.forEach(renderAttrs)
|
||||||
} else {
|
} else {
|
||||||
attrsToRender.forEach(key => renderAttrs(/** @type {Item} */ (parent._map.get(key)), key))
|
attrsToRender.forEach(key => key != null && renderAttrs(/** @type {Item} */ (parent._map.get(key)), key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
54
src/utils/delta-helpers.js
Normal file
54
src/utils/delta-helpers.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import {
|
||||||
|
createInsertSetFromStructStore,
|
||||||
|
createDeleteSetFromStructStore,
|
||||||
|
createAttributionManagerFromDiff,
|
||||||
|
diffIdSet,
|
||||||
|
mergeIdSets,
|
||||||
|
Item,
|
||||||
|
AbstractType, Doc, // eslint-disable-line
|
||||||
|
iterateStructsByIdSet
|
||||||
|
} from '../internals.js'
|
||||||
|
import * as delta from 'lib0/delta'
|
||||||
|
import * as map from 'lib0/map'
|
||||||
|
import * as set from 'lib0/set'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Doc} v1
|
||||||
|
* @param {Doc} v2
|
||||||
|
* @return {delta.DeltaBuilderAny}
|
||||||
|
*/
|
||||||
|
export const diffDocsToDelta = (v1, v2, { am = createAttributionManagerFromDiff(v1, v2) } = {}) => {
|
||||||
|
const d = delta.create()
|
||||||
|
v2.transact(tr => {
|
||||||
|
v2.share.forEach((type, typename) => {
|
||||||
|
const insertDiff = diffIdSet(createInsertSetFromStructStore(v2.store, false), createInsertSetFromStructStore(v1.store, false))
|
||||||
|
const deleteDiff = diffIdSet(createDeleteSetFromStructStore(v2.store), createDeleteSetFromStructStore(v1.store))
|
||||||
|
// don't render items that have been inserted and then deleted
|
||||||
|
const insertsOnly = diffIdSet(insertDiff, deleteDiff)
|
||||||
|
const deletesOnly = diffIdSet(deleteDiff, insertDiff)
|
||||||
|
const itemsToRender = mergeIdSets([insertsOnly, deleteDiff])
|
||||||
|
/**
|
||||||
|
* @type {Map<AbstractType, Set<string|null>>}
|
||||||
|
*/
|
||||||
|
const changedTypes = new Map()
|
||||||
|
iterateStructsByIdSet(tr, itemsToRender, /** @param {any} item */ item => {
|
||||||
|
while (item instanceof Item) {
|
||||||
|
const parent = /** @type {AbstractType} */ (item.parent)
|
||||||
|
const conf = map.setIfUndefined(changedTypes, parent, set.create)
|
||||||
|
if (conf.has(item.parentSub)) break // has already been marked as modified
|
||||||
|
conf.add(item.parentSub)
|
||||||
|
item = parent._item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const typeConf = changedTypes.get(type)
|
||||||
|
if (typeConf) {
|
||||||
|
// @ts-ignore
|
||||||
|
const shareDelta = type.getContent(am, {
|
||||||
|
itemsToRender, retainDeletes: true, renderAttrs: /** @type {Set<string>} */ (changedTypes.get(type)), renderChildren: typeConf.has(null), deletedItems: deletesOnly, modified: changedTypes, deep: true
|
||||||
|
})
|
||||||
|
d.update(typename, shareDelta)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return d
|
||||||
|
}
|
||||||
@@ -86,3 +86,25 @@ export const testInsertionsIntoAttributedContent = _tc => {
|
|||||||
ytext.applyDelta(delta.text().retain(9).insert('l'), am)
|
ytext.applyDelta(delta.text().retain(9).insert('l'), am)
|
||||||
t.assert(ytext.toString() === 'hello world')
|
t.assert(ytext.toString() === 'hello world')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const testYdocDiff = () => {
|
||||||
|
const ydocStart = new Y.Doc()
|
||||||
|
ydocStart.getText('text').insert(0, 'hello')
|
||||||
|
ydocStart.getArray('array').insert(0, [1, 2, 3])
|
||||||
|
ydocStart.getMap('map').set('k', 42)
|
||||||
|
ydocStart.getMap('map').set('nested', new Y.Array())
|
||||||
|
const ydocUpdated = Y.cloneDoc(ydocStart)
|
||||||
|
ydocUpdated.getText('text').insert(5, ' world')
|
||||||
|
ydocUpdated.getArray('array').insert(1, ['x'])
|
||||||
|
ydocUpdated.getMap('map').set('newk', 42)
|
||||||
|
ydocUpdated.getMap('map').get('nested').insert(0, [1])
|
||||||
|
// @todo add custom attribution
|
||||||
|
const d = Y.diffDocsToDelta(ydocStart, ydocUpdated)
|
||||||
|
t.compare(d, delta.create()
|
||||||
|
.update('text', delta.create().retain(5).insert('world'))
|
||||||
|
.update('array', delta.create().retain(1).insert(['x']))
|
||||||
|
.update('map', delta.create().set('newk', 42).update('nested', delta.create().insert([1])))
|
||||||
|
)
|
||||||
|
console.log(d.toJSON())
|
||||||
|
debugger
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user