json-joy
Version:
Collection of libraries for building collaborative editing apps.
176 lines (175 loc) • 6.23 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Encoder = void 0;
const tslib_1 = require("tslib");
const clock_1 = require("../../../../json-crdt-patch/clock");
const ClockTable_1 = require("../../../../json-crdt-patch/codec/clock/ClockTable");
const CrdtWriter_1 = require("../../../../json-crdt-patch/util/binary/CrdtWriter");
const CborEncoder_1 = require("@jsonjoy.com/json-pack/lib/cbor/CborEncoder");
const nodes = tslib_1.__importStar(require("../../../nodes"));
const constants_1 = require("../../structural/binary/constants");
class Encoder {
constructor(writer) {
this.onNode = (result, node) => {
const id = node.id;
const sid = id.sid;
const time = id.time;
const sidIndex = this.clockTable.getBySid(sid).index;
const field = (sidIndex.toString(36) + '_' + time.toString(36));
result[field] = this.encodeNode(node);
};
this.onObjKey = (value, key) => {
this.enc.writeStr(key);
this.ts(value);
};
this.enc = new CborEncoder_1.CborEncoder(writer || new CrdtWriter_1.CrdtWriter());
}
encode(doc, clockTable = ClockTable_1.ClockTable.from(doc.clock)) {
this.clockTable = clockTable;
const writer = this.enc.writer;
writer.reset();
clockTable.write(writer);
const encodedClock = writer.flush();
const rootValueId = doc.root.val;
const result = {
c: encodedClock,
};
if (rootValueId.sid !== 0) {
writer.reset();
this.ts(rootValueId);
result.r = writer.flush();
}
// biome-ignore lint: index is not iterable
doc.index.forEach(({ v: node }) => this.onNode(result, node));
return result;
}
encodeNode(node) {
if (node instanceof nodes.ConNode)
return this.encodeCon(node);
else if (node instanceof nodes.ValNode)
return this.encodeVal(node);
else if (node instanceof nodes.ObjNode)
return this.encodeObj(node);
else if (node instanceof nodes.VecNode)
return this.encodeVec(node);
else if (node instanceof nodes.StrNode)
return this.encodeStr(node);
else if (node instanceof nodes.BinNode)
return this.encodeBin(node);
else if (node instanceof nodes.ArrNode)
return this.encodeArr(node);
throw new Error('UNKNOWN_NODE');
}
ts(id) {
const index = this.clockTable.getBySid(id.sid).index;
this.enc.writer.id(index, id.time);
}
writeTL(majorOverlay, length) {
const writer = this.enc.writer;
if (length < 24)
writer.u8(majorOverlay + length);
else if (length <= 0xff)
writer.u16(((majorOverlay + 24) << 8) + length);
else if (length <= 0xffff)
writer.u8u16(majorOverlay + 25, length);
else
writer.u8u32(majorOverlay + 26, length);
}
encodeCon(node) {
const encoder = this.enc;
const writer = encoder.writer;
const val = node.val;
writer.reset();
if (val instanceof clock_1.Timestamp) {
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.CON, 1);
this.ts(val);
}
else {
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.CON, 0);
encoder.writeAny(val);
}
return writer.flush();
}
encodeVal(node) {
const writer = this.enc.writer;
const child = node.node();
writer.reset();
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.VAL, 0);
this.ts(child.id);
return writer.flush();
}
encodeObj(node) {
const encoder = this.enc;
const writer = encoder.writer;
writer.reset();
const keys = node.keys;
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.OBJ, keys.size);
keys.forEach(this.onObjKey);
return writer.flush();
}
encodeVec(node) {
const writer = this.enc.writer;
writer.reset();
const length = node.elements.length;
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.VEC, length);
for (let i = 0; i < length; i++) {
const childId = node.val(i);
if (!childId)
writer.u8(0);
else {
writer.u8(1);
this.ts(childId);
}
}
return writer.flush();
}
encodeStr(node) {
const encoder = this.enc;
const writer = encoder.writer;
writer.reset();
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.STR, node.count);
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
this.ts(chunk.id);
if (chunk.del)
encoder.writeUInteger(chunk.span);
else
encoder.writeStr(chunk.data);
}
return writer.flush();
}
encodeBin(node) {
const encoder = this.enc;
const writer = encoder.writer;
writer.reset();
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.BIN, node.count);
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
const length = chunk.span;
const deleted = chunk.del;
this.ts(chunk.id);
writer.b1vu56(~~deleted, length);
if (deleted)
continue;
writer.buf(chunk.data, length);
}
return writer.flush();
}
encodeArr(node) {
const encoder = this.enc;
const writer = encoder.writer;
writer.reset();
this.writeTL(constants_1.CRDT_MAJOR_OVERLAY.ARR, node.count);
for (let chunk = node.first(); chunk; chunk = node.next(chunk)) {
const length = chunk.span;
const deleted = chunk.del;
this.ts(chunk.id);
writer.b1vu56(~~deleted, length);
if (deleted)
continue;
const data = chunk.data;
for (let i = 0; i < length; i++)
this.ts(data[i]);
}
return writer.flush();
}
}
exports.Encoder = Encoder;