import type { AggregatedReview, Finding, ReviewSeverity } from "./types.ts"; const SEVERITY_ORDER: ReviewSeverity[] = ["error", "warning", "nit"]; const SEVERITY_LABEL: Record = { error: "Errors", warning: "Warnings", nit: "Nits", }; const SEVERITY_EMOJI: Record = { error: "๐Ÿ”ด", warning: "๐ŸŸก", nit: "๐Ÿ”ต", }; function renderGroup(severity: ReviewSeverity, findings: Finding[]): string { const items = findings.map( (f) => `**\`${f.filename}\`** line ${f.line}\n> ${f.comment}`, ); return `### ${SEVERITY_EMOJI[severity]} ${SEVERITY_LABEL[severity]} (${findings.length})\n\n${items.join("\n\n")}`; } export function formatReview( review: AggregatedReview, files: string[], model: string, ): string { console.log( `Formatting review for ${files.length} file${files.length === 1 ? "" : "s"} with model ${model}...`, ); const parts: string[] = []; parts.push( `## ๐Ÿค– shockbot review\n\n> Reviewed ${files.length} file${files.length === 1 ? "" : "s"} using \`${model}\``, ); // Summary section โ€” join per-chunk summaries const summaries = review.summaries.filter(Boolean); if (summaries.length > 0) { parts.push(`**Summary**\n\n${summaries.join("\n\n")}`); } // Group findings by severity const grouped = new Map(); for (const severity of SEVERITY_ORDER) grouped.set(severity, []); for (const finding of review.findings) { grouped.get(finding.severity)?.push(finding); } const hasFindings = review.findings.length > 0; if (hasFindings) { for (const severity of SEVERITY_ORDER) { const group = grouped.get(severity)!; if (group.length > 0) parts.push(renderGroup(severity, group)); } } else { parts.push("No issues found. โœ…"); } const timestamp = new Date().toISOString(); parts.push(`---\n\nshockbot ยท \`${model}\` ยท ${timestamp}`); return parts.join("\n\n---\n\n"); }