All files / src/support/cache cache.ts

100% Statements 15/15
100% Branches 10/10
100% Functions 4/4
100% Lines 14/14

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                                                                            19x 19x     19x 41x   41x 41x   41x 30x 30x     41x   19x 25x   30x           19x        
export interface CacheOptions<Value> {
  // initial value of _value.
  _initialValue: Value;
  // Custom comparison function if shallow compare isn't enough. Returns true if nothing changed.
  _equal?: EqualCachePropFunction<Value>;
  // If true always updates _value and _previous, otherwise they update only when they changed.
  _alwaysUpdateValues?: boolean;
}
 
export type CacheValues<T> = [
  T, // value
  boolean, // changed
  T | undefined // previous
];
 
export type EqualCachePropFunction<Value> = (currentVal: Value, newVal: Value) => boolean;
 
export type CacheUpdater<Value> = (current: Value, previous?: Value) => Value;
 
export type UpdateCacheContextual<Value> = (newValue: Value, force?: boolean) => CacheValues<Value>;
 
export type UpdateCache<Value> = (force?: boolean) => CacheValues<Value>;
 
export type GetCurrentCache<Value> = (force?: boolean) => CacheValues<Value>;
 
export type Cache<Value> = [UpdateCache<Value>, GetCurrentCache<Value>];
 
export type CacheContextual<Value> = [UpdateCacheContextual<Value>, GetCurrentCache<Value>];
 
export function createCache<Value>(options: CacheOptions<Value>): CacheContextual<Value>;
export function createCache<Value>(
  options: CacheOptions<Value>,
  update: CacheUpdater<Value>
): Cache<Value>;
export function createCache<Value>(
  options: CacheOptions<Value>,
  update?: CacheUpdater<Value>
): CacheContextual<Value> | Cache<Value> {
  const { _initialValue, _equal, _alwaysUpdateValues } = options;
  let _value: Value = _initialValue;
  let _previous: Value | undefined;
 
  const cacheUpdateContextual: UpdateCacheContextual<Value> = (newValue, force?) => {
    const curr = _value;
 
    const newVal = newValue;
    const changed = force || (_equal ? !_equal(curr, newVal) : curr !== newVal);
 
    if (changed || _alwaysUpdateValues) {
      _value = newVal;
      _previous = curr;
    }
 
    return [_value, changed, _previous];
  };
  const cacheUpdateIsolated: UpdateCache<Value> = (force?) =>
    cacheUpdateContextual(update!(_value, _previous), force);
 
  const getCurrentCache: GetCurrentCache<Value> = (force?: boolean) => [
    _value,
    !!force, // changed
    _previous,
  ];
 
  return [update ? cacheUpdateIsolated : cacheUpdateContextual, getCurrentCache] as
    | CacheContextual<Value>
    | Cache<Value>;
}