knip 2.7.1 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/ConfigurationChief.d.ts +2 -0
- package/dist/ConfigurationChief.js +5 -0
- package/dist/DependencyDeputy.d.ts +5 -1
- package/dist/DependencyDeputy.js +42 -24
- package/dist/IssueCollector.d.ts +4 -1
- package/dist/IssueCollector.js +5 -0
- package/dist/cli.js +11 -3
- package/dist/constants.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +14 -8
- package/dist/reporters/index.d.ts +1 -1
- package/dist/reporters/symbols.d.ts +1 -1
- package/dist/reporters/symbols.js +11 -1
- package/dist/types/issues.d.ts +9 -0
- package/dist/typescript/getImportsAndExports.js +9 -11
- package/dist/util/cli-arguments.d.ts +2 -1
- package/dist/util/cli-arguments.js +2 -0
- package/dist/util/get-included-issue-types.js +1 -1
- package/dist/util/map.d.ts +1 -0
- package/dist/util/map.js +6 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -136,6 +136,7 @@ Using workspaces in a monorepo? Please see [workspaces][1] for more details abou
|
|
|
136
136
|
-n, --no-progress Don't show dynamic progress updates
|
|
137
137
|
--reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
|
|
138
138
|
--reporter-options Pass extra options to the reporter (as JSON string, see example)
|
|
139
|
+
--no-config-hints Suppress configuration hints
|
|
139
140
|
--no-exit-code Always exit with code zero (0)
|
|
140
141
|
--max-issues Maximum number of issues before non-zero exit code (default: 0)
|
|
141
142
|
-d, --debug Show debug output
|
|
@@ -44,6 +44,7 @@ export declare class ConfigurationChief {
|
|
|
44
44
|
duplicates: import("./types/issues.js").IssueSeverity;
|
|
45
45
|
enumMembers: import("./types/issues.js").IssueSeverity;
|
|
46
46
|
classMembers: import("./types/issues.js").IssueSeverity;
|
|
47
|
+
binaries: import("./types/issues.js").IssueSeverity;
|
|
47
48
|
};
|
|
48
49
|
include: string[];
|
|
49
50
|
exclude: string[];
|
|
@@ -67,5 +68,6 @@ export declare class ConfigurationChief {
|
|
|
67
68
|
getIssueTypesToReport(): import("./types/issues.js").Report;
|
|
68
69
|
findWorkspaceByFilePath(filePath: string): Workspace | undefined;
|
|
69
70
|
findWorkspaceByPackageName(packageName: string): Workspace | undefined;
|
|
71
|
+
getUnusedIgnoredWorkspaces(): string[];
|
|
70
72
|
}
|
|
71
73
|
export {};
|
|
@@ -264,4 +264,9 @@ export class ConfigurationChief {
|
|
|
264
264
|
findWorkspaceByPackageName(packageName) {
|
|
265
265
|
return this.workspaces.find(workspace => workspace.pkgName === packageName);
|
|
266
266
|
}
|
|
267
|
+
getUnusedIgnoredWorkspaces() {
|
|
268
|
+
const ignoredWorkspaceNames = this.config.ignoreWorkspaces;
|
|
269
|
+
const workspaceNames = this.getAllWorkspaces();
|
|
270
|
+
return ignoredWorkspaceNames.filter(workspaceName => !workspaceNames.includes(workspaceName));
|
|
271
|
+
}
|
|
267
272
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Workspace } from './ConfigurationChief.js';
|
|
2
|
-
import type { Issue } from './types/issues.js';
|
|
2
|
+
import type { ConfigurationHints, Issue } from './types/issues.js';
|
|
3
3
|
import type { WorkspaceManifests } from './types/workspace.js';
|
|
4
4
|
import type { PeerDependencies, InstalledBinaries } from './types/workspace.js';
|
|
5
5
|
import type { PackageJson } from 'type-fest';
|
|
@@ -10,6 +10,7 @@ export declare class DependencyDeputy {
|
|
|
10
10
|
isStrict: boolean;
|
|
11
11
|
_manifests: WorkspaceManifests;
|
|
12
12
|
referencedDependencies: Map<string, Set<string>>;
|
|
13
|
+
referencedBinaries: Map<string, Set<string>>;
|
|
13
14
|
peerDependencies: Map<string, PeerDependencies>;
|
|
14
15
|
installedBinaries: Map<string, InstalledBinaries>;
|
|
15
16
|
constructor({ isStrict }: Options);
|
|
@@ -38,13 +39,16 @@ export declare class DependencyDeputy {
|
|
|
38
39
|
setInstalledBinaries(workspaceName: string, installedBinaries: Map<string, Set<string>>): void;
|
|
39
40
|
getInstalledBinaries(workspaceName: string): InstalledBinaries | undefined;
|
|
40
41
|
addReferencedDependency(workspaceName: string, packageName: string): void;
|
|
42
|
+
addReferencedBinary(workspaceName: string, binaryName: string): void;
|
|
41
43
|
addPeerDependencies(workspaceName: string, peerDependencies: Map<string, Set<string>>): void;
|
|
42
44
|
getPeerDependencies(workspaceName: string, dependency: string): string[];
|
|
43
45
|
maybeAddReferencedExternalDependency(workspace: Workspace, packageName: string): boolean;
|
|
46
|
+
maybeAddReferencedBinary(workspace: Workspace, binaryName: string): boolean;
|
|
44
47
|
private isInDependencies;
|
|
45
48
|
settleDependencyIssues(): {
|
|
46
49
|
dependencyIssues: Issue[];
|
|
47
50
|
devDependencyIssues: Issue[];
|
|
51
|
+
configurationHints: ConfigurationHints;
|
|
48
52
|
};
|
|
49
53
|
}
|
|
50
54
|
export {};
|
package/dist/DependencyDeputy.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { isBuiltin } from 'node:module';
|
|
2
|
-
import { fromBinary, isBinary } from './binaries/util.js';
|
|
3
2
|
import { IGNORE_DEFINITELY_TYPED, IGNORED_DEPENDENCIES, IGNORED_GLOBAL_BINARIES } from './constants.js';
|
|
4
3
|
import { isDefinitelyTyped, getDefinitelyTypedFor, getPackageFromDefinitelyTyped } from './util/modules.js';
|
|
5
4
|
export class DependencyDeputy {
|
|
6
5
|
isStrict;
|
|
7
6
|
_manifests = new Map();
|
|
8
7
|
referencedDependencies;
|
|
8
|
+
referencedBinaries;
|
|
9
9
|
peerDependencies;
|
|
10
10
|
installedBinaries;
|
|
11
11
|
constructor({ isStrict }) {
|
|
12
12
|
this.isStrict = isStrict;
|
|
13
13
|
this.referencedDependencies = new Map();
|
|
14
|
+
this.referencedBinaries = new Map();
|
|
14
15
|
this.peerDependencies = new Map();
|
|
15
16
|
this.installedBinaries = new Map();
|
|
16
17
|
}
|
|
@@ -60,6 +61,12 @@ export class DependencyDeputy {
|
|
|
60
61
|
}
|
|
61
62
|
this.referencedDependencies.get(workspaceName)?.add(packageName);
|
|
62
63
|
}
|
|
64
|
+
addReferencedBinary(workspaceName, binaryName) {
|
|
65
|
+
if (!this.referencedBinaries.has(workspaceName)) {
|
|
66
|
+
this.referencedBinaries.set(workspaceName, new Set());
|
|
67
|
+
}
|
|
68
|
+
this.referencedBinaries.get(workspaceName)?.add(binaryName);
|
|
69
|
+
}
|
|
63
70
|
addPeerDependencies(workspaceName, peerDependencies) {
|
|
64
71
|
this.peerDependencies.set(workspaceName, peerDependencies);
|
|
65
72
|
}
|
|
@@ -73,24 +80,6 @@ export class DependencyDeputy {
|
|
|
73
80
|
return true;
|
|
74
81
|
const workspaceNames = this.isStrict ? [workspace.name] : [workspace.name, ...[...workspace.ancestors].reverse()];
|
|
75
82
|
const closestWorkspaceName = workspaceNames.find(name => this.isInDependencies(name, packageName));
|
|
76
|
-
if (isBinary(packageName)) {
|
|
77
|
-
const binaryName = fromBinary(packageName);
|
|
78
|
-
if (IGNORED_GLOBAL_BINARIES.includes(binaryName))
|
|
79
|
-
return true;
|
|
80
|
-
if (this.getWorkspaceManifest(workspace.name)?.ignoreBinaries.includes(binaryName))
|
|
81
|
-
return true;
|
|
82
|
-
for (const name of workspaceNames) {
|
|
83
|
-
const binaries = this.getInstalledBinaries(name);
|
|
84
|
-
if (binaries?.has(binaryName)) {
|
|
85
|
-
const dependencies = binaries.get(binaryName);
|
|
86
|
-
if (dependencies?.size) {
|
|
87
|
-
dependencies.forEach(dependency => this.addReferencedDependency(name, dependency));
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
83
|
if (this.getWorkspaceManifest(workspace.name)?.ignoreDependencies.includes(packageName))
|
|
95
84
|
return true;
|
|
96
85
|
const typesPackageName = !isDefinitelyTyped(packageName) && getDefinitelyTypedFor(packageName);
|
|
@@ -102,6 +91,25 @@ export class DependencyDeputy {
|
|
|
102
91
|
}
|
|
103
92
|
return false;
|
|
104
93
|
}
|
|
94
|
+
maybeAddReferencedBinary(workspace, binaryName) {
|
|
95
|
+
if (IGNORED_GLOBAL_BINARIES.includes(binaryName))
|
|
96
|
+
return true;
|
|
97
|
+
this.addReferencedBinary(workspace.name, binaryName);
|
|
98
|
+
if (this.getWorkspaceManifest(workspace.name)?.ignoreBinaries.includes(binaryName))
|
|
99
|
+
return true;
|
|
100
|
+
const workspaceNames = this.isStrict ? [workspace.name] : [workspace.name, ...[...workspace.ancestors].reverse()];
|
|
101
|
+
for (const name of workspaceNames) {
|
|
102
|
+
const binaries = this.getInstalledBinaries(name);
|
|
103
|
+
if (binaries?.has(binaryName)) {
|
|
104
|
+
const dependencies = binaries.get(binaryName);
|
|
105
|
+
if (dependencies?.size) {
|
|
106
|
+
dependencies.forEach(dependency => this.addReferencedDependency(name, dependency));
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
105
113
|
isInDependencies(workspaceName, packageName) {
|
|
106
114
|
const manifest = this._manifests.get(workspaceName);
|
|
107
115
|
if (!manifest)
|
|
@@ -112,8 +120,10 @@ export class DependencyDeputy {
|
|
|
112
120
|
settleDependencyIssues() {
|
|
113
121
|
const dependencyIssues = [];
|
|
114
122
|
const devDependencyIssues = [];
|
|
123
|
+
const configurationHints = new Set();
|
|
115
124
|
for (const [workspaceName, { manifestPath, ignoreDependencies, ignoreBinaries }] of this._manifests.entries()) {
|
|
116
125
|
const referencedDependencies = this.referencedDependencies.get(workspaceName);
|
|
126
|
+
const referencedBinaries = this.referencedBinaries.get(workspaceName);
|
|
117
127
|
const installedBinaries = this.getInstalledBinaries(workspaceName);
|
|
118
128
|
const ignoreBins = [...IGNORED_GLOBAL_BINARIES, ...ignoreBinaries];
|
|
119
129
|
const ignoreDeps = [...IGNORED_DEPENDENCIES, ...ignoreDependencies];
|
|
@@ -146,17 +156,25 @@ export class DependencyDeputy {
|
|
|
146
156
|
}
|
|
147
157
|
return false;
|
|
148
158
|
};
|
|
149
|
-
this.getProductionDependencies(workspaceName)
|
|
150
|
-
|
|
159
|
+
const pd = this.getProductionDependencies(workspaceName);
|
|
160
|
+
const dd = this.getDevDependencies(workspaceName);
|
|
161
|
+
pd.filter(isNotIgnoredDependency)
|
|
151
162
|
.filter(isNotIgnoredBinary)
|
|
152
163
|
.filter(isNotReferencedDependency)
|
|
153
164
|
.forEach(symbol => dependencyIssues.push({ type: 'dependencies', filePath: manifestPath, symbol }));
|
|
154
|
-
|
|
155
|
-
.filter(isNotIgnoredDependency)
|
|
165
|
+
dd.filter(isNotIgnoredDependency)
|
|
156
166
|
.filter(isNotIgnoredBinary)
|
|
157
167
|
.filter(isNotReferencedDependency)
|
|
158
168
|
.forEach(symbol => devDependencyIssues.push({ type: 'devDependencies', filePath: manifestPath, symbol }));
|
|
169
|
+
const isReferencedDep = (name) => !([...pd, ...dd].includes(name) && referencedDependencies?.has(name));
|
|
170
|
+
const isReferencedBin = (name) => !installedBinaries?.has(name) && referencedBinaries?.has(name);
|
|
171
|
+
ignoreDependencies
|
|
172
|
+
.filter(packageName => IGNORED_DEPENDENCIES.includes(packageName) || !isReferencedDep(packageName))
|
|
173
|
+
.forEach(identifier => configurationHints.add({ workspaceName, identifier, type: 'ignoreDependencies' }));
|
|
174
|
+
ignoreBinaries
|
|
175
|
+
.filter(binaryName => IGNORED_GLOBAL_BINARIES.includes(binaryName) || !isReferencedBin(binaryName))
|
|
176
|
+
.forEach(identifier => configurationHints.add({ workspaceName, identifier, type: 'ignoreBinaries' }));
|
|
159
177
|
}
|
|
160
|
-
return { dependencyIssues, devDependencyIssues };
|
|
178
|
+
return { dependencyIssues, devDependencyIssues, configurationHints };
|
|
161
179
|
}
|
|
162
180
|
}
|
package/dist/IssueCollector.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Issue, Rules } from './types/issues.js';
|
|
1
|
+
import type { ConfigurationHint, Issue, Rules } from './types/issues.js';
|
|
2
2
|
type IssueCollectorOptions = {
|
|
3
3
|
cwd: string;
|
|
4
4
|
rules: Rules;
|
|
@@ -9,6 +9,7 @@ export declare class IssueCollector {
|
|
|
9
9
|
private issues;
|
|
10
10
|
private counters;
|
|
11
11
|
private referencedFiles;
|
|
12
|
+
private configurationHints;
|
|
12
13
|
constructor({ cwd, rules }: IssueCollectorOptions);
|
|
13
14
|
addFileCounts({ processed, unused }: {
|
|
14
15
|
processed: number;
|
|
@@ -16,9 +17,11 @@ export declare class IssueCollector {
|
|
|
16
17
|
}): void;
|
|
17
18
|
addFilesIssues(filePaths: string[]): void;
|
|
18
19
|
addIssue(issue: Issue): void;
|
|
20
|
+
addConfigurationHint(issue: ConfigurationHint): void;
|
|
19
21
|
getIssues(): {
|
|
20
22
|
issues: import("./types/issues.js").Issues;
|
|
21
23
|
counters: import("./types/issues.js").Counters;
|
|
24
|
+
configurationHints: Set<unknown>;
|
|
22
25
|
};
|
|
23
26
|
}
|
|
24
27
|
export {};
|
package/dist/IssueCollector.js
CHANGED
|
@@ -6,6 +6,7 @@ export class IssueCollector {
|
|
|
6
6
|
issues = initIssues();
|
|
7
7
|
counters = initCounters();
|
|
8
8
|
referencedFiles = new Set();
|
|
9
|
+
configurationHints = new Set();
|
|
9
10
|
constructor({ cwd, rules }) {
|
|
10
11
|
this.cwd = cwd;
|
|
11
12
|
this.rules = rules;
|
|
@@ -32,10 +33,14 @@ export class IssueCollector {
|
|
|
32
33
|
this.counters[issue.type]++;
|
|
33
34
|
}
|
|
34
35
|
}
|
|
36
|
+
addConfigurationHint(issue) {
|
|
37
|
+
this.configurationHints.add(issue);
|
|
38
|
+
}
|
|
35
39
|
getIssues() {
|
|
36
40
|
return {
|
|
37
41
|
issues: this.issues,
|
|
38
42
|
counters: this.counters,
|
|
43
|
+
configurationHints: this.configurationHints,
|
|
39
44
|
};
|
|
40
45
|
}
|
|
41
46
|
}
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import { cwd, resolve } from './util/path.js';
|
|
|
9
9
|
import { Performance } from './util/Performance.js';
|
|
10
10
|
import { version } from './version.js';
|
|
11
11
|
import { main } from './index.js';
|
|
12
|
-
const { debug: isDebug = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, performance: isObservePerf = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, version: isVersion, } = parsedArgValues;
|
|
12
|
+
const { debug: isDebug = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-config-hints': noConfigHints = false, 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = false, performance: isObservePerf = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, version: isVersion, } = parsedArgValues;
|
|
13
13
|
if (isHelp) {
|
|
14
14
|
console.log(helpText);
|
|
15
15
|
process.exit(0);
|
|
@@ -23,7 +23,7 @@ const printReport = reporter in reporters ? reporters[reporter] : await _load(re
|
|
|
23
23
|
const run = async () => {
|
|
24
24
|
try {
|
|
25
25
|
const perfObserver = new Performance(isObservePerf);
|
|
26
|
-
const { report, issues, counters, rules } = await main({
|
|
26
|
+
const { report, issues, counters, rules, configurationHints } = await main({
|
|
27
27
|
cwd,
|
|
28
28
|
tsConfigFile: tsConfig,
|
|
29
29
|
gitignore: !isNoGitIgnore,
|
|
@@ -31,7 +31,15 @@ const run = async () => {
|
|
|
31
31
|
isProduction,
|
|
32
32
|
isShowProgress,
|
|
33
33
|
});
|
|
34
|
-
await printReport({
|
|
34
|
+
await printReport({
|
|
35
|
+
report,
|
|
36
|
+
issues,
|
|
37
|
+
configurationHints,
|
|
38
|
+
noConfigHints,
|
|
39
|
+
cwd,
|
|
40
|
+
isProduction,
|
|
41
|
+
options: reporterOptions,
|
|
42
|
+
});
|
|
35
43
|
const totalErrorCount = Object.keys(report)
|
|
36
44
|
.filter(reportGroup => report[reportGroup] && rules[reportGroup] === 'error')
|
|
37
45
|
.reduce((errorCount, reportGroup) => errorCount + counters[reportGroup], 0);
|
package/dist/constants.js
CHANGED
|
@@ -6,6 +6,7 @@ export const TEST_FILE_PATTERNS = [
|
|
|
6
6
|
'**/{test,__tests__}/**/*.{js,jsx,ts,tsx,mjs,cjs}',
|
|
7
7
|
];
|
|
8
8
|
export const IGNORED_GLOBAL_BINARIES = [
|
|
9
|
+
'bash',
|
|
9
10
|
'bun',
|
|
10
11
|
'deno',
|
|
11
12
|
'git',
|
|
@@ -14,6 +15,7 @@ export const IGNORED_GLOBAL_BINARIES = [
|
|
|
14
15
|
'npx',
|
|
15
16
|
'pnpm',
|
|
16
17
|
'yarn',
|
|
18
|
+
'cat',
|
|
17
19
|
'cd',
|
|
18
20
|
'cp',
|
|
19
21
|
'echo',
|
|
@@ -49,6 +51,7 @@ export const ISSUE_TYPES = [
|
|
|
49
51
|
'dependencies',
|
|
50
52
|
'devDependencies',
|
|
51
53
|
'unlisted',
|
|
54
|
+
'binaries',
|
|
52
55
|
'unresolved',
|
|
53
56
|
'exports',
|
|
54
57
|
'nsExports',
|
|
@@ -63,6 +66,7 @@ export const ISSUE_TYPE_TITLE = {
|
|
|
63
66
|
dependencies: 'Unused dependencies',
|
|
64
67
|
devDependencies: 'Unused devDependencies',
|
|
65
68
|
unlisted: 'Unlisted dependencies',
|
|
69
|
+
binaries: 'Unresolved binaries',
|
|
66
70
|
unresolved: 'Unresolved imports',
|
|
67
71
|
exports: 'Unused exports',
|
|
68
72
|
nsExports: 'Unused exports in namespaces',
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { _getDependenciesFromScripts } from './binaries/index.js';
|
|
2
|
+
import { fromBinary, isBinary } from './binaries/util.js';
|
|
2
3
|
import { ConfigurationChief } from './ConfigurationChief.js';
|
|
3
4
|
import { ConsoleStreamer } from './ConsoleStreamer.js';
|
|
4
5
|
import { ROOT_WORKSPACE_NAME } from './constants.js';
|
|
@@ -47,14 +48,16 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
else {
|
|
50
|
-
if (
|
|
51
|
-
const
|
|
52
|
-
const isHandled = deputy.
|
|
51
|
+
if (isBinary(specifier)) {
|
|
52
|
+
const binaryName = fromBinary(specifier);
|
|
53
|
+
const isHandled = deputy.maybeAddReferencedBinary(workspace, binaryName);
|
|
53
54
|
if (!isHandled)
|
|
54
|
-
collector.addIssue({ type: '
|
|
55
|
+
collector.addIssue({ type: 'binaries', filePath: containingFilePath, symbol: binaryName });
|
|
55
56
|
}
|
|
56
57
|
else {
|
|
57
|
-
const packageName =
|
|
58
|
+
const packageName = isInNodeModules(specifier)
|
|
59
|
+
? getPackageNameFromFilePath(specifier)
|
|
60
|
+
: getPackageNameFromModuleSpecifier(specifier);
|
|
58
61
|
const isHandled = deputy.maybeAddReferencedExternalDependency(workspace, packageName);
|
|
59
62
|
if (!isHandled)
|
|
60
63
|
collector.addIssue({ type: 'unlisted', filePath: containingFilePath, symbol: specifier });
|
|
@@ -296,12 +299,15 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
296
299
|
}
|
|
297
300
|
}
|
|
298
301
|
if (isReportDependencies) {
|
|
299
|
-
const { dependencyIssues, devDependencyIssues } = deputy.settleDependencyIssues();
|
|
302
|
+
const { dependencyIssues, devDependencyIssues, configurationHints } = deputy.settleDependencyIssues();
|
|
300
303
|
dependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
301
304
|
if (!isProduction)
|
|
302
305
|
devDependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
306
|
+
configurationHints.forEach(hint => collector.addConfigurationHint(hint));
|
|
303
307
|
}
|
|
304
|
-
const
|
|
308
|
+
const unusedIgnoredWorkspaces = chief.getUnusedIgnoredWorkspaces();
|
|
309
|
+
unusedIgnoredWorkspaces.forEach(identifier => collector.addConfigurationHint({ type: 'ignoreWorkspaces', identifier }));
|
|
310
|
+
const { issues, counters, configurationHints } = collector.getIssues();
|
|
305
311
|
streamer.clear();
|
|
306
|
-
return { report, issues, counters, rules };
|
|
312
|
+
return { report, issues, counters, rules, configurationHints };
|
|
307
313
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
|
-
symbols: ({ report, issues }: import("../index.js").ReporterOptions) => void;
|
|
2
|
+
symbols: ({ report, issues, configurationHints, noConfigHints }: import("../index.js").ReporterOptions) => void;
|
|
3
3
|
compact: ({ report, issues }: import("../index.js").ReporterOptions) => void;
|
|
4
4
|
codeowners: ({ report, issues, options }: import("../index.js").ReporterOptions) => void;
|
|
5
5
|
json: ({ report, issues, options }: import("../index.js").ReporterOptions) => Promise<void>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import EasyTable from 'easy-table';
|
|
3
|
+
import { ROOT_WORKSPACE_NAME } from '../constants.js';
|
|
3
4
|
import { relative } from '../util/path.js';
|
|
4
5
|
import { getTitle, logTitle, logIssueSet, identity } from './util.js';
|
|
5
6
|
const TRUNCATE_WIDTH = 40;
|
|
@@ -16,7 +17,7 @@ const logIssueRecord = (issues) => {
|
|
|
16
17
|
});
|
|
17
18
|
console.log(table.sort(['filePath', 'parentSymbol', 'symbol']).print().trim());
|
|
18
19
|
};
|
|
19
|
-
export default ({ report, issues }) => {
|
|
20
|
+
export default ({ report, issues, configurationHints, noConfigHints }) => {
|
|
20
21
|
const reportMultipleGroups = Object.values(report).filter(Boolean).length > 1;
|
|
21
22
|
let totalIssues = 0;
|
|
22
23
|
for (const [reportType, isReportType] of Object.entries(report)) {
|
|
@@ -38,6 +39,15 @@ export default ({ report, issues }) => {
|
|
|
38
39
|
totalIssues = totalIssues + issuesForType.length;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
if (!noConfigHints && configurationHints.size > 0) {
|
|
43
|
+
logTitle('Configuration issues', configurationHints.size);
|
|
44
|
+
configurationHints.forEach(hint => {
|
|
45
|
+
const { type, workspaceName, identifier } = hint;
|
|
46
|
+
const message = `Unused item in ${type}`;
|
|
47
|
+
const workspace = workspaceName && workspaceName !== ROOT_WORKSPACE_NAME ? ` (workspace: ${workspaceName})` : ``;
|
|
48
|
+
console.warn(chalk.grey(`${message}${workspace}:`), identifier);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
41
51
|
if (totalIssues === 0) {
|
|
42
52
|
console.log('✂️ Excellent, Knip found no issues.');
|
|
43
53
|
}
|
package/dist/types/issues.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type Issues = {
|
|
|
23
23
|
dependencies: IssueRecords;
|
|
24
24
|
devDependencies: IssueRecords;
|
|
25
25
|
unlisted: IssueRecords;
|
|
26
|
+
binaries: IssueRecords;
|
|
26
27
|
unresolved: IssueRecords;
|
|
27
28
|
exports: IssueRecords;
|
|
28
29
|
types: IssueRecords;
|
|
@@ -41,6 +42,8 @@ export type Counters = Record<IssueType | 'processed' | 'total', number>;
|
|
|
41
42
|
export type ReporterOptions = {
|
|
42
43
|
report: Report;
|
|
43
44
|
issues: Issues;
|
|
45
|
+
configurationHints: ConfigurationHints;
|
|
46
|
+
noConfigHints: boolean;
|
|
44
47
|
cwd: string;
|
|
45
48
|
workingDir: string;
|
|
46
49
|
isProduction: boolean;
|
|
@@ -49,3 +52,9 @@ export type ReporterOptions = {
|
|
|
49
52
|
export type Reporter = (options: ReporterOptions) => void;
|
|
50
53
|
export type IssueSeverity = 'error' | 'warn' | 'off';
|
|
51
54
|
export type Rules = Record<IssueType, IssueSeverity>;
|
|
55
|
+
export type ConfigurationHints = Set<ConfigurationHint>;
|
|
56
|
+
export type ConfigurationHint = {
|
|
57
|
+
type: 'ignoreBinaries' | 'ignoreDependencies' | 'ignoreWorkspaces';
|
|
58
|
+
identifier: string;
|
|
59
|
+
workspaceName?: string;
|
|
60
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isBuiltin } from 'node:module';
|
|
2
2
|
import ts from 'typescript';
|
|
3
|
+
import { getOrSet } from '../util/map.js';
|
|
3
4
|
import { isInNodeModules } from '../util/path.js';
|
|
4
5
|
import { isDeclarationFileExtension, isAccessExpression, getAccessExpressionName } from './ast-helpers.js';
|
|
5
6
|
import getExportVisitors from './visitors/exports/index.js';
|
|
@@ -22,17 +23,14 @@ export const getImportsAndExports = (sourceFile, options) => {
|
|
|
22
23
|
const addInternalImport = ({ identifier, specifier, symbol, filePath, isDynamic }) => {
|
|
23
24
|
const isStar = identifier === '*';
|
|
24
25
|
const isReExported = Boolean(isStar && !symbol);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
const internalImport = internalImports.get(filePath);
|
|
26
|
+
const internalImport = getOrSet(internalImports, filePath, {
|
|
27
|
+
specifier,
|
|
28
|
+
isStar,
|
|
29
|
+
isReExported,
|
|
30
|
+
isReExportedBy: new Set(),
|
|
31
|
+
symbols: new Set(),
|
|
32
|
+
isDynamic,
|
|
33
|
+
});
|
|
36
34
|
if (isReExported) {
|
|
37
35
|
internalImport.isReExported = isReExported;
|
|
38
36
|
internalImport.isReExportedBy.add(sourceFile.fileName);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const helpText = "\u2702\uFE0F Find unused files, dependencies and exports in your JavaScript and TypeScript projects\n\nUsage: knip [options]\n\nOptions:\n -c, --config [file] Configuration file path (default: [.]knip.json[c], knip.js, knip.ts or package.json#knip)\n -t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)\n --production Analyze only production source files (e.g. no tests, devDependencies, exported types)\n --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)\n --workspace Analyze a single workspace (default: analyze all configured workspaces)\n --no-gitignore Don't use .gitignore\n --include Report only provided issue type(s), can be comma-separated or repeated (1)\n --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)\n --dependencies Shortcut for --include dependencies,unlisted,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n -n, --no-progress Don't show dynamic progress updates\n --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-exit-code Always exit with code zero (0)\n --max-issues Maximum number of issues before non-zero exit code (default: 0)\n -d, --debug Show debug output\n --debug-file-filter Filter for files in debug output (regex as string)\n --performance Measure count and running time of expensive functions and display stats table\n --h, --help Print this help text\n --V, version Print version\n\n(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\n$ knip -c ./config/knip.json --reporter compact\n$ knip --reporter codeowners --reporter-options '{\"path\":\".github/CODEOWNERS\"}'\n$ knip --debug --debug-file-filter '(specific|particular)-module'\n\nMore documentation and bug reports: https://github.com/webpro/knip";
|
|
1
|
+
export declare const helpText = "\u2702\uFE0F Find unused files, dependencies and exports in your JavaScript and TypeScript projects\n\nUsage: knip [options]\n\nOptions:\n -c, --config [file] Configuration file path (default: [.]knip.json[c], knip.js, knip.ts or package.json#knip)\n -t, --tsConfig [file] TypeScript configuration path (default: tsconfig.json)\n --production Analyze only production source files (e.g. no tests, devDependencies, exported types)\n --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)\n --workspace Analyze a single workspace (default: analyze all configured workspaces)\n --no-gitignore Don't use .gitignore\n --include Report only provided issue type(s), can be comma-separated or repeated (1)\n --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)\n --dependencies Shortcut for --include dependencies,unlisted,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n -n, --no-progress Don't show dynamic progress updates\n --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-config-hints Suppress configuration hints\n --no-exit-code Always exit with code zero (0)\n --max-issues Maximum number of issues before non-zero exit code (default: 0)\n -d, --debug Show debug output\n --debug-file-filter Filter for files in debug output (regex as string)\n --performance Measure count and running time of expensive functions and display stats table\n --h, --help Print this help text\n --V, version Print version\n\n(1) Issue types: files, dependencies, unlisted, unresolved, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\n$ knip -c ./config/knip.json --reporter compact\n$ knip --reporter codeowners --reporter-options '{\"path\":\".github/CODEOWNERS\"}'\n$ knip --debug --debug-file-filter '(specific|particular)-module'\n\nMore documentation and bug reports: https://github.com/webpro/knip";
|
|
2
2
|
declare const _default: {
|
|
3
3
|
config: string | undefined;
|
|
4
4
|
debug: boolean | undefined;
|
|
@@ -9,6 +9,7 @@ declare const _default: {
|
|
|
9
9
|
help: boolean | undefined;
|
|
10
10
|
include: string[] | undefined;
|
|
11
11
|
'max-issues': string | undefined;
|
|
12
|
+
'no-config-hints': boolean | undefined;
|
|
12
13
|
'no-exit-code': boolean | undefined;
|
|
13
14
|
'no-gitignore': boolean | undefined;
|
|
14
15
|
'no-progress': boolean | undefined;
|
|
@@ -17,6 +17,7 @@ Options:
|
|
|
17
17
|
-n, --no-progress Don't show dynamic progress updates
|
|
18
18
|
--reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
|
|
19
19
|
--reporter-options Pass extra options to the reporter (as JSON string, see example)
|
|
20
|
+
--no-config-hints Suppress configuration hints
|
|
20
21
|
--no-exit-code Always exit with code zero (0)
|
|
21
22
|
--max-issues Maximum number of issues before non-zero exit code (default: 0)
|
|
22
23
|
-d, --debug Show debug output
|
|
@@ -50,6 +51,7 @@ try {
|
|
|
50
51
|
help: { type: 'boolean', short: 'h' },
|
|
51
52
|
include: { type: 'string', multiple: true },
|
|
52
53
|
'max-issues': { type: 'string' },
|
|
54
|
+
'no-config-hints': { type: 'boolean' },
|
|
53
55
|
'no-exit-code': { type: 'boolean' },
|
|
54
56
|
'no-gitignore': { type: 'boolean' },
|
|
55
57
|
'no-progress': { type: 'boolean', short: 'n' },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ISSUE_TYPES } from '../constants.js';
|
|
2
2
|
export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isProduction = false } = {}) => {
|
|
3
3
|
if (cliArgs.dependencies) {
|
|
4
|
-
cliArgs.include = [...cliArgs.include, 'dependencies', 'unlisted', 'unresolved'];
|
|
4
|
+
cliArgs.include = [...cliArgs.include, 'dependencies', 'unlisted', 'binaries', 'unresolved'];
|
|
5
5
|
}
|
|
6
6
|
if (cliArgs.exports) {
|
|
7
7
|
const exports = ['exports', 'nsExports', 'classMembers', 'types', 'nsTypes', 'enumMembers', 'duplicates'];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getOrSet: <K extends string, V, T extends Map<K, V>>(map: T, key: K, value: V) => NonNullable<V>;
|
package/dist/util/map.js
ADDED
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.
|
|
1
|
+
export declare const version = "2.8.1";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.
|
|
1
|
+
export const version = '2.8.1';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knip",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
|
|
5
5
|
"homepage": "https://github.com/webpro/knip",
|
|
6
6
|
"repository": "github:webpro/knip",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@typescript-eslint/parser": "5.57.1",
|
|
75
75
|
"c8": "7.13.0",
|
|
76
76
|
"eslint": "8.37.0",
|
|
77
|
-
"eslint-import-resolver-typescript": "3.5.
|
|
77
|
+
"eslint-import-resolver-typescript": "3.5.5",
|
|
78
78
|
"eslint-plugin-import": "2.27.5",
|
|
79
79
|
"eslint-plugin-n": "15.7.0",
|
|
80
80
|
"globstar": "1.0.0",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"remark-cli": "11.0.0",
|
|
84
84
|
"remark-preset-webpro": "0.0.2",
|
|
85
85
|
"tsx": "3.12.6",
|
|
86
|
-
"type-fest": "3.
|
|
86
|
+
"type-fest": "3.8.0"
|
|
87
87
|
},
|
|
88
88
|
"engines": {
|
|
89
89
|
"node": ">=16.17.0 <17 || >=18.6.0"
|