{"version":3,"file":"ParentCache.mjs","names":["pair: ItemCleanupPair<CacheItem<T>>"],"sources":["../src/ParentCache.ts"],"sourcesContent":["import type {\n  CleanupFn,\n  Factory,\n  ItemCleanupPair,\n} from '@isograph/disposable-types';\nimport type { CacheItem } from './CacheItem';\nimport { createTemporarilyRetainedCacheItem } from './CacheItem';\n\n// TODO convert cache impl to a getter and setter and free functions\n// TODO accept options that get passed to CacheItem\n\n/**\n * ParentCache\n * - A ParentCache can be in two states: populated and unpopulated.\n * - A ParentCache holds a CacheItem, which can choose to remove itself from\n *   the parent ParentCache.\n * - If the ParentCache is populated, the CacheItem (i.e. this.__value) must be\n *   in the InParentCacheAndNotDisposed state, i.e. not disposed, so after we\n *   null-check this.__value, this.__value.getValue(), this.__value.temporaryRetain()\n *   and this.__value.permanentRetain() are safe to be called.\n *\n * - Though we do not do so, it is always safe to call parentCache.delete().\n *\n * Invariant:\n * - A parent cache at a given \"location\" (conceptually, an ID) should always\n *   be called\n */\nexport class ParentCache<T> {\n  private __cacheItem: CacheItem<T> | null = null;\n  private readonly __factory: Factory<T>;\n\n  // TODO pass an onEmpty function, which can e.g. remove this ParentCache\n  // from some parent object.\n  constructor(factory: Factory<T>) {\n    this.__factory = factory;\n  }\n\n  /**\n   * This is called from useCachedResponsivePrecommitValue, when the parent cache is populated\n   * and a previous temporary retain has been disposed. This can occur in scenarios like:\n   * - temporary retain A is created by component B rendering\n   * - temporary retain A expires, emptying the parent cache\n   * - another component renders, sharing the same parent cache, filling\n   *   by calling getOrPopulateAndTemporaryRetain\n   * - component B commits. We see that temporary retain A has been disposed,\n   *   and re-check the parent cache by calling this method.\n   */\n  getAndPermanentRetainIfPresent(): ItemCleanupPair<T> | null {\n    return this.__cacheItem != null\n      ? [this.__cacheItem.getValue(), this.__cacheItem.permanentRetain()]\n      : null;\n  }\n\n  getOrPopulateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn] {\n    return this.__cacheItem == null\n      ? this.__populateAndTemporaryRetain()\n      : temporaryRetain(this.__cacheItem);\n  }\n\n  private __populateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn] {\n    const pair: ItemCleanupPair<CacheItem<T>> =\n      createTemporarilyRetainedCacheItem(this.__factory, () => {\n        // We are doing this check because we don't want to remove the cache item\n        // if it is not the one that was created when the temporary retain was created.\n        //\n        // Consider the following scenario:\n        // - we populate the cache with CacheItem A,\n        // - then manually delete CacheItem A (e.g. to force a refetch)\n        // - then, we re-populate the parent cache with CacheItem B\n        // - then, the temporary retain of CacheItem A is disposed or expires.\n        //\n        // At this point, we don't want to delete CacheItem B from the cache.\n        //\n        // TODO consider what happens if items are === comparable to each other,\n        // e.g. the item is a number!\n        if (this.__cacheItem === pair[0]) {\n          this.empty();\n        }\n      });\n\n    // We deconstruct this here instead of at the definition site because otherwise,\n    // typescript thinks that cacheItem is any, because it's referenced in the closure.\n    const [cacheItem, disposeTemporaryRetain] = pair;\n    this.__cacheItem = cacheItem;\n    return [cacheItem, cacheItem.getValue(), disposeTemporaryRetain];\n  }\n\n  empty() {\n    this.__cacheItem = null;\n  }\n\n  get factory(): Factory<T> {\n    return this.__factory;\n  }\n\n  isEmpty(): boolean {\n    return this.__cacheItem == null;\n  }\n}\n\nfunction temporaryRetain<T>(value: CacheItem<T>): [CacheItem<T>, T, CleanupFn] {\n  return [value, value.getValue(), value.temporaryRetain()];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA2BA,IAAa,cAAb,MAA4B;CAM1B,YAAY,SAAqB;qBALU;AAMzC,OAAK,YAAY;;;;;;;;;;;;CAanB,iCAA4D;AAC1D,SAAO,KAAK,eAAe,OACvB,CAAC,KAAK,YAAY,UAAU,EAAE,KAAK,YAAY,iBAAiB,CAAC,GACjE;;CAGN,kCAAgE;AAC9D,SAAO,KAAK,eAAe,OACvB,KAAK,8BAA8B,GACnC,gBAAgB,KAAK,YAAY;;CAGvC,AAAQ,+BAA6D;EACnE,MAAMA,OACJ,mCAAmC,KAAK,iBAAiB;AAcvD,OAAI,KAAK,gBAAgB,KAAK,GAC5B,MAAK,OAAO;IAEd;EAIJ,MAAM,CAAC,WAAW,0BAA0B;AAC5C,OAAK,cAAc;AACnB,SAAO;GAAC;GAAW,UAAU,UAAU;GAAE;GAAuB;;CAGlE,QAAQ;AACN,OAAK,cAAc;;CAGrB,IAAI,UAAsB;AACxB,SAAO,KAAK;;CAGd,UAAmB;AACjB,SAAO,KAAK,eAAe;;;AAI/B,SAAS,gBAAmB,OAAmD;AAC7E,QAAO;EAAC;EAAO,MAAM,UAAU;EAAE,MAAM,iBAAiB;EAAC"}