UNPKG

agentsqripts

Version:

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

145 lines (124 loc) 4.29 kB
/** * @file Static bug project analyzer * @description Analyzes entire project for static bugs */ /** * Analyze static bugs across a project * @param {string} projectPath - Project directory path * @param {Object} options - Analysis options * @returns {Object} Project bug analysis results */ function analyzeProjectStaticBugs(projectPath, options = {}) { const fs = require('fs'); const path = require('path'); const { analyzeFileStaticBugs } = require('./staticBugFileAnalyzer'); // Create a simple recommendation generator if none exists function generateBugRecommendations(issues) { if (!issues || issues.length === 0) { return []; } const recommendations = []; const categoryCounts = {}; issues.forEach(issue => { categoryCounts[issue.category] = (categoryCounts[issue.category] || 0) + 1; }); Object.entries(categoryCounts).forEach(([category, count]) => { recommendations.push({ category, count, priority: count > 5 ? 'HIGH' : count > 2 ? 'MEDIUM' : 'LOW', recommendation: `Fix ${count} ${category} issue${count > 1 ? 's' : ''}` }); }); return recommendations.sort((a, b) => b.count - a.count); } try { const files = getAllJSFiles(projectPath); console.log(`Found ${files.length} JavaScript files to analyze`); const fileAnalyses = []; const allIssues = []; let totalScore = 0; files.forEach(file => { try { console.log(`Analyzing: ${file}`); const analysis = analyzeFileStaticBugs(file); fileAnalyses.push(analysis); if (analysis.issues) { allIssues.push(...analysis.issues); } totalScore += (analysis.qualityScore || 100); } catch (error) { console.log(`Error analyzing ${file}: ${error.message}`); // Skip files that can't be analyzed but count them fileAnalyses.push({ file, qualityScore: 100, issues: [], error: error.message }); totalScore += 100; } }); const averageScore = files.length > 0 ? Math.round(totalScore / files.length) : 100; // Calculate breakdowns const severityBreakdown = { HIGH: 0, MEDIUM: 0, LOW: 0 }; const categoryBreakdown = {}; let totalEffort = 0; allIssues.forEach(issue => { severityBreakdown[issue.severity] = (severityBreakdown[issue.severity] || 0) + 1; categoryBreakdown[issue.category] = (categoryBreakdown[issue.category] || 0) + 1; totalEffort += issue.effort || 1; }); return { summary: { filesAnalyzed: fileAnalyses.length, totalFiles: fileAnalyses.length, totalIssues: allIssues.length, totalEffort, qualityScore: averageScore, qualityGrade: getQualityGrade(averageScore), highSeverity: allIssues.filter(i => i.severity === 'HIGH').length, severityBreakdown, categoryBreakdown }, files: fileAnalyses, fileResults: fileAnalyses, issues: allIssues, recommendations: generateBugRecommendations(allIssues) }; } catch (error) { console.error(`Project analysis error: ${error.message}`); console.error(`Stack trace: ${error.stack}`); throw error; } } function getAllJSFiles(projectPath) { const fs = require('fs'); const path = require('path'); const files = []; const extensions = ['.js', '.ts', '.jsx', '.tsx']; function traverse(dir) { try { const entries = fs.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory() && !entry.name.includes('node_modules') && !entry.name.startsWith('.')) { traverse(fullPath); } else if (extensions.includes(path.extname(fullPath))) { files.push(fullPath); } } } catch (error) { console.error(`Error reading directory ${dir}: ${error.message}`); } } traverse(projectPath); return files; } const { getLetterGrade } = require('../utils/gradeUtils'); function getQualityGrade(score) { return getLetterGrade(score); } module.exports = { analyzeProjectStaticBugs };