json-joy
Version:
Collection of libraries for building collaborative editing apps.
167 lines (166 loc) • 5.85 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 ClockDecoder_1 = require("../../../../json-crdt-patch/codec/clock/ClockDecoder");
const clock_1 = require("../../../../json-crdt-patch/clock");
const Model_1 = require("../../../model/Model");
const constants_1 = require("../../../../json-crdt-patch/constants");
class Decoder {
decode(doc) {
const [time, root] = doc;
const isServerTime = typeof time === 'number';
if (isServerTime) {
this.time = time;
}
else {
this.clockDecoder = ClockDecoder_1.ClockDecoder.fromArr(time);
}
const model = isServerTime
? Model_1.Model.withServerClock(time)
: Model_1.Model.withLogicalClock(this.clockDecoder.clock);
const val = root ? this.decNode(model, root) : Model_1.UNDEFINED;
model.root = new nodes.RootNode(model, val.id);
return model;
}
ts(x) {
if (typeof x === 'number') {
return new clock_1.Timestamp(constants_1.SESSION.SERVER, this.time - x);
}
else {
const [sid, time] = x;
if (sid < 0) {
return this.clockDecoder.decodeId(-sid, time);
}
else {
return new clock_1.Timestamp(sid, time);
}
}
}
decNode(model, node) {
switch (node[0]) {
case constants_1.JsonCrdtDataType.con:
return this.decCon(model, node);
case constants_1.JsonCrdtDataType.val:
return this.decVal(model, node);
case constants_1.JsonCrdtDataType.obj:
return this.decObj(model, node);
case constants_1.JsonCrdtDataType.vec:
return this.decVec(model, node);
case constants_1.JsonCrdtDataType.str:
return this.decStr(model, node);
case constants_1.JsonCrdtDataType.bin:
return this.decBin(model, node);
case constants_1.JsonCrdtDataType.arr:
return this.decArr(model, node);
}
throw new Error('UNKNOWN_NODE');
}
decCon(doc, node) {
const id = this.ts(node[1]);
let data = node[2];
if (node.length > 3) {
const specialData = node[3];
if (!specialData)
data = undefined;
else
data = this.ts(specialData);
}
const obj = new nodes.ConNode(id, data);
doc.index.set(id, obj);
return obj;
}
decVal(doc, node) {
const id = this.ts(node[1]);
const child = this.decNode(doc, node[2]);
const obj = new nodes.ValNode(doc, id, child.id);
doc.index.set(id, obj);
return obj;
}
decObj(model, node) {
const id = this.ts(node[1]);
const obj = new nodes.ObjNode(model, id);
const map = node[2];
const keys = Object.keys(map);
const length = keys.length;
for (let i = 0; i < length; i++) {
const key = keys[i];
const val = this.decNode(model, map[key]);
obj.put(key, val.id);
}
model.index.set(id, obj);
return obj;
}
decVec(model, node) {
const id = this.ts(node[1]);
const obj = new nodes.VecNode(model, id);
const map = node[2];
const elements = obj.elements;
const length = map.length;
for (let i = 0; i < length; i++) {
const item = map[i];
if (!item)
elements.push(undefined);
else {
const child = this.decNode(model, item);
elements.push(child.id);
}
}
model.index.set(id, obj);
return obj;
}
decStr(doc, node) {
const id = this.ts(node[1]);
const obj = new nodes.StrNode(id);
const chunks = node[2];
const size = chunks.length;
let i = 0;
obj.ingest(size, () => {
const chunk = chunks[i++];
const chunkId = this.ts(chunk[0]);
const content = chunk[1];
if (typeof content === 'number')
return new nodes.StrChunk(chunkId, content, '');
return new nodes.StrChunk(chunkId, content.length, content);
});
doc.index.set(id, obj);
return obj;
}
decBin(doc, node) {
const id = this.ts(node[1]);
const obj = new nodes.BinNode(id);
const chunks = node[2];
const size = chunks.length;
let i = 0;
obj.ingest(size, () => {
const chunk = chunks[i++];
const chunkId = this.ts(chunk[0]);
const content = chunk[1];
if (typeof content === 'number')
return new nodes.BinChunk(chunkId, content, undefined);
return new nodes.BinChunk(chunkId, content.length, content);
});
doc.index.set(id, obj);
return obj;
}
decArr(doc, node) {
const id = this.ts(node[1]);
const obj = new nodes.ArrNode(doc, id);
const chunks = node[2];
const size = chunks.length;
let i = 0;
obj.ingest(size, () => {
const chunk = chunks[i++];
const chunkId = this.ts(chunk[0]);
const content = chunk[1];
if (typeof content === 'number')
return new nodes.ArrChunk(chunkId, content, undefined);
const ids = content.map((c) => this.decNode(doc, c).id);
return new nodes.ArrChunk(chunkId, content.length, ids);
});
doc.index.set(id, obj);
return obj;
}
}
exports.Decoder = Decoder;