All files / src/Cache Cache.ts

97.43% Statements 38/39
83.33% Branches 10/12
85.71% Functions 6/7
97.43% Lines 38/39

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 837x 7x 7x   7x   7x 23x 23x 23x 23x     23x 23x       23x 23x   23x 22x   22x 2x   2x           23x 3x         17x   17x     17x 8x 7x     1x 1x           31x 31x   31x 31x   31x 26x 26x             29x 21x     29x       2x      
import { scope } from '../constants'
import { destroyWatchers, invalidateCache, queueWatchers, watchWithScope } from '../helpers'
import { Observable } from '../Observable'
import { type Observer } from '../types'
import { Watch } from '../Watch'
 
export class Cache<V = unknown> extends Observable<V> implements Observer {
  invalid = true
  updated = false
  destroyed = false
  isCache = true
 
  // Observer
  destructors = new Set<Function>()
  childWatchers = new Set<Observer>()
 
  readonly watcher: (update: boolean) => V
  constructor (watcher: (update: boolean) => V, freeParent?: boolean, fireImmediately?: boolean) {
    super()
    this.watcher = watcher
 
    if (!freeParent) {
      const { activeWatcher } = scope
 
      if (activeWatcher) {
        activeWatcher.childWatchers.add(this)
 
        activeWatcher.destructors.add(() => {
          activeWatcher.childWatchers.delete(this)
        })
      }
    }
 
    if (fireImmediately) {
      this.forceUpdate()
    }
  }
 
  update () {
    invalidateCache(this)
 
    const parents = [...this.observers]
    let parent: Observer
 
    while ((parent = parents.pop())) {
      if (parent instanceof Watch) {
        return this.forceUpdate()
      }
 
      if (parent instanceof Cache) {
        parents.push(...parent.observers)
      }
    }
  }
 
  forceUpdate () {
    if (!this.destroyed) {
      this.invalid = false
 
      watchWithScope(this, () => {
        const newValue = this.watcher(this.updated ? this.updated = true : false)
 
        if (newValue !== this.rawValue) {
          this.rawValue = newValue
          queueWatchers(this.observers)
        }
      })
    }
  }
 
  get value () {
    if (this.invalid) {
      this.forceUpdate()
    }
 
    return this.destroyed ? this.rawValue : super.value
  }
 
  destroy () {
    destroyWatchers(this)
  }
}