depshield
Version:
Smart Dependency Analyzer & Optimizer - Find unused npm packages, reduce bundle size, and improve project health with AST-based detection.
80 lines (79 loc) • 3.12 kB
JavaScript
export class Analyzer {
config;
constructor(config) {
this.config = config;
}
analyze(packageJson, usedDependencies, sizeMap) {
const installedDeps = Object.keys(packageJson.dependencies || {});
const installedDevDeps = Object.keys(packageJson.devDependencies || {});
const unusedDependencies = [];
const unusedDevDependencies = [];
const missingDependencies = [];
let totalSavings = 0;
// Check if package should be ignored
const isIgnored = (dep) => {
if (!this.config?.ignorePackages?.length)
return false;
return this.config.ignorePackages.some(pattern => {
if (pattern.includes('*')) {
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
return regex.test(dep);
}
return dep === pattern;
});
};
// Helper to check if a dependency is used (handling subpaths like 'lodash/fp')
const isUsed = (dep) => {
if (usedDependencies.has(dep))
return true;
for (const used of usedDependencies) {
if (used.startsWith(`${dep}/`))
return true;
if (dep.startsWith('@') && used.startsWith(dep))
return true; // Handle scoped packages
}
return false;
};
// Check production dependencies
for (const dep of installedDeps) {
if (isIgnored(dep))
continue;
if (!isUsed(dep)) {
// Special case: @types packages are usually dev deps but sometimes in deps
if (!dep.startsWith('@types/')) {
const size = sizeMap?.get(dep) || 0;
totalSavings += size;
unusedDependencies.push({
name: dep,
version: packageJson.dependencies[dep],
size,
type: 'production',
});
}
}
}
// Check dev dependencies
const ignoredDevDeps = ['typescript', 'eslint', 'prettier', 'jest', 'ts-jest', 'husky', 'lint-staged', 'vitest'];
for (const dep of installedDevDeps) {
if (isIgnored(dep))
continue;
if (!isUsed(dep) && !dep.startsWith('@types/') && !ignoredDevDeps.includes(dep) && !dep.includes('plugin') && !dep.includes('config')) {
const size = sizeMap?.get(dep) || 0;
totalSavings += size;
unusedDevDependencies.push({
name: dep,
version: packageJson.devDependencies[dep],
size,
type: 'dev',
});
}
}
return {
unusedDependencies,
unusedDevDependencies,
missingDependencies,
usedDependencies: Array.from(usedDependencies),
totalSavings,
};
}
}