{"version":3,"file":"health-tree.cjs","sources":["../../../src/collection/health-tree.ts"],"sourcesContent":["import { getCollectionBuilder } from '../query/live/collection-registry.js'\nimport type { HealthNode } from '../types'\nimport type { CollectionImpl } from './index.js'\n\n/** A Collection that another Collection reads, under its query alias. */\nexport interface HealthSource {\n  readonly alias: string\n  /** Tells apart two sources under one alias, such as two includes. */\n  readonly id?: string\n  readonly collection: CollectionImpl<any, any, any, any, any>\n  readonly kind?: HealthNode[`kind`]\n}\n\n// One cached node per Collection and source. A node keeps its identity until\n// its own fields or one of its children change, so a change replaces only the\n// nodes on its path and readers can compare nodes with `===`.\nconst nodeCache = new WeakMap<object, Map<string, HealthNode>>()\n\n/**\n * Build the health tree for a Collection. A base Collection is one node. A live\n * query is a node with one child per source alias, in query order, and each\n * child that is itself a live query recurses. The tree is read from current\n * state, so every node mirrors its Collection at the moment it is read.\n */\nexport function buildHealthTree(\n  collection: CollectionImpl<any, any, any, any, any>,\n  { alias, id, kind }: Omit<HealthSource, `collection`> = {\n    alias: `root`,\n  },\n  // The reader that caches this node, so a source's node lives only as long\n  // as the query that reads it.\n  owner: object = collection,\n): HealthNode {\n  // A live query's tree shape comes from its query definition.\n  const builder = getCollectionBuilder(collection)\n  const sources = builder?.healthSources() ?? []\n  const { failureReason, error } = collection._lifecycle.problems\n  const children = sources.map((source) =>\n    buildHealthTree(source.collection, source, collection),\n  )\n  return healthNode(owner, id, {\n    alias,\n    collectionId: collection.id,\n    kind: kind ?? (builder ? `live-query` : `source`),\n    status: collection.status,\n    failureReason,\n    error,\n    reloading: collection._lifecycle.reloading,\n    sources: children,\n  })\n}\n\n/**\n * A node from its own facts and its children. It has errors when it or\n * anything below it has a `failureReason` or an `error`.\n */\nexport function healthNode(\n  owner: object,\n  id: string | undefined,\n  fields: Omit<HealthNode, `hasErrors`>,\n): HealthNode {\n  const { failureReason, error, sources } = fields\n  return cachedNode(owner, id ?? fields.alias, {\n    ...fields,\n    hasErrors:\n      failureReason !== null ||\n      error !== null ||\n      sources.some((child) => child.hasErrors),\n  })\n}\n\n/**\n * Every node in a health tree that shows a problem of its own, in tree order:\n * a `failureReason` or an `error`. A node whose only problems are below it is\n * not listed; its descendants are.\n */\nexport function findProblems(health: HealthNode): Array<HealthNode> {\n  if (!health.hasErrors) return []\n  const ownProblem = health.failureReason !== null || health.error !== null\n  return [\n    ...(ownProblem ? [health] : []),\n    ...health.sources.flatMap(findProblems),\n  ]\n}\n\n/** Return the cached node for this Collection and alias if nothing changed. */\nfunction cachedNode(owner: object, key: string, next: HealthNode): HealthNode {\n  let nodes = nodeCache.get(owner)\n  if (!nodes) nodeCache.set(owner, (nodes = new Map()))\n  const previous = nodes.get(key)\n  if (previous && sameNode(previous, next)) return previous\n  nodes.set(key, next)\n  return next\n}\n\nfunction sameNode(a: HealthNode, b: HealthNode): boolean {\n  return (\n    a.collectionId === b.collectionId &&\n    a.kind === b.kind &&\n    a.status === b.status &&\n    a.hasErrors === b.hasErrors &&\n    a.failureReason === b.failureReason &&\n    a.error === b.error &&\n    a.reloading === b.reloading &&\n    a.sources.length === b.sources.length &&\n    a.sources.every((source, index) => source === b.sources[index])\n  )\n}\n"],"names":["getCollectionBuilder"],"mappings":";;;AAgBA,MAAM,gCAAgB,QAAA;AAQf,SAAS,gBACd,YACA,EAAE,OAAO,IAAI,SAA2C;AAAA,EACtD,OAAO;AACT,GAGA,QAAgB,YACJ;AAEZ,QAAM,UAAUA,mBAAAA,qBAAqB,UAAU;AAC/C,QAAM,UAAU,SAAS,cAAA,KAAmB,CAAA;AAC5C,QAAM,EAAE,eAAe,MAAA,IAAU,WAAW,WAAW;AACvD,QAAM,WAAW,QAAQ;AAAA,IAAI,CAAC,WAC5B,gBAAgB,OAAO,YAAY,QAAQ,UAAU;AAAA,EAAA;AAEvD,SAAO,WAAW,OAAO,IAAI;AAAA,IAC3B;AAAA,IACA,cAAc,WAAW;AAAA,IACzB,MAAM,SAAS,UAAU,eAAe;AAAA,IACxC,QAAQ,WAAW;AAAA,IACnB;AAAA,IACA;AAAA,IACA,WAAW,WAAW,WAAW;AAAA,IACjC,SAAS;AAAA,EAAA,CACV;AACH;AAMO,SAAS,WACd,OACA,IACA,QACY;AACZ,QAAM,EAAE,eAAe,OAAO,QAAA,IAAY;AAC1C,SAAO,WAAW,OAAO,MAAM,OAAO,OAAO;AAAA,IAC3C,GAAG;AAAA,IACH,WACE,kBAAkB,QAClB,UAAU,QACV,QAAQ,KAAK,CAAC,UAAU,MAAM,SAAS;AAAA,EAAA,CAC1C;AACH;AAOO,SAAS,aAAa,QAAuC;AAClE,MAAI,CAAC,OAAO,UAAW,QAAO,CAAA;AAC9B,QAAM,aAAa,OAAO,kBAAkB,QAAQ,OAAO,UAAU;AACrE,SAAO;AAAA,IACL,GAAI,aAAa,CAAC,MAAM,IAAI,CAAA;AAAA,IAC5B,GAAG,OAAO,QAAQ,QAAQ,YAAY;AAAA,EAAA;AAE1C;AAGA,SAAS,WAAW,OAAe,KAAa,MAA8B;AAC5E,MAAI,QAAQ,UAAU,IAAI,KAAK;AAC/B,MAAI,CAAC,MAAO,WAAU,IAAI,OAAQ,QAAQ,oBAAI,KAAM;AACpD,QAAM,WAAW,MAAM,IAAI,GAAG;AAC9B,MAAI,YAAY,SAAS,UAAU,IAAI,EAAG,QAAO;AACjD,QAAM,IAAI,KAAK,IAAI;AACnB,SAAO;AACT;AAEA,SAAS,SAAS,GAAe,GAAwB;AACvD,SACE,EAAE,iBAAiB,EAAE,gBACrB,EAAE,SAAS,EAAE,QACb,EAAE,WAAW,EAAE,UACf,EAAE,cAAc,EAAE,aAClB,EAAE,kBAAkB,EAAE,iBACtB,EAAE,UAAU,EAAE,SACd,EAAE,cAAc,EAAE,aAClB,EAAE,QAAQ,WAAW,EAAE,QAAQ,UAC/B,EAAE,QAAQ,MAAM,CAAC,QAAQ,UAAU,WAAW,EAAE,QAAQ,KAAK,CAAC;AAElE;;;;"}