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  17x   17x 17x           17x     171x 171x   171x       31x               143x 143x 35x 10x   113x 113x 113x 113x 113x 113x 5x 113x       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);
  }
}