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
JavaScript
/**
* @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
};