UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

69 lines (68 loc) 2.2 kB
import { AbstractOp } from './AbstractOp'; import { find, isArrayReference, formatJsonPointer } from '@jsonjoy.com/json-pointer'; import { isTextNode, isElementNode } from '../util'; import { OPCODE } from '../constants'; /** * @category JSON Patch Extended */ export class OpMerge extends AbstractOp { pos; props; constructor(path, pos, props) { super(path); this.pos = pos; this.props = props; } op() { return 'merge'; } code() { return OPCODE.merge; } apply(doc) { const ref = find(doc, this.path); if (!isArrayReference(ref)) throw new Error('INVALID_TARGET'); if (ref.key <= 0) throw new Error('INVALID_KEY'); const one = ref.obj[ref.key - 1]; const two = ref.obj[ref.key]; const merged = this.merge(one, two); ref.obj[ref.key - 1] = merged; ref.obj.splice(ref.key, 1); return { doc, old: [one, two] }; } merge(one, two) { if (typeof one === 'string' && typeof two === 'string') return one + two; if (typeof one === 'number' && typeof two === 'number') return one + two; if (isTextNode(one) && isTextNode(two)) return { ...one, ...two, text: one.text + two.text }; if (isElementNode(one) && isElementNode(two)) return { ...one, ...two, children: [...one.children, ...two.children] }; return [one, two]; } toJson(parent) { const op = { op: 'merge', path: formatJsonPointer(this.path), pos: this.pos, }; if (this.props) op.props = this.props; return op; } toCompact(parent, verbose) { const opcode = verbose ? 'merge' : OPCODE.merge; return this.props ? [opcode, this.path, this.pos, this.props] : [opcode, this.path, this.pos]; } encode(encoder, parent) { encoder.encodeArrayHeader(this.props ? 4 : 3); encoder.writer.u8(OPCODE.merge); encoder.encodeArray(this.path); encoder.encodeNumber(this.pos); if (this.props) encoder.encodeAny(this.props); } }