UNPKG

agentsqripts

Version:

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

183 lines (160 loc) 6.84 kB
/** * @file Individual file static bug analyzer with AST-based detection * @description Single responsibility: Perform comprehensive static bug analysis on individual JavaScript files * * This analyzer implements sophisticated AST-based static analysis to detect real programming * errors, logic bugs, and potential runtime issues in individual JavaScript files. It provides * accurate bug detection through syntax tree analysis while minimizing false positives that * plague regex-based detection systems. * * Design rationale: * - AST-based analysis provides superior accuracy compared to regex pattern matching * - Individual file focus enables detailed analysis with comprehensive error context * - Modular pattern matching architecture supports extensible bug detection capabilities * - Quality scoring provides quantitative assessment for tracking improvement progress * - Context-aware detection considers code structure and intent to reduce false positives * * Analysis capabilities: * - Logic errors: Unreachable code, infinite loops, incorrect conditionals, variable scope issues * - Type errors: Undefined variables, incorrect method calls, type mismatches, null reference errors * - Security vulnerabilities: Injection flaws, authentication bypasses, authorization issues * - Performance issues: Inefficient algorithms, memory leaks, blocking operations * - Best practice violations: Deprecated APIs, anti-patterns, maintainability issues */ const fs = require('fs'); // Import utilities const { parseToAST } = require('./utils/astParser'); const { getFileContext, shouldIgnoreBug } = require('./utils/contextAnalyzer'); const { stripStringContent, stripComments } = require('../srp-violations/utils/stringStripper'); // Import detectors const { detectAsyncPatterns } = require('./detectors/asyncPatternDetector'); const { detectNullSafetyPatterns } = require('./detectors/nullSafetyDetector'); const { detectReactPatterns } = require('./detectors/reactPatternDetector'); const { detectResourceLeaks } = require('./detectors/resourceLeakDetector'); const { analyzeDataFlow } = require('./detectors/dataFlowAnalyzer'); // Import legacy detectors const { checkUnreachableCode } = require('./unreachableCodeChecker'); const { generateBugRecommendations } = require('./bugRecommendationGenerator'); /** * Analyze static bugs in a file * @param {string} filePath - File to analyze * @param {Object} options - Analysis options * @returns {Promise<Object>} Bug analysis results */ async function analyzeFileStaticBugs(filePath, options = {}) { try { const content = await fs.promises.readFile(filePath, 'utf8'); // Get file context for intelligent analysis const context = getFileContext(filePath, content); // Parse to AST using original content (not stripped) const ast = parseToAST(content, filePath); // Strip strings and comments only for string-based checks const strippedContent = stripStringContent(content); const codeContent = stripComments(strippedContent); const bugs = []; if (ast) { // Run AST-based detectors bugs.push(...detectAsyncPatterns(ast, filePath)); bugs.push(...detectNullSafetyPatterns(ast, filePath)); bugs.push(...analyzeDataFlow(ast, filePath)); bugs.push(...detectResourceLeaks(ast, filePath)); // Framework-specific detectors if (context.framework === 'react') { bugs.push(...detectReactPatterns(ast, filePath, content)); } } // Run legacy string-based detectors (still useful for some patterns) bugs.push(...checkUnreachableCode(content, filePath)); bugs.push(...checkUnsafePatterns(codeContent, filePath, context)); // Filter bugs based on context const filteredBugs = bugs.filter(bug => !shouldIgnoreBug(bug.type, context)); // Calculate metrics const criticalBugs = filteredBugs.filter(b => b.severity === 'HIGH').length; const mediumBugs = filteredBugs.filter(b => b.severity === 'MEDIUM').length; const lowBugs = filteredBugs.filter(b => b.severity === 'LOW').length; const totalBugs = filteredBugs.length; // More nuanced scoring const qualityScore = Math.max(0, 100 - (criticalBugs * 10) - (mediumBugs * 3) - (lowBugs * 1)); return { file: filePath, context, issues: filteredBugs, bugs: filteredBugs, qualityScore, qualityGrade: getQualityGrade(qualityScore), totalBugs, criticalBugs, mediumBugs, lowBugs, summary: { totalIssues: totalBugs, highSeverity: criticalBugs, mediumSeverity: mediumBugs, lowSeverity: lowBugs, qualityScore, qualityGrade: getQualityGrade(qualityScore) }, recommendations: generateBugRecommendations(filteredBugs) }; } catch (error) { console.error(`Static bug analysis failed for ${filePath}: ${error.message}`); throw new Error(`Failed to analyze ${filePath}: ${error.message}`); } } /** * Check for unsafe patterns with context awareness * @param {string} content - Code content (strings/comments stripped) * @param {string} filePath - File path * @param {Object} context - File context * @returns {Array} Detected bugs */ function checkUnsafePatterns(content, filePath, context) { const bugs = []; const lines = content.split('\n'); lines.forEach((line, index) => { // Check for eval() - but respect context if (line.includes('eval(') && !context.rules.allowEval) { bugs.push({ type: 'dangerous_eval', severity: 'HIGH', category: 'Security', line: index + 1, column: line.indexOf('eval('), description: 'Use of eval() is dangerous and can lead to code injection', recommendation: 'Replace with safer alternatives like JSON.parse() or Function constructor', effort: 2, impact: 'high', file: filePath }); } // Check for console.log in production code if (line.includes('console.log(') && !context.rules.allowConsoleLog) { bugs.push({ type: 'console_log', severity: 'LOW', category: 'Code Quality', line: index + 1, column: line.indexOf('console.log('), description: 'console.log() left in production code', recommendation: 'Remove console.log() or use proper logging library', effort: 1, impact: 'low', file: filePath }); } }); return bugs; } const { getLetterGrade } = require('../utils/gradeUtils'); /** * Get quality grade from score * @param {number} score - Quality score * @returns {string} Grade (A-F) */ function getQualityGrade(score) { return getLetterGrade(score); } module.exports = { analyzeFileStaticBugs, getQualityGrade };