agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
123 lines (111 loc) • 5.24 kB
JavaScript
/**
* @file Individual file refactoring analyzer for export promotion opportunity detection
* @description Single responsibility: Analyze individual files for function export potential and code organization improvements
*
* This analyzer examines individual files to identify functions, classes, and utilities that
* could benefit from being exported for broader reuse across the codebase. It provides
* intelligent assessment of export promotion opportunities while filtering out inappropriate
* candidates like internal helpers and test-specific functions.
*
* Design rationale:
* - File-level analysis enables focused refactoring recommendations for specific modules
* - Intelligent filtering prevents inappropriate export suggestions for private/internal functions
* - Utility detection logic identifies files with high reuse potential for export promotion
* - Comprehensive analysis includes both unexported functions and existing export patterns
* - Priority-based recommendations enable incremental refactoring efforts
*
* Analysis methodology:
* - AST-based extraction identifies exportable functions and classes accurately
* - Context-aware filtering excludes test files, configuration, and internal modules
* - Utility file detection applies more aggressive export promotion strategies
* - Naming convention analysis prevents export of private/internal functionality
* - Comprehensive metrics support data-driven refactoring decisions
*/
const fs = require('fs');
const { promises: fsPromises } = require('fs');
const path = require('path');
// Import from atomic modules
const { isUtilityFile } = require('./utilityFileChecker');
const { extractUnexportedItems } = require('./extractUnexportedItems');
const { extractExistingExports } = require('./existingExportsExtractor');
const { findIndexFiles } = require('./indexFileFinder');
/**
* Analyze a single file for refactoring opportunities
* @param {string} filePath - File path to analyze
* @param {Object} config - Configuration options
* @returns {Object} Analysis results
*/
async function analyzeFileRefactoring(filePath, config = {}) {
try {
const content = await fsPromises.readFile(filePath, 'utf8');
const unexportedItems = extractUnexportedItems(content);
const existingExports = extractExistingExports(content);
const isUtility = isUtilityFile(filePath, config);
// Identify promotion opportunities - more aggressive for utility directories
const promotionOpportunities = [];
if (unexportedItems.length > 0) {
unexportedItems.forEach(item => {
// Skip items that are likely internal/private (starting with _ or containing 'internal')
if (item.name.startsWith('_') || item.name.toLowerCase().includes('internal')) {
return;
}
// Check if this is a utility file (excluding test/index/config files)
const fileName = path.basename(filePath).toLowerCase();
const isTestFile = fileName.includes('.test.') || fileName.includes('.spec.') || fileName.includes('test.js');
const isIndexFile = fileName === 'index.js' || fileName === 'index.ts';
const isConfigFile = fileName.includes('config') || fileName.includes('summary') || fileName.includes('.md');
// More aggressive promotion for files in lib/utility directories (but not test/index/config files)
const shouldPromote = !isTestFile && !isIndexFile && !isConfigFile && (
isUtility ||
filePath.includes('/lib/') ||
filePath.includes('\\lib\\') ||
filePath.includes('/utils/') ||
filePath.includes('\\utils\\')
);
if (shouldPromote) {
promotionOpportunities.push({
type: 'export_promotion',
item,
reason: `${isUtility ? 'Utility' : 'Library'} ${item.type} '${item.name}' could be exported for reuse`,
priority: item.type === 'function' ? 'MEDIUM' : 'LOW',
suggestion: `Add 'export' keyword to line ${item.line}`
});
}
});
}
// Check for barrel file opportunities
const directory = path.dirname(filePath);
const indexFiles = findIndexFiles(directory, config);
const needsBarrelFile = indexFiles.length === 0 && existingExports.length > 0 && isUtility;
if (needsBarrelFile) {
promotionOpportunities.push({
type: 'barrel_file_creation',
reason: `Directory '${directory}' has exports but no index file for easier imports`,
priority: 'LOW',
suggestion: `Create index.ts file to re-export utilities from this directory`
});
}
return {
file: filePath,
isUtility,
unexportedItems,
existingExports,
promotionOpportunities,
indexFiles,
metrics: {
unexportedCount: unexportedItems.length,
exportedCount: existingExports.length,
promotionOpportunityCount: promotionOpportunities.length,
hasRefactoringOpportunities: promotionOpportunities.length > 0
}
};
} catch (error) {
return {
file: filePath,
error: error.message
};
}
}
module.exports = {
analyzeFileRefactoring
};