agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
127 lines (111 loc) • 5.12 kB
JavaScript
/**
* @file Project-wide performance analyzer for comprehensive optimization assessment
* @description Single responsibility: Coordinate performance analysis across entire projects with scalable processing
*
* This analyzer orchestrates comprehensive performance analysis across entire projects,
* efficiently processing large codebases to identify systematic performance issues,
* patterns, and optimization opportunities. It provides project-level metrics, issue
* aggregation, and strategic recommendations for performance improvements.
*
* Design rationale:
* - Project-wide analysis identifies systematic performance patterns missed by file-level analysis
* - Optimized file processing with early filtering prevents analysis of irrelevant files
* - Scalable architecture handles large codebases efficiently through intelligent batching
* - Comprehensive metrics provide project-wide performance visibility and tracking
* - Strategic recommendations prioritize optimization efforts for maximum impact
*
* Analysis optimization strategy:
* - Early file filtering by size and type reduces unnecessary processing overhead
* - Configurable file limits prevent analysis timeouts on extremely large projects
* - Issue aggregation provides project-wide patterns and hotspot identification
* - Performance scoring enables project-wide quality tracking and improvement measurement
* - Directory traversal optimization handles complex project structures efficiently
*/
const fs = require('fs');
const path = require('path');
const { analyzeFilePerformance } = require('./performanceFileAnalyzer');
const { calculatePerformanceScore, getPerformanceGrade } = require('./performanceScoreCalculator');
const { generatePerformanceRecommendations } = require('./performanceRecommendationGenerator');
/**
* Analyzes project performance across multiple files
* @param {string} projectPath - Path to the project
* @param {Object} options - Analysis options
* @returns {Object} Project performance analysis results
*/
async function analyzeProjectPerformance(projectPath, options = {}) {
// Input validation
if (!projectPath || typeof projectPath !== 'string') {
throw new Error('Project path must be a non-empty string');
}
const {
extensions = ['.js', '.ts', '.jsx', '.tsx'], // Use same default as shared directoryScanner
excludePatterns = ['node_modules', '.git', 'dist', 'build', 'coverage'],
maxFiles = Infinity // No file limit by default
} = options;
const startTime = Date.now();
// Get all relevant files using shared directory scanner
const { getAllFiles } = require('../utils/directoryScanner');
const files = await getAllFiles(projectPath, extensions, excludePatterns);
const limitedFiles = files.slice(0, maxFiles);
// Analyze each file
const fileResults = [];
const allIssues = [];
// Optimized file analysis with early filtering and parallel processing concepts
for (const filePath of limitedFiles) {
try {
// Skip empty or very small files early
const stats = await fs.promises.stat(filePath);
if (stats.size < 100) continue;
const result = await analyzeFilePerformance(filePath);
if (result.issues.length > 0) { // Only store files with issues
fileResults.push(result);
allIssues.push(...result.issues);
}
} catch (error) {
console.warn(`Warning: Could not analyze ${filePath}: ${error.message}`);
}
}
// Calculate project-wide metrics
const totalIssues = allIssues.length;
const totalEffort = allIssues.reduce((sum, issue) => sum + (issue.effort || 1), 0);
const projectScore = calculatePerformanceScore(allIssues);
const projectGrade = getPerformanceGrade(projectScore);
// Calculate breakdowns
const categoryBreakdown = {};
const severityBreakdown = { HIGH: 0, MEDIUM: 0, LOW: 0 };
// Optimize breakdown calculation with for...of loop
for (const issue of allIssues) {
categoryBreakdown[issue.category] = (categoryBreakdown[issue.category] || 0) + 1;
severityBreakdown[issue.severity] = (severityBreakdown[issue.severity] || 0) + 1;
}
// Sort all issues by priority score if available
if (allIssues.length > 0 && allIssues[0].priorityScore !== undefined) {
allIssues.sort((a, b) => (b.priorityScore || 0) - (a.priorityScore || 0));
}
// Generate recommendations
const analysisTime = Date.now() - startTime;
const recommendations = generatePerformanceRecommendations(allIssues, totalEffort, analysisTime);
return {
timestamp: new Date().toISOString(),
summary: {
totalFiles: limitedFiles.length,
filesAnalyzed: limitedFiles.length,
filesWithIssues: fileResults.filter(f => f.issues.length > 0).length,
totalIssues,
totalEffort,
performanceScore: projectScore,
projectScore,
projectGrade,
performanceGrade: projectGrade,
categoryBreakdown,
severityBreakdown
},
files: fileResults,
issues: allIssues,
recommendations,
analysisTime
};
}
module.exports = {
analyzeProjectPerformance
};