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
JavaScript
/**
* @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
};