UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

164 lines (163 loc) 5.71 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Decoder = void 0; const tslib_1 = require("tslib"); const nodes = tslib_1.__importStar(require("../../../nodes")); const fromBase64_1 = require("@jsonjoy.com/base64/lib/fromBase64"); const clock_1 = require("../../../../json-crdt-patch/clock"); const model_1 = require("../../../model"); const constants_1 = require("../../../../json-crdt-patch/constants"); class Decoder { decode({ time, root }) { const isServerClock = typeof time === 'number'; const doc = isServerClock ? model_1.Model.withServerClock(time) : model_1.Model.withLogicalClock(this.cClock(time)); this.cRoot(doc, root); return doc; } cClock(timestamps) { const [stamp] = timestamps; const vectorClock = new clock_1.ClockVector(stamp[0], stamp[1]); const length = timestamps.length; for (let i = 1; i < length; i++) { const stamp = timestamps[i]; const [sessionId, time] = stamp; vectorClock.observe((0, clock_1.ts)(sessionId, time), 1); } return vectorClock; } cTs(stamp) { const isServerClock = typeof stamp === 'number'; return isServerClock ? (0, clock_1.ts)(constants_1.SESSION.SERVER, stamp) : (0, clock_1.ts)(stamp[0], stamp[1]); } cRoot(doc, { value }) { const val = value ? this.cNode(doc, value) : new nodes.ConNode(doc.clock.tick(0), null); const root = new nodes.RootNode(doc, val.id); doc.root = root; } cNode(doc, node) { switch (node.type) { case 'obj': return this.cObj(doc, node); case 'arr': return this.cArr(doc, node); case 'str': return this.cStr(doc, node); case 'val': return this.cVal(doc, node); case 'con': return this.cCon(doc, node); case 'vec': return this.cVec(doc, node); case 'bin': return this.cBin(doc, node); } throw new Error('UNKNOWN_NODE'); } cObj(doc, node) { const id = this.cTs(node.id); const obj = new nodes.ObjNode(doc, id); const map = node.map; const keys = Object.keys(map); for (const key of keys) { const keyNode = map[key]; obj.put(key, this.cNode(doc, keyNode).id); } doc.index.set(id, obj); return obj; } cVec(doc, node) { const id = this.cTs(node.id); const obj = new nodes.VecNode(doc, id); const elements = obj.elements; const map = node.map; const length = map.length; for (let i = 0; i < length; i++) { const component = map[i]; if (!component) elements.push(undefined); else elements.push(this.cNode(doc, component).id); } doc.index.set(id, obj); return obj; } cArr(doc, node) { const id = this.cTs(node.id); const rga = new nodes.ArrNode(doc, id); const chunks = node.chunks; const length = chunks.length; if (length) { let i = 0; rga.ingest(length, () => { const c = chunks[i++]; const id = this.cTs(c.id); if (typeof c.span === 'number') return new nodes.ArrChunk(id, c.span, undefined); else { const ids = c.value.map((n) => this.cNode(doc, n).id); return new nodes.ArrChunk(id, ids.length, ids); } }); } doc.index.set(id, rga); return rga; } cStr(doc, node) { const id = this.cTs(node.id); const rga = new nodes.StrNode(id); const chunks = node.chunks; const length = chunks.length; if (length) { let i = 0; rga.ingest(length, () => { const c = chunks[i++]; const id = this.cTs(c.id); if (typeof c.span === 'number') return new nodes.StrChunk(id, c.span, ''); else { const value = c.value; return new nodes.StrChunk(id, value.length, value); } }); } doc.index.set(id, rga); return rga; } cBin(doc, node) { const id = this.cTs(node.id); const rga = new nodes.BinNode(id); const chunks = node.chunks; const length = chunks.length; if (length) { let i = 0; rga.ingest(length, () => { const c = chunks[i++]; const id = this.cTs(c.id); if (typeof c.span === 'number') return new nodes.BinChunk(id, c.span, undefined); else { const value = c.value; const buf = (0, fromBase64_1.fromBase64)(value); return new nodes.BinChunk(id, buf.length, buf); } }); } doc.index.set(id, rga); return rga; } cVal(doc, node) { const id = this.cTs(node.id); const val = this.cNode(doc, node.value); const obj = new nodes.ValNode(doc, id, val.id); doc.index.set(id, obj); return obj; } cCon(doc, node) { const id = this.cTs(node.id); const val = node.timestamp ? this.cTs(node.value) : node.value; const obj = new nodes.ConNode(id, val); doc.index.set(id, obj); return obj; } } exports.Decoder = Decoder;