UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

261 lines (260 loc) 10.3 kB
"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;