UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

135 lines (134 loc) 4.9 kB
"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;