All files / json-hash structHash.ts

96.55% Statements 28/29
92.3% Branches 12/13
100% Functions 1/1
95.83% Lines 23/24

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 488x 8x                         8x 54944x   11884x     27338x   5062x   10660x 8303x 3484x 3484x 8580x 3484x 4819x 22x   4797x 4797x 4797x 4797x 4797x 21416x 21416x   4797x            
import {sort} from '@jsonjoy.com/util/lib/sort/insertion';
import {hash} from './hash';
 
/**
 * Produces a *structural hash* of a JSON value.
 *
 * This is a hash that is not sensitive to the order of properties in object and
 * it preserves spatial information of the JSON nodes.
 *
 * The hash is guaranteed to contain only printable ASCII characters, excluding
 * the newline character.
 *
 * @param val A JSON value to hash.
 */
export const structHash = (val: unknown): string => {
  switch (typeof val) {
    case 'string':
      return hash(val).toString(36);
    case 'number':
    case 'bigint':
      return val.toString(36);
    case 'boolean':
      return val ? 'T' : 'F';
    case 'object':
      if (val === null) return 'N';
      if (Array.isArray(val)) {
        const length = val.length;
        let res = '[';
        for (let i = 0; i < length; i++) res += structHash(val[i]) + ',';
        return res + ']';
      } else if (val instanceof Uint8Array) {
        return hash(val).toString(36);
      } else {
        const keys = Object.keys(val);
        sort(keys);
        let res = '{';
        const length = keys.length;
        for (let i = 0; i < length; i++) {
          const key = keys[i];
          res += hash(key).toString(36) + ':' + structHash((val as Record<string, unknown>)[key]) + ',';
        }
        return res + '}';
      }
    default:
      return 'U';
  }
};