agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
178 lines (162 loc) • 6.21 kB
JavaScript
/**
* @file Context-aware threshold provider for intelligent SRP violation assessment
* @description Single responsibility: Provide file-type-specific thresholds for accurate SRP analysis
*
* This threshold provider implements intelligent context detection and appropriate threshold
* adjustment for different file types and architectural roles. It prevents false positives
* by recognizing that CLI tools, configuration files, and utility modules have different
* legitimate complexity patterns than general application code.
*
* Design rationale:
* - Context detection prevents inappropriate SRP violation flagging on legitimate patterns
* - File type classification enables targeted threshold application
* - Flexible threshold system accommodates different architectural patterns
* - Severity adjustment allows nuanced assessment based on file purpose
* - Conservative approach minimizes disruptive refactoring recommendations
*
* Context classification logic:
* - CLI scripts: Higher thresholds for argument parsing and main function patterns
* - Test files: Relaxed thresholds acknowledging multiple test case patterns
* - Configuration: Higher tolerance for multiple setting and constant definitions
* - Library/utility: Balanced approach recognizing related function clustering
* - Demo files: Relaxed thresholds for example and demonstration patterns
*/
/**
* Detect file context for appropriate SRP thresholds
* @param {string} filePath - File path to analyze
* @param {string} content - File content for additional context
* @returns {string} File context type
*/
function detectFileContext(filePath, content) {
const normalizedPath = filePath.toLowerCase();
const fileName = normalizedPath.split('/').pop() || '';
// CLI script detection
if (content.includes('#!/usr/bin/env node') ||
content.includes('process.argv') ||
content.includes('process.exit') ||
normalizedPath.includes('/cli/') ||
fileName.startsWith('analyze-') ||
fileName.includes('cli')) {
return 'cli';
}
// Test file detection
if (normalizedPath.includes('/test/') ||
normalizedPath.includes('/__tests__/') ||
fileName.includes('.test.') ||
fileName.includes('.spec.') ||
content.includes('describe(') ||
content.includes('it(')) {
return 'test';
}
// Configuration file detection
if (fileName.includes('config') ||
fileName.includes('settings') ||
fileName === 'index.js' ||
normalizedPath.includes('/config/')) {
return 'config';
}
// Utility/library file detection
if (normalizedPath.includes('/lib/') ||
normalizedPath.includes('/utils/') ||
fileName.includes('utils') ||
fileName.includes('helpers')) {
return 'library';
}
// Demo/example file detection
if (normalizedPath.includes('/demo/') ||
normalizedPath.includes('/examples/') ||
fileName.includes('demo') ||
fileName.includes('example')) {
return 'demo';
}
return 'general';
}
/**
* Get context-aware thresholds for SRP analysis
* @param {string} context - File context type
* @returns {Object} Threshold configuration
*/
function getContextualThresholds(context) {
const baseThresholds = {
lines: 100,
functions: 2,
exports: 1,
methods: 5,
concerns: 2
};
switch (context) {
case 'cli':
return {
...baseThresholds,
lines: 600, // CLI scripts can be longer due to argument parsing
functions: 5, // CLI scripts often have main + helper functions
exports: 0, // CLI scripts typically don't export
linePenalty: 0.5 // Reduced line penalty for CLI scripts
};
case 'test':
return {
...baseThresholds,
lines: 300, // Test files can be longer
functions: 10, // Many test functions are expected
exports: 0, // Test files typically don't export
linePenalty: 0.3 // Very reduced penalty for test files
};
case 'config':
return {
...baseThresholds,
lines: 200, // Config files can be longer
functions: 1, // Config files should be mostly data
exports: 2, // Config files often export multiple objects
linePenalty: 0.4 // Reduced penalty for configuration
};
case 'demo':
return {
...baseThresholds,
lines: 400, // Demo files can be longer to show examples
functions: 8, // Demo files often have multiple examples
exports: 3, // Demo files may export multiple examples
linePenalty: 0.2 // Very low penalty for demo files
};
case 'library':
return {
...baseThresholds,
lines: 200, // Library files can be longer for optimized algorithms
functions: 3, // Library files should have focused functionality
exports: 2, // Library files can export related functions
concerns: 3, // Allow more concerns for utility libraries
linePenalty: 0.6 // Reduced penalty for legitimate library complexity
};
default: // 'general'
return {
...baseThresholds,
linePenalty: 1.0 // Standard penalty
};
}
}
/**
* Get severity adjustment based on context
* @param {string} context - File context type
* @param {number} baseScore - Base SRP violation score
* @returns {number} Adjusted score
*/
function getContextualSeverityAdjustment(context, baseScore) {
switch (context) {
case 'cli':
return Math.max(0, baseScore - 2); // Reduce severity for CLI scripts
case 'test':
return Math.max(0, baseScore - 3); // Very lenient for test files
case 'demo':
return Math.max(0, baseScore - 3); // Very lenient for demo files
case 'config':
return Math.max(0, baseScore - 1); // Slightly reduce for config files
case 'library':
return baseScore + 1; // Slightly stricter for library files
default:
return baseScore;
}
}
module.exports = {
detectFileContext,
getContextualThresholds,
getContextualSeverityAdjustment
};