All files / fuse-ui-shared memoize.ts

100% Statements 27/27
100% Branches 6/6
100% Functions 6/6
100% Lines 22/22
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  1x         230x 230x     23x 6x 6x 6x 6x   17x 12x     17x       6x     1x 1x 3x   110x 60x 60x 54x   6x 6x   6x      
//tslint:disable-next-line
const Symbol = require('es6-symbol');
 
export type Traversable<T> = T | { [key: string]: Traversable<T> };
export type ValueArg = string | number | Symbol;
 
function traverseGet<T>(ctx: Traversable<T>, ...args: string[]): T {
  return args.reduce((cur: any, key) => cur ? cur[key] : undefined, ctx);
}
 
function traverseSet<T>(ctx: Traversable<T>, val: any, ...args: string[]) {
  const length = args.length;
  const last = args[length - 1];
  const ancestors = args.slice(0, -1);
  const parent = ancestors.reduce(
    (cur: any, key) => {
      if (!cur[key]) {
        cur[key] = {};
      }
 
      return cur[key];
    },
    ctx);
 
  parent[last] = val;
}
 
const endMarker = Symbol('memoize-end-marker');
export function memoize<T>(memory: Traversable<T>, func: (...args: ValueArg[]) => T): (...args: ValueArg[]) => T {
  const marker = Symbol();
 
  return (...args: ValueArg[]) => {
    const prev: T = traverseGet.call(null, memory, marker, ...args, endMarker);
    if (prev !== undefined) {
      return prev;
    }
    const result: T = func.call(null, ...args);
    traverseSet.call(null, memory, result, marker, ...args, endMarker);
 
    return result;
  };
}