UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

158 lines (157 loc) 6.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LogDecoder = void 0; const model_1 = require("../../model"); const Log_1 = require("../Log"); const json_crdt_patch_1 = require("../../../json-crdt-patch"); const constants_1 = require("./constants"); const constants_2 = require("../../../json-crdt-patch/constants"); class LogDecoder { constructor(opts = {}) { this.opts = opts; } decode(blob, params = {}) { switch (params.format) { case 'ndjson': { const components = this.decodeNdjsonComponents(blob); const result = this.deserialize(components, params); return result; } default: { // 'seq.cbor' const components = this.decodeSeqCborComponents(blob); const result = this.deserialize(components, params); return result; } } } decodeNdjsonComponents(blob) { const decoder = this.opts.jsonDecoder; if (!decoder) throw new Error('NO_JSON_DECODER'); const reader = decoder.reader; reader.reset(blob); const components = []; while (reader.x < blob.length) { components.push(decoder.readAny()); const nl = reader.u8(); if (nl !== '\n'.charCodeAt(0)) throw new Error('NDJSON_UNEXPECTED_NEWLINE'); } return components; } decodeSeqCborComponents(blob) { const decoder = this.opts.cborDecoder; if (!decoder) throw new Error('NO_CBOR_DECODER'); const reader = decoder.reader; reader.reset(blob); const components = []; while (reader.x < blob.length) components.push(decoder.val()); return components; } deserialize(components, params = {}) { const [view, metadata, model, , ...frontier] = components; const result = {}; if (params.view) result.view = view; if (params.history) result.history = this.deserializeHistory(components); if (params.frontier) { if (!model) result.history = this.deserializeHistory(components); if (result.history) { result.frontier = result.history; } else if (model) { const modelFormat = metadata[1]; const start = () => { const isSidecar = modelFormat === constants_1.FileModelEncoding.SidecarBinary; if (isSidecar) { const decoder = this.opts.sidecarDecoder; if (!decoder) throw new Error('NO_SIDECAR_DECODER'); if (!(model instanceof Uint8Array)) throw new Error('NOT_BLOB'); return decoder.decode(view, model); } return this.deserializeModel(model); }; const log = new Log_1.Log(start); const end = log.end; if (frontier && frontier.length) for (const patch of frontier) end.applyPatch(this.deserializePatch(patch)); result.frontier = log; } else { throw new Error('NO_MODEL'); } } return result; } deserializeHistory(components) { const [, , , history, ...frontier] = components; const [startSerialized] = history; const start = () => { if (!history || !startSerialized) { // TODO: Handle case where new model should be started with server clock: `return Model.withServerClock()`. // TODO: Handle case where model has to be started with extensions... return model_1.Model.withLogicalClock(constants_2.SESSION.GLOBAL); } return this.deserializeModel(startSerialized); }; const log = new Log_1.Log(start); const end = log.end; if (history) { const [, patches] = history; if (patches) for (const patch of patches) end.applyPatch(this.deserializePatch(patch)); } if (frontier.length) for (const patch of frontier) end.applyPatch(this.deserializePatch(patch)); return log; } deserializeModel(serialized) { if (!serialized) throw new Error('NO_MODEL'); if (serialized instanceof Uint8Array) return model_1.Model.fromBinary(serialized); if (Array.isArray(serialized)) { const decoder = this.opts.structuralCompactDecoder; if (!decoder) throw new Error('NO_STRUCTURAL_COMPACT_DECODER'); return decoder.decode(serialized); } if (typeof serialized === 'object') { const decoder = this.opts.structuralVerboseDecoder; if (!decoder) throw new Error('NO_STRUCTURAL_VERBOSE_DECODER'); return decoder.decode(serialized); } throw new Error('UNKNOWN_MODEL'); } deserializePatch(serialized) { if (!serialized) throw new Error('NO_MODEL'); if (serialized instanceof Uint8Array) return json_crdt_patch_1.Patch.fromBinary(serialized); if (Array.isArray(serialized)) { const decodeCompact = this.opts.patchCompactDecoder; if (!decodeCompact) throw new Error('NO_PATCH_COMPACT_DECODER'); return decodeCompact(serialized); } if (typeof serialized === 'object') { const decodeVerbose = this.opts.patchVerboseDecoder; if (!decodeVerbose) throw new Error('NO_PATCH_VERBOSE_DECODER'); return decodeVerbose(serialized); } throw new Error('UNKNOWN_MODEL'); } } exports.LogDecoder = LogDecoder;