UNPKG

agentsqripts

Version:

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

100 lines (93 loc) 4.32 kB
/** * @file Calculate cyclomatic complexity score for code blocks * @description Single responsibility: Compute complexity metric for WET code analysis * * This utility calculates cyclomatic complexity for code blocks using a weighted * approach that considers control flow statements, nested functions, and modern * JavaScript patterns like callbacks and promises. The complexity score helps * identify code blocks that may be difficult to maintain or test. * * Design rationale: * - Base complexity of 1 follows standard cyclomatic complexity principles * - Pattern-based approach handles various JavaScript control flow constructs * - Weighted scoring for callbacks reflects their impact on cognitive complexity * - Regex matching provides efficient detection across formatted code styles */ /** * Calculate weighted cyclomatic complexity score for a code block * * Technical function: Analyzes code content to compute complexity metric based on control flow * * Implementation rationale: * - Base complexity of 1 represents linear execution path (standard practice) * - Regex patterns efficiently detect control flow keywords across various formatting * - Incremental complexity addition follows traditional cyclomatic complexity principles * - Modern JavaScript patterns (callbacks, promises) receive weighted scoring * * Complexity calculation algorithm: * - Base complexity: 1 (single execution path) * - Control flow statements: +1 each (if, for, while, switch, case, catch) * - Nested functions: +1 each (beyond first function) * - Callbacks/promises: +0.5 each (reflect cognitive overhead, not branching) * * Control flow pattern detection: * - if statements: Conditional branching increases execution paths * - else if: Additional conditional branches * - Loops (for/while): Iterative complexity and potential branching * - Switch/case: Multiple execution paths based on value * - Exception handling (catch): Error handling complexity * * Modern JavaScript considerations: * - Nested functions add cognitive complexity for understanding scope * - Callbacks and arrow functions increase maintenance complexity * - Promise chains represent asynchronous complexity without traditional branching * - Weighted scoring (0.5) acknowledges cognitive load without full branching complexity * * Regex pattern analysis: * - Word boundaries (\b) ensure matching actual keywords, not substrings * - Whitespace patterns (\s*) accommodate various formatting styles * - Global flags (g) count all occurrences within the code block * - Escaped parentheses match function call syntax specifically * * Alternative approaches considered: * - AST-based complexity: Rejected for performance in pattern detection context * - Simple line counting: Rejected as inadequate for true complexity measurement * - McCabe complexity only: Rejected as missing modern JavaScript patterns * * @param {Object} node - AST node representing the code block (used for future enhancements) * @param {string} content - String content of the code block to analyze * @returns {number} Complexity score (integer, minimum 1) * @example * // For: if (x) { for (let i = 0; i < arr.length; i++) { ... } } * // Returns: 3 (base=1 + if=1 + for=1) * * // For: items.map(x => x.process()).filter(x => x.valid) * // Returns: 2 (base=1 + 2 callbacks * 0.5 = rounded to 2) */ function calculateComplexity(node, content) { let complexity = 1; // Base complexity // Count control flow statements const controlFlowPatterns = [ /\bif\s*\(/g, /\belse\s+if\s*\(/g, /\bfor\s*\(/g, /\bwhile\s*\(/g, /\bswitch\s*\(/g, /\bcase\s+/g, /\bcatch\s*\(/g ]; controlFlowPatterns.forEach(pattern => { const matches = content.match(pattern); if (matches) complexity += matches.length; }); // Add complexity for nested functions const nestedFunctions = content.match(/function\s*\w*\s*\(/g); if (nestedFunctions && nestedFunctions.length > 1) { complexity += nestedFunctions.length - 1; } // Add complexity for callbacks and promises const callbacks = content.match(/\.\w+\s*\([^)]*=>/g); if (callbacks) complexity += callbacks.length * 0.5; return Math.round(complexity); } module.exports = calculateComplexity;