All files / json-patch/op OpStrIns.ts

96.96% Statements 32/33
100% Branches 9/9
85.71% Functions 6/7
96.66% Lines 29/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67  15x   15x 15x           15x     149x 149x   149x       31x               121x 121x 35x 10x   91x 91x 91x 91x 91x 91x 5x 91x       14x           14x       8x 8x       4x 4x 4x 4x 4x      
import type {CompactStrInsOp, OPCODE_STR_INS} from '../codec/compact/types';
import {AbstractOp} from './AbstractOp';
import type {OperationStrIns} from '../types';
import {find, type Path, formatJsonPointer} from '@jsonjoy.com/json-pointer';
import {OPCODE} from '../constants';
import type {IMessagePackEncoder} from '@jsonjoy.com/json-pack/lib/msgpack';
 
/**
 * @category JSON Patch Extended
 */
export class OpStrIns extends AbstractOp<'str_ins'> {
  constructor(
    path: Path,
    public readonly pos: number,
    public readonly str: string,
  ) {
    super(path);
  }
 
  public op() {
    return 'str_ins' as const;
  }
 
  public code() {
    return OPCODE.str_ins;
  }
 
  public apply(doc: unknown) {
    const {val, key, obj} = find(doc, this.path);
    if (typeof val !== 'string') {
      if (val !== undefined) throw new Error('NOT_A_STRING');
      if (this.pos !== 0) throw new Error('POS');
    }
    const str: string = typeof val === 'string' ? val : '';
    const pos = Math.min(this.pos, str.length);
    const before = str.slice(0, pos);
    const after = str.slice(pos);
    const result = before + this.str + after;
    if (obj) (obj as any)[key as any] = result;
    else doc = result;
    return {doc, old: val};
  }
 
  public toJson(parent?: AbstractOp): OperationStrIns {
    const op: OperationStrIns = {
      op: 'str_ins',
      path: formatJsonPointer(this.path),
      pos: this.pos,
      str: this.str,
    };
    return op;
  }
 
  public toCompact(parent: undefined | AbstractOp, verbose: boolean): CompactStrInsOp {
    const opcode: OPCODE_STR_INS = verbose ? 'str_ins' : OPCODE.str_ins;
    return [opcode, this.path, this.pos, this.str];
  }
 
  public encode(encoder: IMessagePackEncoder, parent?: AbstractOp) {
    encoder.encodeArrayHeader(4);
    encoder.writer.u8(OPCODE.str_ins);
    encoder.encodeArray(this.path as unknown[]);
    encoder.encodeNumber(this.pos);
    encoder.encodeString(this.str);
  }
}