json-joy
Version:
Collection of libraries for building collaborative editing apps.
164 lines (163 loc) • 5.71 kB
JavaScript
"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;