From ec01628f7393b7a753054ebc97c603d664d9fe66 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Tue, 3 Feb 2026 10:30:12 +0000 Subject: [PATCH] Initial upload of ai-code-audit-cli project --- src/reporting/formatter.py | 149 +++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/reporting/formatter.py diff --git a/src/reporting/formatter.py b/src/reporting/formatter.py new file mode 100644 index 0000000..4ddede2 --- /dev/null +++ b/src/reporting/formatter.py @@ -0,0 +1,149 @@ +"""Report formatting for AI Code Audit CLI.""" + +import json +from datetime import datetime +from typing import Optional + +from ..cli.options import OutputFormat, ScanOptions +from .confidence import ConfidenceScorer +from ..core.models import ScanResult, Issue, IssueCategory, SeverityLevel + + +class ReportFormatter: + """Format scan results into various output formats.""" + + def __init__(self, options: ScanOptions): + """Initialize the report formatter.""" + self.options = options + + def format_json( + self, result: ScanResult, confidence_scorer: ConfidenceScorer + ) -> str: + """Format results as JSON.""" + score = confidence_scorer.calculate(result) + breakdown = confidence_scorer.get_score_breakdown(result) + + report = { + "audit_report": { + "generated_at": datetime.now().isoformat(), + "target_path": result.target_path, + "summary": { + "files_scanned": result.files_scanned, + "total_issues": len(result.issues), + "confidence_score": score, + "score_grade": confidence_scorer.get_score_grade(score), + }, + "score_breakdown": breakdown, + "issues_by_severity": self._count_by_severity(result), + "issues_by_category": self._count_by_category(result), + "issues": [self._format_issue(issue) for issue in result.issues], + "warnings": result.warnings, + } + } + + return json.dumps(report, indent=2) + + def format_markdown( + self, result: ScanResult, confidence_scorer: ConfidenceScorer + ) -> str: + """Format results as Markdown.""" + score = confidence_scorer.calculate(result) + + lines = [ + "# AI Code Audit Report", + "", + f"**Generated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", + f"**Target:** {result.target_path}", + f"**Files Scanned:** {result.files_scanned}", + "", + "## Summary", + "", + f"| Metric | Value |", + f"|--------|-------|", + f"| Confidence Score | **{score}/100** |", + f"| Grade | {confidence_scorer.get_score_grade(score)} |", + f"| Total Issues | {len(result.issues)} |", + f"| Warnings | {len(result.warnings)} |", + "", + "### Issues by Severity", + "", + self._markdown_severity_table(result), + "", + "### Issues by Category", + "", + self._markdown_category_table(result), + "", + "## Issues Detail", + "", + ] + + if result.issues: + for i, issue in enumerate(result.issues, 1): + lines.append(f"### {i}. [{issue.severity.value.upper()}] {issue.category.value}") + lines.append(f"- **File:** `{issue.file_path}`") + lines.append(f"- **Line:** {issue.line_number}") + lines.append(f"- **Message:** {issue.message}") + if issue.suggestion: + lines.append(f"- **Suggestion:** {issue.suggestion}") + lines.append("") + else: + lines.append("No issues found! Great job!") + lines.append("") + + if result.warnings: + lines.append("## Warnings") + lines.append("") + for warning in result.warnings: + lines.append(f"- {warning}") + lines.append("") + + lines.append("---") + lines.append("*Generated by AI Code Audit CLI*") + + return "\n".join(lines) + + def _markdown_severity_table(self, result: ScanResult) -> str: + """Generate markdown table for severity counts.""" + counts = self._count_by_severity(result) + table = "| Severity | Count |\n|---------|-------|\n" + for severity in SeverityLevel: + count = counts.get(severity.value, 0) + table += f"| {severity.value.capitalize()} | {count} |\n" + return table + + def _markdown_category_table(self, result: ScanResult) -> str: + """Generate markdown table for category counts.""" + counts = self._count_by_category(result) + table = "| Category | Count |\n|---------|-------|\n" + for category in IssueCategory: + count = counts.get(category.value, 0) + table += f"| {category.value.replace('_', ' ').title()} | {count} |\n" + return table + + def _count_by_severity(self, result: ScanResult) -> dict: + """Count issues by severity.""" + counts = {} + for issue in result.issues: + sev = issue.severity.value + counts[sev] = counts.get(sev, 0) + 1 + return counts + + def _count_by_category(self, result: ScanResult) -> dict: + """Count issues by category.""" + counts = {} + for issue in result.issues: + cat = issue.category.value + counts[cat] = counts.get(cat, 0) + 1 + return counts + + def _format_issue(self, issue: Issue) -> dict: + """Format an issue for JSON output.""" + return { + "severity": issue.severity.value, + "category": issue.category.value, + "file_path": issue.file_path, + "line_number": issue.line_number, + "message": issue.message, + "suggestion": issue.suggestion, + "scanner": issue.scanner_name, + }