json-joy
Version:
Collection of libraries for building collaborative editing apps.
135 lines (134 loc) • 4.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Encoder = void 0;
const tslib_1 = require("tslib");
const nodes = tslib_1.__importStar(require("../../../nodes"));
const ClockEncoder_1 = require("../../../../json-crdt-patch/codec/clock/ClockEncoder");
const clock_1 = require("../../../../json-crdt-patch/clock");
const constants_1 = require("../../../../json-crdt-patch/constants");
const constants_2 = require("../../../../json-crdt-patch/constants");
class Encoder {
encode(model) {
this.model = model;
const isServerTime = model.clock.sid === constants_2.SESSION.SERVER;
const clock = model.clock;
if (isServerTime) {
this.time = clock.time;
}
else {
this.clock = new ClockEncoder_1.ClockEncoder();
this.clock.reset(model.clock);
}
const root = model.root;
const doc = [0, !root.val.time ? 0 : this.cNode(root.node())];
doc[0] = isServerTime ? this.time : this.clock.toJson();
return doc;
}
ts(ts) {
switch (ts.sid) {
case constants_2.SESSION.SYSTEM:
return [ts.sid, ts.time];
case constants_2.SESSION.SERVER:
return this.time - ts.time;
default: {
const relativeId = this.clock.append(ts);
return [-relativeId.sessionIndex, relativeId.timeDiff];
}
}
}
cNode(node) {
// TODO: PERF: use switch with `node.constructor`.
if (node instanceof nodes.ObjNode)
return this.cObj(node);
else if (node instanceof nodes.ArrNode)
return this.cArr(node);
else if (node instanceof nodes.StrNode)
return this.cStr(node);
else if (node instanceof nodes.ValNode)
return this.cVal(node);
else if (node instanceof nodes.VecNode)
return this.cVec(node);
else if (node instanceof nodes.ConNode)
return this.cCon(node);
else if (node instanceof nodes.BinNode)
return this.cBin(node);
throw new Error('UNKNOWN_NODE');
}
cObj(obj) {
const map = {};
obj.nodes((child, key) => (map[key] = this.cNode(child)));
const res = [constants_1.JsonCrdtDataType.obj, this.ts(obj.id), map];
return res;
}
cVec(vec) {
const elements = vec.elements;
const length = elements.length;
const index = this.model.index;
const map = [];
for (let i = 0; i < length; i++) {
const elementId = elements[i];
if (!elementId)
map.push(0);
else {
const node = index.get(elementId);
map.push(this.cNode(node));
}
}
const res = [constants_1.JsonCrdtDataType.vec, this.ts(vec.id), map];
return res;
}
cArr(node) {
const chunks = [];
const index = this.model.index;
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
const deleted = chunk.del;
const span = chunk.span;
const chunkIdEncoded = this.ts(chunk.id);
if (deleted) {
chunks.push([chunkIdEncoded, span]);
}
else {
const nodeIds = chunk.data;
const nodes = [];
for (let i = 0; i < span; i++)
nodes.push(this.cNode(index.get(nodeIds[i])));
chunks.push([chunkIdEncoded, nodes]);
}
}
const res = [constants_1.JsonCrdtDataType.arr, this.ts(node.id), chunks];
return res;
}
cStr(node) {
const chunks = [];
for (let chunk = node.first(); chunk; chunk = node.next(chunk))
chunks.push([this.ts(chunk.id), chunk.del ? chunk.span : chunk.data]);
const res = [constants_1.JsonCrdtDataType.str, this.ts(node.id), chunks];
return res;
}
cBin(node) {
const chunks = [];
for (let chunk = node.first(); chunk; chunk = node.next(chunk))
chunks.push([this.ts(chunk.id), chunk.del ? chunk.span : chunk.data]);
const res = [constants_1.JsonCrdtDataType.bin, this.ts(node.id), chunks];
return res;
}
cVal(node) {
const res = [constants_1.JsonCrdtDataType.val, this.ts(node.id), this.cNode(node.node())];
return res;
}
cCon(node) {
const val = node.val;
const res = [constants_1.JsonCrdtDataType.con, this.ts(node.id), val];
if (val instanceof clock_1.Timestamp) {
res[2] = 0;
const specialData = this.ts(val);
res.push(specialData);
}
else if (val === undefined) {
res[2] = 0;
res.push(0);
}
return res;
}
}
exports.Encoder = Encoder;