All files / json-patch/codec/json decode.ts

98.78% Statements 81/82
97.29% Branches 36/37
100% Functions 6/6
98.73% Lines 78/79

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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132    15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x   15x   15x 2586x   478x   134x   278x   105x   83x   72x   90x   133x   98x   153x   47x   53x   862x       15x 1016x   273x   52x   53x   52x   90x   40x   68x   55x   62x   63x   14x   45x   45x   45x   32x 32x   76x       13x 13x   38x       14x 14x   40x               15x 987x 987x 987x 1007x 1007x   987x    
import type {Op, PredicateOp} from '../../op';
import type {Operation} from './types';
import {OpAdd} from '../../op/OpAdd';
import {OpRemove} from '../../op/OpRemove';
import {OpReplace} from '../../op/OpReplace';
import {OpMove} from '../../op/OpMove';
import {OpCopy} from '../../op/OpCopy';
import {OpTest} from '../../op/OpTest';
import {OpFlip} from '../../op/OpFlip';
import {OpInc} from '../../op/OpInc';
import {OpStrIns} from '../../op/OpStrIns';
import {OpStrDel} from '../../op/OpStrDel';
import {OpSplit} from '../../op/OpSplit';
import {OpMerge} from '../../op/OpMerge';
import {OpExtend} from '../../op/OpExtend';
import {OpDefined} from '../../op/OpDefined';
import {OpUndefined} from '../../op/OpUndefined';
import {OpTestType} from '../../op/OpTestType';
import {OpTestString} from '../../op/OpTestString';
import {OpTestStringLen} from '../../op/OpTestStringLen';
import {OpContains} from '../../op/OpContains';
import {OpEnds} from '../../op/OpEnds';
import {OpStarts} from '../../op/OpStarts';
import {OpIn} from '../../op/OpIn';
import {OpLess} from '../../op/OpLess';
import {OpMore} from '../../op/OpMore';
import {OpAnd} from '../../op/OpAnd';
import {OpOr} from '../../op/OpOr';
import {OpNot} from '../../op/OpNot';
import {OpMatches} from '../../op/OpMatches';
import {OpType} from '../../op/OpType';
import {toPath} from '@jsonjoy.com/json-pointer';
import type {JsonPatchOptions} from '../../types';
import {createMatcherDefault} from '../../util';
 
export const operationToOp = (op: Operation, options: JsonPatchOptions): Op => {
  switch (op.op) {
    case 'add':
      return new OpAdd(toPath(op.path), op.value);
    case 'remove':
      return new OpRemove(toPath(op.path), op.oldValue);
    case 'replace':
      return new OpReplace(toPath(op.path), op.value, op.oldValue);
    case 'move':
      return new OpMove(toPath(op.path), toPath(op.from));
    case 'copy':
      return new OpCopy(toPath(op.path), toPath(op.from));
    case 'flip':
      return new OpFlip(toPath(op.path));
    case 'inc':
      return new OpInc(toPath(op.path), op.inc);
    case 'str_ins':
      return new OpStrIns(toPath(op.path), op.pos, op.str);
    case 'str_del':
      return new OpStrDel(toPath(op.path), op.pos, op.str, op.len);
    case 'split':
      return new OpSplit(toPath(op.path), op.pos, op.props || null);
    case 'merge':
      return new OpMerge(toPath(op.path), op.pos, op.props || null);
    case 'extend':
      return new OpExtend(toPath(op.path), op.props, !!op.deleteNull);
    default:
      return operationToPredicateOp(op, options);
  }
};
 
export const operationToPredicateOp = (op: Operation, options: JsonPatchOptions): PredicateOp => {
  switch (op.op) {
    case 'test':
      return new OpTest(toPath(op.path), op.value, !!op.not);
    case 'defined':
      return new OpDefined(toPath(op.path));
    case 'undefined':
      return new OpUndefined(toPath(op.path));
    case 'type':
      return new OpType(toPath(op.path), op.value);
    case 'test_type':
      return new OpTestType(toPath(op.path), op.type);
    case 'test_string':
      return new OpTestString(toPath(op.path), op.pos, op.str, !!op.not);
    case 'test_string_len':
      return new OpTestStringLen(toPath(op.path), op.len, !!op.not);
    case 'contains':
      return new OpContains(toPath(op.path), op.value, !!op.ignore_case);
    case 'ends':
      return new OpEnds(toPath(op.path), op.value, !!op.ignore_case);
    case 'starts':
      return new OpStarts(toPath(op.path), op.value, !!op.ignore_case);
    case 'matches':
      return new OpMatches(toPath(op.path), op.value, !!op.ignore_case, options.createMatcher || createMatcherDefault);
    case 'in':
      return new OpIn(toPath(op.path), op.value);
    case 'less':
      return new OpLess(toPath(op.path), op.value);
    case 'more':
      return new OpMore(toPath(op.path), op.value);
    case 'and': {
      const path = toPath(op.path);
      return new OpAnd(
        path,
        op.apply.map((x) => operationToPredicateOp({...x, path: [...path, ...toPath(x.path)]}, options)),
      );
    }
    case 'or': {
      const path = toPath(op.path);
      return new OpOr(
        path,
        op.apply.map((x) => operationToPredicateOp({...x, path: [...path, ...toPath(x.path)]}, options)),
      );
    }
    case 'not': {
      const path = toPath(op.path);
      return new OpNot(
        path,
        op.apply.map((x) => operationToPredicateOp({...x, path: [...path, ...toPath(x.path)]}, options)),
      );
    }
    default:
      throw new Error('OP_UNKNOWN');
  }
};
 
export function decode(patch: readonly Operation[], options: JsonPatchOptions): Op[] {
  const ops: Op[] = [];
  const length = patch.length;
  for (let i = 0; i < length; i++) {
    const op = operationToOp(patch[i], options);
    ops.push(op);
  }
  return ops;
}