agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
67 lines (60 loc) • 2.27 kB
JavaScript
/**
* @file Detect React hooks violations
* @description Single responsibility: Detect conditional hooks and hooks in loops
*/
const walk = require('acorn-walk');
const { getLineNumber } = require('../../../utils/astParser');
/**
* Detect hooks violations (conditional hooks, hooks in loops)
* @param {Object} ast - AST tree
* @param {string} filePath - File path
* @returns {Array} Detected bugs
*/
function detectHooksViolations(ast, filePath) {
const bugs = [];
const hookNames = ['useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext'];
walk.ancestor(ast, {
CallExpression(node, ancestors) {
if (node.callee.type === 'Identifier' && hookNames.includes(node.callee.name)) {
// Check if hook is inside a condition or loop
for (let i = ancestors.length - 1; i >= 0; i--) {
const ancestor = ancestors[i];
if (ancestor.type === 'IfStatement' || ancestor.type === 'ConditionalExpression') {
bugs.push({
type: 'conditional_hook',
severity: 'HIGH',
category: 'React',
line: getLineNumber(node),
column: node.loc ? node.loc.start.column : 0,
description: `React Hook "${node.callee.name}" called conditionally`,
recommendation: 'Move the hook to the top level of the component',
effort: 2,
impact: 'high',
file: filePath
});
break;
}
if (ancestor.type === 'ForStatement' ||
ancestor.type === 'WhileStatement' ||
ancestor.type === 'DoWhileStatement') {
bugs.push({
type: 'hook_in_loop',
severity: 'HIGH',
category: 'React',
line: getLineNumber(node),
column: node.loc ? node.loc.start.column : 0,
description: `React Hook "${node.callee.name}" called in a loop`,
recommendation: 'Move the hook outside the loop',
effort: 2,
impact: 'high',
file: filePath
});
break;
}
}
}
}
});
return bugs;
}
module.exports = detectHooksViolations;