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 2935083x     178x 63543x 63543x 63543x 63543x 541134x 63543x     178x 44x 44x 44x 44x 94x 44x     178x 185425x   113344x   58618x 58618x   12838x 12579x 11474x 11474x 15135x 11474x   1105x 1061x 1061x 1061x 1061x 4925x 4925x 4925x   1061x     601x   24x     155987x  
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;