73 lines · 2.3 KB · TypeScript
RawDownload
import type { PullRequestRef, PullRequestStack, ThreadPullRequestLink } from "@t3tools/contracts"; /** Saved native membership is enough for navigation, but never supplies action head SHAs. */export function savedPullRequestStack(  links: ReadonlyArray<ThreadPullRequestLink>,  reference: PullRequestRef,): PullRequestStack | null {  const host = reference.host?.toLowerCase();  if (!host) return null;  const matching = links.filter(    (link) =>      link.host.toLowerCase() === host &&      link.repository.toLowerCase() === reference.repository.toLowerCase(),  );  const exact = matching.filter((link) => link.number === reference.number);  const candidates =    exact.length > 0      ? exact      : matching.filter((link) =>          link.stack?.layers.some((layer) => layer.number === reference.number),        );  const newest = candidates.toSorted(    (a, b) =>      Date.parse(b.snapshot?.syncedAt ?? b.linkedAt) -      Date.parse(a.snapshot?.syncedAt ?? a.linkedAt),  )[0];  const stack = newest?.stack;  if (!stack || !stack.layers.some((layer) => layer.number === reference.number)) return null;  return {    id: stack.id,    number: stack.number,    url: stack.url,    base: stack.base,    layers: stack.layers.map((layer) => {      const snapshot = matching        .filter((link) => link.number === layer.number)        .toSorted(          (a, b) =>            Date.parse(b.snapshot?.syncedAt ?? b.linkedAt) -            Date.parse(a.snapshot?.syncedAt ?? a.linkedAt),        )[0]?.snapshot;      return {        ...layer,        ...(snapshot ? { title: snapshot.title, isDraft: snapshot.isDraft } : {}),      };    }),  };} /** A fresh absence overrides saved membership; failed refreshes preserve available navigation. */export function pullRequestStackView(  query: {    data: PullRequestStack | null;    isSuccess: boolean;    isPending: boolean;    error: string | null;  },  saved: PullRequestStack | null,) {  const data = query.isSuccess ? query.data : (query.data ?? saved);  return {    data,    isFresh: query.isSuccess && !query.isPending,    notice:      data === null        ? null        : query.error          ? "Stack data may be stale. We couldn’t refresh it."          : !query.isSuccess || query.isPending            ? "Refreshing stack… Showing saved data."            : null,  };}