{"version":3,"file":"helpers.mjs","names":[],"sources":["../../src/helpers.ts"],"sourcesContent":["import type { Package, Version, Dependency, Maintainer, URLBuilder } from \"./core/types.ts\";\nimport type { Client } from \"./core/client.ts\";\nimport { createFromPURL } from \"./core/purl.ts\";\nimport { InvalidPURLError } from \"./core/errors.ts\";\n\n/**\n * Fetch normalized package metadata from a package URL.\n *\n * @param purl - Package URL.\n * @param signal - Optional cancellation signal.\n * @param client - Optional HTTP client.\n * @returns {Promise<Package>} Normalized package metadata.\n */\nexport async function fetchPackageFromPURL(\n  purl: string,\n  signal?: AbortSignal,\n  client?: Client,\n): Promise<Package> {\n  const [reg, name] = await createFromPURL(purl, client);\n  return reg.fetchPackage(name, signal);\n}\n\n/**\n * Fetch all versions from a package URL.\n *\n * @param purl - Package URL.\n * @param signal - Optional cancellation signal.\n * @param client - Optional HTTP client.\n * @returns {Promise<Version[]>} Normalized versions.\n */\nexport async function fetchVersionsFromPURL(\n  purl: string,\n  signal?: AbortSignal,\n  client?: Client,\n): Promise<Version[]> {\n  const [reg, name] = await createFromPURL(purl, client);\n  return reg.fetchVersions(name, signal);\n}\n\n/**\n * Fetch dependencies for a versioned package URL.\n *\n * @param purl - Versioned package URL.\n * @param signal - Optional cancellation signal.\n * @param client - Optional HTTP client.\n * @returns {Promise<Dependency[]>} Normalized dependencies.\n */\nexport async function fetchDependenciesFromPURL(\n  purl: string,\n  signal?: AbortSignal,\n  client?: Client,\n): Promise<Dependency[]> {\n  const [reg, name, version] = await createFromPURL(purl, client);\n  if (!version) {\n    throw new InvalidPURLError(purl, \"must include a version for dependency lookup\");\n  }\n  return reg.fetchDependencies(name, version, signal);\n}\n\n/**\n * Fetch maintainers from a package URL.\n *\n * @param purl - Package URL.\n * @param signal - Optional cancellation signal.\n * @param client - Optional HTTP client.\n * @returns {Promise<Maintainer[]>} Normalized maintainers.\n */\nexport async function fetchMaintainersFromPURL(\n  purl: string,\n  signal?: AbortSignal,\n  client?: Client,\n): Promise<Maintainer[]> {\n  const [reg, name] = await createFromPURL(purl, client);\n  return reg.fetchMaintainers(name, signal);\n}\n\nconst DEFAULT_CONCURRENCY = 15;\n\n/**\n * Fetch packages concurrently, skipping failed lookups.\n *\n * @param purls - Package URLs to fetch.\n * @param options - Optional concurrency, cancellation, and client settings.\n * @returns {Promise<Map<string, Package>>} Results keyed by package URL.\n */\nexport async function bulkFetchPackages(\n  purls: readonly string[],\n  options?: Readonly<{ concurrency?: number; signal?: AbortSignal; client?: Client }>,\n): Promise<Map<string, Package>> {\n  const concurrency = options?.concurrency ?? DEFAULT_CONCURRENCY;\n  const results = new Map<string, Package>();\n  const queue = [...purls];\n\n  const signal = options?.signal;\n\n  const workers = Array.from({ length: Math.min(concurrency, queue.length) }, async () => {\n    while (queue.length > 0) {\n      if (signal?.aborted) break;\n\n      const purl = queue.shift()!;\n      try {\n        const pkg = await fetchPackageFromPURL(purl, signal, options?.client);\n        results.set(purl, pkg);\n      } catch {\n        if (signal?.aborted) break;\n        // Silently skip failed lookups — absent from results map\n      }\n    }\n  });\n\n  await Promise.all(workers);\n  return results;\n}\n\n/**\n * Select an exact requested or latest version, then the newest usable one.\n *\n * @param versions - Candidate versions.\n * @param options - Optional requested and latest version numbers.\n * @returns {Version | null} The selected version, or null.\n */\nexport function selectVersion(\n  versions: readonly Version[],\n  options?: Readonly<{\n    requested?: string;\n    latest?: string;\n  }>,\n): Version | null {\n  const { requested, latest } = options ?? {};\n\n  if (requested) {\n    const exact = versions.find((v) => v.number === requested && v.status === \"\");\n    if (exact) return exact;\n  }\n\n  if (latest) {\n    const latestV = versions.find((v) => v.number === latest && v.status === \"\");\n    if (latestV) return latestV;\n  }\n\n  const usable = versions.filter((v) => v.status === \"\");\n  if (usable.length === 0) return null;\n\n  usable.sort((a, b) => {\n    const at = a.publishedAt?.getTime() ?? 0;\n    const bt = b.publishedAt?.getTime() ?? 0;\n    return bt - at;\n  });\n\n  return usable[0] ?? null;\n}\n\n/**\n * Resolve the best documentation URL for a package.\n *\n * @param pkg - Package metadata.\n * @param urls - Ecosystem URL builder.\n * @param version - Optional package version.\n * @returns {string} The explicit, homepage, or ecosystem documentation URL.\n */\nexport function resolveDocsUrl(pkg: Package, urls: URLBuilder, version?: string): string {\n  return pkg.documentation || pkg.homepage || urls.documentation(pkg.name, version);\n}\n\n/**\n * Resolve the ecosystem README URL for a package.\n *\n * @param pkg - Package metadata.\n * @param urls - Ecosystem URL builder.\n * @param version - Optional package version.\n * @returns {string} The README URL.\n */\nexport function resolveReadmeUrl(pkg: Package, urls: URLBuilder, version?: string): string {\n  return urls.readme(pkg.name, version);\n}\n"],"mappings":";;;;;;;;CAaA,OAAA,IAAA,cAAsB,MAAA,MACpB;AAIA;AAEF,eAAA,0BAAA,MAAA,QAAA,QAAA;;;;;;;;AAUA;AAKE,MAAA,sBAA0B;AAE5B,eAAA,kBAAA,OAAA,SAAA;;;;;;;;;GAUA,IAAA;IAKE,MAAO,MAAK,MAAM,qBAAiB,MAAA,QAAqB,SAAM,MAAA;IAC9D,QAAK,IACH,MAAM,GAAI;GAEZ,QAAO;IACT,IAAA,QAAA,SAAA;;;;;;;;CAUA,MAAA,EAAA,WAAsB,WAAA,WACpB,CAAA;CAIA,IAAA,WAAY;EACZ,MAAO,QAAI,SAAA,MAAiB,MAAM,EAAA,WAAM,aAAA,EAAA,WAAA,EAAA;EAC1C,IAAA,OAAA,OAAA;CAEA;;;;;;;;EASA,MAAA,KAAA,EAAsB,aAAA,QACpB,KACA;EAEA,QAAM,EAAA,aAAc,QAAS,KAAA,KAAA;CAC7B,CAAA;CACA,OAAM,OAAQ,MAAI;AAElB;AAGE,SAAO,eAAe,KAAG,MAAA,SAAA;CACvB,OAAI,IAAA,iBAAiB,IAAA,YAAA,KAAA,cAAA,IAAA,MAAA,OAAA;AAErB;AAEE,SAAA,iBAAkB,KAAA,MAAA,SAAqB;CACvC,OAAA,KAAQ,OAAI,IAAM,MAAG,OAAA;AACvB;AAGA,SAAA,mBAAA,2BAAA,0BAAA,sBAAA,uBAAA,gBAAA,kBAAA"}