Socket
Book a DemoSign in
Socket

knip

Package Overview
Dependencies
Maintainers
1
Versions
569
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

knip - npm Package Compare versions

Comparing version
6.0.1
to
6.0.2
+2
-0
dist/graph/build.js

@@ -119,2 +119,4 @@ import { _getInputsFromScripts } from "../binaries/index.js";

principal.addPaths(config.paths, dir);
if (compilerOptions.rootDirs)
principal.addRootDirs(compilerOptions.rootDirs);
const inputsFromPlugins = await worker.runPlugins();

@@ -121,0 +123,0 @@ for (const id of inputsFromPlugins)

@@ -21,2 +21,3 @@ import type { ParseResult } from 'oxc-parser';

private paths;
private rootDirs;
private extensions;

@@ -32,2 +33,3 @@ cache: CacheConsultant<FileNode>;

addPaths(paths: Paths, basePath: string): void;
addRootDirs(rootDirs: string[]): void;
init(): void;

@@ -34,0 +36,0 @@ readFile(filePath: string): string;

@@ -30,2 +30,3 @@ import { extractSpecifiers } from "./typescript/follow-imports.js";

paths = {};
rootDirs = [];
extensions = new Set(DEFAULT_EXTENSIONS);

@@ -73,2 +74,8 @@ cache;

}
addRootDirs(rootDirs) {
for (const dir of rootDirs) {
if (!this.rootDirs.includes(dir))
this.rootDirs.push(dir);
}
}
init() {

@@ -81,3 +88,4 @@ this.extensions = new Set([

const pathsOrUndefined = Object.keys(this.paths).length > 0 ? this.paths : undefined;
this.resolveModule = createCustomModuleResolver({ paths: pathsOrUndefined }, customCompilerExtensions, this.toSourceFilePath);
const rootDirsOrUndefined = this.rootDirs.length > 1 ? this.rootDirs : undefined;
this.resolveModule = createCustomModuleResolver({ paths: pathsOrUndefined, rootDirs: rootDirsOrUndefined }, customCompilerExtensions, this.toSourceFilePath);
}

@@ -228,3 +236,3 @@ readFile(filePath) {

if (!this._visitor)
this._visitor = buildVisitor(this.pluginVisitorObjects);
this._visitor = buildVisitor(this.pluginVisitorObjects, !!ignoreExportsUsedInFile);
return _getImportsAndExports(filePath, sourceText, this.resolveModule, options, ignoreExportsUsedInFile, skipExports, this._visitor, this.pluginVisitorObjects.length > 0 ? this.pluginCtx : undefined, parseResult);

@@ -231,0 +239,0 @@ }

@@ -25,2 +25,3 @@ export type Paths = Record<string, string[]> | undefined;

rootDir?: string;
rootDirs?: string[];
skipDefaultLibCheck?: boolean;

@@ -27,0 +28,0 @@ skipLibCheck?: boolean;

+2
-3

@@ -10,3 +10,2 @@ import { isBuiltin } from 'node:module';

import { buildJSDocTagLookup } from "./visitors/jsdoc.js";
import { collectLocalRefs } from "./visitors/local-refs.js";
import { walkAST } from "./visitors/walk.js";

@@ -248,3 +247,3 @@ const jsDocImportRe = /import\(\s*['"]([^'"]+)['"]\s*\)(?:\.(\w+))?/g;

}
walkAST(result.program, sourceText, filePath, {
const localRefs = walkAST(result.program, sourceText, filePath, {
lineStarts,

@@ -266,2 +265,3 @@ skipExports,

skipBareExprRefs: !!ignoreExportsUsedInFile,
localRefs: ignoreExportsUsedInFile ? new Set() : undefined,
destructuredExports,

@@ -315,3 +315,2 @@ hasNodeModuleImport,

}
const localRefs = ignoreExportsUsedInFile ? collectLocalRefs(result.program, localImportMap, exports) : undefined;
for (const [id, item] of exports) {

@@ -318,0 +317,0 @@ item.referencedIn = referencedInExport.get(id);

@@ -5,2 +5,3 @@ import type { ToSourceFilePath } from '../util/to-source-path.ts';

paths?: Record<string, string[]>;
rootDirs?: string[];
}, customCompilerExtensions: string[], toSourceFilePath: ToSourceFilePath): ResolveModule;

@@ -15,2 +15,3 @@ import { existsSync } from 'node:fs';

const resolveWithAlias = alias ? _createSyncModuleResolver(extensions, alias) : undefined;
const rootDirs = compilerOptions.rootDirs;
function toSourcePath(resolvedFileName) {

@@ -47,4 +48,20 @@ if (!hasCustomExts || !customCompilerExtensionsSet.has(extname(resolvedFileName))) {

}
if (rootDirs && !isAbsolute(sanitizedSpecifier)) {
const containingDir = dirname(containingFile);
for (const srcRoot of rootDirs) {
if (!containingDir.startsWith(srcRoot))
continue;
const relPath = containingDir.slice(srcRoot.length);
for (const targetRoot of rootDirs) {
if (targetRoot === srcRoot)
continue;
const mapped = join(targetRoot, relPath, sanitizedSpecifier);
const resolved = resolveSync(mapped, containingFile);
if (resolved)
return toResult(resolved);
}
}
}
}
return timerify(resolveModuleName);
}

@@ -136,3 +136,2 @@ import { ALIAS_TAG, FIX_FLAGS, IMPORT_FLAGS, IMPORT_STAR, SYMBOL_TYPE } from "../../constants.js";

s.addExport(decl.id.name, SYMBOL_TYPE.FUNCTION, decl.id.start, [], fix, false, s.getJSDocTags(exportStart));
s.collectRefsInType(decl, decl.id.name, true);
}

@@ -152,2 +151,6 @@ else if (decl.type === 'ClassDeclaration' && decl.id) {

s.collectRefsInType(decl.body, decl.id.name, false);
for (const ext of decl.extends ?? []) {
if (ext.expression?.type === 'Identifier')
s.addRefInExport(ext.expression.name, decl.id.name);
}
}

@@ -212,3 +215,2 @@ else if (decl.type === 'TSEnumDeclaration') {

pos = decl.id?.start ?? decl.start;
s.collectRefsInType(decl, 'default', false);
}

@@ -215,0 +217,0 @@ else if (decl.type === 'ClassDeclaration') {

import type { MemberExpression, JSXMemberExpression } from 'oxc-parser';
import type { WalkState } from './walk.ts';
import { type WalkState } from './walk.ts';
export declare function handleMemberExpression(node: MemberExpression, s: WalkState): void;
export declare function handleJSXMemberExpression(node: JSXMemberExpression, s: WalkState): void;
import { OPAQUE } from "../../constants.js";
import { addValue } from "../../util/module-graph.js";
import { getStringValue, isStringLiteral } from "./helpers.js";
import { isShadowed } from "./walk.js";
export function handleMemberExpression(node, s) {

@@ -10,3 +11,4 @@ if (node.object.type === 'MemberExpression' && node.object.object.type === 'MemberExpression') {

const localName = node.object.name;
const _import = s.localImportMap.get(localName);
const shadowed = isShadowed(localName, node.object.start);
const _import = !shadowed ? s.localImportMap.get(localName) : undefined;
if (_import) {

@@ -36,3 +38,3 @@ const internalImport = s.internal.get(_import.filePath);

}
else {
else if (!shadowed) {
const memberName = node.computed === false && node.property.type === 'Identifier' ? node.property.name : undefined;

@@ -76,30 +78,32 @@ if (memberName) {

const rootName = node.object.object.name;
const _import = s.localImportMap.get(rootName);
if (_import) {
const internalImport = s.internal.get(_import.filePath);
if (internalImport) {
const mid = node.object.property.name;
s.addNsMemberRefs(internalImport, rootName, mid);
if (!s.chainedMemberExprs.has(node)) {
s.addNsMemberRefs(internalImport, rootName, `${mid}.${node.property.name}`);
if (!isShadowed(rootName, node.object.object.start)) {
const _import = s.localImportMap.get(rootName);
if (_import) {
const internalImport = s.internal.get(_import.filePath);
if (internalImport) {
const mid = node.object.property.name;
s.addNsMemberRefs(internalImport, rootName, mid);
if (!s.chainedMemberExprs.has(node)) {
s.addNsMemberRefs(internalImport, rootName, `${mid}.${node.property.name}`);
}
}
}
if (!_import.isNamespace) {
const mid = node.object.property.name;
const _import = s.localImportMap.get(mid);
if (_import) {
const midImport = s.internal.get(_import.filePath);
if (midImport)
s.addNsMemberRefs(midImport, mid, node.property.name);
if (!_import.isNamespace) {
const mid = node.object.property.name;
const _import = s.localImportMap.get(mid);
if (_import) {
const midImport = s.internal.get(_import.filePath);
if (midImport)
s.addNsMemberRefs(midImport, mid, node.property.name);
}
}
}
}
else {
const exp = s.exports.get(rootName);
if (exp && exp.members.length > 0) {
const mid = node.object.property.name;
const dottedName = `${mid}.${node.property.name}`;
for (const member of exp.members) {
if (member.identifier === mid || member.identifier === dottedName)
member.hasRefsInFile = true;
else {
const exp = s.exports.get(rootName);
if (exp && exp.members.length > 0) {
const mid = node.object.property.name;
const dottedName = `${mid}.${node.property.name}`;
for (const member of exp.members) {
if (member.identifier === mid || member.identifier === dottedName)
member.hasRefsInFile = true;
}
}

@@ -119,24 +123,26 @@ }

const rootName = node.object.object.object.name;
const _import = s.localImportMap.get(rootName);
if (_import) {
const internalImport = s.internal.get(_import.filePath);
if (internalImport) {
const a = node.object.object.property.name;
const b = node.object.property.name;
const c = node.property.name;
s.addNsMemberRefs(internalImport, rootName, a);
s.addNsMemberRefs(internalImport, rootName, `${a}.${b}`);
s.addNsMemberRefs(internalImport, rootName, `${a}.${b}.${c}`);
if (!isShadowed(rootName, node.object.object.object.start)) {
const _import = s.localImportMap.get(rootName);
if (_import) {
const internalImport = s.internal.get(_import.filePath);
if (internalImport) {
const a = node.object.object.property.name;
const b = node.object.property.name;
const c = node.property.name;
s.addNsMemberRefs(internalImport, rootName, a);
s.addNsMemberRefs(internalImport, rootName, `${a}.${b}`);
s.addNsMemberRefs(internalImport, rootName, `${a}.${b}.${c}`);
}
}
}
else {
const exp = s.exports.get(rootName);
if (exp && exp.members.length > 0) {
const a = node.object.object.property.name;
const b = node.object.property.name;
const c = node.property.name;
const dottedName = `${a}.${b}.${c}`;
for (const member of exp.members) {
if (member.identifier === a || member.identifier === `${a}.${b}` || member.identifier === dottedName)
member.hasRefsInFile = true;
else {
const exp = s.exports.get(rootName);
if (exp && exp.members.length > 0) {
const a = node.object.object.property.name;
const b = node.object.property.name;
const c = node.property.name;
const dottedName = `${a}.${b}.${c}`;
for (const member of exp.members) {
if (member.identifier === a || member.identifier === `${a}.${b}` || member.identifier === dottedName)
member.hasRefsInFile = true;
}
}

@@ -143,0 +149,0 @@ }

@@ -33,2 +33,3 @@ import { Visitor, type Program, type Span } from 'oxc-parser';

skipBareExprRefs: boolean;
localRefs: Set<string> | undefined;
destructuredExports: Set<string>;

@@ -54,2 +55,6 @@ hasNodeModuleImport: boolean;

nsRanges: [number, number][];
scopeDepth: number;
scopeStarts: number[];
scopeEnds: number[];
shadowScopes: Map<string, [number, number][]>;
addExport: (identifier: string, type: SymbolType, pos: number, members: ExportMember[], fix: Fix, isReExport: boolean, jsDocTags: Set<string>) => void;

@@ -59,6 +64,8 @@ getFix: (start: number, end: number, flags?: number) => Fix;

collectRefsInType: (node: any, exportName: string, signatureOnly: boolean) => void;
addRefInExport: (name: string, exportName: string) => void;
isInNamespace: (node: Span) => boolean;
}
export declare function buildVisitor(pluginVisitorObjects: PluginVisitorObject[]): Visitor;
export declare function walkAST(program: Program, sourceText: string, filePath: string, ctx: WalkContext): void;
export declare const isShadowed: (name: string, pos: number) => boolean;
export declare function buildVisitor(pluginVisitorObjects: PluginVisitorObject[], includeLocalRefs?: boolean): Visitor;
export declare function walkAST(program: Program, sourceText: string, filePath: string, ctx: WalkContext): Set<string> | undefined;
export {};

@@ -89,4 +89,46 @@ import { Visitor } from 'oxc-parser';

};
const _addRefInExport = (name, exportName) => {
const refs = state.referencedInExport.get(name);
if (refs)
refs.add(exportName);
else
state.referencedInExport.set(name, new Set([exportName]));
};
const _isInNamespace = (node) => state.nsRanges.length > 0 && state.nsRanges.some(([start, end]) => node.start >= start && node.end <= end);
export const isShadowed = (name, pos) => {
if (state.shadowScopes.size === 0)
return false;
const ranges = state.shadowScopes.get(name);
if (!ranges)
return false;
if (state.localImportMap.get(name)?.isDynamicImport)
return false;
for (const range of ranges) {
if (pos >= range[0] && pos <= range[1])
return true;
}
return false;
};
const _addLocalRef = (name, pos) => {
if (!state.localImportMap.has(name) && !isShadowed(name, pos))
state.localRefs.add(name);
};
const _addShadow = (name) => {
const i = state.scopeDepth - 1;
const range = [state.scopeStarts[i], state.scopeEnds[i]];
const ranges = state.shadowScopes.get(name);
if (ranges)
ranges.push(range);
else
state.shadowScopes.set(name, [range]);
};
const coreVisitorObject = {
BlockStatement(node) {
state.scopeStarts[state.scopeDepth] = node.start;
state.scopeEnds[state.scopeDepth] = node.end;
state.scopeDepth++;
},
'BlockStatement:exit'() {
state.scopeDepth--;
},
TSModuleDeclaration(node) {

@@ -100,11 +142,24 @@ state.nsRanges.push([node.start, node.end]);

FunctionDeclaration(node) {
if (node.id?.name)
if (node.id?.name) {
state.localDeclarationTypes.set(node.id.name, SYMBOL_TYPE.FUNCTION);
if (state.scopeDepth > 0)
_addShadow(node.id.name);
}
},
VariableDeclaration(node) {
state.currentVarDeclStart = node.start;
for (const decl of node.declarations) {
if (decl.id.type === 'Identifier')
state.localDeclarationTypes.set(decl.id.name, SYMBOL_TYPE.VARIABLE);
if (state.scopeDepth > 0) {
for (const decl of node.declarations) {
if (decl.id.type === 'Identifier') {
state.localDeclarationTypes.set(decl.id.name, SYMBOL_TYPE.VARIABLE);
_addShadow(decl.id.name);
}
}
}
else {
for (const decl of node.declarations) {
if (decl.id.type === 'Identifier')
state.localDeclarationTypes.set(decl.id.name, SYMBOL_TYPE.VARIABLE);
}
}
},

@@ -146,3 +201,3 @@ TSEnumDeclaration(node) {

ForInStatement(node) {
if (node.right.type === 'Identifier') {
if (node.right.type === 'Identifier' && !isShadowed(node.right.name, node.right.start)) {
const _import = state.localImportMap.get(node.right.name);

@@ -157,3 +212,3 @@ if (_import?.isNamespace) {

ForOfStatement(node) {
if (node.right.type === 'Identifier') {
if (node.right.type === 'Identifier' && !isShadowed(node.right.name, node.right.start)) {
const _import = state.localImportMap.get(node.right.name);

@@ -175,3 +230,3 @@ if (_import?.isNamespace) {

}
if (left.type === 'Identifier') {
if (left.type === 'Identifier' && !isShadowed(left.name, left.start)) {
const rootName = left.name;

@@ -212,7 +267,9 @@ const _import = state.localImportMap.get(rootName);

const name = node.typeName.name;
const _import = state.localImportMap.get(name);
if (_import) {
const internalImport = state.internal.get(_import.filePath);
if (internalImport)
internalImport.refs.add(name);
if (!isShadowed(name, node.typeName.start)) {
const _import = state.localImportMap.get(name);
if (_import) {
const internalImport = state.internal.get(_import.filePath);
if (internalImport)
internalImport.refs.add(name);
}
}

@@ -224,7 +281,9 @@ }

const name = node.exprName.name;
const _import = state.localImportMap.get(name);
if (_import) {
const internalImport = state.internal.get(_import.filePath);
if (internalImport)
internalImport.refs.add(name);
if (!isShadowed(name, node.exprName.start)) {
const _import = state.localImportMap.get(name);
if (_import) {
const internalImport = state.internal.get(_import.filePath);
if (internalImport)
internalImport.refs.add(name);
}
}

@@ -274,5 +333,231 @@ }

};
export function buildVisitor(pluginVisitorObjects) {
if (pluginVisitorObjects.length === 0)
return new Visitor(coreVisitorObject);
const localRefsVisitorObject = {
ClassDeclaration(node) {
if (node.superClass?.type === 'Identifier')
_addLocalRef(node.superClass.name, node.superClass.start);
for (const impl of node.implements ?? []) {
if (impl.expression?.type === 'Identifier')
_addLocalRef(impl.expression.name, impl.expression.start);
}
},
TSInterfaceDeclaration(node) {
for (const ext of node.extends ?? []) {
if (ext.expression?.type === 'Identifier')
_addLocalRef(ext.expression.name, ext.expression.start);
}
},
Property(node) {
if (node.value?.type === 'Identifier')
_addLocalRef(node.value.name, node.value.start);
},
ReturnStatement(node) {
if (node.argument?.type === 'Identifier')
_addLocalRef(node.argument.name, node.argument.start);
},
AssignmentExpression(node) {
if (node.right?.type === 'Identifier')
_addLocalRef(node.right.name, node.right.start);
},
SpreadElement(node) {
if (node.argument?.type === 'Identifier')
_addLocalRef(node.argument.name, node.argument.start);
},
ConditionalExpression(node) {
if (node.test?.type === 'Identifier')
_addLocalRef(node.test.name, node.test.start);
if (node.consequent?.type === 'Identifier')
_addLocalRef(node.consequent.name, node.consequent.start);
if (node.alternate?.type === 'Identifier')
_addLocalRef(node.alternate.name, node.alternate.start);
},
ArrayExpression(node) {
for (const el of node.elements ?? []) {
if (el?.type === 'Identifier')
_addLocalRef(el.name, el.start);
}
},
TemplateLiteral(node) {
for (const expr of node.expressions ?? []) {
if (expr.type === 'Identifier')
_addLocalRef(expr.name, expr.start);
}
},
BinaryExpression(node) {
if (node.left?.type === 'Identifier')
_addLocalRef(node.left.name, node.left.start);
if (node.right?.type === 'Identifier')
_addLocalRef(node.right.name, node.right.start);
},
LogicalExpression(node) {
if (node.left?.type === 'Identifier')
_addLocalRef(node.left.name, node.left.start);
if (node.right?.type === 'Identifier')
_addLocalRef(node.right.name, node.right.start);
},
UnaryExpression(node) {
if (node.argument?.type === 'Identifier')
_addLocalRef(node.argument.name, node.argument.start);
},
SwitchStatement(node) {
if (node.discriminant?.type === 'Identifier')
_addLocalRef(node.discriminant.name, node.discriminant.start);
for (const c of node.cases ?? []) {
if (c.test?.type === 'Identifier')
_addLocalRef(c.test.name, c.test.start);
}
},
IfStatement(node) {
if (node.test?.type === 'Identifier')
_addLocalRef(node.test.name, node.test.start);
},
ThrowStatement(node) {
if (node.argument?.type === 'Identifier')
_addLocalRef(node.argument.name, node.argument.start);
},
WhileStatement(node) {
if (node.test?.type === 'Identifier')
_addLocalRef(node.test.name, node.test.start);
},
DoWhileStatement(node) {
if (node.test?.type === 'Identifier')
_addLocalRef(node.test.name, node.test.start);
},
YieldExpression(node) {
if (node.argument?.type === 'Identifier')
_addLocalRef(node.argument.name, node.argument.start);
},
AwaitExpression(node) {
if (node.argument?.type === 'Identifier')
_addLocalRef(node.argument.name, node.argument.start);
},
ArrowFunctionExpression(node) {
if (node.body?.type === 'Identifier')
_addLocalRef(node.body.name, node.body.start);
},
AssignmentPattern(node) {
if (node.right?.type === 'Identifier')
_addLocalRef(node.right.name, node.right.start);
},
SequenceExpression(node) {
for (const expr of node.expressions ?? []) {
if (expr.type === 'Identifier')
_addLocalRef(expr.name, expr.start);
}
},
TSAsExpression(node) {
if (node.expression?.type === 'Identifier')
_addLocalRef(node.expression.name, node.expression.start);
},
TSSatisfiesExpression(node) {
if (node.expression?.type === 'Identifier')
_addLocalRef(node.expression.name, node.expression.start);
},
TSNonNullExpression(node) {
if (node.expression?.type === 'Identifier')
_addLocalRef(node.expression.name, node.expression.start);
},
TSTypeAssertion(node) {
if (node.expression?.type === 'Identifier')
_addLocalRef(node.expression.name, node.expression.start);
},
ParenthesizedExpression(node) {
if (node.expression?.type === 'Identifier')
_addLocalRef(node.expression.name, node.expression.start);
},
PropertyDefinition(node) {
if (node.value?.type === 'Identifier')
_addLocalRef(node.value.name, node.value.start);
},
ForInStatement(node) {
if (node.right?.type === 'Identifier')
_addLocalRef(node.right.name, node.right.start);
},
ForOfStatement(node) {
if (node.right?.type === 'Identifier')
_addLocalRef(node.right.name, node.right.start);
},
JSXOpeningElement(node) {
if (node.name?.type === 'JSXIdentifier')
_addLocalRef(node.name.name, node.name.start);
for (const attr of node.attributes ?? []) {
if (attr.type === 'JSXSpreadAttribute' && attr.argument?.type === 'Identifier')
_addLocalRef(attr.argument.name, attr.argument.start);
}
},
JSXExpressionContainer(node) {
if (node.expression?.type === 'Identifier')
_addLocalRef(node.expression.name, node.expression.start);
},
VariableDeclarator(node) {
if (node.init?.type === 'Identifier')
_addLocalRef(node.init.name, node.init.start);
},
ExpressionStatement(node) {
if (node.expression?.type === 'Identifier')
_addLocalRef(node.expression.name, node.expression.start);
},
CallExpression(node) {
if (node.callee?.type === 'Identifier')
_addLocalRef(node.callee.name, node.callee.start);
for (const arg of node.arguments ?? []) {
if (arg.type === 'Identifier')
_addLocalRef(arg.name, arg.start);
}
},
NewExpression(node) {
if (node.callee?.type === 'Identifier')
_addLocalRef(node.callee.name, node.callee.start);
for (const arg of node.arguments ?? []) {
if (arg.type === 'Identifier')
_addLocalRef(arg.name, arg.start);
}
},
MemberExpression(node) {
if (node.object?.type === 'Identifier')
_addLocalRef(node.object.name, node.object.start);
if (node.computed && node.property?.type === 'Identifier')
_addLocalRef(node.property.name, node.property.start);
},
TaggedTemplateExpression(node) {
if (node.tag?.type === 'Identifier')
_addLocalRef(node.tag.name, node.tag.start);
},
TSQualifiedName(node) {
let left = node;
const parts = [];
while (left.type === 'TSQualifiedName') {
if (left.right.type === 'Identifier')
parts.unshift(left.right.name);
left = left.left;
}
if (left.type === 'Identifier') {
const rootName = left.name;
if (!state.localImportMap.has(rootName) && !isShadowed(rootName, left.start) && parts.length > 0) {
const exp = state.exports.get(rootName);
if (exp) {
state.localRefs.add(rootName);
for (const member of exp.members) {
if (member.identifier === parts[0])
member.hasRefsInFile = true;
}
}
}
}
},
TSTypeReference(node) {
if (node.typeName?.type === 'Identifier') {
const name = node.typeName.name;
if (!state.localImportMap.has(name))
_addLocalRef(name, node.typeName.start);
}
},
TSTypeQuery(node) {
if (node.exprName?.type === 'Identifier') {
const name = node.exprName.name;
if (!state.localImportMap.has(name))
_addLocalRef(name, node.exprName.start);
}
},
};
export function buildVisitor(pluginVisitorObjects, includeLocalRefs) {
const handlerLists = new Map();

@@ -285,6 +570,8 @@ const coreHandlers = coreVisitorObject;

}
for (const obj of pluginVisitorObjects) {
const handlers = obj;
for (const key in handlers) {
const fn = handlers[key];
const extras = includeLocalRefs
? [localRefsVisitorObject, ...pluginVisitorObjects]
: pluginVisitorObjects;
for (const obj of extras) {
for (const key in obj) {
const fn = obj[key];
if (!fn)

@@ -299,2 +586,4 @@ continue;

}
if (extras.length === 0)
return new Visitor(coreVisitorObject);
const merged = {};

@@ -330,2 +619,6 @@ for (const [key, list] of handlerLists) {

nsRanges: [],
scopeDepth: 0,
scopeStarts: [],
scopeEnds: [],
shadowScopes: new Map(),
addExport: _addExport,

@@ -335,2 +628,3 @@ getFix: _getFix,

collectRefsInType: _collectRefsInType,
addRefInExport: _addRefInExport,
isInNamespace: _isInNamespace,

@@ -372,3 +666,5 @@ };

}
const localRefs = state.localRefs;
state = undefined;
return localRefs;
}

@@ -50,2 +50,15 @@ import { readFileSync } from 'node:fs';

};
const findRootDirsBase = (tsConfigFilePath) => {
try {
const raw = JSON.parse(stripJsonComments(readFileSync(tsConfigFilePath, 'utf8')));
if (raw.compilerOptions?.rootDirs)
return dirname(tsConfigFilePath);
if (raw.extends) {
const extPath = join(dirname(tsConfigFilePath), raw.extends);
return findRootDirsBase(extPath);
}
}
catch { }
return undefined;
};
const resolveConfig = (tsConfigFilePath) => {

@@ -81,2 +94,6 @@ try {

}
if (compilerOptions.rootDirs) {
const rootDirsBase = findRootDirsBase(tsConfigFilePath) ?? dir;
compilerOptions.rootDirs = compilerOptions.rootDirs.map((d) => isAbsolute(d) ? d : join(rootDirsBase, d));
}
const include = resolvePatterns(config.include, dir, true);

@@ -83,0 +100,0 @@ const exclude = resolvePatterns(config.exclude, dir, true);

@@ -1,1 +0,1 @@

export declare const version = "6.0.1";
export declare const version = "6.0.2";

@@ -1,1 +0,1 @@

export const version = '6.0.1';
export const version = '6.0.2';
{
"name": "knip",
"version": "6.0.1",
"version": "6.0.2",
"description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",

@@ -83,3 +83,3 @@ "keywords": [

"formatly": "^0.3.0",
"get-tsconfig": "4.13.6",
"get-tsconfig": "4.13.7",
"jiti": "^2.6.0",

@@ -86,0 +86,0 @@ "minimist": "^1.2.8",

import { type Program } from 'oxc-parser';
import type { Export } from '../../types/module-graph.ts';
export declare function collectLocalRefs(program: Program, localImportMap: Map<string, {
importedName: string;
filePath: string;
isNamespace: boolean;
}>, fileExports: Map<string, Export>): Set<string>;
import { Visitor } from 'oxc-parser';
let refs;
let importNames;
let exportsMap;
const add = (name) => {
if (!importNames.has(name))
refs.add(name);
};
const visitor = new Visitor({
ClassDeclaration(node) {
if (node.superClass?.type === 'Identifier')
add(node.superClass.name);
for (const impl of node.implements ?? []) {
if (impl.expression?.type === 'Identifier')
add(impl.expression.name);
}
},
TSInterfaceDeclaration(node) {
for (const ext of node.extends ?? []) {
if (ext.expression?.type === 'Identifier')
add(ext.expression.name);
}
},
Property(node) {
if (node.value?.type === 'Identifier')
add(node.value.name);
},
ReturnStatement(node) {
if (node.argument?.type === 'Identifier')
add(node.argument.name);
},
AssignmentExpression(node) {
if (node.right?.type === 'Identifier')
add(node.right.name);
},
SpreadElement(node) {
if (node.argument?.type === 'Identifier')
add(node.argument.name);
},
ConditionalExpression(node) {
if (node.test?.type === 'Identifier')
add(node.test.name);
if (node.consequent?.type === 'Identifier')
add(node.consequent.name);
if (node.alternate?.type === 'Identifier')
add(node.alternate.name);
},
ArrayExpression(node) {
for (const el of node.elements ?? []) {
if (el?.type === 'Identifier')
add(el.name);
}
},
TemplateLiteral(node) {
for (const expr of node.expressions ?? []) {
if (expr.type === 'Identifier')
add(expr.name);
}
},
BinaryExpression(node) {
if (node.left?.type === 'Identifier')
add(node.left.name);
if (node.right?.type === 'Identifier')
add(node.right.name);
},
LogicalExpression(node) {
if (node.left?.type === 'Identifier')
add(node.left.name);
if (node.right?.type === 'Identifier')
add(node.right.name);
},
UnaryExpression(node) {
if (node.argument?.type === 'Identifier')
add(node.argument.name);
},
SwitchStatement(node) {
if (node.discriminant?.type === 'Identifier')
add(node.discriminant.name);
for (const c of node.cases ?? []) {
if (c.test?.type === 'Identifier')
add(c.test.name);
}
},
IfStatement(node) {
if (node.test?.type === 'Identifier')
add(node.test.name);
},
ThrowStatement(node) {
if (node.argument?.type === 'Identifier')
add(node.argument.name);
},
WhileStatement(node) {
if (node.test?.type === 'Identifier')
add(node.test.name);
},
DoWhileStatement(node) {
if (node.test?.type === 'Identifier')
add(node.test.name);
},
YieldExpression(node) {
if (node.argument?.type === 'Identifier')
add(node.argument.name);
},
AwaitExpression(node) {
if (node.argument?.type === 'Identifier')
add(node.argument.name);
},
ArrowFunctionExpression(node) {
if (node.body?.type === 'Identifier')
add(node.body.name);
},
AssignmentPattern(node) {
if (node.right?.type === 'Identifier')
add(node.right.name);
},
SequenceExpression(node) {
for (const expr of node.expressions ?? []) {
if (expr.type === 'Identifier')
add(expr.name);
}
},
TSAsExpression(node) {
if (node.expression?.type === 'Identifier')
add(node.expression.name);
},
TSSatisfiesExpression(node) {
if (node.expression?.type === 'Identifier')
add(node.expression.name);
},
TSNonNullExpression(node) {
if (node.expression?.type === 'Identifier')
add(node.expression.name);
},
TSTypeAssertion(node) {
if (node.expression?.type === 'Identifier')
add(node.expression.name);
},
ParenthesizedExpression(node) {
if (node.expression?.type === 'Identifier')
add(node.expression.name);
},
PropertyDefinition(node) {
if (node.value?.type === 'Identifier')
add(node.value.name);
},
ForInStatement(node) {
if (node.right?.type === 'Identifier')
add(node.right.name);
},
ForOfStatement(node) {
if (node.right?.type === 'Identifier')
add(node.right.name);
},
JSXOpeningElement(node) {
if (node.name?.type === 'JSXIdentifier')
add(node.name.name);
for (const attr of node.attributes ?? []) {
if (attr.type === 'JSXSpreadAttribute' && attr.argument?.type === 'Identifier')
add(attr.argument.name);
}
},
JSXExpressionContainer(node) {
if (node.expression?.type === 'Identifier')
add(node.expression.name);
},
VariableDeclarator(node) {
if (node.init?.type === 'Identifier')
add(node.init.name);
},
ExpressionStatement(node) {
if (node.expression?.type === 'Identifier')
add(node.expression.name);
},
CallExpression(node) {
if (node.callee?.type === 'Identifier')
add(node.callee.name);
for (const arg of node.arguments ?? []) {
if (arg.type === 'Identifier')
add(arg.name);
}
},
NewExpression(node) {
if (node.callee?.type === 'Identifier')
add(node.callee.name);
for (const arg of node.arguments ?? []) {
if (arg.type === 'Identifier')
add(arg.name);
}
},
MemberExpression(node) {
if (node.object?.type === 'Identifier')
add(node.object.name);
if (node.computed && node.property?.type === 'Identifier')
add(node.property.name);
},
TaggedTemplateExpression(node) {
if (node.tag?.type === 'Identifier')
add(node.tag.name);
},
TSQualifiedName(node) {
let left = node;
const parts = [];
while (left.type === 'TSQualifiedName') {
if (left.right.type === 'Identifier')
parts.unshift(left.right.name);
left = left.left;
}
if (left.type === 'Identifier') {
const rootName = left.name;
if (!importNames.has(rootName) && parts.length > 0) {
const exp = exportsMap.get(rootName);
if (exp) {
refs.add(rootName);
for (const member of exp.members) {
if (member.identifier === parts[0])
member.hasRefsInFile = true;
}
}
}
}
},
TSTypeReference(node) {
if (node.typeName?.type === 'Identifier') {
const name = node.typeName.name;
if (!importNames.has(name))
refs.add(name);
}
},
TSTypeQuery(node) {
if (node.exprName?.type === 'Identifier') {
const name = node.exprName.name;
if (!importNames.has(name))
refs.add(name);
}
},
});
export function collectLocalRefs(program, localImportMap, fileExports) {
refs = new Set();
importNames = localImportMap;
exportsMap = fileExports;
visitor.visit(program);
return refs;
}