json-joy
Version:
Collection of libraries for building collaborative editing apps.
158 lines (157 loc) • 6.1 kB
JavaScript
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;
;