UNPKG

agentsqripts

Version:

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

127 lines (118 loc) 5.89 kB
/** * @file Calculate multi-dimensional semantic similarity between code blocks * @description Single responsibility: Compute weighted similarity for WET code detection * * This utility calculates comprehensive semantic similarity between code blocks using * multiple dimensions: structure, parameters, complexity, length, dependencies, and content. * The weighted approach enables nuanced detection of code duplication that goes beyond * simple text matching to identify semantically equivalent code patterns. * * Design rationale: * - Multi-dimensional analysis captures various aspects of code similarity * - Weighted scoring prioritizes structural similarity over surface-level matches * - Early exit optimizations improve performance for common cases * - Graceful handling of missing metrics maintains robustness */ const calculateStructureSimilarity = require('./calculateStructureSimilarity'); const calculateParameterSimilarity = require('./calculateParameterSimilarity'); const calculateComplexitySimilarity = require('./calculateComplexitySimilarity'); const calculateLengthSimilarity = require('./calculateLengthSimilarity'); const calculateDependencySimilarity = require('./calculateDependencySimilarity'); const calculateContentSimilarity = require('./calculateContentSimilarity'); /** * Calculate comprehensive semantic similarity score between two code blocks * * Technical function: Computes weighted similarity across multiple code dimensions * * Implementation rationale: * - Hash comparison provides O(1) exact match detection before expensive analysis * - Type checking prevents meaningless comparisons (e.g., function vs class) * - Weighted scoring reflects relative importance of different similarity aspects * - Null handling allows graceful degradation when specific metrics unavailable * * Similarity weighting strategy: * - Structure (40%): AST similarity most important for detecting logical equivalence * - Parameters (20%): Function signatures critical for semantic equivalence * - Complexity (10%): Similar complexity suggests similar algorithmic approach * - Length (10%): Code size similarity indicates comparable implementation scale * - Dependencies (10%): Similar imports/requires suggest related functionality * - Content (10%): Textual similarity catches remaining edge cases * * Performance optimizations: * - Hash comparison (O(1)) before expensive similarity calculations * - Type filter prevents unnecessary computation on incompatible blocks * - Weighted average calculation only for available metrics * - Early return for trivial cases (exact matches, type mismatches) * * Weighted average calculation: * - Only includes metrics that return non-null values * - Adjusts total weight to accommodate missing metrics * - Prevents division by zero when all metrics return null * - Maintains proportional weighting when some metrics unavailable * * Edge case handling: * - Exact hash matches: Return 1.0 immediately * - Type mismatches: Return 0.0 (no similarity possible) * - All null metrics: Return 0.0 (no calculable similarity) * - Partial metrics: Adjust weights proportionally * * Semantic similarity dimensions: * - Structure: AST node patterns and control flow similarity * - Parameters: Function argument count, types, and naming patterns * - Complexity: Cyclomatic complexity and nesting similarity * - Length: Code size and statement count similarity * - Dependencies: Import/require statement and API usage similarity * - Content: Normalized textual content similarity after variable renaming * * Alternative approaches considered: * - Equal weighting: Rejected as structure more important than surface features * - Binary similarity: Rejected as doesn't capture gradual similarity levels * - Single-metric comparison: Rejected as misses important similarity dimensions * * @param {Object} block1 - First code block with extracted features and metadata * @param {Object} block2 - Second code block to compare against first block * @returns {number} Similarity score from 0.0 (no similarity) to 1.0 (identical) * @example * // Identical functions with different variable names: * // function add(a, b) { return a + b; } * // function sum(x, y) { return x + y; } * // Returns: ~0.85 (high structure/parameter similarity, lower content similarity) * * // Completely different block types: * // function vs class declaration * // Returns: 0.0 (immediate type mismatch) */ function calculateSemanticSimilarity(block1, block2) { // Quick checks for exact matches if (block1.hash === block2.hash) return 1.0; // Don't compare different types of blocks if (block1.type !== block2.type) return 0.0; // Calculate weighted similarity score const weights = { structure: 0.4, // AST structure similarity parameters: 0.2, // Parameter similarity complexity: 0.1, // Complexity similarity length: 0.1, // Length similarity dependencies: 0.1, // Dependency similarity content: 0.1 // Normalized content similarity }; const scores = { structure: calculateStructureSimilarity(block1, block2), parameters: calculateParameterSimilarity(block1, block2), complexity: calculateComplexitySimilarity(block1, block2), length: calculateLengthSimilarity(block1, block2), dependencies: calculateDependencySimilarity(block1, block2), content: calculateContentSimilarity(block1, block2) }; // Calculate weighted average let totalScore = 0; let totalWeight = 0; for (const [metric, weight] of Object.entries(weights)) { if (scores[metric] !== null) { totalScore += scores[metric] * weight; totalWeight += weight; } } return totalWeight > 0 ? totalScore / totalWeight : 0; } module.exports = calculateSemanticSimilarity;