agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
121 lines (102 loc) • 4.52 kB
JavaScript
/**
* @file Analyze entire project for WET code using improved approach
* @description Single responsibility: Orchestrate project-wide WET code analysis
*/
const fs = require('fs');
const path = require('path');
const { fsPromises } = require('../../fileSystemUtils');
const qerrors = require('qerrors');
const { extractSemanticBlocks } = require('../../ast/astBlockExtractor');
const { analyzeFileContext } = require('../../ast/contextAnalyzer');
const { generateRefactoringRecommendations } = require('../../ast/refactoringRecommendationEngine');
const { getDryGrade, getWetGrade } = require('../../gradeCalculator');
const { getAllFiles, pathExists } = require('../../fileSystemUtils');
const { VALID_EXTENSIONS } = require('../../wetCodeConfig');
const findSemanticDuplicatesOptimized = require('./findSemanticDuplicatesOptimized');
const calculateProjectMetrics = require('../metrics/calculateProjectMetrics');
const identifyTopOffenders = require('../recommendations/identifyTopOffenders');
/**
* Analyze entire project for WET code using improved approach
* @param {string} projectPath - Root path of the project
* @param {Object} options - Analysis options
* @returns {Promise<Object>} Project-wide analysis results
*/
async function analyzeProjectWetCodeImproved(projectPath, options = {}) {
try {
console.log('🚀 Starting improved WET code analysis...');
const startTime = Date.now();
// Get all relevant files
const extensions = options.extensions || VALID_EXTENSIONS;
const files = await getAllFiles(projectPath, extensions, options.excludePatterns);
console.log(`📁 Found ${files.length} files to analyze`);
// Extract all blocks from all files with progress
const allBlocks = [];
const fileContexts = {};
const fileResults = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
// Show progress for large projects
if (i % 50 === 0 && i > 0) {
console.log(` Processing file ${i}/${files.length}...`);
}
try {
const content = await fsPromises.readFile(file, 'utf8');
const context = analyzeFileContext(file, content);
fileContexts[file] = context;
if (!context.rules.skipAnalysis) {
const blocks = extractSemanticBlocks(content, file);
const relevantBlocks = blocks.filter(block =>
block.lineCount >= context.rules.minLines &&
block.complexity >= context.rules.minComplexity
);
allBlocks.push(...relevantBlocks);
fileResults.push({
file,
blocks: relevantBlocks.length,
context
});
}
} catch (error) {
console.warn(` Warning: Could not analyze ${file}: ${error.message}`);
}
}
console.log(`📊 Extracted ${allBlocks.length} semantic blocks`);
// Find cross-file duplicates using optimized algorithm
console.log('🔍 Finding semantic duplicates...');
const duplicateGroups = findSemanticDuplicatesOptimized(allBlocks, fileContexts);
console.log(`✨ Found ${duplicateGroups.length} duplicate groups`);
// Generate refactoring recommendations
console.log('💡 Generating refactoring recommendations...');
const hasLibDirectory = await pathExists(path.join(projectPath, 'lib'));
const recommendations = generateRefactoringRecommendations(duplicateGroups, {
projectPath,
hasLibDirectory
});
// Calculate project metrics
const metrics = calculateProjectMetrics(fileResults, duplicateGroups, allBlocks);
const analysisTime = Date.now() - startTime;
console.log(`✅ Analysis completed in ${(analysisTime / 1000).toFixed(1)}s`);
return {
summary: {
projectPath,
filesAnalyzed: files.length,
blocksAnalyzed: allBlocks.length,
duplicateGroups: duplicateGroups.length,
wetScore: metrics.wetScore,
dryScore: 100 - metrics.wetScore,
wetGrade: getWetGrade(metrics.wetScore),
dryGrade: getDryGrade(100 - metrics.wetScore),
analysisTime,
...metrics
},
duplicateGroups,
recommendations,
fileResults,
topOffenders: identifyTopOffenders(duplicateGroups)
};
} catch (error) {
qerrors.default(error, 'analyzeProjectWetCodeImproved failed', { projectPath });
throw error;
}
}
module.exports = analyzeProjectWetCodeImproved;