knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
72 lines (71 loc) • 2.52 kB
JavaScript
import ts from 'typescript';
import { timerify } from "../util/Performance.js";
import { isIdChar } from "../util/regex.js";
const findInFlow = (flowNode, targetSymbol) => {
if (!flowNode?.node)
return false;
if (flowNode.node.symbol === targetSymbol)
return true;
return findInFlow(flowNode.antecedent, targetSymbol);
};
const hasRefsInFile = (item, sourceFile, typeChecker) => {
if (!item.symbol)
return false;
if (item.identifier === '')
return true;
if (item.symbol.flags & ts.SymbolFlags.AliasExcludes)
return true;
const text = sourceFile.text;
const id = item.identifier;
const symbols = new Set();
const pos = item.pos;
const declarationRanges = [];
for (const decl of item.symbol.declarations ?? []) {
const name = decl.name;
if (name)
declarationRanges.push({ start: name.pos, end: name.end });
}
let index = 0;
while (index < text.length && (index = text.indexOf(id, index)) !== -1) {
if (isIdChar(text.charAt(index - 1)) || isIdChar(text.charAt(index + id.length))) {
index += id.length;
continue;
}
if (index === pos || index === pos + 1) {
index += id.length;
continue;
}
let skip = false;
for (const range of declarationRanges) {
if (index >= range.start && index < range.end) {
skip = true;
break;
}
}
if (skip) {
index += id.length;
continue;
}
const symbol = typeChecker.getSymbolAtLocation(ts.getTokenAtPosition(sourceFile, index));
if (symbol && id === symbol.escapedName) {
if (item.symbol === symbol)
return true;
const declaration = symbol.declarations?.[0];
if (declaration) {
if (findInFlow(declaration.name?.flowNode, item.symbol))
return true;
if (ts.isImportSpecifier(declaration) && symbols.has(symbol))
return true;
}
if (symbol.flags & ts.SymbolFlags.Property) {
const type = typeChecker.getTypeOfSymbol(symbol);
if (type?.symbol && item.symbol === type.symbol)
return true;
}
symbols.add(symbol);
}
index += id.length;
}
return false;
};
export const _hasRefsInFile = timerify(hasRefsInFile);