All files / json-crdt/equal index.ts

80.76% Statements 42/52
75.67% Branches 28/37
100% Functions 1/1
97.05% Lines 33/34

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 471x 1x                     1x 67x 67x 52x 32x 6x 26x 11x 11x 11x 11x 11x 11x 10x 18x 18x   6x 15x 10x 10x 10x 16x 10x 5x 1x 1x 1x 2x 1x 4x 4x      
import {deepEqual} from '@jsonjoy.com/util/lib/json-equal/deepEqual';
import {ArrNode, BinNode, ConNode, type JsonNode, ObjNode, StrNode, ValNode, VecNode} from '../nodes';
 
/**
 * Deeply checks if two JSON nodes have the same schema and values. Does not
 * verify that the CRDT metadata (like timestamps) are the same, only that
 * the structure and values are equal.
 *
 * @param a The first JSON CRDT node.
 * @param b The second JSON CRDT node.
 * @returns True if the schemas and values are equal, false otherwise.
 */
export const equalSchema = <A extends JsonNode<any>>(a: A, b: unknown, compareContent: boolean): b is A => {
  Iif (a === b) return true;
  if (a instanceof ConNode) return b instanceof ConNode && (!compareContent || deepEqual(a.val, b.val));
  else if (a instanceof ValNode) return b instanceof ValNode && equalSchema(a.node(), b.node(), compareContent);
  else if (a instanceof StrNode)
    return b instanceof StrNode && (!compareContent || (a.length() === b.length() && a.view() === b.view()));
  else if (a instanceof ObjNode) {
    Iif (!(b instanceof ObjNode)) return false;
    const keys1 = a.keys;
    const keys2 = b.keys;
    const length1 = keys1.size;
    const length2 = keys2.size;
    if (length1 !== length2) return false;
    for (const key of keys1.keys()) {
      Iif (!keys2.has(key)) return false;
      if (!equalSchema(a.get(key), b.get(key), compareContent)) return false;
    }
    return true;
  } else if (a instanceof ArrNode) {
    Iif (!(b instanceof ArrNode)) return false;
    const length = a.length();
    Iif (length !== b.length()) return false;
    for (let i = 0; i < length; i++) Iif (!equalSchema(a.getNode(i)!, b.getNode(i), compareContent)) return false;
    return true;
  } else if (a instanceof VecNode) {
    Iif (!(b instanceof VecNode)) return false;
    const length = a.length();
    Iif (length !== b.length()) return false;
    for (let i = 0; i < length; i++) Iif (!equalSchema(a.get(i), b.get(i), compareContent)) return false;
    return true;
  } else if (a instanceof BinNode)
    return b instanceof BinNode && (!compareContent || (a.length() === b.length() && deepEqual(a.view(), b.view())));
  return false;
};