fs-memo.ts 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import path from 'node:path';
  2. import { Cache } from './cache-filesystem';
  3. import type { CacheApplyOption } from './cache-filesystem';
  4. import { isCI } from 'ci-info';
  5. const fsMemoCache = new Cache({ cachePath: path.resolve(__dirname, '../../.cache') });
  6. const TTL = isCI
  7. // We run CI daily, so 1.5 days TTL is enough to persist the cache across runs
  8. ? 1.5 * 86400 * 1000
  9. // We run locally less frequently, so we need to persist the cache for longer, 7 days
  10. : 7 * 86400 * 1000;
  11. type JSONValue =
  12. | string
  13. | number
  14. | boolean
  15. | null
  16. | JSONObject
  17. | JSONArray;
  18. interface JSONObject {
  19. [key: string]: JSONValue
  20. }
  21. interface JSONArray extends Array<JSONValue> {}
  22. export function cache<Args extends JSONValue[], T>(
  23. cb: (...args: Args) => Promise<T>,
  24. opt: Omit<CacheApplyOption<T, string>, 'ttl'>
  25. ): (...args: Args) => Promise<T> {
  26. // TODO if cb.toString() is long we should hash it
  27. const fixedKey = cb.toString();
  28. return async function cachedCb(...args: Args) {
  29. // Construct the complete cache key for this function invocation
  30. // TODO stringify is limited. For now we uses typescript to guard the args.
  31. const cacheKey = `${fixedKey}|${JSON.stringify(args)}`;
  32. const cacheName = cb.name || cacheKey;
  33. return fsMemoCache.apply(
  34. cacheKey,
  35. cb,
  36. {
  37. cacheName,
  38. ...opt,
  39. ttl: TTL
  40. } as CacheApplyOption<T, string>
  41. );
  42. };
  43. }