knip 2.9.0 → 2.10.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 +10 -6
- package/dist/ConfigurationChief.d.ts +2 -0
- package/dist/ConfigurationChief.js +12 -5
- package/dist/DependencyDeputy.d.ts +5 -0
- package/dist/DependencyDeputy.js +60 -23
- package/dist/IssueCollector.d.ts +1 -1
- package/dist/IssueCollector.js +7 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -7
- package/dist/plugins/eslint/helpers.js +9 -13
- package/dist/types/config.d.ts +2 -0
- package/dist/types/imports.d.ts +1 -1
- package/dist/typescript/getImportsAndExports.d.ts +1 -0
- package/dist/typescript/getImportsAndExports.js +10 -10
- package/dist/typescript/visitors/imports/reExportDeclaration.js +3 -3
- package/dist/util/modules.d.ts +1 -1
- package/dist/util/modules.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -44,12 +44,17 @@ Knip has good defaults and you can run it without any configuration. Here's the
|
|
|
44
44
|
|
|
45
45
|
```json
|
|
46
46
|
{
|
|
47
|
-
"entry": ["index.
|
|
48
|
-
"project": ["**/*.
|
|
47
|
+
"entry": ["index.js", "src/index.js"],
|
|
48
|
+
"project": ["**/*.js"]
|
|
49
49
|
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
In addition to `index.js`, the following file names and extensions are also considered entry files:
|
|
53
|
+
|
|
54
|
+
- `index`, `main` and `cli`
|
|
55
|
+
- `js`, `mjs`, `cjs`, `jsx`, `ts`, `mts`, `cts` and `tsx`
|
|
56
|
+
|
|
57
|
+
This means files like `main.cjs` and `src/cli.ts` are automatically added as entry files.
|
|
53
58
|
|
|
54
59
|
### Entry Files
|
|
55
60
|
|
|
@@ -58,10 +63,9 @@ Knip looks for entry files at those default locations, but also in other places:
|
|
|
58
63
|
- The `main`, `bin` and `exports` fields of `package.json`.
|
|
59
64
|
- [Plugins][2] such as for Next.js, Remix, Gatsby or Svelte add entry files.
|
|
60
65
|
- The `scripts` in package.json or other scripts may provide entry files.
|
|
61
|
-
- Knip does this for each [workspace][1] it finds.
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
everything is according to defaults you
|
|
67
|
+
Knip does this for each [workspace][1] it finds, trying to minimize the configuration to suit your project. In a
|
|
68
|
+
perfectly boring world where everything is according to defaults you wouldn't even need a `knip.json` file at all.
|
|
65
69
|
|
|
66
70
|
Larger projects tend to have more things customized, and therefore probably get more out of Knip with a configuration
|
|
67
71
|
file. Let's say you are using `.ts` files exclusively and have all source files only in the `src` directory:
|
|
@@ -49,6 +49,8 @@ export declare class ConfigurationChief {
|
|
|
49
49
|
include: string[];
|
|
50
50
|
exclude: string[];
|
|
51
51
|
ignore: string[];
|
|
52
|
+
ignoreBinaries: string[];
|
|
53
|
+
ignoreDependencies: string[];
|
|
52
54
|
ignoreWorkspaces: string[];
|
|
53
55
|
syncCompilers: Map<string, (args_0: string, ...args_1: unknown[]) => string>;
|
|
54
56
|
asyncCompilers: Map<string, (args_0: string, ...args_1: unknown[]) => Promise<string>>;
|
|
@@ -21,7 +21,7 @@ const workspaceArg = rawWorkspaceArg ? toPosix(rawWorkspaceArg).replace(/^\.\//,
|
|
|
21
21
|
const getDefaultWorkspaceConfig = (extensions) => {
|
|
22
22
|
const exts = [...DEFAULT_EXTENSIONS, ...(extensions ?? [])].map(ext => ext.slice(1)).join(',');
|
|
23
23
|
return {
|
|
24
|
-
entry: [`index.{${exts}}!`, `src/index.{${exts}}!`],
|
|
24
|
+
entry: [`{index,cli,main}.{${exts}}!`, `src/{index,cli,main}.{${exts}}!`],
|
|
25
25
|
project: [`**/*.{${exts}}!`],
|
|
26
26
|
paths: {},
|
|
27
27
|
ignore: [],
|
|
@@ -34,6 +34,8 @@ const defaultConfig = {
|
|
|
34
34
|
include: [],
|
|
35
35
|
exclude: [],
|
|
36
36
|
ignore: [],
|
|
37
|
+
ignoreBinaries: [],
|
|
38
|
+
ignoreDependencies: [],
|
|
37
39
|
ignoreWorkspaces: [],
|
|
38
40
|
syncCompilers: new Map(),
|
|
39
41
|
asyncCompilers: new Map(),
|
|
@@ -122,8 +124,8 @@ export class ConfigurationChief {
|
|
|
122
124
|
project,
|
|
123
125
|
paths,
|
|
124
126
|
ignore: arrayify(workspaceConfig.ignore),
|
|
125
|
-
ignoreBinaries:
|
|
126
|
-
ignoreDependencies:
|
|
127
|
+
ignoreBinaries: arrayify(workspaceConfig.ignoreBinaries),
|
|
128
|
+
ignoreDependencies: arrayify(workspaceConfig.ignoreDependencies),
|
|
127
129
|
};
|
|
128
130
|
for (const [name, pluginConfig] of Object.entries(workspaceConfig)) {
|
|
129
131
|
const pluginName = toCamelCase(name);
|
|
@@ -151,6 +153,8 @@ export class ConfigurationChief {
|
|
|
151
153
|
include,
|
|
152
154
|
exclude,
|
|
153
155
|
ignore,
|
|
156
|
+
ignoreBinaries,
|
|
157
|
+
ignoreDependencies,
|
|
154
158
|
ignoreWorkspaces,
|
|
155
159
|
syncCompilers: new Map(Object.entries(syncCompilers ?? {})),
|
|
156
160
|
asyncCompilers: new Map(Object.entries(asyncCompilers ?? {})),
|
|
@@ -172,7 +176,6 @@ export class ConfigurationChief {
|
|
|
172
176
|
const workspaces = await mapWorkspaces({
|
|
173
177
|
pkg: this.manifest ?? {},
|
|
174
178
|
cwd: this.cwd,
|
|
175
|
-
ignore: this.config.ignoreWorkspaces,
|
|
176
179
|
});
|
|
177
180
|
const manifestWorkspaces = new Map();
|
|
178
181
|
for (const [pkgName, dir] of workspaces.entries()) {
|
|
@@ -192,6 +195,7 @@ export class ConfigurationChief {
|
|
|
192
195
|
}
|
|
193
196
|
getEnabledWorkspaces() {
|
|
194
197
|
const allWorkspaces = this.getAllWorkspaces();
|
|
198
|
+
const ignoredWorkspaces = this.getIgnoredWorkspaces();
|
|
195
199
|
const getAncestors = (name) => (ancestors, ancestorName) => {
|
|
196
200
|
if (name === ancestorName)
|
|
197
201
|
return ancestors;
|
|
@@ -200,7 +204,10 @@ export class ConfigurationChief {
|
|
|
200
204
|
return ancestors;
|
|
201
205
|
};
|
|
202
206
|
const workspaces = workspaceArg ? [workspaceArg] : allWorkspaces;
|
|
203
|
-
return workspaces
|
|
207
|
+
return workspaces
|
|
208
|
+
.filter(w => !ignoredWorkspaces.includes(w))
|
|
209
|
+
.sort(byPathDepth)
|
|
210
|
+
.map((name) => ({
|
|
204
211
|
name,
|
|
205
212
|
pkgName: this.manifestWorkspaces.get(name) ?? this.manifest?.name,
|
|
206
213
|
dir: join(this.cwd, name),
|
|
@@ -13,6 +13,8 @@ export declare class DependencyDeputy {
|
|
|
13
13
|
referencedBinaries: Map<string, Set<string>>;
|
|
14
14
|
peerDependencies: Map<string, PeerDependencies>;
|
|
15
15
|
installedBinaries: Map<string, InstalledBinaries>;
|
|
16
|
+
ignoreBinaries: string[];
|
|
17
|
+
ignoreDependencies: string[];
|
|
16
18
|
constructor({ isStrict }: Options);
|
|
17
19
|
addWorkspace({ name, dir, manifestPath, manifest, ignoreDependencies, ignoreBinaries, }: {
|
|
18
20
|
name: string;
|
|
@@ -22,6 +24,7 @@ export declare class DependencyDeputy {
|
|
|
22
24
|
ignoreDependencies: string[];
|
|
23
25
|
ignoreBinaries: string[];
|
|
24
26
|
}): void;
|
|
27
|
+
addIgnored(ignoreBinaries: string[], ignoreDependencies: string[]): void;
|
|
25
28
|
getWorkspaceManifest(workspaceName: string): {
|
|
26
29
|
workspaceDir: string;
|
|
27
30
|
manifestPath: string;
|
|
@@ -48,6 +51,8 @@ export declare class DependencyDeputy {
|
|
|
48
51
|
settleDependencyIssues(): {
|
|
49
52
|
dependencyIssues: Issue[];
|
|
50
53
|
devDependencyIssues: Issue[];
|
|
54
|
+
};
|
|
55
|
+
getConfigurationHints(): {
|
|
51
56
|
configurationHints: ConfigurationHints;
|
|
52
57
|
};
|
|
53
58
|
}
|
package/dist/DependencyDeputy.js
CHANGED
|
@@ -8,6 +8,8 @@ export class DependencyDeputy {
|
|
|
8
8
|
referencedBinaries;
|
|
9
9
|
peerDependencies;
|
|
10
10
|
installedBinaries;
|
|
11
|
+
ignoreBinaries = [];
|
|
12
|
+
ignoreDependencies = [];
|
|
11
13
|
constructor({ isStrict }) {
|
|
12
14
|
this.isStrict = isStrict;
|
|
13
15
|
this.referencedDependencies = new Map();
|
|
@@ -35,6 +37,10 @@ export class DependencyDeputy {
|
|
|
35
37
|
allDependencies,
|
|
36
38
|
});
|
|
37
39
|
}
|
|
40
|
+
addIgnored(ignoreBinaries, ignoreDependencies) {
|
|
41
|
+
this.ignoreBinaries = ignoreBinaries;
|
|
42
|
+
this.ignoreDependencies = ignoreDependencies;
|
|
43
|
+
}
|
|
38
44
|
getWorkspaceManifest(workspaceName) {
|
|
39
45
|
return this._manifests.get(workspaceName);
|
|
40
46
|
}
|
|
@@ -80,8 +86,6 @@ export class DependencyDeputy {
|
|
|
80
86
|
return true;
|
|
81
87
|
const workspaceNames = this.isStrict ? [workspace.name] : [workspace.name, ...[...workspace.ancestors].reverse()];
|
|
82
88
|
const closestWorkspaceName = workspaceNames.find(name => this.isInDependencies(name, packageName));
|
|
83
|
-
if (this.getWorkspaceManifest(workspace.name)?.ignoreDependencies.includes(packageName))
|
|
84
|
-
return true;
|
|
85
89
|
const typesPackageName = !isDefinitelyTyped(packageName) && getDefinitelyTypedFor(packageName);
|
|
86
90
|
const closestWorkspaceNameForTypes = typesPackageName && workspaceNames.find(name => this.isInDependencies(name, typesPackageName));
|
|
87
91
|
if (closestWorkspaceName || closestWorkspaceNameForTypes) {
|
|
@@ -89,14 +93,19 @@ export class DependencyDeputy {
|
|
|
89
93
|
closestWorkspaceNameForTypes && this.addReferencedDependency(closestWorkspaceNameForTypes, typesPackageName);
|
|
90
94
|
return true;
|
|
91
95
|
}
|
|
96
|
+
else {
|
|
97
|
+
this.addReferencedDependency(workspace.name, packageName);
|
|
98
|
+
}
|
|
99
|
+
if (this.getWorkspaceManifest(workspace.name)?.ignoreDependencies.includes(packageName))
|
|
100
|
+
return true;
|
|
101
|
+
if (this.ignoreDependencies.includes(packageName))
|
|
102
|
+
return true;
|
|
92
103
|
return false;
|
|
93
104
|
}
|
|
94
105
|
maybeAddReferencedBinary(workspace, binaryName) {
|
|
95
106
|
if (IGNORED_GLOBAL_BINARIES.includes(binaryName))
|
|
96
107
|
return true;
|
|
97
108
|
this.addReferencedBinary(workspace.name, binaryName);
|
|
98
|
-
if (this.getWorkspaceManifest(workspace.name)?.ignoreBinaries.includes(binaryName))
|
|
99
|
-
return true;
|
|
100
109
|
const workspaceNames = this.isStrict ? [workspace.name] : [workspace.name, ...[...workspace.ancestors].reverse()];
|
|
101
110
|
for (const name of workspaceNames) {
|
|
102
111
|
const binaries = this.getInstalledBinaries(name);
|
|
@@ -108,6 +117,10 @@ export class DependencyDeputy {
|
|
|
108
117
|
}
|
|
109
118
|
}
|
|
110
119
|
}
|
|
120
|
+
if (this.getWorkspaceManifest(workspace.name)?.ignoreBinaries.includes(binaryName))
|
|
121
|
+
return true;
|
|
122
|
+
if (this.ignoreBinaries.includes(binaryName))
|
|
123
|
+
return true;
|
|
111
124
|
return false;
|
|
112
125
|
}
|
|
113
126
|
isInDependencies(workspaceName, packageName) {
|
|
@@ -120,25 +133,28 @@ export class DependencyDeputy {
|
|
|
120
133
|
settleDependencyIssues() {
|
|
121
134
|
const dependencyIssues = [];
|
|
122
135
|
const devDependencyIssues = [];
|
|
123
|
-
const configurationHints = new Set();
|
|
124
136
|
for (const [workspaceName, { manifestPath, ignoreDependencies, ignoreBinaries }] of this._manifests.entries()) {
|
|
125
137
|
const referencedDependencies = this.referencedDependencies.get(workspaceName);
|
|
126
|
-
const referencedBinaries = this.referencedBinaries.get(workspaceName);
|
|
127
138
|
const installedBinaries = this.getInstalledBinaries(workspaceName);
|
|
128
|
-
const ignoreBins = [...IGNORED_GLOBAL_BINARIES, ...ignoreBinaries];
|
|
129
|
-
const ignoreDeps = [...IGNORED_DEPENDENCIES, ...ignoreDependencies];
|
|
139
|
+
const ignoreBins = [...IGNORED_GLOBAL_BINARIES, ...this.ignoreBinaries, ...ignoreBinaries];
|
|
140
|
+
const ignoreDeps = [...IGNORED_DEPENDENCIES, ...this.ignoreDependencies, ...ignoreDependencies];
|
|
130
141
|
const isNotIgnoredDependency = (packageName) => !ignoreDeps.includes(packageName);
|
|
131
142
|
const isNotIgnoredBinary = (packageName) => {
|
|
132
143
|
if (installedBinaries?.has(packageName)) {
|
|
133
144
|
const binaryNames = installedBinaries.get(packageName);
|
|
134
|
-
if (binaryNames
|
|
135
|
-
|
|
145
|
+
if (binaryNames) {
|
|
146
|
+
if (ignoreBins.some(ignoredBinary => binaryNames.has(ignoredBinary)))
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
136
149
|
}
|
|
137
150
|
return true;
|
|
138
151
|
};
|
|
139
|
-
const
|
|
152
|
+
const peerDepRecs = {};
|
|
153
|
+
const isNotReferencedDependency = (dependency, isPeerDep) => {
|
|
140
154
|
if (referencedDependencies?.has(dependency))
|
|
141
155
|
return false;
|
|
156
|
+
if (isPeerDep && peerDepRecs[dependency])
|
|
157
|
+
return true;
|
|
142
158
|
const [scope, typedDependency] = dependency.split('/');
|
|
143
159
|
if (scope === '@types') {
|
|
144
160
|
const typedPackageName = getPackageFromDefinitelyTyped(typedDependency);
|
|
@@ -146,35 +162,56 @@ export class DependencyDeputy {
|
|
|
146
162
|
return false;
|
|
147
163
|
const peerDependencies = this.getPeerDependencies(workspaceName, typedPackageName);
|
|
148
164
|
if (peerDependencies.length) {
|
|
149
|
-
return !peerDependencies.find(peerDependency => !isNotReferencedDependency(peerDependency));
|
|
165
|
+
return !peerDependencies.find(peerDependency => !isNotReferencedDependency(peerDependency, true));
|
|
150
166
|
}
|
|
151
167
|
return !referencedDependencies?.has(typedPackageName);
|
|
152
168
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
return false;
|
|
169
|
+
const peerDependencies = this.getPeerDependencies(workspaceName, dependency);
|
|
170
|
+
peerDependencies.forEach(dep => (!peerDepRecs[dep] ? (peerDepRecs[dep] = 1) : peerDepRecs[dep]++));
|
|
171
|
+
return !peerDependencies.find(peerDependency => !isNotReferencedDependency(peerDependency, true));
|
|
158
172
|
};
|
|
159
173
|
const pd = this.getProductionDependencies(workspaceName);
|
|
160
174
|
const dd = this.getDevDependencies(workspaceName);
|
|
161
175
|
pd.filter(isNotIgnoredDependency)
|
|
162
176
|
.filter(isNotIgnoredBinary)
|
|
163
|
-
.filter(isNotReferencedDependency)
|
|
177
|
+
.filter(d => isNotReferencedDependency(d))
|
|
164
178
|
.forEach(symbol => dependencyIssues.push({ type: 'dependencies', filePath: manifestPath, symbol }));
|
|
165
179
|
dd.filter(isNotIgnoredDependency)
|
|
166
180
|
.filter(isNotIgnoredBinary)
|
|
167
|
-
.filter(isNotReferencedDependency)
|
|
181
|
+
.filter(d => isNotReferencedDependency(d))
|
|
168
182
|
.forEach(symbol => devDependencyIssues.push({ type: 'devDependencies', filePath: manifestPath, symbol }));
|
|
169
|
-
|
|
183
|
+
}
|
|
184
|
+
return { dependencyIssues, devDependencyIssues };
|
|
185
|
+
}
|
|
186
|
+
getConfigurationHints() {
|
|
187
|
+
const configurationHints = new Set();
|
|
188
|
+
const rootIgnoreBinaries = Object.fromEntries(this.ignoreBinaries.map(key => [key, 0]));
|
|
189
|
+
const rootIgnoreDependencies = Object.fromEntries(this.ignoreDependencies.map(key => [key, 0]));
|
|
190
|
+
for (const [workspaceName, { ignoreDependencies, ignoreBinaries }] of this._manifests.entries()) {
|
|
191
|
+
const referencedDependencies = this.referencedDependencies.get(workspaceName);
|
|
192
|
+
const referencedBinaries = this.referencedBinaries.get(workspaceName);
|
|
193
|
+
const installedBinaries = this.getInstalledBinaries(workspaceName);
|
|
194
|
+
referencedBinaries?.forEach(binaryName => binaryName in rootIgnoreBinaries && rootIgnoreBinaries[binaryName]++);
|
|
195
|
+
const allDeps = [...this.getProductionDependencies(workspaceName), ...this.getDevDependencies(workspaceName)];
|
|
196
|
+
const isReferencedDep = (name) => referencedDependencies?.has(name) || (allDeps.includes(name) && !referencedDependencies?.has(name));
|
|
170
197
|
const isReferencedBin = (name) => !installedBinaries?.has(name) && referencedBinaries?.has(name);
|
|
171
198
|
ignoreDependencies
|
|
172
|
-
.filter(packageName => IGNORED_DEPENDENCIES.includes(packageName) ||
|
|
199
|
+
.filter(packageName => IGNORED_DEPENDENCIES.includes(packageName) ||
|
|
200
|
+
(workspaceName !== '.' && this.ignoreDependencies.includes(packageName)) ||
|
|
201
|
+
!isReferencedDep(packageName))
|
|
173
202
|
.forEach(identifier => configurationHints.add({ workspaceName, identifier, type: 'ignoreDependencies' }));
|
|
174
203
|
ignoreBinaries
|
|
175
|
-
.filter(binaryName => IGNORED_GLOBAL_BINARIES.includes(binaryName) ||
|
|
204
|
+
.filter(binaryName => IGNORED_GLOBAL_BINARIES.includes(binaryName) ||
|
|
205
|
+
(workspaceName !== '.' && this.ignoreBinaries.includes(binaryName)) ||
|
|
206
|
+
!isReferencedBin(binaryName))
|
|
176
207
|
.forEach(identifier => configurationHints.add({ workspaceName, identifier, type: 'ignoreBinaries' }));
|
|
177
208
|
}
|
|
178
|
-
|
|
209
|
+
Object.keys(rootIgnoreBinaries)
|
|
210
|
+
.filter(key => rootIgnoreBinaries[key] === 0)
|
|
211
|
+
.forEach(identifier => configurationHints.add({ workspaceName: '.', identifier, type: 'ignoreBinaries' }));
|
|
212
|
+
Object.keys(rootIgnoreDependencies)
|
|
213
|
+
.filter(key => rootIgnoreDependencies[key] === 0)
|
|
214
|
+
.forEach(identifier => configurationHints.add({ workspaceName: '.', identifier, type: 'ignoreDependencies' }));
|
|
215
|
+
return { configurationHints };
|
|
179
216
|
}
|
|
180
217
|
}
|
package/dist/IssueCollector.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare class IssueCollector {
|
|
|
21
21
|
getIssues(): {
|
|
22
22
|
issues: import("./types/issues.js").Issues;
|
|
23
23
|
counters: import("./types/issues.js").Counters;
|
|
24
|
-
configurationHints: Set<
|
|
24
|
+
configurationHints: Set<ConfigurationHint>;
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
export {};
|
package/dist/IssueCollector.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { initIssues, initCounters } from './issues/initializers.js';
|
|
2
2
|
import { relative } from './util/path.js';
|
|
3
|
+
function objectInSet(set, obj) {
|
|
4
|
+
const objJSON = JSON.stringify(obj);
|
|
5
|
+
return Array.from(set).some(item => JSON.stringify(item) === objJSON);
|
|
6
|
+
}
|
|
3
7
|
export class IssueCollector {
|
|
4
8
|
cwd;
|
|
5
9
|
rules;
|
|
@@ -34,7 +38,9 @@ export class IssueCollector {
|
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
addConfigurationHint(issue) {
|
|
37
|
-
this.configurationHints
|
|
41
|
+
if (!objectInSet(this.configurationHints, issue)) {
|
|
42
|
+
this.configurationHints.add(issue);
|
|
43
|
+
}
|
|
38
44
|
}
|
|
39
45
|
getIssues() {
|
|
40
46
|
return {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export declare const main: (unresolvedConfiguration: CommandLineOptions) => Prom
|
|
|
6
6
|
issues: import("./types/issues.js").Issues;
|
|
7
7
|
counters: import("./types/issues.js").Counters;
|
|
8
8
|
rules: import("./types/issues.js").Rules;
|
|
9
|
-
configurationHints: Set<
|
|
9
|
+
configurationHints: Set<import("./types/issues.js").ConfigurationHint>;
|
|
10
10
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
35
35
|
const isReportTypes = report.types || report.nsTypes || report.enumMembers;
|
|
36
36
|
const collector = new IssueCollector({ cwd, rules });
|
|
37
37
|
const enabledPluginsStore = new Map();
|
|
38
|
+
deputy.addIgnored(chief.config.ignoreBinaries, chief.config.ignoreDependencies);
|
|
38
39
|
debugLogObject('Included workspaces', workspaces);
|
|
39
40
|
const handleReferencedDependency = ({ specifier, containingFilePath, principal, workspace, }) => {
|
|
40
41
|
if (isInternal(specifier)) {
|
|
@@ -102,7 +103,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
102
103
|
});
|
|
103
104
|
await worker.init();
|
|
104
105
|
const sharedGlobOptions = { cwd, workingDir: dir, gitignore, ignore: worker.getIgnorePatterns() };
|
|
105
|
-
const entryPathsFromManifest = await getEntryPathFromManifest(dir, manifest);
|
|
106
|
+
const entryPathsFromManifest = await getEntryPathFromManifest(cwd, dir, manifest);
|
|
106
107
|
debugLogArray(`Found entry paths from manifest (${name})`, entryPathsFromManifest);
|
|
107
108
|
principal.addEntryPaths(entryPathsFromManifest);
|
|
108
109
|
if (isProduction) {
|
|
@@ -199,8 +200,8 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
199
200
|
for (const identifier of importItems.symbols) {
|
|
200
201
|
importedModule.symbols.add(identifier);
|
|
201
202
|
}
|
|
202
|
-
if (importItems.
|
|
203
|
-
importedModule.
|
|
203
|
+
if (importItems.isReExport) {
|
|
204
|
+
importedModule.isReExport = importItems.isReExport;
|
|
204
205
|
importedModule.isReExportedBy.add(filePath);
|
|
205
206
|
}
|
|
206
207
|
if (importItems.isDynamic) {
|
|
@@ -229,10 +230,10 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
229
230
|
const isExportedInEntryFile = (importedModule) => {
|
|
230
231
|
if (!importedModule)
|
|
231
232
|
return false;
|
|
232
|
-
const {
|
|
233
|
+
const { isReExport, isReExportedBy } = importedModule;
|
|
233
234
|
const { entryPaths } = principal;
|
|
234
235
|
const hasFile = (file) => entryPaths.has(file) || isExportedInEntryFile(importedSymbols.get(file));
|
|
235
|
-
return
|
|
236
|
+
return isReExport ? Array.from(isReExportedBy).some(hasFile) : false;
|
|
236
237
|
};
|
|
237
238
|
streamer.cast('Running async compilers...');
|
|
238
239
|
await principal.runAsyncCompilers();
|
|
@@ -262,6 +263,8 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
262
263
|
if (principal.isPublicExport(exportedItem))
|
|
263
264
|
continue;
|
|
264
265
|
if (importedModule.symbols.has(symbol)) {
|
|
266
|
+
if (importedModule.isReExport && isExportedInEntryFile(importedModule))
|
|
267
|
+
continue;
|
|
265
268
|
if (report.enumMembers && exportedItem.type === 'enum' && exportedItem.members) {
|
|
266
269
|
principal.findUnusedMembers(filePath, exportedItem.members).forEach(member => {
|
|
267
270
|
collector.addIssue({ type: 'enumMembers', filePath, symbol: member, parentSymbol: symbol });
|
|
@@ -274,7 +277,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
274
277
|
}
|
|
275
278
|
continue;
|
|
276
279
|
}
|
|
277
|
-
if (importedModule.
|
|
280
|
+
if (importedModule.isReExport || importedModule.isStar) {
|
|
278
281
|
const isReExportedByEntryFile = isExportedInEntryFile(importedModule);
|
|
279
282
|
if (!isReExportedByEntryFile && !principal.hasExternalReferences(filePath, exportedItem)) {
|
|
280
283
|
if (['enum', 'type', 'interface'].includes(exportedItem.type)) {
|
|
@@ -299,7 +302,8 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
299
302
|
}
|
|
300
303
|
}
|
|
301
304
|
if (isReportDependencies) {
|
|
302
|
-
const { dependencyIssues, devDependencyIssues
|
|
305
|
+
const { dependencyIssues, devDependencyIssues } = deputy.settleDependencyIssues();
|
|
306
|
+
const { configurationHints } = deputy.getConfigurationHints();
|
|
303
307
|
dependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
304
308
|
if (!isProduction)
|
|
305
309
|
devDependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
@@ -60,19 +60,15 @@ const resolveExtendsSpecifier = (specifier) => {
|
|
|
60
60
|
return;
|
|
61
61
|
return resolvePackageName(specifier.startsWith('plugin:') ? 'eslint-plugin' : 'eslint-config', pluginName);
|
|
62
62
|
};
|
|
63
|
-
const getImportPluginDependencies = (settings) => {
|
|
64
|
-
const knownKeys = ['typescript'];
|
|
65
|
-
if (Array.isArray(settings))
|
|
66
|
-
return [];
|
|
67
|
-
return Object.keys(settings)
|
|
68
|
-
.filter(key => key !== 'node')
|
|
69
|
-
.map(key => (knownKeys.includes(key) ? `eslint-import-resolver-${key}` : key));
|
|
70
|
-
};
|
|
71
63
|
const getDependenciesFromSettings = (settings = {}) => {
|
|
72
|
-
return compact(Object.entries(settings).
|
|
73
|
-
if (
|
|
74
|
-
return [
|
|
64
|
+
return compact(Object.entries(settings).flatMap(([settingKey, settings]) => {
|
|
65
|
+
if (settingKey === 'import/resolver') {
|
|
66
|
+
return (typeof settings === 'string' ? [settings] : Object.keys(settings))
|
|
67
|
+
.filter(key => key !== 'node')
|
|
68
|
+
.map(key => `eslint-import-resolver-${key}`);
|
|
69
|
+
}
|
|
70
|
+
if (settingKey === 'import/parsers') {
|
|
71
|
+
return typeof settings === 'string' ? [settings] : Object.keys(settings);
|
|
75
72
|
}
|
|
76
|
-
|
|
77
|
-
}, []));
|
|
73
|
+
}));
|
|
78
74
|
};
|
package/dist/types/config.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export interface Configuration {
|
|
|
27
27
|
include: string[];
|
|
28
28
|
exclude: string[];
|
|
29
29
|
ignore: NormalizedGlob;
|
|
30
|
+
ignoreBinaries: string[];
|
|
31
|
+
ignoreDependencies: string[];
|
|
30
32
|
ignoreWorkspaces: string[];
|
|
31
33
|
workspaces: Record<string, WorkspaceConfiguration>;
|
|
32
34
|
syncCompilers: SyncCompilers;
|
package/dist/types/imports.d.ts
CHANGED
|
@@ -20,32 +20,32 @@ export const getImportsAndExports = (sourceFile, options) => {
|
|
|
20
20
|
const scripts = new Set();
|
|
21
21
|
const importedInternalSymbols = new Map();
|
|
22
22
|
const visitors = getVisitors(sourceFile);
|
|
23
|
-
const addInternalImport = (
|
|
23
|
+
const addInternalImport = (options) => {
|
|
24
|
+
const { identifier, specifier, symbol, filePath, isDynamic, isReExport } = options;
|
|
24
25
|
const isStar = identifier === '*';
|
|
25
|
-
const isReExported = Boolean(isStar && !symbol);
|
|
26
26
|
const internalImport = getOrSet(internalImports, filePath, {
|
|
27
27
|
specifier,
|
|
28
28
|
isStar,
|
|
29
|
-
|
|
29
|
+
isReExport,
|
|
30
30
|
isReExportedBy: new Set(),
|
|
31
31
|
symbols: new Set(),
|
|
32
32
|
isDynamic,
|
|
33
33
|
});
|
|
34
|
-
if (
|
|
35
|
-
internalImport.
|
|
34
|
+
if (isReExport) {
|
|
35
|
+
internalImport.isReExport = isReExport;
|
|
36
36
|
internalImport.isReExportedBy.add(sourceFile.fileName);
|
|
37
37
|
}
|
|
38
38
|
if (isStar)
|
|
39
39
|
internalImport.isStar = isStar;
|
|
40
40
|
if (!isStar)
|
|
41
41
|
internalImport.symbols.add(identifier);
|
|
42
|
-
if (isStar && symbol)
|
|
42
|
+
if (isStar && symbol)
|
|
43
43
|
importedInternalSymbols.set(symbol, filePath);
|
|
44
|
-
}
|
|
45
44
|
if (isDynamic)
|
|
46
45
|
internalImport.isDynamic = isDynamic;
|
|
47
46
|
};
|
|
48
|
-
const addImport = (
|
|
47
|
+
const addImport = (options) => {
|
|
48
|
+
const { specifier, symbol, identifier = '__anonymous', isDynamic = false, isReExport = false } = options;
|
|
49
49
|
if (isBuiltin(specifier))
|
|
50
50
|
return;
|
|
51
51
|
const module = sourceFile.resolvedModules?.get(specifier, undefined);
|
|
@@ -54,7 +54,7 @@ export const getImportsAndExports = (sourceFile, options) => {
|
|
|
54
54
|
if (filePath) {
|
|
55
55
|
if (module.resolvedModule.isExternalLibraryImport) {
|
|
56
56
|
if (!isInNodeModules(filePath)) {
|
|
57
|
-
addInternalImport({ identifier, specifier, symbol, filePath, isDynamic });
|
|
57
|
+
addInternalImport({ identifier, specifier, symbol, filePath, isDynamic, isReExport });
|
|
58
58
|
}
|
|
59
59
|
else if (isDeclarationFileExtension(module.resolvedModule.extension)) {
|
|
60
60
|
externalImports.add(specifier);
|
|
@@ -64,7 +64,7 @@ export const getImportsAndExports = (sourceFile, options) => {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
else {
|
|
67
|
-
addInternalImport({ identifier, specifier, symbol, filePath, isDynamic });
|
|
67
|
+
addInternalImport({ identifier, specifier, symbol, filePath, isDynamic, isReExport });
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -4,16 +4,16 @@ export default visit(() => true, node => {
|
|
|
4
4
|
if (ts.isExportDeclaration(node)) {
|
|
5
5
|
if (node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) {
|
|
6
6
|
if (!node.exportClause) {
|
|
7
|
-
return { identifier: '*', specifier: node.moduleSpecifier.text };
|
|
7
|
+
return { identifier: '*', specifier: node.moduleSpecifier.text, isReExport: true };
|
|
8
8
|
}
|
|
9
9
|
else if (node.exportClause.kind === ts.SyntaxKind.NamespaceExport) {
|
|
10
|
-
return { identifier: '*', specifier: node.moduleSpecifier.text };
|
|
10
|
+
return { identifier: '*', specifier: node.moduleSpecifier.text, isReExport: true };
|
|
11
11
|
}
|
|
12
12
|
else {
|
|
13
13
|
const specifier = node.moduleSpecifier;
|
|
14
14
|
return node.exportClause.elements.map(element => {
|
|
15
15
|
const identifier = (element.propertyName ?? element.name).getText();
|
|
16
|
-
return { identifier, specifier: specifier.text };
|
|
16
|
+
return { identifier, specifier: specifier.text, isReExport: true };
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
}
|
package/dist/util/modules.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export declare const getPackageNameFromFilePath: (value: string) => string;
|
|
|
4
4
|
export declare const isDefinitelyTyped: (packageName: string) => boolean;
|
|
5
5
|
export declare const getDefinitelyTypedFor: (packageName: string) => string;
|
|
6
6
|
export declare const getPackageFromDefinitelyTyped: (typedDependency: string) => string;
|
|
7
|
-
export declare const getEntryPathFromManifest: (dir: string, manifest: PackageJson) => Promise<string[]>;
|
|
7
|
+
export declare const getEntryPathFromManifest: (cwd: string, dir: string, manifest: PackageJson) => Promise<string[]>;
|
package/dist/util/modules.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _glob } from './glob.js';
|
|
2
2
|
import { getStringValues } from './object.js';
|
|
3
3
|
import { toPosix } from './path.js';
|
|
4
4
|
export const getPackageNameFromModuleSpecifier = (moduleSpecifier) => {
|
|
@@ -26,7 +26,7 @@ export const getPackageFromDefinitelyTyped = (typedDependency) => {
|
|
|
26
26
|
}
|
|
27
27
|
return typedDependency;
|
|
28
28
|
};
|
|
29
|
-
export const getEntryPathFromManifest = (dir, manifest) => {
|
|
29
|
+
export const getEntryPathFromManifest = (cwd, dir, manifest) => {
|
|
30
30
|
const { main, bin, exports } = manifest;
|
|
31
31
|
const entryPaths = new Set();
|
|
32
32
|
if (typeof main === 'string')
|
|
@@ -45,5 +45,5 @@ export const getEntryPathFromManifest = (dir, manifest) => {
|
|
|
45
45
|
getStringValues(exports).forEach(item => entryPaths.add(item));
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
return
|
|
48
|
+
return _glob({ cwd, workingDir: dir, patterns: Array.from(entryPaths) });
|
|
49
49
|
};
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.
|
|
1
|
+
export declare const version = "2.10.1";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.
|
|
1
|
+
export const version = '2.10.1';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knip",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.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",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"summary": "^2.1.0",
|
|
58
58
|
"typescript": "^5.0.2",
|
|
59
59
|
"zod": "^3.20.6",
|
|
60
|
-
"zod-validation-error": "1.
|
|
60
|
+
"zod-validation-error": "1.3.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@jest/types": "29.5.0",
|
|
@@ -67,13 +67,13 @@
|
|
|
67
67
|
"@types/js-yaml": "4.0.5",
|
|
68
68
|
"@types/micromatch": "4.0.2",
|
|
69
69
|
"@types/minimist": "1.2.2",
|
|
70
|
-
"@types/node": "18.15.
|
|
71
|
-
"@types/npmcli__map-workspaces": "3.0.
|
|
70
|
+
"@types/node": "18.15.13",
|
|
71
|
+
"@types/npmcli__map-workspaces": "3.0.1",
|
|
72
72
|
"@types/webpack": "5.28.1",
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
74
|
-
"@typescript-eslint/parser": "5.
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "5.59.0",
|
|
74
|
+
"@typescript-eslint/parser": "5.59.0",
|
|
75
75
|
"c8": "7.13.0",
|
|
76
|
-
"eslint": "8.
|
|
76
|
+
"eslint": "8.39.0",
|
|
77
77
|
"eslint-import-resolver-typescript": "3.5.5",
|
|
78
78
|
"eslint-plugin-import": "2.27.5",
|
|
79
79
|
"eslint-plugin-n": "15.7.0",
|