UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

184 lines (183 loc) 7.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Decoder = void 0; const tslib_1 = require("tslib"); const ClockDecoder_1 = require("../../../../json-crdt-patch/codec/clock/ClockDecoder"); const CrdtReader_1 = require("../../../../json-crdt-patch/util/binary/CrdtReader"); const Model_1 = require("../../../model/Model"); const CborDecoderBase_1 = require("@jsonjoy.com/json-pack/lib/cbor/CborDecoderBase"); const nodes = tslib_1.__importStar(require("../../../nodes")); const constants_1 = require("../../structural/binary/constants"); const insertion_1 = require("@jsonjoy.com/util/lib/sort/insertion"); const constants_2 = require("../../../../json-crdt-patch/constants"); class Decoder { constructor() { this.clockDecoder = undefined; this.time = -1; this.decoder = new CborDecoderBase_1.CborDecoderBase(new CrdtReader_1.CrdtReader()); } decode(view, meta) { this.clockDecoder = undefined; this.time = -1; this.decoder.reader.reset(meta); this.decodeClockTable(); const clock = this.clockDecoder.clock; this.doc = Model_1.Model.withLogicalClock(clock); this.doc.root = new nodes.RootNode(this.doc, this.cRoot(view).id); this.clockDecoder = undefined; return this.doc; } decodeClockTable() { const reader = this.decoder.reader; const clockTableOffset = reader.u32(); const offset = reader.x; reader.x += clockTableOffset; const length = reader.vu57(); const sessionId = reader.vu57(); const time = reader.vu57(); this.clockDecoder = new ClockDecoder_1.ClockDecoder(sessionId, time); for (let i = 1; i < length; i++) { const sid = reader.vu57(); const time = reader.vu57(); this.clockDecoder.pushTuple(sid, time); } reader.x = offset; } ts() { const decoderTime = this.time; const [sessionIndex, timeDiff] = this.decoder.reader.id(); return this.clockDecoder.decodeId(sessionIndex, timeDiff); } cRoot(view) { const reader = this.decoder.reader; const peek = reader.uint8[reader.x]; return !peek ? Model_1.UNDEFINED : this.cNode(view); } cNode(view) { const reader = this.decoder.reader; const id = this.ts(); const octet = reader.u8(); const major = octet >> 5; const minor = octet & 0b11111; const length = minor < 24 ? minor : minor === 24 ? reader.u8() : minor === 25 ? reader.u16() : reader.u32(); switch (major) { case constants_1.CRDT_MAJOR.CON: return this.cCon(view, id, length); case constants_1.CRDT_MAJOR.VAL: return this.cVal(view, id); case constants_1.CRDT_MAJOR.OBJ: return this.cObj(view, id, length); case constants_1.CRDT_MAJOR.VEC: return this.cVec(view, id, length); case constants_1.CRDT_MAJOR.STR: return this.cStr(view, id, length); case constants_1.CRDT_MAJOR.BIN: return this.cBin(view, id, length); case constants_1.CRDT_MAJOR.ARR: return this.cArr(view, id, length); } throw new Error('UNKNOWN_NODE'); } cCon(view, id, length) { const doc = this.doc; const node = new nodes.ConNode(id, length ? this.ts() : view); doc.index.set(id, node); return node; } cVal(view, id) { const child = this.cNode(view); const doc = this.doc; const node = new nodes.ValNode(doc, id, child.id); doc.index.set(id, node); return node; } cObj(view, id, length) { const obj = new nodes.ObjNode(this.doc, id); if (!view || typeof view !== 'object') throw new Error('INVALID_OBJ'); const keys = (0, insertion_1.sort)(Object.keys(view)); if (keys.length !== length) throw new Error('INVALID_OBJ'); const objKeys = obj.keys; for (let i = 0; i < length; i++) { const key = keys[i]; const childNode = this.cNode(view[key]); objKeys.set(key, childNode.id); } this.doc.index.set(id, obj); return obj; } cVec(view, id, length) { const obj = new nodes.VecNode(this.doc, id); if (!Array.isArray(view) || view.length !== length) throw new Error('INVALID_VEC'); const elements = obj.elements; const reader = this.decoder.reader; for (let i = 0; i < length; i++) { const child = this.cNode(view[i]); const childId = child.id; if (childId.sid === constants_2.SESSION.SYSTEM) elements.push(undefined); else elements.push(childId); } this.doc.index.set(id, obj); return obj; } cStr(view, id, length) { if (typeof view !== 'string') throw new Error('INVALID_STR'); const node = new nodes.StrNode(id); const reader = this.decoder.reader; let offset = 0; node.ingest(length, () => { const id = this.ts(); const [deleted, span] = reader.b1vu56(); if (deleted) return new nodes.StrChunk(id, span, ''); const text = view.slice(offset, offset + span); offset += span; return new nodes.StrChunk(id, text.length, text); }); this.doc.index.set(id, node); return node; } cBin(view, id, length) { if (!(view instanceof Uint8Array)) throw new Error('INVALID_BIN'); const node = new nodes.BinNode(id); const reader = this.decoder.reader; let offset = 0; node.ingest(length, () => { const id = this.ts(); const [deleted, span] = reader.b1vu56(); if (deleted) return new nodes.BinChunk(id, span, undefined); const slice = view.slice(offset, offset + span); offset += span; return new nodes.BinChunk(id, slice.length, slice); }); this.doc.index.set(id, node); return node; } cArr(view, id, length) { if (!Array.isArray(view)) throw new Error('INVALID_ARR'); const obj = new nodes.ArrNode(this.doc, id); const reader = this.decoder.reader; let i = 0; obj.ingest(length, () => { const id = this.ts(); const [deleted, span] = reader.b1vu56(); if (deleted) return new nodes.ArrChunk(id, span, undefined); const ids = []; for (let j = 0; j < span; j++) ids.push(this.cNode(view[i++]).id); return new nodes.ArrChunk(id, span, ids); }); this.doc.index.set(id, obj); return obj; } } exports.Decoder = Decoder;