crapifyme
Version:
Ultra-fast developer productivity CLI tools - remove comments, logs, and more
342 lines • 15.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DepsProcessor = void 0;
const child_process_1 = require("child_process");
const util_1 = require("util");
const bundle_analyzer_1 = require("./bundle-analyzer");
const package_analyzer_1 = require("./package-analyzer");
const security_scanner_1 = require("./security-scanner");
const types_1 = require("./types");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
class DepsProcessor {
constructor(options = {}, cwd = process.cwd()) {
this.cwd = cwd;
this.options = {
packageManager: 'auto',
includeDevDependencies: true,
includePeerDependencies: false,
includeOptionalDependencies: false,
checkSecurity: true,
analyzeBundleSize: true,
checkUnused: true,
workspaces: false,
timeout: 120000,
cacheTimeout: 3600000,
verbose: false,
...options
};
this.packageAnalyzer = new package_analyzer_1.PackageAnalyzer(cwd);
this.securityScanner = new security_scanner_1.SecurityScanner(cwd, this.options.timeout);
this.bundleAnalyzer = new bundle_analyzer_1.BundleAnalyzer(this.options.cacheTimeout);
}
async analyzeProject(analysisTypes = [types_1.AnalysisType.FULL]) {
const startTime = Date.now();
const errors = [];
const warnings = [];
try {
if (this.options.verbose) {
}
const packageManager = await this.packageAnalyzer.detectPackageManager();
const packageJson = await this.packageAnalyzer.readPackageJson();
if (this.options.verbose) {
}
const projectAnalysis = {
projectInfo: {
name: packageJson.name,
version: packageJson.version,
path: this.cwd,
packageManager
},
dependencies: {
production: [],
development: [],
peer: [],
optional: []
},
summary: {
total: { production: 0, development: 0, peer: 0, optional: 0 },
outdated: 0,
vulnerable: 0,
unused: 0,
duplicates: 0,
heavyPackages: 0
},
security: {
vulnerabilities: [],
auditSummary: { critical: 0, high: 0, moderate: 0, low: 0 }
},
bundle: {
totalSize: { raw: 0, gzip: 0, formatted: { raw: '0B', gzip: '0B' } },
largestPackages: [],
treeshakeable: [],
nonTreeshakeable: [],
sideEffects: []
},
unusedDependencies: [],
duplicateDependencies: new Map()
};
const shouldAnalyze = (type) => analysisTypes.includes(types_1.AnalysisType.FULL) || analysisTypes.includes(type);
const dependencies = await this.packageAnalyzer.getInstalledDependencies();
this.categorizeDependencies(dependencies, projectAnalysis);
if (shouldAnalyze(types_1.AnalysisType.SECURITY) && this.options.checkSecurity) {
if (this.options.verbose) {
process.stdout.write('🔒 Checking security vulnerabilities');
const timer = setInterval(() => process.stdout.write('.'), 800);
setTimeout(() => {
clearInterval(timer);
process.stdout.write('\n');
}, 2000);
}
await this.analyzeSecurity(projectAnalysis, errors);
}
if (shouldAnalyze(types_1.AnalysisType.SIZE) && this.options.analyzeBundleSize) {
if (this.options.verbose) {
process.stdout.write('📊 Analyzing bundle sizes...\n');
}
await this.analyzeBundleSize(projectAnalysis, errors);
}
if (shouldAnalyze(types_1.AnalysisType.DUPLICATES)) {
if (this.options.verbose) {
process.stdout.write('🔍 Checking for duplicate dependencies...\n');
}
await this.analyzeDuplicates(projectAnalysis, warnings);
}
if (shouldAnalyze(types_1.AnalysisType.UNUSED) && this.options.checkUnused) {
if (this.options.verbose) {
process.stdout.write('📋 Checking for unused dependencies...\n');
}
await this.analyzeUnused(projectAnalysis, warnings);
}
this.calculateSummary(projectAnalysis);
return {
analysis: projectAnalysis,
errors,
warnings,
processingTime: Date.now() - startTime,
cacheMisses: 0, // TODO: Implement cache metrics
cacheHits: 0
};
}
catch (error) {
errors.push({
type: 'general',
message: `Fatal error during analysis: ${error.message}`
});
throw error;
}
}
categorizeDependencies(dependencies, analysis) {
for (const [name, dep] of dependencies) {
if (dep.isPeer) {
analysis.dependencies.peer.push(dep);
}
else if (dep.isOptional) {
analysis.dependencies.optional.push(dep);
}
else if (dep.isDev) {
analysis.dependencies.development.push(dep);
}
else {
analysis.dependencies.production.push(dep);
}
}
analysis.summary.total = {
production: analysis.dependencies.production.length,
development: analysis.dependencies.development.length,
peer: analysis.dependencies.peer.length,
optional: analysis.dependencies.optional.length
};
}
async analyzeSecurity(analysis, errors) {
try {
const securityResult = await this.securityScanner.scanVulnerabilities(analysis.projectInfo.packageManager);
analysis.security.vulnerabilities = securityResult.vulnerabilities;
analysis.security.auditSummary = securityResult.summary;
const allDependencies = [
...analysis.dependencies.production,
...(this.options.includeDevDependencies ? analysis.dependencies.development : [])
];
const deprecationChecks = await this.securityScanner.batchCheckVulnerabilities(allDependencies.map(dep => ({ name: dep.name, version: dep.currentVersion })));
for (const [packageName, vulns] of deprecationChecks) {
analysis.security.vulnerabilities.push(...vulns);
}
}
catch (error) {
errors.push({
type: 'security',
message: `Security analysis failed: ${error.message}`
});
}
}
async analyzeBundleSize(analysis, errors) {
try {
const productionDeps = new Map(analysis.dependencies.production.map(dep => [dep.name, dep]));
const bundleAnalysis = await this.bundleAnalyzer.analyzeBundleSize(productionDeps);
analysis.bundle = bundleAnalysis;
for (const dep of analysis.dependencies.production) {
const largePackage = bundleAnalysis.largestPackages.find(pkg => pkg.name === dep.name);
if (largePackage) {
dep.size = {
raw: largePackage.size.raw,
gzip: largePackage.size.gzip,
formatted: {
raw: this.formatSize(largePackage.size.raw),
gzip: this.formatSize(largePackage.size.gzip)
}
};
}
}
}
catch (error) {
errors.push({
type: 'size',
message: `Bundle size analysis failed: ${error.message}`
});
}
}
async analyzeDuplicates(analysis, warnings) {
try {
analysis.duplicateDependencies = await this.packageAnalyzer.findDuplicateDependencies();
for (const [packageName, versions] of analysis.duplicateDependencies) {
if (versions.length > 1) {
warnings.push({
type: 'performance',
message: `Duplicate versions found: ${versions.join(', ')}`,
package: packageName
});
}
}
}
catch (error) {
warnings.push({
type: 'performance',
message: `Duplicate analysis failed: ${error.message}`
});
}
}
async analyzeUnused(analysis, warnings) {
try {
analysis.unusedDependencies = await this.findUnusedDependencies();
for (const unusedPkg of analysis.unusedDependencies) {
const dep = [
...analysis.dependencies.production,
...analysis.dependencies.development
].find(d => d.name === unusedPkg);
if (dep) {
dep.unusedReason = 'Not imported in source code';
warnings.push({
type: 'performance',
message: 'Package appears to be unused',
package: unusedPkg
});
}
}
}
catch (error) {
warnings.push({
type: 'performance',
message: `Unused dependencies analysis failed: ${error.message}`
});
}
}
async findUnusedDependencies() {
try {
const { stdout } = await execAsync('npx depcheck --json', {
cwd: this.cwd,
timeout: this.options.timeout,
maxBuffer: 10 * 1024 * 1024
});
const depcheckResult = JSON.parse(stdout);
return depcheckResult.dependencies || [];
}
catch (error) {
if (this.options.verbose) {
console.warn('Note: Install depcheck to analyze unused dependencies: npm install -g depcheck');
}
return [];
}
}
calculateSummary(analysis) {
const allDeps = [
...analysis.dependencies.production,
...analysis.dependencies.development,
...analysis.dependencies.peer,
...analysis.dependencies.optional
];
analysis.summary.outdated = allDeps.filter(dep => dep.isOutdated).length;
analysis.summary.vulnerable = analysis.security.vulnerabilities.length;
analysis.summary.unused = analysis.unusedDependencies.length;
analysis.summary.duplicates = analysis.duplicateDependencies.size;
analysis.summary.heavyPackages = analysis.bundle.largestPackages.filter(pkg => pkg.size.raw > 100 * 1024).length;
}
async generateReport(analysis) {
const lines = [
'',
'📦 DEPENDENCY ANALYSIS',
`Project: ${analysis.projectInfo.name}`,
`Dependencies: ${analysis.summary.total.production} production, ${analysis.summary.total.development} dev`,
`Package Manager: ${analysis.projectInfo.packageManager.type} v${analysis.projectInfo.packageManager.version}`,
''
];
if (analysis.security.vulnerabilities.length > 0) {
lines.push('🚨 SECURITY ISSUES');
lines.push('┌─────────────────────┬──────────┬────────────────┐');
lines.push('│ Package │ Severity │ Recommendation │');
lines.push('├─────────────────────┼──────────┼────────────────┤');
const displayVulns = analysis.security.vulnerabilities.slice(0, 5);
for (const vuln of displayVulns) {
const pkgName = vuln.packageName || 'unknown';
const severity = vuln.severity.toUpperCase();
const recommendation = (vuln.recommendation || 'Review package').substring(0, 14);
lines.push(`│ ${pkgName.substring(0, 19).padEnd(19)} │ ${severity.padEnd(8)} │ ${recommendation.padEnd(14)} │`);
}
lines.push('└─────────────────────┴──────────┴────────────────┘');
lines.push('');
}
if (analysis.bundle.largestPackages.length > 0) {
lines.push('📊 PACKAGE SIZES');
lines.push('┌─────────────────────┬─────────┬─────────┬─────────┐');
lines.push('│ Package │ Raw │ Gzipped │ % Total │');
lines.push('├─────────────────────┼─────────┼─────────┼─────────┤');
const displayPackages = analysis.bundle.largestPackages.slice(0, 50);
for (const pkg of displayPackages) {
const rawSize = this.formatSize(pkg.size.raw);
const gzipSize = this.formatSize(pkg.size.gzip);
const percentage = pkg.size.percentage.toFixed(1) + '%';
lines.push(`│ ${pkg.name.substring(0, 19).padEnd(19)} │ ${rawSize.padEnd(7)} │ ${gzipSize.padEnd(7)} │ ${percentage.padEnd(7)} │`);
}
lines.push('└─────────────────────┴─────────┴─────────┴─────────┘');
lines.push('');
lines.push(`Total Bundle Size: ${analysis.bundle.totalSize.formatted.raw} (${analysis.bundle.totalSize.formatted.gzip} gzipped)`);
lines.push('');
}
const statusLines = [];
if (analysis.summary.outdated > 0) {
statusLines.push(`🔄 OUTDATED (${analysis.summary.outdated})`);
}
if (analysis.summary.unused > 0) {
statusLines.push(`📋 UNUSED (${analysis.summary.unused})`);
}
if (analysis.summary.duplicates > 0) {
statusLines.push(`🔀 DUPLICATES (${analysis.summary.duplicates})`);
}
if (statusLines.length > 0) {
lines.push(statusLines.join(' '));
}
return lines.join('\n');
}
formatSize(bytes) {
if (bytes === 0)
return '0B';
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(unitIndex === 0 ? 0 : 1)}${units[unitIndex]}`;
}
}
exports.DepsProcessor = DepsProcessor;
//# sourceMappingURL=logic.js.map