UNPKG

mobx-keystone-yjs

Version:

Yjs bindings for mobx-keystone

99 lines (94 loc) 3.23 kB
import { Patch } from "mobx-keystone" import * as Y from "yjs" import { failure } from "../utils/error" import { convertJsonToYjsData } from "./convertJsonToYjsData" import { PlainValue } from "../plainTypes" export function applyMobxKeystonePatchToYjsObject(patch: Patch, yjs: unknown): void { if (patch.path.length > 1) { const [key, ...rest] = patch.path if (yjs instanceof Y.Map) { const child = yjs.get(String(key)) as unknown if (child === undefined) { throw failure( `invalid patch path, key "${key}" not found in Yjs map - patch: ${JSON.stringify(patch)}` ) } applyMobxKeystonePatchToYjsObject({ ...patch, path: rest }, child) } else if (yjs instanceof Y.Array) { const child = yjs.get(Number(key)) as unknown if (child === undefined) { throw failure( `invalid patch path, key "${key}" not found in Yjs array - patch: ${JSON.stringify( patch )}` ) } applyMobxKeystonePatchToYjsObject({ ...patch, path: rest }, child) } else if (yjs instanceof Y.Text) { // changes to deltaList will be handled by the array observe in the YjsTextModel class } else { throw failure( `invalid patch path, key "${key}" not found in unknown Yjs object - patch: ${JSON.stringify( patch )}` ) } } else if (patch.path.length === 1) { if (yjs instanceof Y.Map) { const key = String(patch.path[0]) switch (patch.op) { case "add": case "replace": { yjs.set(key, convertJsonToYjsData(patch.value as PlainValue)) break } case "remove": { yjs.delete(key) break } default: { throw failure(`invalid patch operation for map`) } } } else if (yjs instanceof Y.Array) { const key = patch.path[0] switch (patch.op) { case "replace": { if (key === "length") { const newLength = patch.value as number if (yjs.length > newLength) { const toDelete = yjs.length - newLength yjs.delete(newLength, toDelete) } else if (yjs.length < patch.value) { const toInsert = patch.value - yjs.length yjs.insert(yjs.length, Array.from({ length: toInsert }).fill(undefined)) } } else { yjs.delete(Number(key)) yjs.insert(Number(key), [convertJsonToYjsData(patch.value as PlainValue)]) } break } case "add": { yjs.insert(Number(key), [convertJsonToYjsData(patch.value as PlainValue)]) break } case "remove": { yjs.delete(Number(key)) break } default: { throw failure(`invalid patch operation for array`) } } } else if (yjs instanceof Y.Text) { // initialization of a YjsTextModel, do nothing } else { throw failure( `invalid patch path, the Yjs object is of an unkown type, so key "${String(patch.path[0])}" cannot be found in it` ) } } else { throw failure(`invalid patch path, it cannot be empty`) } }