UNPKG

agentsqripts

Version:

Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems

259 lines (225 loc) 8.74 kB
/** * @file Shared summary formatting utilities for all CLI tools * @description Provides configurable summary formatters to eliminate duplication */ const path = require('path'); const { formatNumber, formatPercentage, getGradeEmoji, formatSeverity, truncateText } = require('./commonFormatters'); /** * Create a customized summary formatter for any analysis tool * @param {Object} config - Configuration for the formatter * @returns {Function} Summary formatter function */ function createSummaryFormatter(config) { const { title, scoreField = 'score', gradeField = 'grade', filesField = 'totalFiles', issuesField = 'totalIssues', showEffort = false, effortField = 'totalEffort', customMetrics = [], breakdowns = [], customSections = [] } = config; return function formatSummary(results, options = {}) { const output = []; const summary = results.summary || results; // Title output.push(`${title}\n`); // Main metrics if (summary[scoreField] !== undefined) { const grade = summary[gradeField] || calculateGrade(summary[scoreField]); output.push(`📊 ${scoreField.charAt(0).toUpperCase() + scoreField.slice(1)}: ${summary[scoreField]}/100 (Grade ${grade})`); } if (summary[filesField] !== undefined) { output.push(`📁 Files Analyzed: ${formatNumber(summary[filesField])}`); } if (summary[issuesField] !== undefined) { output.push(`⚠️ Total Issues: ${formatNumber(summary[issuesField])}`); } if (showEffort && summary[effortField] !== undefined) { output.push(`⏱️ Total Effort: ${summary[effortField]} points`); } // Custom metrics customMetrics.forEach(metric => { if (summary[metric.field] !== undefined) { const value = metric.formatter ? metric.formatter(summary[metric.field]) : summary[metric.field]; output.push(`${metric.icon} ${metric.label}: ${value}`); } }); output.push(''); // Add wisdom warnings for high DRY scores (90+) if (scoreField === 'projectDryScore' && summary[scoreField] >= 90) { output.push('🎓 Wisdom Warning: High DRY Score Detected\n'); if (summary[scoreField] === 100) { output.push('🌟 LEGENDARY ACHIEVEMENT: Perfect DRY Score!'); output.push(''); output.push(' You\'ve eliminated ALL code duplication. This is extraordinarily rare!'); output.push(' '); output.push(' ⚠️ Important Considerations:'); output.push(' • Perfect DRYness might indicate over-engineering'); output.push(' • Some "duplication" serves important purposes:'); output.push(' - Test fixtures often need similar setup'); output.push(' - Framework patterns require boilerplate'); output.push(' - Explicit code can be clearer than abstractions'); output.push(' '); output.push(' • Monitor for these warning signs:'); output.push(' - Overly complex abstractions'); output.push(' - Difficulty onboarding new developers'); output.push(' - Simple changes requiring multiple file edits'); output.push(' '); output.push(' 💡 Recommendation: Consider if some strategic duplication might'); output.push(' actually improve your codebase\'s maintainability and clarity.'); } else { output.push('⚠️ Your DRY score is already excellent (Grade A). Consider these important points:'); output.push(''); if (summary[scoreField] >= 95) { output.push(' 🏆 Achievement Unlocked: Near-Perfect DRY Score!'); output.push(' • Reaching 100 means eliminating ALL duplicates - a monumental task'); output.push(' • The effort to go from 95→100 often exceeds the benefit'); output.push(' • Some duplicates may be intentional (test patterns, framework boilerplate)'); output.push(' • Over-DRYing can harm readability and create unnecessary abstractions'); } else { output.push(' ✨ You\'ve achieved Grade A performance!'); output.push(' • Focus on high-impact duplicates for maximum benefit'); output.push(' • Consider if remaining duplicates serve a purpose'); output.push(' • Balance DRYness with code clarity and maintainability'); } output.push(''); output.push(' 📚 Remember: Perfect is the enemy of good. Your codebase is already'); output.push(' in the top tier of DRYness. Further optimization should be strategic,'); output.push(' not exhaustive.'); } output.push(''); } // Breakdowns breakdowns.forEach(breakdown => { const data = summary[breakdown.field]; if (data && (Array.isArray(data) ? data.length > 0 : Object.keys(data).length > 0)) { output.push(`${breakdown.icon} ${breakdown.title}:`); if (breakdown.type === 'severity') { formatSeverityBreakdown(data, output, breakdown.levels || ['HIGH', 'MEDIUM', 'LOW']); } else if (breakdown.type === 'category') { formatCategoryBreakdown(data, output, breakdown.icons || {}); } else if (breakdown.type === 'custom') { breakdown.formatter(data, output); } output.push(''); } }); // Custom sections customSections.forEach(section => { if (section.condition ? section.condition(results, options) : true) { section.formatter(results, output, options); } }); return output.join('\n'); }; } /** * Format severity breakdown */ function formatSeverityBreakdown(data, output, levels) { const severityIcons = { 'CRITICAL': '🔴', 'HIGH': '🔥', 'MEDIUM': '⚡', 'LOW': '💡', 'INFO': 'ℹ️' }; levels.forEach(level => { if (data[level] > 0) { const icon = severityIcons[level] || '•'; output.push(` ${icon} ${level.charAt(0) + level.slice(1).toLowerCase()}: ${formatNumber(data[level])}`); } }); } /** * Format category breakdown */ function formatCategoryBreakdown(data, output, customIcons) { Object.entries(data).forEach(([category, count]) => { const icon = customIcons[category] || '•'; output.push(` ${icon} ${category}: ${formatNumber(count)}`); }); } const { getLetterGrade } = require('../../lib/utils/gradeUtils'); /** * Calculate grade from score */ function calculateGrade(score) { return getLetterGrade(score); } /** * Create a recommendations section formatter */ function createRecommendationsSection(title = 'Recommendations', icon = '💡', formatRec) { return { formatter: (results, output) => { if (results.recommendations && results.recommendations.length > 0) { output.push(`${icon} ${title}:`); results.recommendations.forEach((rec, i) => { const formatted = formatRec ? formatRec(rec) : rec.toString(); output.push(` ${i + 1}. ${formatted}`); }); output.push(''); } } }; } /** * Create a top issues section formatter */ function createTopIssuesSection(config) { const { field = 'issues', title = 'Top Issues', icon = '🔥', limit = 10, formatItem } = config; return { formatter: (results, output, options) => { const issues = results[field] || []; const filtered = filterIssues(issues, options); if (filtered.length > 0) { output.push(`${icon} ${title}:`); filtered.slice(0, limit).forEach((issue, i) => { if (formatItem) { output.push(formatItem(issue, i)); } else { output.push(` ${i + 1}. ${issue.description || issue.message}`); } }); output.push(''); } } }; } /** * Filter issues based on options */ function filterIssues(issues, options) { return issues.filter(issue => { const { severity, category, minSeverity } = options; if (minSeverity) { const severityOrder = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']; const minIndex = severityOrder.indexOf(minSeverity); const issueIndex = severityOrder.indexOf(issue.severity); if (issueIndex < minIndex) return false; } if (severity && issue.severity !== severity) return false; if (category && issue.category !== category) return false; return true; }); } module.exports = { createSummaryFormatter, createRecommendationsSection, createTopIssuesSection, formatSeverityBreakdown, formatCategoryBreakdown, calculateGrade, filterIssues };