knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
102 lines (101 loc) • 4.09 kB
JavaScript
import { OPAQUE } from "../../constants.js";
import { getAliasReExportMap, getNamespaceReExportSources, getPassThroughReExportSources, getStarReExportSources, } from "../visitors.js";
const hasOnlyNsRefs = (file) => {
if (file.importNs.size === 0)
return false;
for (const ns of file.importNs.keys()) {
if (!file.refs.has(ns))
return false;
for (const ref of file.refs) {
if (ref.startsWith(`${ns}.`))
return false;
}
}
return true;
};
export const isReferenced = (graph, entryPaths, filePath, id, options) => {
const seen = new Set();
const walkDown = (path, id) => {
const isEntryFile = entryPaths.has(path);
let reExportingEntryFile = isEntryFile ? path : undefined;
if (seen.has(path))
return [false, reExportingEntryFile];
seen.add(path);
const restIds = id.split('.');
const identifier = restIds.shift();
const file = graph.get(path)?.importedBy;
if (!identifier || !file) {
return [false, reExportingEntryFile];
}
const follow = (sources, nextId) => {
for (const byFilePath of sources) {
if (seen.has(byFilePath))
continue;
const result = walkDown(byFilePath, nextId);
if (result[1])
reExportingEntryFile = result[1];
if (result[0])
return true;
}
return false;
};
if ((file.import.get(OPAQUE) && !hasOnlyNsRefs(file)) ||
((identifier === id || (identifier !== id && file.refs.has(id))) &&
(file.import.has(identifier) || file.importAs.has(identifier)))) {
return [true, reExportingEntryFile];
}
for (const [exportId, aliases] of file.importAs) {
if (identifier === exportId) {
for (const alias of aliases.keys()) {
const aliasedRef = [alias, ...restIds].join('.');
if (file.refs.has(aliasedRef)) {
return [true, reExportingEntryFile];
}
}
}
}
for (const namespace of file.importNs.keys()) {
if (file.refs.has(`${namespace}.${id}`)) {
return [true, reExportingEntryFile];
}
const nsAliasMap = getAliasReExportMap(file, namespace);
if (nsAliasMap) {
for (const [alias, sources] of nsAliasMap) {
if (follow(sources, `${alias}.${id}`))
return [true, reExportingEntryFile];
}
}
const nsReExportSources = getNamespaceReExportSources(file, namespace);
if (nsReExportSources) {
if (follow(nsReExportSources, `${namespace}.${id}`))
return [true, reExportingEntryFile];
}
}
if (isEntryFile && !options.includeEntryExports)
return [false, reExportingEntryFile];
const aliasMap = getAliasReExportMap(file, identifier);
if (aliasMap) {
for (const [alias, sources] of aliasMap) {
if (follow(sources, [alias, ...restIds].join('.')))
return [true, reExportingEntryFile];
}
}
const directSources = getPassThroughReExportSources(file, identifier);
const starSources = getStarReExportSources(file);
if (directSources) {
if (follow(directSources, id))
return [true, reExportingEntryFile];
}
else if (starSources) {
if (follow(starSources, id))
return [true, reExportingEntryFile];
}
for (const [namespace, sources] of file.reExportNs) {
if (follow(sources, `${namespace}.${id}`)) {
return [true, reExportingEntryFile];
}
}
return [false, reExportingEntryFile];
};
return walkDown(filePath, id);
};