knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
121 lines (120 loc) • 5.44 kB
JavaScript
import { IMPORT_FLAGS, OPAQUE } from "../../constants.js";
import { addValue } from "../../util/module-graph.js";
import { getStringValue, isStringLiteral } from "./helpers.js";
export function handleCallExpression(node, s) {
if (node.callee.type === 'Identifier' &&
node.callee.name === 'require' &&
node.arguments.length === 1 &&
isStringLiteral(node.arguments[0])) {
const specifier = getStringValue(node.arguments[0]);
const reqTags = s.currentVarDeclStart >= 0 ? s.getJSDocTags(s.currentVarDeclStart) : undefined;
s.addImport(specifier, 'default', undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.NONE, undefined, reqTags);
return;
}
if (node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'require' &&
!node.callee.computed &&
node.callee.property.name === 'resolve' &&
node.arguments.length >= 1 &&
isStringLiteral(node.arguments[0])) {
const specifier = getStringValue(node.arguments[0]);
s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY);
return;
}
if (node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'MetaProperty' &&
!node.callee.computed &&
node.callee.property.name === 'resolve' &&
node.arguments.length >= 1 &&
isStringLiteral(node.arguments[0])) {
const specifier = getStringValue(node.arguments[0]);
s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY);
return;
}
if (s.hasNodeModuleImport &&
((node.callee.type === 'MemberExpression' &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'module' &&
!node.callee.computed &&
node.callee.property.name === 'register') ||
(node.callee.type === 'Identifier' && node.callee.name === 'register')) &&
node.arguments.length >= 1 &&
isStringLiteral(node.arguments[0])) {
const specifier = getStringValue(node.arguments[0]);
const arg1 = node.arguments[1];
if (specifier &&
(!specifier.startsWith('.') ||
(arg1?.type === 'MemberExpression' &&
!arg1.computed &&
arg1.object.type === 'MetaProperty' &&
arg1.property.name === 'url'))) {
s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY);
return;
}
}
if (node.callee.type === 'MemberExpression' &&
!node.callee.computed &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'Object' &&
node.callee.property.type === 'Identifier' &&
(node.callee.property.name === 'keys' ||
node.callee.property.name === 'values' ||
node.callee.property.name === 'entries' ||
node.callee.property.name === 'getOwnPropertyNames')) {
for (const arg of node.arguments) {
if (arg.type === 'Identifier') {
const _import = s.localImportMap.get(arg.name);
if (_import) {
const internalImport = s.internal.get(_import.filePath);
if (internalImport) {
if (_import.isNamespace)
addValue(internalImport.import, OPAQUE, s.filePath);
else
internalImport.refs.add(arg.name);
}
}
}
}
}
const markRefIfNs = (name) => {
const _import = s.localImportMap.get(name);
if (_import?.isNamespace) {
const internalImport = s.internal.get(_import.filePath);
if (internalImport)
internalImport.refs.add(name);
}
};
for (const arg of node.arguments) {
if (arg.type === 'Identifier')
markRefIfNs(arg.name);
else if (arg.type === 'ArrayExpression') {
for (const el of arg.elements ?? []) {
if (el?.type === 'Identifier')
markRefIfNs(el.name);
}
}
else if (arg.type === 'ObjectExpression') {
for (const prop of arg.properties ?? []) {
if (prop.type === 'Property' && !prop.computed && prop.value?.type === 'Identifier')
markRefIfNs(prop.value.name);
if (prop.type === 'SpreadElement' && prop.argument?.type === 'Identifier')
markRefIfNs(prop.argument.name);
}
}
}
}
export function handleNewExpression(node, s) {
if (node.callee.type === 'Identifier' &&
node.callee.name === 'URL' &&
node.arguments.length >= 2 &&
isStringLiteral(node.arguments[0]) &&
node.arguments[1].type === 'MemberExpression' &&
!node.arguments[1].computed &&
node.arguments[1].object.type === 'MetaProperty' &&
node.arguments[1].property.name === 'url') {
const specifier = getStringValue(node.arguments[0]);
if (specifier)
s.addImport(specifier, undefined, undefined, undefined, node.arguments[0].start, IMPORT_FLAGS.ENTRY | IMPORT_FLAGS.OPTIONAL);
}
}