knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
114 lines (113 loc) • 4.5 kB
JavaScript
import { STOP } from './constants.js';
import { getAliasReExportMap, getPassThroughReExportSources, getStarReExportSources } from './visitors.js';
export const walkDown = (graph, filePath, identifier, visitor, entryPaths, visited = new Set()) => {
const key = `${filePath}:${identifier}`;
if (visited.has(key))
return false;
visited.add(key);
const file = graph.get(filePath);
if (!file?.imported)
return false;
const restIds = identifier.split('.');
const id = restIds.shift();
if (!id)
return false;
const imported = file.imported;
const importedByFiles = imported.imported.get(id);
if (importedByFiles) {
for (const importingFile of importedByFiles) {
const isEntry = entryPaths.has(importingFile);
if (visitor(filePath, id, importingFile, id, isEntry, 'import') === STOP)
return true;
}
}
const importedAsAliases = imported.importedAs.get(id);
if (importedAsAliases) {
for (const [alias, byFilePaths] of importedAsAliases) {
for (const importingFile of byFilePaths) {
const isEntry = entryPaths.has(importingFile);
if (visitor(filePath, id, importingFile, alias, isEntry, 'importAs') === STOP)
return true;
}
}
}
for (const [namespace, byFilePaths] of imported.importedNs) {
for (const importingFile of byFilePaths) {
const isEntry = entryPaths.has(importingFile);
if (visitor(filePath, identifier, importingFile, `${namespace}.${identifier}`, isEntry, 'importNS') === STOP) {
return true;
}
}
}
let done = false;
if (!done) {
const passThroughSources = getPassThroughReExportSources(imported, id);
if (passThroughSources) {
for (const reExportingFile of passThroughSources) {
const isEntry = entryPaths.has(reExportingFile);
if (visitor(filePath, id, reExportingFile, id, isEntry, 'reExport') === STOP) {
done = true;
break;
}
if (walkDown(graph, reExportingFile, identifier, visitor, entryPaths, visited)) {
done = true;
break;
}
}
}
}
if (!done) {
const aliasReExportMap = getAliasReExportMap(imported, id);
if (aliasReExportMap) {
for (const [alias, sources] of aliasReExportMap) {
for (const reExportingFile of sources) {
const isEntry = entryPaths.has(reExportingFile);
if (visitor(filePath, id, reExportingFile, alias, isEntry, 'reExportAs') === STOP) {
done = true;
break;
}
if (walkDown(graph, reExportingFile, [alias, ...restIds].join('.'), visitor, entryPaths, visited)) {
done = true;
break;
}
}
if (done)
break;
}
}
}
if (!done) {
for (const [namespace, sources] of imported.reExportedNs) {
for (const reExportingFile of sources) {
const isEntry = entryPaths.has(reExportingFile);
if (visitor(filePath, identifier, reExportingFile, `${namespace}.${identifier}`, isEntry, 'reExportNS') === STOP) {
done = true;
break;
}
if (walkDown(graph, reExportingFile, `${namespace}.${identifier}`, visitor, entryPaths, visited)) {
done = true;
break;
}
}
if (done)
break;
}
}
if (!done) {
const starSources = getStarReExportSources(imported);
if (starSources) {
for (const reExportingFile of starSources) {
const isEntry = entryPaths.has(reExportingFile);
if (visitor(filePath, id, reExportingFile, id, isEntry, 'reExportStar') === STOP) {
done = true;
break;
}
if (walkDown(graph, reExportingFile, identifier, visitor, entryPaths, visited)) {
done = true;
break;
}
}
}
}
return done;
};