agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
116 lines (106 loc) • 4.86 kB
JavaScript
/**
* @file Barrel file detection for module organization analysis
* @description Single responsibility: Identify files that primarily re-export other modules
*
* This module detects "barrel files" - files that exist solely to re-export other modules
* for convenient importing. While barrel files serve legitimate organizational purposes,
* excessive use can indicate architectural issues or unnecessary indirection. This analysis
* helps identify optimization opportunities in module structure.
*
* Design rationale:
* - Ratio-based detection balances legitimate barrels vs architectural issues
* - Content analysis excludes comments and formatting for accurate assessment
* - File path context prevents false positives on legitimate index files
* - Conservative thresholds minimize false identification of utility modules
*/
/**
* Identify barrel files using content ratio analysis with contextual filtering
*
* Technical function: Ratio-based barrel file detection with path-aware exclusions
*
* Implementation rationale:
* - Export/import ratio analysis identifies primary file purpose
* - Comment filtering ensures accurate code content assessment
* - Path-based exclusions prevent false positives on legitimate index files
* - Conservative thresholds (80% exports, <3 other lines) balance precision and recall
*
* Barrel file characteristics:
* - High ratio of export/import statements to other code
* - Minimal business logic or implementation details
* - Primary purpose is module aggregation and re-export
* - Common patterns: export * from, export { } from, module.exports = require()
*
* Detection algorithm:
* - Filter out comments and empty lines for accurate analysis
* - Count export/import statements vs other meaningful code lines
* - Apply ratio threshold (>80% exports) with absolute limit (<3 other lines)
* - Exclude legitimate organizational files (index.js in lib directories)
*
* Legitimate barrel file patterns:
* - Public API aggregation in library index files
* - Feature module consolidation for clean imports
* - Framework adapter pattern implementations
* - Plugin or extension registration modules
*
* Problematic barrel file indicators:
* - Deep nesting of barrel files creating import chains
* - Single-export barrels that don't provide aggregation value
* - Circular dependencies introduced through barrel indirection
* - Performance impact from unnecessary module resolution
*
* Path exclusion strategy:
* - index.js files in lib/ directories often serve legitimate aggregation purposes
* - Non-JavaScript files excluded to prevent type errors
* - Main entry points identified by conventional naming patterns
* - Allow-list approach for known architectural patterns
*
* @param {string} content - File content to analyze for barrel characteristics
* @param {string} filePath - File path for contextual exclusion logic
* @returns {boolean} True if file appears to be primarily a barrel/re-export file
* @example
* const isBarrel = isBarrelFile(`
* export { UserService } from './user.js';
* export { AuthService } from './auth.js';
* export { DataService } from './data.js';
* `, 'src/services/index.js');
* // Returns: true (100% exports, minimal other code)
*/
function isBarrelFile(content, filePath) {
if (!content || typeof content !== 'string') return false;
// Skip non-JS files and certain patterns
if (!filePath.match(/\.(js|ts|jsx|tsx)$/)) return false;
if (filePath.includes('index.') && filePath.includes('/lib/')) return false; // Main exports
const allLines = content.split('\n');
const lines = [];
for (let i = 0; i < allLines.length; i++) {
const trimmed = allLines[i].trim();
if (trimmed.length > 0 && !trimmed.startsWith('//') && !trimmed.startsWith('/*')) {
lines.push(trimmed);
}
}
if (lines.length === 0) return false;
// Count export/import lines vs other code
let exportImportLines = 0;
let otherCodeLines = 0;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
// Remove block comments
if (line.includes('/*') && line.includes('*/')) {
line = line.replace(/\/\*.*?\*\//g, '').trim();
}
if (!line) continue;
if (line.startsWith('export') || line.startsWith('import') ||
line.startsWith('const') && line.includes('require(') ||
line.startsWith('module.exports')) {
exportImportLines++;
} else if (!line.startsWith('//') && line !== '{' && line !== '}' && line !== ';') {
otherCodeLines++;
}
}
// File is a barrel if it's mostly exports/imports with minimal other code
const totalLines = exportImportLines + otherCodeLines;
return totalLines > 0 && (exportImportLines / totalLines) > 0.8 && otherCodeLines < 3;
}
module.exports = {
isBarrelFile
};