UNPKG

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
/** * @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 };