report-formatter.tsโข13.4 kB
/**
* Detailed Report Formatter for Python Code Review
* Generates comprehensive, consistent reports for code analysis
*/
import { AnalysisResult, CodeIssue } from './python-analyzer.js';
export class ReportFormatter {
public generateDetailedReport(result: AnalysisResult): string {
const sections = [
this.generateHeader(result),
this.generateExecutiveSummary(result),
this.generateScorecard(result),
this.generateIssuesBreakdown(result),
this.generateDetailedIssues(result),
this.generateRecommendations(result),
this.generateFooter()
];
return sections.join('\n\n');
}
public generateSummaryReport(result: AnalysisResult): string {
const sections = [
this.generateHeader(result),
this.generateScorecard(result),
this.generateTopIssues(result, 5),
this.generateQuickRecommendations(result)
];
return sections.join('\n\n');
}
public generateSecurityReport(result: AnalysisResult): string {
const securityIssues = result.issues.filter(issue => issue.type === 'security');
const sections = [
'๐ **SECURITY ANALYSIS REPORT**',
'=' + '='.repeat(50),
`**File:** ${result.fileName}`,
`**Security Score:** ${result.securityScore}/100 ${this.getSecurityRating(result.securityScore)}`,
`**Security Issues Found:** ${securityIssues.length}`,
'',
this.generateSecurityIssuesDetail(securityIssues),
this.generateSecurityRecommendations(securityIssues)
];
return sections.join('\n');
}
private generateHeader(result: AnalysisResult): string {
const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
return [
'๐ **PYTHON CODE REVIEW REPORT**',
'=' + '='.repeat(50),
`**File:** ${result.fileName}`,
`**Analysis Date:** ${timestamp}`,
`**Total Lines:** ${result.totalLines}`,
`**Total Issues:** ${result.totalIssues}`
].join('\n');
}
private generateExecutiveSummary(result: AnalysisResult): string {
const riskLevel = this.calculateRiskLevel(result);
const deploymentReady = result.criticalIssues === 0 && result.highIssues <= 2;
return [
'## ๐ **EXECUTIVE SUMMARY**',
'',
`**Overall Risk Level:** ${riskLevel}`,
`**Production Ready:** ${deploymentReady ? 'โ
YES' : 'โ NO'}`,
`**Summary:** ${result.summary}`,
'',
this.generateRiskBreakdown(result)
].join('\n');
}
private generateScorecard(result: AnalysisResult): string {
return [
'## ๐ฏ **QUALITY SCORECARD**',
'',
`| Metric | Score | Rating |`,
`|--------|-------|--------|`,
`| Code Quality | ${result.codeQualityScore}/100 | ${this.getRating(result.codeQualityScore)} |`,
`| Security | ${result.securityScore}/100 | ${this.getSecurityRating(result.securityScore)} |`,
`| Issues Density | ${(result.totalIssues / result.totalLines * 100).toFixed(2)} per 100 lines | ${this.getDensityRating(result.totalIssues / result.totalLines)} |`,
''
].join('\n');
}
private generateIssuesBreakdown(result: AnalysisResult): string {
const typeBreakdown = this.getIssueTypeBreakdown(result.issues);
return [
'## ๐ **ISSUES BREAKDOWN**',
'',
'### By Severity:',
`- ๐ด **Critical:** ${result.criticalIssues} issues`,
`- ๐ **High:** ${result.highIssues} issues`,
`- ๐ก **Medium:** ${result.mediumIssues} issues`,
`- ๐ต **Low:** ${result.lowIssues} issues`,
'',
'### By Category:',
...Object.entries(typeBreakdown).map(([type, count]) =>
`- ${this.getTypeIcon(type)} **${this.capitalize(type)}:** ${count} issues`
)
].join('\n');
}
private generateDetailedIssues(result: AnalysisResult): string {
if (result.issues.length === 0) {
return '## โ
**NO ISSUES FOUND**\n\nExcellent work! Your code follows best practices.';
}
const sections = ['## ๐จ **DETAILED ISSUES**', ''];
const groupedIssues = this.groupIssuesBySeverity(result.issues);
Object.entries(groupedIssues).forEach(([severity, issues]) => {
if (issues.length > 0) {
sections.push(`### ${this.getSeverityIcon(severity)} ${this.capitalize(severity)} Issues (${issues.length})`);
sections.push('');
issues.forEach((issue, index) => {
sections.push(this.formatDetailedIssue(issue, index + 1));
sections.push('');
});
}
});
return sections.join('\n');
}
private generateRecommendations(result: AnalysisResult): string {
return [
'## ๐ก **RECOMMENDATIONS**',
'',
...result.recommendations.map(rec => `- ${rec}`),
'',
'### Next Steps:',
this.generateNextSteps(result)
].join('\n');
}
private generateTopIssues(result: AnalysisResult, limit: number): string {
const topIssues = result.issues
.slice(0, limit)
.map((issue, index) => this.formatBriefIssue(issue, index + 1));
if (topIssues.length === 0) {
return '## โ
**NO MAJOR ISSUES**\n\nYour code looks great!';
}
return [
`## ๐ **TOP ${limit} ISSUES**`,
'',
...topIssues
].join('\n');
}
private generateSecurityIssuesDetail(issues: CodeIssue[]): string {
if (issues.length === 0) {
return 'โ
**NO SECURITY VULNERABILITIES DETECTED**\n\nYour code appears secure from common vulnerabilities.';
}
const sections = ['## ๐ก๏ธ **SECURITY VULNERABILITIES**', ''];
issues.forEach((issue, index) => {
sections.push(`### ${index + 1}. ${issue.message}`);
sections.push(`**Severity:** ${this.getSeverityIcon(issue.severity)} ${issue.severity.toUpperCase()}`);
sections.push(`**Line:** ${issue.line}`);
sections.push(`**Rule:** ${issue.rule}`);
if (issue.codeSnippet) {
sections.push(`**Code:** \`${issue.codeSnippet}\``);
}
if (issue.suggestion) {
sections.push(`**Fix:** ${issue.suggestion}`);
}
sections.push('');
});
return sections.join('\n');
}
private generateSecurityRecommendations(issues: CodeIssue[]): string {
const recommendations = [
'## ๐ ๏ธ **SECURITY RECOMMENDATIONS**',
''
];
if (issues.length === 0) {
recommendations.push('- Continue following secure coding practices');
recommendations.push('- Regular security audits and dependency updates');
recommendations.push('- Consider implementing automated security scanning in CI/CD');
return recommendations.join('\n');
}
const criticalCount = issues.filter(i => i.severity === 'critical').length;
const highCount = issues.filter(i => i.severity === 'high').length;
if (criticalCount > 0) {
recommendations.push('๐จ **IMMEDIATE ACTIONS REQUIRED:**');
recommendations.push(`- Fix all ${criticalCount} critical vulnerabilities before production deployment`);
recommendations.push('- Conduct thorough penetration testing');
recommendations.push('- Review access controls and authentication mechanisms');
recommendations.push('');
}
if (highCount > 0) {
recommendations.push('โ ๏ธ **HIGH PRIORITY ACTIONS:**');
recommendations.push(`- Address ${highCount} high-priority security issues`);
recommendations.push('- Implement input validation and sanitization');
recommendations.push('- Review error handling and information disclosure');
recommendations.push('');
}
recommendations.push('๐ **GENERAL SECURITY BEST PRACTICES:**');
recommendations.push('- Use parameterized queries for database operations');
recommendations.push('- Store sensitive data in environment variables');
recommendations.push('- Enable SSL/TLS verification');
recommendations.push('- Use cryptographically secure random number generation');
recommendations.push('- Implement proper error handling without information leakage');
return recommendations.join('\n');
}
private formatDetailedIssue(issue: CodeIssue, index: number): string {
const lines = [
`#### ${index}. ${issue.message}`,
'',
`**Type:** ${this.getTypeIcon(issue.type)} ${this.capitalize(issue.type)}`,
`**Severity:** ${this.getSeverityIcon(issue.severity)} ${issue.severity.toUpperCase()}`,
`**Line:** ${issue.line}`,
`**Rule:** \`${issue.rule}\``
];
if (issue.codeSnippet) {
lines.push(`**Code:**`);
lines.push('```python');
lines.push(issue.codeSnippet);
lines.push('```');
}
if (issue.suggestion) {
lines.push(`**๐ก Suggestion:** ${issue.suggestion}`);
}
return lines.join('\n');
}
private formatBriefIssue(issue: CodeIssue, index: number): string {
return `${index}. ${this.getSeverityIcon(issue.severity)} **Line ${issue.line}:** ${issue.message}`;
}
private generateNextSteps(result: AnalysisResult): string {
const steps = [];
if (result.criticalIssues > 0) {
steps.push('1. ๐จ **CRITICAL:** Address all critical security vulnerabilities immediately');
}
if (result.highIssues > 0) {
steps.push(`${steps.length + 1}. โ ๏ธ **HIGH:** Fix ${result.highIssues} high-priority issues`);
}
if (result.mediumIssues > 0) {
steps.push(`${steps.length + 1}. ๐ **MEDIUM:** Plan to address ${result.mediumIssues} medium-priority issues`);
}
if (result.lowIssues > 0) {
steps.push(`${steps.length + 1}. ๐ง **MAINTENANCE:** Address ${result.lowIssues} low-priority issues during refactoring`);
}
steps.push(`${steps.length + 1}. โ
**VERIFY:** Run tests and verify all fixes work correctly`);
steps.push(`${steps.length + 1}. ๐ **REPEAT:** Re-run code review after fixes are applied`);
return steps.join('\n');
}
private generateQuickRecommendations(result: AnalysisResult): string {
const quickRecs = result.recommendations.slice(0, 3);
return [
'## ๐ฏ **QUICK WINS**',
'',
...quickRecs.map(rec => `- ${rec}`)
].join('\n');
}
private generateFooter(): string {
return [
'---',
'**Report Generated by Python Code Review MCP Agent**',
'',
'๐ก *This automated analysis focuses on code quality and security.*',
'๐ *Re-run analysis after applying fixes to track improvements.*'
].join('\n');
}
// Helper methods
private calculateRiskLevel(result: AnalysisResult): string {
if (result.criticalIssues > 0) return '๐ด **CRITICAL RISK**';
if (result.highIssues > 3) return '๐ **HIGH RISK**';
if (result.mediumIssues > 5) return '๐ก **MEDIUM RISK**';
return '๐ข **LOW RISK**';
}
private generateRiskBreakdown(result: AnalysisResult): string {
const risks = [];
if (result.criticalIssues > 0) {
risks.push(`- ๐จ ${result.criticalIssues} critical security vulnerabilities`);
}
if (result.securityScore < 70) {
risks.push(`- ๐ Security score below acceptable threshold (${result.securityScore}/100)`);
}
if (result.codeQualityScore < 70) {
risks.push(`- ๐ Code quality needs improvement (${result.codeQualityScore}/100)`);
}
if (risks.length === 0) {
return '- โ
No significant risks identified';
}
return risks.join('\n');
}
private getIssueTypeBreakdown(issues: CodeIssue[]): Record<string, number> {
const breakdown: Record<string, number> = {};
issues.forEach(issue => {
breakdown[issue.type] = (breakdown[issue.type] || 0) + 1;
});
return breakdown;
}
private groupIssuesBySeverity(issues: CodeIssue[]): Record<string, CodeIssue[]> {
const groups: Record<string, CodeIssue[]> = {
critical: [],
high: [],
medium: [],
low: []
};
issues.forEach(issue => {
groups[issue.severity].push(issue);
});
return groups;
}
private getRating(score: number): string {
if (score >= 90) return '๐ Excellent';
if (score >= 80) return 'โ
Good';
if (score >= 70) return 'โ ๏ธ Fair';
if (score >= 60) return 'โ Poor';
return '๐จ Critical';
}
private getSecurityRating(score: number): string {
if (score >= 90) return '๐ Secure';
if (score >= 70) return 'โ ๏ธ Moderate Risk';
if (score >= 50) return 'โ High Risk';
return '๐จ Critical Risk';
}
private getDensityRating(density: number): string {
if (density < 0.05) return '๐ Excellent';
if (density < 0.1) return 'โ
Good';
if (density < 0.2) return 'โ ๏ธ Moderate';
return 'โ High';
}
private getSeverityIcon(severity: string): string {
const icons = {
critical: '๐จ',
high: '๐ด',
medium: '๐ก',
low: '๐ต'
};
return icons[severity as keyof typeof icons] || 'โ';
}
private getTypeIcon(type: string): string {
const icons = {
security: '๐',
quality: '๐',
style: '๐
',
performance: 'โก',
maintainability: '๐ง'
};
return icons[type as keyof typeof icons] || '๐';
}
private capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
}