sicua
Version:
A tool for analyzing project structure and dependencies
130 lines (129 loc) • 5.93 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.analyzeDependencies = analyzeDependencies;
const fileParser_1 = require("../../../parsers/fileParser");
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
const dependencyAnalyzer_constants_1 = require("../../../constants/dependencyAnalyzer.constants");
const fast_glob_1 = __importDefault(require("fast-glob"));
const pathUtils_1 = require("../../../utils/common/pathUtils");
/**
* Analyzes package dependencies using optimized path resolution
* @param components The list of components to analyze
* @param config The config manager with project path
* @param scanResult The enhanced scan result with file metadata
* @param pathResolver Pre-initialized path resolver for O(1) external package detection
* @returns Analysis result with unused and missing dependencies
*/
async function analyzeDependencies(components, config, pathResolver) {
const packageDependencies = await (0, fileParser_1.parsePackageJson)(config.projectPath);
const context = {
usedDependencies: new Set(),
usedInConfigs: new Set(),
};
// Analyze components - only collect external package dependencies
collectExternalDependencies(components, context, pathResolver);
// Analyze config files - only collect external package dependencies
await collectConfigExternalDependencies(config.projectPath, context, pathResolver);
// Find unused dependencies
const unusedDependencies = Object.keys(packageDependencies).filter((dep) => !context.usedDependencies.has(dep) &&
!context.usedInConfigs.has(dep) &&
!(0, dependencyAnalyzer_constants_1.isSpecialPackage)(dep) &&
!(0, dependencyAnalyzer_constants_1.isDevToolPackage)(dep));
// Find missing dependencies (should now only be actual external packages)
const missingDependencies = Array.from(context.usedDependencies).filter((dep) => !packageDependencies[dep]);
return {
unusedDependencies,
missingDependencies,
};
}
/**
* Collects only external package dependencies from components using optimized path resolution
*/
function collectExternalDependencies(components, context, pathResolver) {
for (const component of components) {
for (const importPath of component.imports) {
const resolution = pathResolver.resolveImportPath(importPath, component.fullPath);
// Only process external packages
if (resolution.isExternal && resolution.packageName) {
if (!(0, pathUtils_1.isPathAlias)(resolution.packageName)) {
context.usedDependencies.add(resolution.packageName);
}
}
}
}
}
/**
* Collects only external package dependencies from config files using optimized detection
*/
async function collectConfigExternalDependencies(projectPath, context, pathResolver) {
const configPatterns = [...dependencyAnalyzer_constants_1.CONFIG_FILES];
const configFiles = await (0, fast_glob_1.default)(configPatterns, {
cwd: projectPath,
absolute: true,
onlyFiles: true,
ignore: ["**/node_modules/**"],
});
await Promise.all(configFiles.map(async (configPath) => {
try {
const content = await fs.readFile(path.resolve(configPath), "utf8");
// Extract all import/require patterns efficiently
const importPatterns = extractImportPatterns(content);
for (const importPath of importPatterns) {
// Use PathResolver for consistent external package detection
if (pathResolver.isExternalPackage(importPath)) {
const packageName = pathResolver.extractPackageName(importPath);
if (packageName && !(0, pathUtils_1.isPathAlias)(packageName)) {
context.usedInConfigs.add(packageName);
}
}
}
}
catch (error) {
console.warn(`Error processing config file ${configPath}:`, error);
}
}));
}
/**
* Extract import patterns from file content efficiently
*/
function extractImportPatterns(content) {
const patterns = [];
// Combined regex for all import/require patterns
const importRegex = /(?:require\s*\(\s*['"]([^'"]+)['"]|import\s+.*?from\s*['"]([^'"]+)['"]|import\s*\(\s*['"]([^'"]+)['"])/g;
let match;
while ((match = importRegex.exec(content)) !== null) {
// match[1] = require, match[2] = import from, match[3] = dynamic import
const importPath = match[1] || match[2] || match[3];
if (importPath) {
patterns.push(importPath);
}
}
return patterns;
}