import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import type { DependencyReport, Dependency, OutdatedPackage, Vulnerability, DependencyAnalysisOptions } from '../types/index.js';
export class DependencyAnalyzer {
/**
* Analyze project dependencies
*/
async analyzeDependencies(
projectPath: string = process.cwd(),
options?: DependencyAnalysisOptions
): Promise<DependencyReport> {
const packageJsonPath = join(projectPath, 'package.json');
if (!existsSync(packageJsonPath)) {
throw new Error('package.json not found');
}
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
const dependencies = this.extractDependencies(packageJson);
const report: DependencyReport = {
dependencies,
unused: options?.checkUnused !== false ? await this.findUnusedDependencies(projectPath) : [],
outdated: options?.checkOutdated !== false ? await this.findOutdatedPackages(packageJson) : [],
vulnerabilities: options?.checkVulnerabilities !== false ? await this.findVulnerabilities(projectPath) : [],
totalDependencies: dependencies.length,
};
return report;
}
/**
* Extract dependencies from package.json
*/
private extractDependencies(packageJson: any): Dependency[] {
const deps: Dependency[] = [];
if (packageJson.dependencies) {
for (const [name, version] of Object.entries(packageJson.dependencies)) {
deps.push({
name,
version: version as string,
type: 'dependencies',
});
}
}
if (packageJson.devDependencies) {
for (const [name, version] of Object.entries(packageJson.devDependencies)) {
deps.push({
name,
version: version as string,
type: 'devDependencies',
});
}
}
if (packageJson.peerDependencies) {
for (const [name, version] of Object.entries(packageJson.peerDependencies)) {
deps.push({
name,
version: version as string,
type: 'peerDependencies',
});
}
}
return deps;
}
/**
* Find unused dependencies (simplified - would use depcheck in production)
*/
private async findUnusedDependencies(_projectPath: string): Promise<string[]> {
// This is a simplified version. In production, we'd use the depcheck library
// For now, return empty array - actual implementation would require depcheck
try {
// Would use: const { depcheck } = await import('depcheck');
// const result = await depcheck(projectPath, {});
// return result.dependencies || [];
return [];
} catch {
return [];
}
}
/**
* Find outdated packages (simplified)
*/
private async findOutdatedPackages(_packageJson: any): Promise<OutdatedPackage[]> {
// This is a simplified version. In production, we'd check npm registry
// For now, return empty array - actual implementation would require npm API calls
const outdated: OutdatedPackage[] = [];
// Would need to:
// 1. Check npm registry for each package
// 2. Compare versions
// 3. Return outdated packages
return outdated;
}
/**
* Find security vulnerabilities (simplified)
*/
private async findVulnerabilities(_projectPath: string): Promise<Vulnerability[]> {
// This is a simplified version. In production, we'd use npm audit
// For now, return empty array - actual implementation would require npm audit API
try {
// Would use: const { execSync } = require('child_process');
// const auditResult = JSON.parse(execSync('npm audit --json', { cwd: projectPath }).toString());
// return parseAuditResults(auditResult);
return [];
} catch {
return [];
}
}
/**
* Analyze bundle size (simplified)
*/
async analyzeBundleSize(_projectPath: string): Promise<number | undefined> {
// This is a simplified version. In production, we'd use bundle-phobia or webpack-bundle-analyzer
// For now, return undefined
return undefined;
}
}