agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
165 lines (142 loc) • 5.12 kB
JavaScript
/**
* @file Contextual performance scorer
* @description Provides context-aware scoring for performance issues
*/
/**
* Calculate contextual effort score based on issue characteristics
* @param {Object} issue - Performance issue object
* @param {string} fileContent - Full file content for context
* @returns {number} Contextual effort score (1-5)
*/
function calculateContextualEffort(issue, fileContent) {
let baseEffort = issue.effort || 3;
let multiplier = 1;
// Check if issue is in a hot path (common function names, event handlers)
const hotPathPatterns = [
/render/i,
/update/i,
/handle/i,
/process/i,
/calculate/i,
/validate/i,
/onScroll/i,
/onChange/i,
/onInput/i
];
const surroundingCode = getSurroundingCode(fileContent, issue.line, 10);
const isHotPath = hotPathPatterns.some(pattern => pattern.test(surroundingCode));
if (isHotPath) {
multiplier *= 1.5; // Increase effort for hot path issues
}
// Check if inside a loop or recursive function
if (surroundingCode.includes('while') || surroundingCode.includes('for') ||
surroundingCode.includes('forEach') || surroundingCode.includes('map')) {
multiplier *= 1.2;
}
// Adjust for issue type specifics
switch (issue.type) {
case 'o_n_squared':
// Check approximate data size
if (surroundingCode.includes('.length > 1000') || surroundingCode.includes('large')) {
multiplier *= 1.3;
}
break;
case 'memory_leak':
// Memory leaks in constructors or initialization are worse
if (surroundingCode.includes('constructor') || surroundingCode.includes('init')) {
multiplier *= 1.4;
}
break;
case 'react_render_issue':
// Render issues in frequently updated components are worse
if (surroundingCode.includes('interval') || surroundingCode.includes('animation')) {
multiplier *= 1.3;
}
break;
}
return Math.min(5, Math.round(baseEffort * multiplier));
}
/**
* Calculate contextual impact score based on issue characteristics
* @param {Object} issue - Performance issue object
* @param {string} fileContent - Full file content for context
* @returns {string} Contextual impact description
*/
function calculateContextualImpact(issue, fileContent) {
const surroundingCode = getSurroundingCode(fileContent, issue.line, 20);
switch (issue.type) {
case 'o_n_squared':
// Estimate data size from context
if (surroundingCode.includes('users') || surroundingCode.includes('items') ||
surroundingCode.includes('records') || surroundingCode.includes('data')) {
return '40-80% reduction for large datasets (1000+ items)';
} else if (surroundingCode.includes('config') || surroundingCode.includes('settings') ||
surroundingCode.includes('options')) {
return '10-20% reduction for small datasets';
}
break;
case 'promise_in_loop':
// Check loop size indicators
if (surroundingCode.match(/\.length|count|size/)) {
return '50-70% faster with Promise.all for 10+ items';
}
break;
case 'repeated_dom_query':
// Check frequency of updates
if (surroundingCode.includes('animation') || surroundingCode.includes('interval')) {
return '60-90% DOM performance gain in animations';
} else {
return '20-40% DOM performance improvement';
}
break;
}
return issue.impact; // Fallback to default impact
}
/**
* Get surrounding code context
* @param {string} content - File content
* @param {number} lineNumber - Target line number
* @param {number} radius - Lines before/after to include
* @returns {string} Surrounding code
*/
function getSurroundingCode(content, lineNumber, radius = 10) {
const lines = content.split('\n');
const start = Math.max(0, lineNumber - radius - 1);
const end = Math.min(lines.length, lineNumber + radius);
return lines.slice(start, end).join('\n');
}
/**
* Calculate priority score for issue ordering
* @param {Object} issue - Performance issue
* @param {string} fileContent - File content
* @returns {number} Priority score (higher = more important)
*/
function calculatePriorityScore(issue, fileContent) {
let score = 0;
// Severity weights
const severityWeights = {
'HIGH': 100,
'MEDIUM': 50,
'LOW': 10
};
score += severityWeights[issue.severity] || 50;
// Add effort consideration (lower effort = higher priority for quick wins)
const contextualEffort = calculateContextualEffort(issue, fileContent);
score += (6 - contextualEffort) * 10;
// Hot path bonus
const surroundingCode = getSurroundingCode(fileContent, issue.line, 10);
if (/render|update|handle|process/.test(surroundingCode)) {
score += 25;
}
// Framework-specific issues get priority
if (issue.category === 'Framework') {
score += 20;
}
return score;
}
module.exports = {
calculateContextualEffort,
calculateContextualImpact,
calculatePriorityScore,
getSurroundingCode
};