UNPKG

agentsqripts

Version:

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

130 lines (114 loc) 5.36 kB
/** * @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', 'demo', 'tmp', 'test', 'tests', 'spec', '__tests__', 'examples', 'documentation', 'docs', '.cache', '.local', '.config', '.upm', 'tempAgentFiles', 'attached_assets', 'logs'], 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 };