json-joy
Version:
Collection of libraries for building collaborative editing apps.
261 lines (260 loc) • 10.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Decoder = void 0;
const op_1 = require("../../op");
const MsgPackDecoderFast_1 = require("@jsonjoy.com/json-pack/lib/msgpack/MsgPackDecoderFast");
const constants_1 = require("../../constants");
const util_1 = require("../../util");
class Decoder extends MsgPackDecoderFast_1.MsgPackDecoderFast {
constructor(options) {
super();
this.options = options;
}
decode(uint8) {
this.reader.reset(uint8);
return this.decodePatch();
}
decodePatch() {
const len = this.decodeArrayHeader();
const ops = [];
for (let i = 0; i < len; i++)
ops.push(this.decodeOp(undefined));
return ops;
}
decodeOp(parent) {
const length = this.decodeArrayHeader();
const opcode = this.reader.u8();
switch (opcode) {
case constants_1.OPCODE.add: {
const path = this.decodeArray();
const value = this.val();
return new op_1.OpAdd(path, value);
}
case constants_1.OPCODE.and: {
const path = this.decodePath(parent);
const length = this.decodeArrayHeader();
const ops = [];
const op = new op_1.OpAnd(path, ops);
for (let i = 0; i < length; i++)
ops.push(this.decodeOp(op));
return op;
}
case constants_1.OPCODE.contains: {
const path = this.decodePath(parent);
const value = this.decodeString();
const ignoreCase = length > 3;
return new op_1.OpContains(path, value, ignoreCase);
}
case constants_1.OPCODE.copy: {
const path = this.decodeArray();
const from = this.decodeArray();
return new op_1.OpCopy(path, from);
}
case constants_1.OPCODE.defined: {
const path = this.decodePath(parent);
return new op_1.OpDefined(path);
}
case constants_1.OPCODE.ends: {
const path = this.decodePath(parent);
const value = this.decodeString();
const ignoreCase = length > 3;
return new op_1.OpEnds(path, value, ignoreCase);
}
case constants_1.OPCODE.extend: {
const path = this.decodeArray();
const props = this.decodeObject();
const deleteNull = length > 3;
return new op_1.OpExtend(path, props, deleteNull);
}
case constants_1.OPCODE.flip: {
const path = this.decodeArray();
return new op_1.OpFlip(path);
}
case constants_1.OPCODE.in: {
const path = this.decodePath(parent);
const value = this.decodeArray();
return new op_1.OpIn(path, value);
}
case constants_1.OPCODE.inc: {
const path = this.decodePath(parent);
const inc = this.val();
return new op_1.OpInc(path, inc);
}
case constants_1.OPCODE.less: {
const path = this.decodePath(parent);
const value = this.val();
return new op_1.OpLess(path, value);
}
case constants_1.OPCODE.matches: {
const path = this.decodePath(parent);
const value = this.decodeString();
const ignoreCase = length > 3;
return new op_1.OpMatches(path, value, ignoreCase, this.options.createMatcher || util_1.createMatcherDefault);
}
case constants_1.OPCODE.merge: {
const hasProps = length > 3;
const path = this.decodeArray();
const pos = this.val();
const props = hasProps ? this.decodeObject() : null;
return new op_1.OpMerge(path, pos, props);
}
case constants_1.OPCODE.more: {
const path = this.decodePath(parent);
const value = this.val();
return new op_1.OpMore(path, value);
}
case constants_1.OPCODE.move: {
const path = this.decodeArray();
const from = this.decodeArray();
return new op_1.OpMove(path, from);
}
case constants_1.OPCODE.not: {
const path = this.decodePath(parent);
const length = this.decodeArrayHeader();
const ops = [];
const op = new op_1.OpNot(path, ops);
for (let i = 0; i < length; i++)
ops.push(this.decodeOp(op));
return op;
}
case constants_1.OPCODE.or: {
const path = this.decodePath(parent);
const length = this.decodeArrayHeader();
const ops = [];
const op = new op_1.OpOr(path, ops);
for (let i = 0; i < length; i++)
ops.push(this.decodeOp(op));
return op;
}
case constants_1.OPCODE.remove: {
const path = this.decodeArray();
const hasOldValue = length > 2;
const oldValue = hasOldValue ? this.val() : undefined;
return new op_1.OpRemove(path, oldValue);
}
case constants_1.OPCODE.replace: {
const path = this.decodeArray();
const value = this.val();
const hasOldValue = length > 3;
const oldValue = hasOldValue ? this.val() : undefined;
return new op_1.OpReplace(path, value, oldValue);
}
case constants_1.OPCODE.split: {
const path = this.decodeArray();
const pos = this.val();
const hasProps = length > 3;
const props = hasProps ? this.decodeObject() : null;
return new op_1.OpSplit(path, pos, props);
}
case constants_1.OPCODE.starts: {
const ignoreCase = length > 3;
const path = this.decodePath(parent);
const value = this.decodeString();
return new op_1.OpStarts(path, value, ignoreCase);
}
case constants_1.OPCODE.str_del: {
const hasStr = length < 5;
const path = this.decodeArray();
const pos = this.val();
if (hasStr) {
const str = this.decodeString();
return new op_1.OpStrDel(path, pos, str, undefined);
}
else {
this.reader.u8();
const len = this.val();
return new op_1.OpStrDel(path, pos, undefined, len);
}
}
case constants_1.OPCODE.str_ins: {
const path = this.decodeArray();
const pos = this.val();
const str = this.decodeString();
return new op_1.OpStrIns(path, pos, str);
}
case constants_1.OPCODE.test: {
const not = length > 3;
const path = this.decodePath(parent);
const value = this.val();
return new op_1.OpTest(path, value, not);
}
case constants_1.OPCODE.test_string: {
const not = length > 4;
const path = this.decodePath(parent);
const pos = this.val();
const str = this.decodeString();
return new op_1.OpTestString(path, pos, str, not);
}
case constants_1.OPCODE.test_string_len: {
const not = length > 3;
const path = this.decodePath(parent);
const len = this.val();
return new op_1.OpTestStringLen(path, len, not);
}
case constants_1.OPCODE.test_type: {
const path = this.decodePath(parent);
const type = this.decodeArray();
return new op_1.OpTestType(path, type);
}
case constants_1.OPCODE.type: {
const path = this.decodePath(parent);
const value = this.decodeString();
return new op_1.OpType(path, value);
}
case constants_1.OPCODE.undefined: {
const path = this.decodePath(parent);
return new op_1.OpUndefined(path);
}
}
throw new Error('OP_UNKNOWN');
}
decodePath(parent) {
const path = this.decodeArray();
if (!parent)
return path;
return [...parent.path, ...path];
}
decodeObject() {
const reader = this.reader;
const byte = reader.u8();
if (byte <= 0xbf)
return this.obj(byte & 0b1111);
else if (byte === 0xde)
return this.obj(reader.u16());
/* 0xdf */ else
return this.obj(reader.u32());
}
decodeArray() {
const reader = this.reader;
const byte = reader.u8();
if (byte < 0b10011111)
return this.arr(byte & 0b1111);
else if (byte === 0xdc)
return this.arr(reader.u16());
else
return this.arr(reader.u32());
}
decodeArrayHeader() {
const reader = this.reader;
const byte = reader.u8();
if (byte < 0b10011111)
return byte & 0b1111;
else if (byte === 0xdc)
return reader.u16();
else
return reader.u32();
}
decodeString() {
const reader = this.reader;
const byte = reader.u8();
if (byte <= 0xbf)
return reader.utf8(byte & 0b11111);
else if (byte === 0xd9)
return reader.utf8(reader.u8());
else if (byte === 0xda)
return reader.utf8(reader.u16());
/* 0xDB */ else
return reader.utf8(reader.u32());
}
}
exports.Decoder = Decoder;