Skip to content

Commit

Permalink
Add findUnusedMember and defer usage
Browse files Browse the repository at this point in the history
  • Loading branch information
webpro committed Jan 15, 2025
1 parent 50a777f commit 718bf1a
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 18 deletions.
13 changes: 12 additions & 1 deletion packages/knip/src/ProjectPrincipal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ts from 'typescript';
import { CacheConsultant } from './CacheConsultant.js';
import { getCompilerExtensions } from './compilers/index.js';
import type { AsyncCompilers, SyncCompilers } from './compilers/types.js';
import { ANONYMOUS, DEFAULT_EXTENSIONS, FOREIGN_FILE_EXTENSIONS, PUBLIC_TAG } from './constants.js';
import { ANONYMOUS, DEFAULT_EXTENSIONS, FOREIGN_FILE_EXTENSIONS } from './constants.js';
import type { GetImportsAndExportsOptions } from './types/config.js';
import type { DependencyGraph, Export, ExportMember, FileNode, UnresolvedImport } from './types/dependency-graph.js';
import type { PrincipalOptions } from './types/project.js';
Expand Down Expand Up @@ -357,6 +357,17 @@ export class ProjectPrincipal {
});
}

public findUnusedMember(filePath: string, member: ExportMember) {
if (!this.findReferences) {
const languageService = ts.createLanguageService(this.backend.languageServiceHost, ts.createDocumentRegistry());
this.findReferences = timerify(languageService.findReferences);
}

const referencedSymbols = this.findReferences?.(filePath, member.pos) ?? [];
const refs = referencedSymbols.flatMap(refs => refs.references).filter(ref => !ref.isDefinition);
return refs.length === 0;
}

public findUnusedMembers(filePath: string, members: ExportMember[]) {
if (!this.findReferences) {
const languageService = ts.createLanguageService(this.backend.languageServiceHost, ts.createDocumentRegistry());
Expand Down
39 changes: 22 additions & 17 deletions packages/knip/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,13 @@ export const main = async (unresolvedConfiguration: CommandLineOptions) => {

if (members.length === 0 || !principal.shouldAnalyzeTypeMembers(filePath, exportedItem)) continue;

const unused: string[] = [];
const isParentUnused = (id: string) => id.includes('.') && unused.some(p => id.startsWith(`${p}.`));
const unusedParents = new Set<string>();

for (const member of principal.findUnusedMembers(filePath, members)) {
if (isParentUnused(member.identifier)) continue;
for (const member of members) {
if (member.identifier.includes('.')) {
const parentId = member.identifier.split('.')[0];
if (unusedParents.has(parentId)) continue;
}

const id = `${identifier}.${member.identifier}`;
const { isReferenced: isMemberReferenced } = isIdentifierReferenced(filePath, id, true);
Expand All @@ -538,19 +540,22 @@ export const main = async (unresolvedConfiguration: CommandLineOptions) => {
if (!isMemberReferenced && !(!isReferenced && !isUnignoreMembers)) {
if (isIgnored) continue;

const isIssueAdded = collector.addIssue({
type: 'typeMembers',
filePath,
workspace: workspace.name,
symbol: member.identifier,
parentSymbol: exportedItem.identifier,
pos: member.pos,
line: member.line,
col: member.col,
});

unused.push(member.identifier);
if (isFix && isIssueAdded && member.fix) fixer.addUnusedTypeNode(filePath, [member.fix]);
if (principal.findUnusedMember(filePath, member)) {
const isIssueAdded = collector.addIssue({
type: 'typeMembers',
filePath,
workspace: workspace.name,
symbol: member.identifier,
parentSymbol: exportedItem.identifier,
pos: member.pos,
line: member.line,
col: member.col,
});

if (!member.identifier.includes('.')) unusedParents.add(member.identifier);

if (isFix && isIssueAdded && member.fix) fixer.addUnusedTypeNode(filePath, [member.fix]);
}
} else if (isIgnored) {
const identifier = `${exportedItem.identifier}.${member.identifier}`;
for (const tagName of exportedItem.jsDocTags) {
Expand Down

0 comments on commit 718bf1a

Please sign in to comment.