UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

298 lines 12.3 kB
import { MsgPackEncoderFast as EncoderMessagePack } from '@jsonjoy.com/json-pack/lib/msgpack/MsgPackEncoderFast'; import { OPCODE } from '../../constants'; export class Encoder extends EncoderMessagePack { encode(patch) { this.writer.reset(); this.encodeArrayHeader(patch.length); const length = patch.length; for (let i = 0; i < length; i++) this.encodeOp(patch[i]); return this.writer.flush(); } encodeOp(op, parent) { switch (op.code()) { case OPCODE.add: { const addOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.add); this.encodeArray(addOp.path); this.encodeAny(addOp.value); break; } case OPCODE.remove: { const removeOp = op; const hasOldValue = removeOp.oldValue !== undefined; this.encodeArrayHeader(hasOldValue ? 3 : 2); this.writer.u8(OPCODE.remove); this.encodeArray(removeOp.path); if (hasOldValue) this.encodeAny(removeOp.oldValue); break; } case OPCODE.replace: { const replaceOp = op; const hasOldValue = replaceOp.oldValue !== undefined; this.encodeArrayHeader(hasOldValue ? 4 : 3); this.writer.u8(OPCODE.replace); this.encodeArray(replaceOp.path); this.encodeAny(replaceOp.value); if (hasOldValue) this.encodeAny(replaceOp.oldValue); break; } case OPCODE.copy: { const copyOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.copy); this.encodeArray(copyOp.path); this.encodeArray(copyOp.from); break; } case OPCODE.move: { const moveOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.move); this.encodeArray(moveOp.path); this.encodeArray(moveOp.from); break; } case OPCODE.test: { const testOp = op; this.encodeArrayHeader(testOp.not ? 4 : 3); this.writer.u8(OPCODE.test); this.encodeArray(parent ? testOp.path.slice(parent.path.length) : testOp.path); this.encodeAny(testOp.value); if (testOp.not) this.writer.u8(1); break; } case OPCODE.str_ins: { const strInsOp = op; this.encodeArrayHeader(4); this.writer.u8(OPCODE.str_ins); this.encodeArray(strInsOp.path); this.encodeNumber(strInsOp.pos); this.encodeString(strInsOp.str); break; } case OPCODE.str_del: { const strDelOp = op; const hasStr = typeof strDelOp.str === 'string'; this.encodeArrayHeader(hasStr ? 4 : 5); this.writer.u8(OPCODE.str_del); this.encodeArray(strDelOp.path); this.encodeNumber(strDelOp.pos); if (hasStr) { this.encodeString(strDelOp.str); } else { this.writer.u8(0); this.encodeNumber(strDelOp.len); } break; } case OPCODE.flip: { const flipOp = op; this.encodeArrayHeader(2); this.writer.u8(OPCODE.flip); this.encodeArray(flipOp.path); break; } case OPCODE.inc: { const incOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.inc); this.encodeArray(incOp.path); this.encodeNumber(incOp.inc); break; } case OPCODE.split: { const splitOp = op; this.encodeArrayHeader(splitOp.props ? 4 : 3); this.writer.u8(OPCODE.split); this.encodeArray(splitOp.path); this.encodeNumber(splitOp.pos); if (splitOp.props) this.encodeObject(splitOp.props); break; } case OPCODE.merge: { const mergeOp = op; this.encodeArrayHeader(mergeOp.props ? 4 : 3); this.writer.u8(OPCODE.merge); this.encodeArray(mergeOp.path); this.encodeNumber(mergeOp.pos); if (mergeOp.props) this.encodeAny(mergeOp.props); break; } case OPCODE.extend: { const extendOp = op; const { deleteNull } = extendOp; this.encodeArrayHeader(deleteNull ? 4 : 3); this.writer.u8(OPCODE.extend); this.encodeArray(extendOp.path); this.encodeObject(extendOp.props); if (deleteNull) this.writer.u8(1); break; } case OPCODE.contains: { const containsOp = op; const ignoreCase = containsOp.ignore_case; this.encodeArrayHeader(ignoreCase ? 4 : 3); this.writer.u8(OPCODE.contains); this.encodeArray(parent ? containsOp.path.slice(parent.path.length) : containsOp.path); this.encodeString(containsOp.value); if (ignoreCase) this.writer.u8(1); break; } case OPCODE.defined: { const definedOp = op; this.encodeArrayHeader(2); this.writer.u8(OPCODE.defined); this.encodeArray(parent ? definedOp.path.slice(parent.path.length) : definedOp.path); break; } case OPCODE.ends: { const endsOp = op; const ignoreCase = endsOp.ignore_case; this.encodeArrayHeader(ignoreCase ? 4 : 3); this.writer.u8(OPCODE.ends); this.encodeArray(parent ? endsOp.path.slice(parent.path.length) : endsOp.path); this.encodeString(endsOp.value); if (ignoreCase) this.writer.u8(1); break; } case OPCODE.in: { const inOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.in); this.encodeArray(parent ? inOp.path.slice(parent.path.length) : inOp.path); this.encodeArray(inOp.value); break; } case OPCODE.less: { const lessOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.less); this.encodeArray(parent ? lessOp.path.slice(parent.path.length) : lessOp.path); this.encodeNumber(lessOp.value); break; } case OPCODE.matches: { const matchesOp = op; const ignoreCase = matchesOp.ignore_case; this.encodeArrayHeader(ignoreCase ? 4 : 3); this.writer.u8(OPCODE.matches); this.encodeArray(parent ? matchesOp.path.slice(parent.path.length) : matchesOp.path); this.encodeString(matchesOp.value); if (ignoreCase) this.writer.u8(1); break; } case OPCODE.more: { const moreOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.more); this.encodeArray(parent ? moreOp.path.slice(parent.path.length) : moreOp.path); this.encodeNumber(moreOp.value); break; } case OPCODE.starts: { const startsOp = op; const ignoreCase = startsOp.ignore_case; this.encodeArrayHeader(ignoreCase ? 4 : 3); this.writer.u8(OPCODE.starts); this.encodeArray(parent ? startsOp.path.slice(parent.path.length) : startsOp.path); this.encodeString(startsOp.value); if (ignoreCase) this.writer.u8(1); break; } case OPCODE.test_type: { const testTypeOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.test_type); this.encodeArray(parent ? testTypeOp.path.slice(parent.path.length) : testTypeOp.path); this.encodeArray(testTypeOp.type); break; } case OPCODE.test_string: { const testStringOp = op; this.encodeArrayHeader(testStringOp.not ? 5 : 4); this.writer.u8(OPCODE.test_string); this.encodeArray(parent ? testStringOp.path.slice(parent.path.length) : testStringOp.path); this.encodeNumber(testStringOp.pos); this.encodeString(testStringOp.str); if (testStringOp.not) this.writer.u8(1); break; } case OPCODE.test_string_len: { const testStringLenOp = op; this.encodeArrayHeader(testStringLenOp.not ? 4 : 3); this.writer.u8(OPCODE.test_string_len); this.encodeArray(parent ? testStringLenOp.path.slice(parent.path.length) : testStringLenOp.path); this.encodeNumber(testStringLenOp.len); if (testStringLenOp.not) this.writer.u8(1); break; } case OPCODE.type: { const typeOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.type); this.encodeArray(parent ? typeOp.path.slice(parent.path.length) : typeOp.path); this.encodeString(typeOp.value); break; } case OPCODE.undefined: { const undefinedOp = op; this.encodeArrayHeader(2); this.writer.u8(OPCODE.undefined); this.encodeArray(parent ? undefinedOp.path.slice(parent.path.length) : undefinedOp.path); break; } case OPCODE.and: { const andOp = op; const path = parent ? andOp.path.slice(parent.path.length) : andOp.path; this.encodeArrayHeader(3); this.writer.u8(OPCODE.and); this.encodeArray(path); const length = andOp.ops.length; this.encodeArrayHeader(length); for (let i = 0; i < length; i++) this.encodeOp(andOp.ops[i], andOp); break; } case OPCODE.not: { const notOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.not); this.encodeArray(parent ? notOp.path.slice(parent.path.length) : notOp.path); const length = notOp.ops.length; this.encodeArrayHeader(length); for (let i = 0; i < length; i++) this.encodeOp(notOp.ops[i], notOp); break; } case OPCODE.or: { const orOp = op; this.encodeArrayHeader(3); this.writer.u8(OPCODE.or); this.encodeArray(parent ? orOp.path.slice(parent.path.length) : orOp.path); const length = orOp.ops.length; this.encodeArrayHeader(length); for (let i = 0; i < length; i++) this.encodeOp(orOp.ops[i], orOp); break; } default: throw new Error(`Unknown operation code: ${op.code()}`); } } } //# sourceMappingURL=Encoder.js.map