UNPKG

agentsqripts

Version:

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

111 lines (106 loc) 4.12 kB
/** * @file Cyclomatic complexity calculation for code quality analysis * @description Single responsibility: Calculate McCabe cyclomatic complexity metrics * * This module implements McCabe's cyclomatic complexity calculation using pattern-based * detection of decision points in JavaScript code. Cyclomatic complexity measures the * number of linearly independent paths through a program, serving as a key indicator * of code maintainability, testability, and potential defect density. * * Design rationale: * - Pattern-based approach handles JavaScript syntax variations efficiently * - Comprehensive decision point coverage captures all complexity contributors * - Simple implementation maintains performance for large codebases * - Conservative counting avoids over-penalizing modern JavaScript patterns */ /** * Calculate McCabe cyclomatic complexity using decision point enumeration * * Technical function: Pattern-based complexity calculation with comprehensive decision point detection * * Implementation rationale: * - Base complexity of 1 represents single linear execution path * - Each decision point adds one additional independent path * - Regex patterns efficiently identify all JavaScript decision constructs * - Global matching ensures all occurrences contribute to complexity score * * Cyclomatic complexity theory: * - M = E - N + 2P (where E=edges, N=nodes, P=connected components) * - Simplified: M = decision_points + 1 for single function analysis * - Each branching statement creates additional execution paths * - Complexity correlates with testing effort and defect probability * * Decision point coverage: * - Conditional statements: if, else if (each adds 1) * - Loop constructs: while, for (each adds 1) * - Switch cases: each case label adds 1 * - Exception handling: catch blocks add 1 * - Logical operators: && and || in conditions add 1 each * - Ternary operators: ? : conditional expressions add 1 * * JavaScript-specific considerations: * - Logical operators (&&, ||) create implicit branching * - Ternary operators provide compact conditional logic * - Switch statements: each case increases complexity * - Try-catch: exception paths increase complexity * - Arrow functions and modern syntax handled through pattern matching * * Complexity interpretation guidelines: * - 1-10: Simple, low risk * - 11-20: Moderate complexity, some risk * - 21-50: Complex, high risk * - >50: Very complex, very high risk, consider refactoring * * Alternative approaches considered: * - AST-based analysis: More accurate but higher overhead * - Control flow graph construction: Precise but complex implementation * - Static analysis tools: External dependencies and integration complexity * - Pattern matching chosen for balance of accuracy and performance * * @param {string} content - JavaScript code content to analyze for complexity * @returns {number} Cyclomatic complexity score (minimum 1) * @example * const complexity = calculateCyclomaticComplexity(` * function process(x) { * if (x > 0) { // +1 * while (x > 5) { // +1 * x--; * } * } else if (x < 0) { // +1 * x = -x; * } * return x; * } * `); * // Returns: 4 (base 1 + 3 decision points) */ // Precompiled regex patterns for better performance - avoids recompiling on every function call const DECISION_PATTERNS = [ /\bif\b/g, /\belse\s+if\b/g, /\bwhile\b/g, /\bfor\b/g, /\bcase\b/g, /\bcatch\b/g, /\b&&\b/g, /\b\|\|\b/g, /\?\s*[^:]*:/g, // ternary operator /\bswitch\b/g ]; function calculateCyclomaticComplexity(content) { // Start with base complexity of 1 let complexity = 1; // Count decision points using precompiled patterns DECISION_PATTERNS.forEach(pattern => { // Reset regex lastIndex for global patterns pattern.lastIndex = 0; const matches = content.match(pattern); if (matches) { complexity += matches.length; } }); return complexity; } module.exports = { calculateCyclomaticComplexity };