UNPKG

agentsqripts

Version:

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

204 lines (186 loc) 8.19 kB
/** * @file Blocking synchronous operation detector for scalability analysis * @description Single responsibility: Identify synchronous operations that prevent concurrent execution * * This detector identifies synchronous operations that can block the event loop in Node.js * applications, preventing concurrent request handling and reducing application scalability. * It uses contextual analysis to differentiate between problematic blocking calls in server * contexts versus acceptable usage in CLI tools and utility scripts. * * Design rationale: * - Context-aware analysis prevents false positives in appropriate usage scenarios * - Synchronous operation patterns checked against scalability impact database * - Severity adjustment based on execution context (server vs CLI vs library) * - Conservative approach excludes operations that are unavoidable or typically fast */ const { detectExecutionContext, getContextualScalabilityConcerns } = require('./contextDetector'); /** * Detect blocking synchronous operations using context-aware pattern matching * * Technical function: Context-sensitive detection of event loop blocking operations * * Implementation rationale: * - Context detection differentiates server code (critical) from CLI tools (acceptable) * - Curated list focuses on operations with significant blocking potential * - Excludes fast operations like JSON.parse/stringify that are typically unavoidable * - Special handling for library contexts distinguishes result writing from problematic patterns * * Blocking operation categories: * - File system: readFileSync, writeFileSync, appendFileSync block I/O operations * - Process execution: execSync blocks until child process completion * - Cryptographic: Synchronous hashing operations can be CPU intensive * - Network: Synchronous network calls (less common but critical when present) * * Context-specific severity assessment: * - Server/API context: HIGH severity due to concurrent request impact * - CLI context: MEDIUM severity as single-threaded execution is expected * - Library context: Variable severity based on intended usage patterns * - Test context: LOW severity as blocking behavior may be intentional * * False positive prevention: * - Result writing in analysis libraries often requires synchronous operations * - Configuration loading at startup may legitimately use sync operations * - CLI tools naturally have different scalability requirements than servers * - Build scripts and utilities may require synchronous execution flow * * Performance impact considerations: * - Event loop blocking prevents concurrent request processing * - File I/O blocking scales poorly with disk latency and file size * - Process execution blocking depends on child process execution time * - CPU-intensive sync operations block regardless of I/O wait time * * @param {string} content - File content to analyze for synchronous operations * @param {string} filePath - File path for context detection and severity assessment * @returns {Array<Object>} Array of blocking synchronous operation issues with contextual recommendations * @example * const issues = detectBlockingSync(` * const data = fs.readFileSync('./config.json'); * const result = child_process.execSync('git status'); * `, 'server/api/handler.js'); * // Returns issues with HIGH severity due to server context */ function detectBlockingSync(content, filePath) { const issues = []; const context = detectExecutionContext(content, filePath); const concerns = getContextualScalabilityConcerns(context); // Skip if blocking operations aren't relevant for this context if (!concerns.blockingOperations.relevant) { return issues; } const syncCalls = [ 'fs.readFileSync', 'fs.writeFileSync', 'fs.appendFileSync', 'child_process.execSync', 'crypto.createHash().digest()' // Removed JSON.parse and JSON.stringify - these are unavoidable and typically fast ]; syncCalls.forEach(call => { if (content.includes(call)) { // Enhanced analysis for library context - distinguish benign result writing from problematic patterns if (context.type === 'library' && call.includes('writeFileSync')) { const isBenignResultWriting = analyzeForBenignResultWriting(content, call); if (isBenignResultWriting) { // Skip flagging benign result writing in analysis libraries // Final report/result writing is expected and non-problematic return; } } // Adjust severity based on context const severity = concerns.blockingOperations.severity; const contextualRecommendation = getContextualRecommendation(call, context); issues.push({ type: 'blocking_sync', severity, category: context.isServer ? 'API' : 'Performance', location: filePath, pattern: call, summary: `Blocking sync call '${call}' in ${context.type} context`, recommendation: contextualRecommendation.recommendation, impact: contextualRecommendation.impact, context: { type: context.type, confidence: context.confidence, reason: concerns.blockingOperations.reason } }); } }); return issues; } /** * Analyzes if writeFileSync is benign result writing * @param {string} content - File content * @param {string} call - The sync call being analyzed * @returns {boolean} True if this appears to be benign result writing */ function analyzeForBenignResultWriting(content, call) { // Patterns that indicate final result/report writing (benign) const benignWritingPatterns = [ // Final result writing /writeFileSync.*result/i, /writeFileSync.*report/i, /writeFileSync.*output/i, /writeFileSync.*analysis/i, /writeFileSync.*summary/i, // Configuration or final data writing /writeFileSync.*config/i, /writeFileSync.*json/i, /writeFileSync.*\.json/, // Single write operations (not in loops) /^\s*fs\.writeFileSync/m, /return.*writeFileSync/, ]; // Patterns that indicate problematic writing (should still be flagged) const problematicWritingPatterns = [ // Writing in loops (potentially many files) /for.*writeFileSync/s, /forEach.*writeFileSync/s, /while.*writeFileSync/s, /\.map.*writeFileSync/s, // Frequent/repeated writing /setInterval.*writeFileSync/s, /setTimeout.*writeFileSync/s, // Large file processing /writeFileSync.*large/i, /writeFileSync.*huge/i, /writeFileSync.*massive/i ]; const hasBenignPatterns = benignWritingPatterns.some(pattern => pattern.test(content)); const hasProblematicPatterns = problematicWritingPatterns.some(pattern => pattern.test(content)); // Consider it benign if it has benign patterns and no problematic patterns return hasBenignPatterns && !hasProblematicPatterns; } /** * Gets contextual recommendation for blocking sync calls * @param {string} call - The sync call being flagged * @param {Object} context - Execution context * @returns {Object} Contextual recommendation and impact */ function getContextualRecommendation(call, context) { switch (context.type) { case 'server': return { recommendation: `Replace '${call}' with its async version to prevent blocking under load`, impact: 'Can block event loop and hurt concurrent request handling' }; case 'cli': return { recommendation: `Consider '${call}' async version for better error handling and consistency`, impact: 'Minor performance impact in CLI context' }; case 'library': return { recommendation: `Provide both sync and async versions, or use async '${call}' to avoid blocking consumers`, impact: 'May block consumers depending on their usage context' }; default: return { recommendation: `Replace '${call}' with its async version to prevent blocking`, impact: 'Can block event loop in runtime contexts' }; } } module.exports = { detectBlockingSync };