agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
128 lines (122 loc) • 5.84 kB
JavaScript
/**
* @file Detect legacy callback-based async patterns for modernization
* @description Single responsibility: Identify callback patterns that could benefit from async/await
*
* This detector analyzes JavaScript code for legacy callback-based asynchronous patterns,
* particularly Node.js-style error-first callbacks and nested callback structures
* (callback hell). It helps identify opportunities to modernize codebases with
* Promise-based patterns and async/await syntax for improved maintainability.
*
* Design rationale:
* - Focuses on two main problematic patterns: error-first callbacks and callback nesting
* - Uses regex pattern matching for efficient detection across large codebases
* - Provides specific modernization recommendations based on detected patterns
* - Categorizes issues by severity to help prioritize refactoring efforts
*/
/**
* Detect callback-based async patterns that could be modernized
*
* Technical function: Scans code lines for legacy callback patterns and nesting issues
*
* Implementation rationale:
* - Line-by-line analysis provides precise location information for issues
* - Regex patterns efficiently identify callback signatures and nesting structures
* - Severity differentiation helps prioritize refactoring (callback hell > simple callbacks)
* - Comprehensive issue objects provide context and actionable recommendations
*
* Pattern detection strategy:
* - Error-first callback pattern: `function(err, ...)` or `(err, ...)` arrow functions
* - Nested callback detection: Multiple function declarations within single line
* - Whitespace normalization handles various coding styles and formatting
* - Conservative matching prevents false positives while catching common patterns
*
* Regex pattern breakdown:
* - `\w+\s*\([^)]*,\s*function\s*\(\s*err\s*,`: Named function with error-first callback
* - `\w+\s*\([^)]*,\s*\(\s*err\s*,`: Function call with arrow function error-first callback
* - `function\s*\([^)]*\)\s*{.*function\s*\([^)]*\)\s*{`: Nested function declarations
*
* Severity classification rationale:
* - Callback patterns (LOW): Modernization improves maintainability but not critical
* - Callback hell (MEDIUM): Significantly impacts code readability and error handling
* - Effort estimates based on typical refactoring complexity for each pattern type
*
* Modernization recommendations:
* - Simple callbacks: Use util.promisify() or native Promise-based APIs
* - Callback hell: Refactor to async/await with proper error handling
* - Focus on maintainability improvements rather than performance gains
*
* Performance considerations:
* - O(n) time complexity for single pass through all code lines
* - Regex compilation cached by JavaScript engine for repeated patterns
* - Memory usage scales linearly with number of detected issues
* - Early continue optimization when no patterns match
*
* Limitations and trade-offs:
* - Line-based analysis may miss multi-line callback patterns
* - Regex matching may have false positives in comments or strings
* - Simple pattern detection chosen over AST parsing for performance
* - Focus on common Node.js patterns rather than all possible callback styles
*
* Alternative approaches considered:
* - AST-based analysis: Rejected for performance overhead in large codebases
* - Multi-line pattern detection: Rejected for complexity vs benefit trade-off
* - Framework-specific callback detection: Rejected to maintain general applicability
*
* @param {string[]} lines - Array of code lines to analyze for callback patterns
* @param {string} filePath - File path for issue location reporting
* @returns {Array<Object>} Array of detected callback-related issues with modernization recommendations
* @example
* // For: fs.readFile('file.txt', function(err, data) { ... })
* [{
* type: 'callback_pattern',
* severity: 'LOW',
* location: 'src/file.js:10',
* description: 'Callback-based async pattern - consider modernizing to async/await',
* recommendation: 'Consider using promisify() or native Promise-based APIs'
* }]
*/
function detectAsyncCallbacks(lines, filePath) {
const issues = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const lineNumber = i + 1;
const trimmed = line.trim();
// Node.js callback patterns
if (/\w+\s*\([^)]*,\s*function\s*\(\s*err\s*,/.test(trimmed) ||
/\w+\s*\([^)]*,\s*\(\s*err\s*,/.test(trimmed)) {
issues.push({
type: 'callback_pattern',
severity: 'LOW',
category: 'Async',
location: `${filePath}:${lineNumber}`,
line: lineNumber,
code: trimmed,
description: 'Callback-based async pattern - consider modernizing to async/await',
summary: 'Legacy callback pattern detected',
recommendation: 'Consider using promisify() or native Promise-based APIs',
effort: 2,
impact: 'Modernizes codebase and improves error handling',
estimatedSavings: 'improved maintainability'
});
}
// Nested callbacks (callback hell)
if (/function\s*\([^)]*\)\s*{.*function\s*\([^)]*\)\s*{/.test(trimmed)) {
issues.push({
type: 'callback_hell',
severity: 'MEDIUM',
category: 'Async',
location: `${filePath}:${lineNumber}`,
line: lineNumber,
code: trimmed,
description: 'Nested callbacks detected - callback hell pattern',
summary: 'Callback hell pattern',
recommendation: 'Refactor to async/await or Promise chains',
effort: 3,
impact: 'Significantly improves code readability and maintainability',
estimatedSavings: 'major maintainability improvement'
});
}
}
return issues;
}
module.exports = detectAsyncCallbacks;