mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
708 lines (705 loc) ⢠29.7 kB
JavaScript
/**
* Detailed Report Generator
* Generates comprehensive reports with actionable recommendations
*/
import fs from 'fs-extra';
import * as path from 'path';
import chalk from 'chalk';
export class DetailedReportGenerator {
options;
constructor(options = {}) {
this.options = {
format: 'console',
includeDetails: true,
includeExamples: true,
includeTrends: false,
maxIssuesPerCategory: 10,
...options
};
}
async generateReport(analysisResults, projectPath) {
const report = this.buildReport(analysisResults, projectPath);
switch (this.options.format) {
case 'console':
this.outputConsoleReport(report);
break;
case 'markdown':
await this.outputMarkdownReport(report);
break;
case 'html':
await this.outputHTMLReport(report);
break;
case 'json':
await this.outputJSONReport(report);
break;
}
}
buildReport(results, projectPath) {
const projectName = path.basename(projectPath);
const timestamp = new Date().toISOString();
// Calculate summary
const summary = this.calculateSummary(results);
// Build individual reports
const report = {
projectName,
timestamp,
summary,
recommendations: this.generatePrioritizedRecommendations(results)
};
if (results.security) {
report.securityReport = this.buildSecurityReport(results.security);
}
if (results.performance) {
report.performanceReport = this.buildPerformanceReport(results.performance);
}
if (results.documentation) {
report.documentationReport = this.buildDocumentationReport(results.documentation);
}
if (results.codeQuality) {
report.codeQualityReport = this.buildCodeQualityReport(results.codeQuality);
}
if (results.crossPlatform) {
report.crossPlatformReport = this.buildCrossPlatformReport(results.crossPlatform);
}
if (results.unusedCode) {
report.unusedCodeReport = this.buildUnusedCodeReport(results.unusedCode);
}
return report;
}
calculateSummary(results) {
let totalScore = 0;
let analyzersRun = 0;
let totalIssues = 0;
let criticalIssues = 0;
const topConcerns = [];
// Aggregate scores and issues
const analyzers = ['security', 'performance', 'documentation', 'codeQuality', 'crossPlatform', 'unusedCode'];
for (const analyzer of analyzers) {
if (results[analyzer]) {
analyzersRun++;
// Get score
const score = results[analyzer].score ||
results[analyzer].securityScore ||
results[analyzer].overallScore || 0;
totalScore += score;
// Count issues
if (results[analyzer].issues) {
totalIssues += Array.isArray(results[analyzer].issues)
? results[analyzer].issues.length
: results[analyzer].issues;
}
// Count critical issues
if (results[analyzer].criticalIssues) {
criticalIssues += results[analyzer].criticalIssues;
}
// Add top concerns
if (score < 50) {
topConcerns.push(`${analyzer} score: ${score}/100`);
}
}
}
const overallScore = analyzersRun > 0 ? Math.round(totalScore / analyzersRun) : 0;
return {
overallScore,
overallGrade: this.scoreToGrade(overallScore),
totalIssues,
criticalIssues,
analyzersRun,
executionTime: 0, // Would need to track this
topConcerns: topConcerns.slice(0, 3)
};
}
buildSecurityReport(security) {
const score = security.securityScore || 0;
// Count vulnerabilities by severity
const vulnerabilities = {
critical: 0,
high: 0,
medium: 0,
low: 0
};
if (security.vulnerabilities) {
for (const vuln of security.vulnerabilities) {
vulnerabilities[vuln.severity]++;
}
}
// Get top vulnerabilities
const vulnTypes = new Map();
if (security.vulnerabilities) {
for (const vuln of security.vulnerabilities) {
if (!vulnTypes.has(vuln.type)) {
vulnTypes.set(vuln.type, {
type: vuln.type,
severity: vuln.severity,
count: 0,
impact: '',
recommendation: vuln.recommendation || ''
});
}
vulnTypes.get(vuln.type).count++;
}
}
const topVulnerabilities = Array.from(vulnTypes.values())
.sort((a, b) => {
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
return severityOrder[a.severity] -
severityOrder[b.severity];
})
.slice(0, 5);
// Build recommendations
const recommendations = [];
if (vulnerabilities.critical > 0) {
recommendations.push('Address critical vulnerabilities immediately');
}
if (security.owaspCompliance && security.owaspCompliance.overallCompliance < 70) {
recommendations.push('Improve OWASP compliance score');
}
if (security.entropyAnalysis && security.entropyAnalysis.totalHighEntropyStrings > 0) {
recommendations.push('Review and secure high-entropy strings (potential secrets)');
}
return {
score,
grade: this.scoreToGrade(score),
riskLevel: security.riskLevel || 'unknown',
vulnerabilities,
topVulnerabilities,
owaspCompliance: security.owaspCompliance ? {
score: security.owaspCompliance.overallCompliance,
failingCategories: Object.entries(security.owaspCompliance.categoryScores)
.filter(([_, cat]) => cat.score < 70)
.map(([name]) => name)
} : undefined,
recommendations
};
}
buildPerformanceReport(performance) {
const score = performance.score || 0;
const metrics = {};
const bottlenecks = [];
const optimizationOpportunities = [];
// Extract metrics
if (performance.bundleSize) {
metrics.bundleSize = {
current: performance.bundleSize,
recommended: 250 // KB
};
if (performance.bundleSize > 500) {
bottlenecks.push({
type: 'Bundle Size',
location: 'JavaScript bundles',
impact: 'Slow initial page load',
solution: 'Implement code splitting and tree shaking'
});
}
}
if (performance.issues) {
// Group issues by type
const issueTypes = new Map();
for (const issue of performance.issues) {
issueTypes.set(issue.type, (issueTypes.get(issue.type) || 0) + 1);
}
// Add optimization opportunities
if (issueTypes.has('large_file')) {
optimizationOpportunities.push('Split large files into smaller modules');
}
if (issueTypes.has('complex_function')) {
optimizationOpportunities.push('Refactor complex functions for better performance');
}
if (issueTypes.has('memory_leak')) {
optimizationOpportunities.push('Fix memory leaks in event listeners and timers');
}
}
return {
score,
grade: this.scoreToGrade(score),
metrics,
bottlenecks: bottlenecks.slice(0, 5),
optimizationOpportunities: optimizationOpportunities.slice(0, 5)
};
}
buildDocumentationReport(documentation) {
const score = documentation.score || 0;
const coverage = documentation.coverage || 0;
const missingDocs = [];
const qualityIssues = [];
const recommendations = [];
if (documentation.missingFiles) {
missingDocs.push(...documentation.missingFiles);
}
if (documentation.issues) {
for (const issue of documentation.issues.slice(0, 10)) {
qualityIssues.push({
file: issue.file,
issue: issue.message,
suggestion: issue.recommendation || 'Improve documentation'
});
}
}
// Generate recommendations
if (coverage < 80) {
recommendations.push(`Increase documentation coverage from ${coverage}% to at least 80%`);
}
if (!missingDocs.includes('README.md')) {
recommendations.push('Improve README with installation, usage, and API sections');
}
if (missingDocs.includes('CONTRIBUTING.md')) {
recommendations.push('Add CONTRIBUTING.md for open source contributions');
}
return {
score,
grade: this.scoreToGrade(score),
coverage,
missingDocs: missingDocs.slice(0, 10),
qualityIssues: qualityIssues.slice(0, 10),
recommendations: recommendations.slice(0, 5)
};
}
buildCodeQualityReport(codeQuality) {
const score = codeQuality.score || 0;
const metrics = {
duplicateCode: codeQuality.duplicationAnalysis?.duplicationPercentage || 0,
complexity: codeQuality.avgComplexity || 0,
maintainability: codeQuality.maintainabilityIndex?.overallScore || 0,
testCoverage: codeQuality.testCoverage
};
const codeSmells = [];
const improvements = [];
if (codeQuality.issues) {
// Group code smells
const smellTypes = new Map();
for (const issue of codeQuality.issues) {
if (!smellTypes.has(issue.type)) {
smellTypes.set(issue.type, {
type: issue.type,
locations: [],
refactoringSuggestion: issue.suggestion || ''
});
}
smellTypes.get(issue.type).locations.push(issue.file);
}
codeSmells.push(...Array.from(smellTypes.values()).slice(0, 5));
}
// Generate improvements
if (metrics.duplicateCode > 5) {
improvements.push('Extract duplicate code into reusable functions');
}
if (metrics.complexity > 10) {
improvements.push('Reduce cyclomatic complexity by splitting complex functions');
}
if (metrics.maintainability < 70) {
improvements.push('Improve maintainability through better code organization');
}
return {
score,
grade: this.scoreToGrade(score),
metrics,
codeSmells: codeSmells.slice(0, 5),
improvements: improvements.slice(0, 5)
};
}
buildCrossPlatformReport(crossPlatform) {
const score = crossPlatform.overallScore || 0;
const platformScores = {
windows: crossPlatform.platformCompatibility?.windows?.score || 0,
macOS: crossPlatform.platformCompatibility?.macOS?.score || 0,
linux: crossPlatform.platformCompatibility?.linux?.score || 0
};
const compatibility = crossPlatform.platformCompatibility?.overall?.status || 'unknown';
const criticalIssues = [];
const recommendations = [];
if (crossPlatform.issues) {
// Get critical platform issues
const critical = crossPlatform.issues
.filter((i) => i.severity === 'critical')
.slice(0, 5)
.map((issue) => ({
issue: issue.message,
platforms: issue.affectedPlatforms,
solution: issue.recommendation
}));
criticalIssues.push(...critical);
}
// Generate recommendations
if (platformScores.windows < 70) {
recommendations.push('Improve Windows compatibility');
}
if (crossPlatform.environmentAnalysis?.dependencies?.some((d) => d.nativeModules)) {
recommendations.push('Document native module build requirements for all platforms');
}
return {
score,
grade: this.scoreToGrade(score),
platformScores,
compatibility,
criticalIssues,
recommendations: recommendations.slice(0, 5)
};
}
buildUnusedCodeReport(unusedCode) {
const score = unusedCode.score || 0;
const statistics = {
unusedFunctions: unusedCode.unusedFunctions?.length || 0,
unusedFiles: unusedCode.unusedFiles?.length || 0,
deadCode: unusedCode.deadCode?.length || 0,
potentialSavingsKB: 0
};
// Estimate savings
if (unusedCode.unusedFiles) {
statistics.potentialSavingsKB = unusedCode.unusedFiles.length * 10; // Rough estimate
}
const topUnused = [];
const cleanupPlan = [];
// Get top unused items
if (unusedCode.unusedFunctions) {
for (const func of unusedCode.unusedFunctions.slice(0, 3)) {
topUnused.push({
type: 'Function',
name: func.name,
location: func.file,
lastModified: 'Unknown'
});
}
}
if (unusedCode.unusedFiles) {
for (const file of unusedCode.unusedFiles.slice(0, 2)) {
topUnused.push({
type: 'File',
name: path.basename(file),
location: file,
lastModified: 'Unknown'
});
}
}
// Generate cleanup plan
if (statistics.unusedFiles > 0) {
cleanupPlan.push('Review and remove unused files');
}
if (statistics.unusedFunctions > 10) {
cleanupPlan.push('Remove unused functions after confirming they are not needed');
}
if (statistics.deadCode > 0) {
cleanupPlan.push('Clean up unreachable and commented code');
}
return {
score,
grade: this.scoreToGrade(score),
statistics,
topUnused,
cleanupPlan
};
}
generatePrioritizedRecommendations(results) {
const immediate = [];
const shortTerm = [];
const longTerm = [];
// Security critical issues
if (results.security?.criticalIssues > 0) {
immediate.push({
title: 'Fix Critical Security Vulnerabilities',
impact: 'critical',
effort: 'medium',
category: 'Security',
description: `${results.security.criticalIssues} critical security vulnerabilities require immediate attention`,
steps: [
'Review security report for critical vulnerabilities',
'Apply security patches or fixes',
'Test fixes thoroughly',
'Deploy to production immediately'
],
expectedOutcome: 'Elimination of critical security risks',
resources: ['OWASP Guidelines', 'Security best practices']
});
}
// Performance critical issues
if (results.performance?.score < 40) {
immediate.push({
title: 'Address Performance Bottlenecks',
impact: 'high',
effort: 'high',
category: 'Performance',
description: 'Critical performance issues affecting user experience',
steps: [
'Profile application performance',
'Implement code splitting',
'Optimize bundle sizes',
'Add caching strategies'
],
expectedOutcome: 'Significant improvement in load times and responsiveness'
});
}
// Documentation improvements
if (results.documentation?.score < 60) {
shortTerm.push({
title: 'Improve Documentation Coverage',
impact: 'medium',
effort: 'medium',
category: 'Documentation',
description: 'Documentation needs significant improvement',
steps: [
'Document all public APIs',
'Update README with examples',
'Add inline code comments',
'Create architecture documentation'
],
expectedOutcome: 'Better developer experience and maintainability'
});
}
// Code quality improvements
if (results.codeQuality?.duplicationAnalysis?.duplicationPercentage > 10) {
shortTerm.push({
title: 'Reduce Code Duplication',
impact: 'medium',
effort: 'medium',
category: 'Code Quality',
description: 'High code duplication affecting maintainability',
steps: [
'Identify duplicate code blocks',
'Extract common functionality',
'Create reusable utilities',
'Update all references'
],
expectedOutcome: 'Improved maintainability and reduced bugs'
});
}
// Cross-platform improvements
if (results.crossPlatform?.overallScore < 70) {
longTerm.push({
title: 'Enhance Cross-Platform Compatibility',
impact: 'medium',
effort: 'high',
category: 'Compatibility',
description: 'Improve support across different operating systems',
steps: [
'Replace platform-specific code',
'Use cross-platform libraries',
'Test on all target platforms',
'Document platform requirements'
],
expectedOutcome: 'Wider platform support and fewer compatibility issues'
});
}
// Unused code cleanup
if (results.unusedCode?.statistics?.unusedFiles > 20) {
longTerm.push({
title: 'Clean Up Unused Code',
impact: 'low',
effort: 'low',
category: 'Maintenance',
description: 'Remove unused code to improve maintainability',
steps: [
'Verify unused code detection',
'Create backup branch',
'Remove unused files and functions',
'Run full test suite'
],
expectedOutcome: 'Cleaner, more maintainable codebase'
});
}
return { immediate, shortTerm, longTerm };
}
scoreToGrade(score) {
if (score >= 90)
return 'A';
if (score >= 80)
return 'B';
if (score >= 70)
return 'C';
if (score >= 60)
return 'D';
return 'F';
}
outputConsoleReport(report) {
console.log(chalk.cyan.bold(`\nš ${report.projectName} - Detailed Analysis Report\n`));
console.log(chalk.gray(`Generated: ${new Date(report.timestamp).toLocaleString()}\n`));
// Summary
console.log(chalk.yellow.bold('Executive Summary'));
console.log(chalk.white('ā'.repeat(50)));
console.log(`Overall Score: ${this.getGradeColor(report.summary.overallGrade)}${report.summary.overallScore}/100 (${report.summary.overallGrade})${chalk.reset()}`);
console.log(`Total Issues: ${report.summary.totalIssues} (${report.summary.criticalIssues} critical)`);
console.log(`Analyzers Run: ${report.summary.analyzersRun}`);
if (report.summary.topConcerns.length > 0) {
console.log(chalk.red('\nTop Concerns:'));
report.summary.topConcerns.forEach(concern => {
console.log(chalk.red(` ⢠${concern}`));
});
}
// Individual Reports
if (report.securityReport) {
console.log(chalk.yellow.bold('\nš Security Analysis'));
console.log(chalk.white('ā'.repeat(50)));
console.log(`Score: ${this.getGradeColor(report.securityReport.grade)}${report.securityReport.score}/100 (${report.securityReport.grade})${chalk.reset()}`);
console.log(`Risk Level: ${this.getRiskColor(report.securityReport.riskLevel)}${report.securityReport.riskLevel}${chalk.reset()}`);
console.log(`Vulnerabilities: ${report.securityReport.vulnerabilities.critical} critical, ${report.securityReport.vulnerabilities.high} high, ${report.securityReport.vulnerabilities.medium} medium, ${report.securityReport.vulnerabilities.low} low`);
if (report.securityReport.owaspCompliance) {
console.log(`OWASP Compliance: ${report.securityReport.owaspCompliance.score}%`);
}
}
// Recommendations
console.log(chalk.yellow.bold('\nšÆ Prioritized Recommendations'));
console.log(chalk.white('ā'.repeat(50)));
if (report.recommendations.immediate.length > 0) {
console.log(chalk.red.bold('\nImmediate Actions:'));
report.recommendations.immediate.forEach((rec, i) => {
console.log(chalk.red(`${i + 1}. ${rec.title}`));
console.log(chalk.gray(` Impact: ${rec.impact} | Effort: ${rec.effort}`));
console.log(chalk.white(` ${rec.description}`));
});
}
if (report.recommendations.shortTerm.length > 0) {
console.log(chalk.yellow.bold('\nShort-term Improvements:'));
report.recommendations.shortTerm.forEach((rec, i) => {
console.log(chalk.yellow(`${i + 1}. ${rec.title}`));
console.log(chalk.gray(` Impact: ${rec.impact} | Effort: ${rec.effort}`));
});
}
if (report.recommendations.longTerm.length > 0) {
console.log(chalk.blue.bold('\nLong-term Goals:'));
report.recommendations.longTerm.forEach((rec, i) => {
console.log(chalk.blue(`${i + 1}. ${rec.title}`));
console.log(chalk.gray(` Impact: ${rec.impact} | Effort: ${rec.effort}`));
});
}
console.log(chalk.gray('\nš” For detailed recommendations, use --format markdown or --format html\n'));
}
async outputMarkdownReport(report) {
const markdown = this.generateMarkdownReport(report);
if (this.options.outputPath) {
await fs.writeFile(this.options.outputPath, markdown);
console.log(chalk.green(`ā
Markdown report saved to: ${this.options.outputPath}`));
}
else {
console.log(markdown);
}
}
generateMarkdownReport(report) {
let md = `# ${report.projectName} - Analysis Report\n\n`;
md += `**Generated:** ${new Date(report.timestamp).toLocaleString()}\n\n`;
// Summary
md += `## Executive Summary\n\n`;
md += `- **Overall Score:** ${report.summary.overallScore}/100 (${report.summary.overallGrade})\n`;
md += `- **Total Issues:** ${report.summary.totalIssues} (${report.summary.criticalIssues} critical)\n`;
md += `- **Analyzers Run:** ${report.summary.analyzersRun}\n\n`;
if (report.summary.topConcerns.length > 0) {
md += `### Top Concerns\n\n`;
report.summary.topConcerns.forEach(concern => {
md += `- ā ļø ${concern}\n`;
});
md += '\n';
}
// Security Report
if (report.securityReport) {
md += `## š Security Analysis\n\n`;
md += `- **Score:** ${report.securityReport.score}/100 (${report.securityReport.grade})\n`;
md += `- **Risk Level:** ${report.securityReport.riskLevel}\n`;
md += `- **Vulnerabilities:**\n`;
md += ` - Critical: ${report.securityReport.vulnerabilities.critical}\n`;
md += ` - High: ${report.securityReport.vulnerabilities.high}\n`;
md += ` - Medium: ${report.securityReport.vulnerabilities.medium}\n`;
md += ` - Low: ${report.securityReport.vulnerabilities.low}\n\n`;
if (report.securityReport.topVulnerabilities.length > 0) {
md += `### Top Vulnerabilities\n\n`;
md += `| Type | Severity | Count | Recommendation |\n`;
md += `|------|----------|-------|----------------|\n`;
report.securityReport.topVulnerabilities.forEach(vuln => {
md += `| ${vuln.type} | ${vuln.severity} | ${vuln.count} | ${vuln.recommendation} |\n`;
});
md += '\n';
}
}
// Recommendations
md += `## šÆ Recommendations\n\n`;
if (report.recommendations.immediate.length > 0) {
md += `### Immediate Actions\n\n`;
report.recommendations.immediate.forEach((rec, i) => {
md += `#### ${i + 1}. ${rec.title}\n\n`;
md += `- **Impact:** ${rec.impact}\n`;
md += `- **Effort:** ${rec.effort}\n`;
md += `- **Description:** ${rec.description}\n\n`;
md += `**Steps:**\n`;
rec.steps.forEach(step => {
md += `1. ${step}\n`;
});
md += `\n**Expected Outcome:** ${rec.expectedOutcome}\n\n`;
});
}
return md;
}
async outputHTMLReport(report) {
const html = this.generateHTMLReport(report);
if (this.options.outputPath) {
await fs.writeFile(this.options.outputPath, html);
console.log(chalk.green(`ā
HTML report saved to: ${this.options.outputPath}`));
}
else {
console.log('HTML output to console not supported. Please specify --output-path');
}
}
generateHTMLReport(report) {
return `<!DOCTYPE html>
<html>
<head>
<title>${report.projectName} - Analysis Report</title>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; max-width: 1200px; margin: 0 auto; padding: 20px; }
h1, h2, h3 { color: #333; }
.summary { background: #f4f4f4; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
.score { font-size: 48px; font-weight: bold; }
.grade-A { color: #28a745; }
.grade-B { color: #17a2b8; }
.grade-C { color: #ffc107; }
.grade-D { color: #fd7e14; }
.grade-F { color: #dc3545; }
.section { margin-bottom: 30px; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
th { background: #f8f9fa; font-weight: bold; }
.recommendation { background: #e9ecef; padding: 15px; margin: 10px 0; border-radius: 5px; }
.immediate { border-left: 4px solid #dc3545; }
.short-term { border-left: 4px solid #ffc107; }
.long-term { border-left: 4px solid #17a2b8; }
</style>
</head>
<body>
<h1>${report.projectName} - Analysis Report</h1>
<p><strong>Generated:</strong> ${new Date(report.timestamp).toLocaleString()}</p>
<div class="summary">
<h2>Executive Summary</h2>
<div class="score grade-${report.summary.overallGrade}">${report.summary.overallScore}/100</div>
<p>Grade: ${report.summary.overallGrade}</p>
<p>Total Issues: ${report.summary.totalIssues} (${report.summary.criticalIssues} critical)</p>
</div>
<!-- Add more sections here -->
</body>
</html>`;
}
async outputJSONReport(report) {
const json = JSON.stringify(report, null, 2);
if (this.options.outputPath) {
await fs.writeFile(this.options.outputPath, json);
console.log(chalk.green(`ā
JSON report saved to: ${this.options.outputPath}`));
}
else {
console.log(json);
}
}
getGradeColor(grade) {
switch (grade) {
case 'A': return chalk.green('');
case 'B': return chalk.cyan('');
case 'C': return chalk.yellow('');
case 'D': return chalk.rgb(255, 165, 0)('');
case 'F': return chalk.red('');
default: return chalk.gray('');
}
}
getRiskColor(risk) {
switch (risk) {
case 'low': return chalk.green('');
case 'medium': return chalk.yellow('');
case 'high': return chalk.rgb(255, 165, 0)('');
case 'critical': return chalk.red('');
default: return chalk.gray('');
}
}
}
//# sourceMappingURL=DetailedReportGenerator.js.map