Skip to content

Instantly share code, notes, and snippets.

@AdventureBeard
Created March 16, 2022 17:07
Show Gist options
  • Save AdventureBeard/4393adfbb8c7645c80d480b6237e53ee to your computer and use it in GitHub Desktop.
Save AdventureBeard/4393adfbb8c7645c80d480b6237e53ee to your computer and use it in GitHub Desktop.
import * as Y from 'yjs'
import {AbstractType} from 'yjs'
import {YXmlFragment} from "yjs/dist/src/types/YXmlFragment";
import { isEqual } from 'lodash'
type CopyParams = {
fromDoc: Y.Doc,
toDoc: Y.Doc
}
/**
*
* Apply destructive transformation so that {to} becomes equivalent to {from}.
*
* Ignore keys in ignore
*
* @param fromDoc
* @param toDoc
*/
export const copy = ({ fromDoc, toDoc }: CopyParams) => {
let changed = false
toDoc.transact(() => {
toDoc.share.forEach((value, key) => {
if (!fromDoc.share.has(key)) {
if (value instanceof Y.Map) {
value.forEach((v, k) => value.delete(k))
changed = true
} else if (value instanceof Y.Array) {
value.delete(0, value.length)
changed = true
} else if (value instanceof Y.Text) {
value.delete(0, value.length)
changed = true
} else if (value instanceof Y.XmlFragment) {
value.delete(0, value.length)
}
}
})
fromDoc.share.forEach((from, key) => {
if (from instanceof Y.Map) {
let to = toDoc.getMap(key)
if (deepEqual(from, to)) return
copyMap(from, to)
changed = true
} else if (from instanceof Y.Array) {
let to = toDoc.getArray(key)
if (deepEqual(from, to)) return
copyArray(from, to)
changed = true
} else if (from instanceof Y.Text) {
let to = toDoc.getText(key)
if (deepEqual(from, to)) return
copyText(from, to)
changed = true
} else if (from instanceof Y.XmlFragment) {
let to = toDoc.getXmlFragment(key)
if (deepEqual(from, to)) return
copyXmlFragment(from, to)
changed = true
}
})
})
return { doc: toDoc, changed }
}
const copyArray = (from: Y.Array<any>, to: Y.Array<any>) => {
to.delete(0, to.length)
to.insert(0, from.toArray().map( el =>
el instanceof AbstractType ? el.clone() : el
))
return to
}
const copyMap = (from: Y.Map<any>, to: Y.Map<any>) => {
to.forEach((value, key) => {
to.delete(key)
})
from.forEach((value, key) => {
to.set(key, value instanceof AbstractType ? value.clone() : value)
})
return to
}
const copyText = (from: Y.Text, to: Y.Text) => {
to.delete(0, to.length)
to.applyDelta(from.toDelta())
return to
}
const copyXmlFragment = (from: YXmlFragment, to: YXmlFragment) => {
to.delete(0, to.length)
// @ts-ignore
to.insert(0, from.toArray().map(item => item instanceof AbstractType ? item.clone() : item))
return to
}
const deepEqual = (a: AbstractType<any>, b: AbstractType<any>) => {
let objA = a.toJSON()
let objB = b.toJSON()
return isEqual(objA, objB)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment