All files index.ts

100% Statements 52/52
100% Branches 35/35
100% Functions 5/5
100% Lines 50/50

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                  4x   4x 4x 4x           36x             50x 50x 1x   49x 1850x   1850x 1850x   49x       41x 41x 41x   41x 41x 41x   41x 12x 4x     8x 8x     37x 1x     36x   36x 166x 4x     162x 162x 162x     36x 32x 28x       36x 190x     36x       7x 5x     2x 2x 2x 2x       4x 4x 4x 4x 4x    
import emojiTable from './generated/table';
import type { EmojiHasher, EmojiTable, Options } from './types';
 
class EmojiHasherSingletone implements EmojiHasher {
  table: EmojiTable;
  defaultOptions: Options;
  maxBase: number;
 
  constructor() {
    this.table = emojiTable as EmojiTable;
 
    const base = Object.keys(this.table).length;
    this.maxBase = base;
    this.defaultOptions = {
      base
    };
  }
 
  getHash(input: string, options?: Options): string {
    return this.transformBinary(this.getBitwise(input), options);
  }
 
  /**
   * @see {@link http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/}
   */
  getBitwise(str: string): number {
    let hash = 0;
    if (str.length == 0) {
      return hash;
    }
    for (let i = 0; i < str.length; i++) {
      const ch = str.charCodeAt(i);
 
      hash = (hash << 5) - hash + ch;
      hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }
 
  transformBinary(input: number, options?: Options): string {
    const stack = [];
    const sign = input < 0 ? this.table[0] : '';
    const { base, length } = options ?? this.defaultOptions;
    let num;
    let result = '';
    let expectedLength = 0;
    let shouldUseLength = false;
 
    if (length !== null && length !== undefined && !Number.isNaN(length)) {
      if (length <= 0) {
        throw new Error('property `length` must equals at least 1');
      }
 
      shouldUseLength = true;
      expectedLength = length - (sign ? 1 : 0);
    }
 
    if (base > this.maxBase) {
      throw new Error(`'base' mustn't be bigger than ${this.maxBase}`);
    }
 
    input = Math.abs(input);
 
    while (input >= base) {
      if (shouldUseLength && stack.length >= expectedLength) {
        break;
      }
 
      num = input % base;
      input = Math.floor(input / base);
      stack.push(this.table[num]);
    }
 
    if (input > 0 && input < base) {
      if (!shouldUseLength || (shouldUseLength && stack.length < expectedLength)) {
        stack.push(this.table[input]);
      }
    }
 
    for (let i = stack.length - 1; i >= 0; i--) {
      result += stack[i];
    }
 
    return sign + result;
  }
 
  useTable(newTable: EmojiTable): void {
    if (!newTable || typeof newTable !== 'object' || !Object.keys(newTable).length) {
      throw new Error('newTable must contains dictionary');
    }
 
    this.table = newTable;
    const base = Object.keys(this.table).length;
    this.maxBase = base;
    this.defaultOptions = { ...this.defaultOptions, base };
  }
}
 
const instance = new EmojiHasherSingletone();
export const getHash = instance.getHash.bind(instance);
export const useTable = instance.useTable.bind(instance);
export const getBitwise = instance.getBitwise.bind(instance);
export const transformBinary = instance.transformBinary.bind(instance);
export default instance;