UNPKG

agentsqripts

Version:

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

134 lines (123 loc) 4.99 kB
/** * @file React/Vue render issue detector * @description Detects inefficient rendering patterns in React/Vue components */ /** * Detects React/Vue rendering issues * @param {string} content - File content * @param {string} filePath - Path to the file * @returns {Array} Array of rendering issues */ function detectReactRenderIssues(content, filePath) { const issues = []; const lines = content.split('\n'); const { PERFORMANCE_PATTERNS } = require('./performancePatterns'); // Check if this is a React/Vue file const isReact = content.includes('import React') || content.includes('from \'react\'') || content.includes('from "react"') || /\.jsx$/.test(filePath); const isVue = content.includes('from \'vue\'') || content.includes('from "vue"') || /\.vue$/.test(filePath); if (!isReact && !isVue) return issues; lines.forEach((line, index) => { const lineNumber = index + 1; const trimmedLine = line.trim(); // React-specific patterns if (isReact) { // Inline function props (creates new function every render) if (/onClick\s*=\s*\{(?!\w+\s*\})\s*\(/.test(line) || /onChange\s*=\s*\{(?!\w+\s*\})\s*\(/.test(line) || /onSubmit\s*=\s*\{(?!\w+\s*\})\s*\(/.test(line)) { const pattern = PERFORMANCE_PATTERNS['react_render_issue']; issues.push({ type: 'react_render_issue', severity: pattern.severity, category: pattern.category, location: `${filePath}:${lineNumber}`, line: lineNumber, code: line.trim(), issue: 'inline_function_prop', description: 'Inline function in props causes unnecessary re-renders', summary: 'Inline function prop creates new function every render', recommendation: 'Use useCallback hook or define function outside render', effort: pattern.effort, impact: pattern.impact, estimatedSavings: '40-70% reduction in unnecessary renders' }); } // Object/Array literals in props if (/\w+\s*=\s*\{\s*\{[^}]+\}\s*\}/.test(line) && !line.includes('style=')) { const pattern = PERFORMANCE_PATTERNS['react_render_issue']; issues.push({ type: 'react_render_issue', severity: pattern.severity, category: pattern.category, location: `${filePath}:${lineNumber}`, line: lineNumber, code: line.trim(), issue: 'inline_object_prop', description: 'Inline object in props causes unnecessary re-renders', summary: 'Inline object prop creates new object every render', recommendation: 'Use useMemo hook or define object outside render', effort: pattern.effort, impact: pattern.impact, estimatedSavings: '40-70% reduction in unnecessary renders' }); } // Missing key prop in lists if (/\.map\s*\([^)]*\)\s*(?:=>|{)/.test(line)) { // Check next few lines for missing key prop let hasKey = false; for (let j = index; j < Math.min(index + 5, lines.length); j++) { if (/key\s*=/.test(lines[j])) { hasKey = true; break; } } if (!hasKey && (line.includes('<') || lines[index + 1]?.includes('<'))) { const pattern = PERFORMANCE_PATTERNS['react_render_issue']; issues.push({ type: 'react_render_issue', severity: 'HIGH', category: pattern.category, location: `${filePath}:${lineNumber}`, line: lineNumber, code: line.trim(), issue: 'missing_key_prop', description: 'Missing key prop in list rendering causes reconciliation issues', summary: 'Missing key prop in mapped elements', recommendation: 'Add unique key prop to list items', effort: 1, impact: pattern.impact, estimatedSavings: 'Prevents unnecessary DOM updates' }); } } } // Vue-specific patterns if (isVue) { // v-for without key if (/v-for\s*=/.test(line) && !/:key\s*=/.test(line)) { const pattern = PERFORMANCE_PATTERNS['react_render_issue']; issues.push({ type: 'react_render_issue', severity: 'HIGH', category: pattern.category, location: `${filePath}:${lineNumber}`, line: lineNumber, code: line.trim(), issue: 'missing_vue_key', description: 'v-for without :key causes inefficient updates', summary: 'Missing :key in v-for directive', recommendation: 'Add :key with unique value to v-for elements', effort: 1, impact: pattern.impact, estimatedSavings: 'Prevents unnecessary DOM updates' }); } } }); return issues; } module.exports = { detectReactRenderIssues };