import { isChangedPosition, parseDiff } from "./diff.ts"; import type { Finding, ValidatorOutput } from "./types.ts"; function normalized(value: string): string { return value .toLowerCase() .replace(/[^a-z0-9]+/g, " ") .trim(); } function dedupeKey(finding: Finding): string { const location = finding.kind === "code" ? `${finding.path}:${finding.side}:${finding.line}` : finding.requirement; return `${finding.category}|${location}|${normalized(finding.title)}|${normalized(finding.description)}`; } export function finalizeFindings( validations: ValidatorOutput[], diff: string, ): Finding[] { const parsed = parseDiff(diff); const seen = new Set(); const findings: Finding[] = []; for (const validation of validations) { if ( !validation.valid || validation.confidence < 80 || validation.findingId !== validation.finding.id ) continue; const finding = validation.finding; if ( finding.kind === "code" && !isChangedPosition(parsed, finding.path, finding.line, finding.side) ) continue; const key = dedupeKey(finding); if (seen.has(key)) continue; seen.add(key); findings.push(finding); } return findings.sort((left, right) => { const leftPath = left.kind === "code" ? left.path : (left.path ?? ""); const rightPath = right.kind === "code" ? right.path : (right.path ?? ""); return ( leftPath.localeCompare(rightPath) || left.title.localeCompare(right.title) ); }); }