Skip to content

Commit

Permalink
Improve enum/member handling
Browse files Browse the repository at this point in the history
  • Loading branch information
webpro committed Jan 24, 2025
1 parent e5e57c8 commit fc5982e
Show file tree
Hide file tree
Showing 11 changed files with 41 additions and 15 deletions.
5 changes: 4 additions & 1 deletion packages/knip/fixtures/enum-members/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { MyEnum, TestEnum } from './members';
import { MyEnum, TestEnum, Category } from './members';

const a: MyEnum.A_UsedExternal = 1;

const b: TestEnum = { ['']: 'test' };

export enum EntryEnum {
UsedMemberInEntryEnum = 1,
UnusedMemberInEntryEnum = 1,
}

function setCategory(cat: Category) {}
7 changes: 7 additions & 0 deletions packages/knip/fixtures/enum-members/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ const myNumber: MyEnum.C_UsedInternal = 1;

type Used = EntryEnum;

const U: EntryEnum.UsedMemberInEntryEnum = 1;

export enum TestEnum {
'' = 'test',
}

export enum Category {
Ambient = 'Ambient',
Playback = 'Playback',
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class $Dollar {}
export type $DollarType = string;

export enum Characters {
Used = 1,
' ' = ' ',
'-' = '-',
',' = ',',
Expand Down
2 changes: 2 additions & 0 deletions packages/knip/fixtures/exports-special-characters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ import { type Characters, DollarMembers } from './exports';

type Ref = Characters;

const u: Characters.Used = 1;

const instance = new DollarMembers();
1 change: 0 additions & 1 deletion packages/knip/fixtures/re-exports-enum-unused/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
// biome-ignore lint/correctness/noUnusedImports: <explanation>
import MyEnum from './mid';
2 changes: 2 additions & 0 deletions packages/knip/fixtures/tags/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ import { ignored, notIgnored } from './unimported.js';

const x: MyEnum = {};

const xm = MyEnum.UsedUntagged;

const y = new MyClass();
2 changes: 2 additions & 0 deletions packages/knip/fixtures/tags/tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export const UnusedCustomAndInternal = 1;
* @internal
*/
export enum MyEnum {
UsedUntagged = 1,

UnusedUntagged = 1,

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/knip/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { getOrCreateFileNode, updateImportMap } from './util/dependency-graph.js
import { getReferencedInputsHandler } from './util/get-referenced-inputs.js';
import { getGitIgnoredHandler } from './util/glob-core.js';
import { _glob, negate } from './util/glob.js';
import { getHasStrictlyNsReferences, getType } from './util/has-strictly-ns-references.js';
import { getHasStrictlyNsReferences, getType, hasStrictlyEnumReferences } from './util/has-strictly-ns-references.js';
import { type Input, isConfigPattern, isEntry, isProductionEntry, toProductionEntry } from './util/input.js';
import { getIsIdentifierReferencedHandler } from './util/is-identifier-referenced.js';
import { getPackageNameFromModuleSpecifier } from './util/modules.js';
Expand Down Expand Up @@ -473,7 +473,7 @@ export const main = async (unresolvedConfiguration: CommandLineOptions) => {

if (isReferenced) {
if (report.enumMembers && exportedItem.type === 'enum') {
if (importsForExport.refs.has(identifier)) continue; // consider members referenced (isObjectEnumerationCallExpressionArgument)
if (hasStrictlyEnumReferences(importsForExport, identifier)) continue;

for (const member of exportedItem.members) {
if (findMatch(workspace.ignoreMembers, member.identifier)) continue;
Expand Down
5 changes: 2 additions & 3 deletions packages/knip/src/typescript/ast-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,9 @@ export const isInForIteration = (node: ts.Node) =>
export const isTopLevel = (node: ts.Node) =>
ts.isSourceFile(node.parent) || (node.parent && ts.isSourceFile(node.parent.parent));

export const getTypeName = (node: ts.Identifier) => {
export const getTypeRef = (node: ts.Identifier) => {
if (!node.parent?.parent) return;
const typeRef = findAncestor<ts.TypeReferenceNode>(node, _node => ts.isTypeReferenceNode(_node));
if (typeRef && ts.isQualifiedName(typeRef.typeName)) return typeRef.typeName;
return findAncestor<ts.TypeReferenceNode>(node, _node => ts.isTypeReferenceNode(_node));
};

export const isImportSpecifier = (node: ts.Node) =>
Expand Down
21 changes: 13 additions & 8 deletions packages/knip/src/typescript/get-imports-and-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
getDestructuredIds,
getJSDocTags,
getLineAndCharacterOfPosition,
getTypeName,
getTypeRef,
isAccessExpression,
isConsiderReferencedNS,
isDestructuring,
Expand Down Expand Up @@ -342,12 +342,17 @@ const getImportsAndExports = (
const members = getDestructuredIds(node.parent.name);
addNsMemberRefs(imports, id, members);
} else {
const typeName = getTypeName(node);
if (typeName) {
// Pattern: NS.TypeId
const [ns, ...right] = [typeName.left.getText(), typeName.right.getText()].join('.').split('.');
const members = right.map((_r, index) => right.slice(0, index + 1).join('.'));
addNsMemberRefs(imports, ns, members);
const typeRef = getTypeRef(node);
if (typeRef) {
if (ts.isQualifiedName(typeRef.typeName)) {
const typeName = typeRef.typeName;
// Pattern: NS.TypeId
const [ns, ...right] = [typeName.left.getText(), typeName.right.getText()].join('.').split('.');
const members = right.map((_r, index) => right.slice(0, index + 1).join('.'));
addNsMemberRefs(imports, ns, members);
} else {
imports.refs.add(id);
}
} else if (imports.importedNs.has(id)) {
if (isConsiderReferencedNS(node)) {
// Pattern: fn(NS), { ...NS } etc. (https://knip.dev/guides/namespace-imports)
Expand All @@ -367,7 +372,7 @@ const getImportsAndExports = (
}

// Store exports referenced in exported types, including `typeof` values
// Simplifies and speeds up (*) below while we're still in the realm of bound AST
// Simplifies and speeds up (*) below while we still have the typeChecker
if (!isTopLevel && symbol.exportSymbol && isReferencedInExport(node)) {
referencedSymbolsInExport.add(symbol.exportSymbol);
}
Expand Down
6 changes: 6 additions & 0 deletions packages/knip/src/util/has-strictly-ns-references.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { IMPORT_STAR } from '../constants.js';
import type { DependencyGraph, ImportDetails } from '../types/dependency-graph.js';

export const hasStrictlyEnumReferences = (importsForExport: ImportDetails | undefined, id: string) => {
if (!importsForExport || !importsForExport.refs.has(id)) return false;
for (const ref of importsForExport.refs) if (ref.startsWith(`${id}.`)) return false;
return true;
};

export const getHasStrictlyNsReferences = (
graph: DependencyGraph,
importsForExport: ImportDetails | undefined,
Expand Down

0 comments on commit fc5982e

Please sign in to comment.