All files / json-hash hash.ts

100% Statements 62/62
100% Branches 11/11
100% Functions 6/6
100% Lines 49/49

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 71178x     178x 178x   178x 178x 178x 178x 178x 178x 178x     178x 2999552x     178x 62904x 62904x 62904x 62904x 536045x 62904x     178x 44x 44x 44x 44x 94x 44x     178x 184792x   113414x   57915x 57915x   12868x 12584x 11524x 11524x 15071x 11524x   1060x 1016x 1016x 1016x 1016x 4989x 4989x 4989x   1016x     571x   24x     155354x  
import {sort} from '@jsonjoy.com/util/lib/sort/insertion';
import type {PackValue} from '@jsonjoy.com/json-pack/lib/types';
 
export enum CONST {
  START_STATE = 5381,
 
  NULL = 982452847,
  TRUE = 982453247,
  FALSE = 982454243,
  ARRAY = 982452259,
  STRING = 982453601,
  OBJECT = 982454533,
  BINARY = 982454837,
}
 
export const updateNum = (state: number, num: number): number => {
  return (state << 5) + state + num;
};
 
export const updateStr = (state: number, str: string): number => {
  const length = str.length;
  state = updateNum(state, CONST.STRING);
  state = updateNum(state, length);
  let i = length;
  while (i) state = (state << 5) + state + str.charCodeAt(--i);
  return state;
};
 
export const updateBin = (state: number, bin: Uint8Array): number => {
  const length = bin.length;
  state = updateNum(state, CONST.BINARY);
  state = updateNum(state, length);
  let i = length;
  while (i) state = (state << 5) + state + bin[--i];
  return state;
};
 
export const updateJson = (state: number, json: unknown): number => {
  switch (typeof json) {
    case 'number':
      return updateNum(state, json);
    case 'string':
      state = updateNum(state, CONST.STRING);
      return updateStr(state, json);
    case 'object': {
      if (json === null) return updateNum(state, CONST.NULL);
      if (Array.isArray(json)) {
        const length = json.length;
        state = updateNum(state, CONST.ARRAY);
        for (let i = 0; i < length; i++) state = updateJson(state, json[i]);
        return state;
      }
      if (json instanceof Uint8Array) return updateBin(state, json);
      state = updateNum(state, CONST.OBJECT);
      const keys = sort(Object.keys(json as object));
      const length = keys.length;
      for (let i = 0; i < length; i++) {
        const key = keys[i];
        state = updateStr(state, key);
        state = updateJson(state, (json as any)[key]);
      }
      return state;
    }
    case 'boolean':
      return updateNum(state, json ? CONST.TRUE : CONST.FALSE);
  }
  return state;
};
 
export const hash = (json: PackValue) => updateJson(CONST.START_STATE, json) >>> 0;