Comparing version 0.12.0 to 0.13.0-members.0
@@ -8,5 +8,5 @@ export const printHelp = () => { | ||
--dir Working directory (default: current working directory) | ||
--include Report only listed issue type(s) (see below) | ||
--exclude Exclude issue type(s) from report (see below) | ||
--ignore Ignore files matching this glob pattern (can be set multiple times) | ||
--include Report only listed issue type(s), can be repeated | ||
--exclude Exclude issue type(s) from report, can be repeated | ||
--ignore Ignore files matching this glob pattern, can be repeated | ||
--no-gitignore Don't use .gitignore | ||
@@ -24,3 +24,3 @@ --dev Include \`devDependencies\` in report(s) | ||
Issue types: files, dependencies, unlisted, exports, nsExports, types, nsTypes, duplicates | ||
Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates | ||
@@ -27,0 +27,0 @@ Examples: |
@@ -26,2 +26,4 @@ import { getLine, LineRewriter } from './log.js'; | ||
report.nsTypes && messages.push(getLine(counters.nsTypes, 'unused types in namespace')); | ||
report.enumMembers && messages.push(getLine(counters.enumMembers, 'unused enum members')); | ||
report.classMembers && messages.push(getLine(counters.classMembers, 'unused class members')); | ||
report.duplicates && messages.push(getLine(counters.duplicates, 'duplicate exports')); | ||
@@ -28,0 +30,0 @@ if (processed < total) { |
@@ -10,3 +10,5 @@ export declare const ISSUE_TYPE_TITLE: { | ||
nsTypes: string; | ||
enumMembers: string; | ||
classMembers: string; | ||
duplicates: string; | ||
}; |
@@ -10,3 +10,5 @@ export const ISSUE_TYPE_TITLE = { | ||
nsTypes: 'UNUSED TYPES IN NAMESPACE', | ||
enumMembers: 'UNUSED ENUM MEMBERS', | ||
classMembers: 'UNUSED CLASS MEMBERS', | ||
duplicates: 'DUPLICATE EXPORTS', | ||
}; |
import path from 'node:path'; | ||
import { ts } from 'ts-morph'; | ||
import { partitionSourceFiles, _findDuplicateExportedNames, _hasReferencingDefaultImport, _findReferencingNamespaceNodes, _getExportedDeclarations, _findReferences, } from './util/project.js'; | ||
import { partitionSourceFiles, _findDuplicateExportedNames, _hasReferencingDefaultImport, _findReferencingNamespaceNodes, _getExportedDeclarations, _findReferences, hasExternalReferences, hasInternalReferences, } from './util/project.js'; | ||
import { getType } from './util/type.js'; | ||
@@ -30,2 +30,4 @@ import { getDependencyAnalyzer } from './util/dependencies.js'; | ||
duplicates: {}, | ||
enumMembers: {}, | ||
classMembers: {}, | ||
}; | ||
@@ -42,2 +44,4 @@ const counters = { | ||
duplicates: 0, | ||
enumMembers: 0, | ||
classMembers: 0, | ||
processed: issues.files.size, | ||
@@ -112,8 +116,34 @@ total: projectFiles.length, | ||
else if (declaration.isKind(ts.SyntaxKind.FunctionDeclaration) || | ||
declaration.isKind(ts.SyntaxKind.ClassDeclaration) || | ||
declaration.isKind(ts.SyntaxKind.TypeAliasDeclaration) || | ||
declaration.isKind(ts.SyntaxKind.InterfaceDeclaration) || | ||
declaration.isKind(ts.SyntaxKind.EnumDeclaration)) { | ||
declaration.isKind(ts.SyntaxKind.InterfaceDeclaration)) { | ||
identifier = declaration.getFirstChildByKindOrThrow(ts.SyntaxKind.Identifier); | ||
} | ||
else if (declaration.isKind(ts.SyntaxKind.EnumDeclaration)) { | ||
identifier = declaration.getFirstChildByKindOrThrow(ts.SyntaxKind.Identifier); | ||
const members = declaration.getMembers(); | ||
members.forEach(member => { | ||
const refs = _findReferences(member); | ||
if (hasExternalReferences(refs, filePath)) | ||
return; | ||
if (hasInternalReferences(refs)) | ||
return; | ||
addSymbolIssue('enumMembers', { filePath, symbol: member.getName() }); | ||
}); | ||
} | ||
else if (declaration.isKind(ts.SyntaxKind.ClassDeclaration)) { | ||
identifier = declaration.getFirstChildByKindOrThrow(ts.SyntaxKind.Identifier); | ||
const members = declaration.getMembers(); | ||
members.forEach(member => { | ||
const isPrivate = member.getCombinedModifierFlags() & ts.ModifierFlags.Private; | ||
if (!isPrivate && | ||
(member.isKind(ts.SyntaxKind.PropertyDeclaration) || member.isKind(ts.SyntaxKind.MethodDeclaration))) { | ||
const refs = _findReferences(member); | ||
if (hasExternalReferences(refs, filePath)) | ||
return; | ||
if (hasInternalReferences(refs)) | ||
return; | ||
addSymbolIssue('classMembers', { filePath, symbol: member.getName() }); | ||
} | ||
}); | ||
} | ||
else if (declaration.isKind(ts.SyntaxKind.PropertyAccessExpression)) { | ||
@@ -140,5 +170,3 @@ identifier = declaration.getLastChildByKindOrThrow(ts.SyntaxKind.Identifier); | ||
else { | ||
const refFiles = new Set(refs.map(r => r.compilerObject.references.map(r => r.fileName)).flat()); | ||
const isReferencedOnlyBySelf = refFiles.size === 1 && [...refFiles][0] === filePath; | ||
if (!isReferencedOnlyBySelf) | ||
if (hasExternalReferences(refs, filePath)) | ||
return; | ||
@@ -145,0 +173,0 @@ if (_findReferencingNamespaceNodes(sourceFile).length > 0) { |
@@ -21,2 +21,4 @@ import { SourceFile } from 'ts-morph'; | ||
duplicates: IssueRecords; | ||
enumMembers: IssueRecords; | ||
classMembers: IssueRecords; | ||
}; | ||
@@ -23,0 +25,0 @@ export declare type IssueType = keyof Issues; |
@@ -33,2 +33,4 @@ import micromatch from 'micromatch'; | ||
'nsTypes', | ||
'classMembers', | ||
'enumMembers', | ||
'duplicates', | ||
@@ -35,0 +37,0 @@ ]; |
import { Project } from 'ts-morph'; | ||
import type { ProjectOptions, SourceFile, Identifier } from 'ts-morph'; | ||
import type { ProjectOptions, SourceFile, ReferenceFindableNode, ReferencedSymbol } from 'ts-morph'; | ||
export declare const partitionSourceFiles: (projectFiles: SourceFile[], productionFiles: SourceFile[]) => SourceFile[][]; | ||
export declare const hasExternalReferences: (refs: ReferencedSymbol[], filePath: string) => boolean; | ||
export declare const hasInternalReferences: (refs: ReferencedSymbol[]) => boolean; | ||
export declare const _createProject: (projectOptions: ProjectOptions, paths?: string[]) => Project; | ||
@@ -11,2 +13,2 @@ export declare const _resolveSourceFileDependencies: (project: Project) => SourceFile[]; | ||
export declare const _getExportedDeclarations: (sourceFile: SourceFile) => ReadonlyMap<string, import("ts-morph").ExportedDeclarations[]>; | ||
export declare const _findReferences: (identifier?: Identifier) => import("ts-morph").ReferencedSymbol[]; | ||
export declare const _findReferences: (identifier?: ReferenceFindableNode) => ReferencedSymbol[]; |
@@ -34,2 +34,9 @@ import { Project } from 'ts-morph'; | ||
}; | ||
export const hasExternalReferences = (refs, filePath) => { | ||
const refFiles = new Set(refs.map(r => r.compilerObject.references.map(r => r.fileName)).flat()); | ||
return !(refFiles.size === 1 && [...refFiles][0] === filePath); | ||
}; | ||
export const hasInternalReferences = (refs) => { | ||
return refs.map(ref => ref.getReferences()).flat().length > 1; | ||
}; | ||
export const _createProject = timerify(createProject); | ||
@@ -36,0 +43,0 @@ export const _resolveSourceFileDependencies = timerify(resolveSourceFileDependencies); |
{ | ||
"name": "knip", | ||
"version": "0.12.0", | ||
"version": "0.13.0-members.0", | ||
"description": "Find unused files, dependencies and exports in your TypeScript and JavaScript project", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
82754
1277