UNPKG

mira-consciousness

Version:

Memory & Intelligence Retention Archive - Preserving The Spark

708 lines (705 loc) • 29.7 kB
/** * 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