import type { FileDiffMetadata } from "@pierre/diffs"; import type { PullRequestDiffSide } from "@t3tools/contracts"; /** Only rendered hunks can anchor comments; list others off-diff. */ export function isLineInFileDiff( file: FileDiffMetadata, side: PullRequestDiffSide, line: number, ): boolean { return file.hunks.some((hunk) => side === "left" ? line >= hunk.deletionStart && line < hunk.deletionStart + hunk.deletionCount : line >= hunk.additionStart && line < hunk.additionStart + hunk.additionCount, ); } export type DiffFoldOverride = "expanded" | "folded" | null; /** The reader's own fold choice per file. It is absolute, so a Viewed mark loading later keeps it. */ export type FileDiffFoldChoices = ReadonlyMap; /** * A reader's own choice wins. Otherwise the toolbar decides, and a file still marked Viewed * starts folded. Fold all and Expand all clear the choices, so later pages follow the toolbar. */ export function isFileDiffCollapsed( fileKey: string, foldOverride: DiffFoldOverride, choices: FileDiffFoldChoices, viewed = false, ): boolean { return choices.get(fileKey) ?? (foldOverride === "folded" || viewed); } export function withFileDiffFold( choices: FileDiffFoldChoices, fileKey: string, collapsed: boolean, ): FileDiffFoldChoices { if (choices.get(fileKey) === collapsed) return choices; return new Map(choices).set(fileKey, collapsed); } export function getFileViewedRange( files: ReadonlyArray, fileKey: string, anchorFileKey: string | null, ): ReadonlyArray { const index = files.findIndex((file) => file.fileKey === fileKey); if (index === -1) return []; const anchorIndex = files.findIndex((file) => file.fileKey === anchorFileKey); if (anchorIndex === -1) return files.slice(index, index + 1); return files.slice(Math.min(index, anchorIndex), Math.max(index, anchorIndex) + 1); }