knip 0.7.1 → 0.7.3
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 +236 -197
- package/dist/help.js +3 -3
- package/dist/util/debug.js +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
# ✂️ Knip
|
|
2
2
|
|
|
3
|
-
Knip
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
For comparison, ESLint finds unused variables inside files in isolation, but this will not be flagged:
|
|
3
|
+
Knip finds **unused files, dependencies and exports** in your JavaScript and TypeScript projects. Less code leads to
|
|
4
|
+
improved performance, less maintenance and easier refactorings.
|
|
7
5
|
|
|
8
6
|
```ts
|
|
9
7
|
export const myVar = true;
|
|
10
8
|
```
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
ESLint handles files in isolation, so the `export` keyword "blocks" further analysis. Unused files and dependencies will
|
|
11
|
+
also not be detected. You could think of Knip as going (far!) beyond the `no-unused-vars` rule of ESLint. Knip lints the
|
|
12
|
+
project as a whole (or parts of it).
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
It's only human to forget removing things that you no longer use. But how do you find out? Where to even start finding
|
|
15
|
+
things that can be removed?
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
The dots don't connect themselves. This is where Knip comes in:
|
|
18
|
+
|
|
19
|
+
- [x] Finds **unused files, dependencies and exports**.
|
|
19
20
|
- [x] Finds dependencies not listed in `package.json`.
|
|
21
|
+
- [x] Verifies that exported symbols are actually used in other files, even when part of an imported namespace.
|
|
22
|
+
- [x] Supports JavaScript inside TypeScript projects (`"allowJs": true`).
|
|
20
23
|
- [x] Finds duplicate exports of the same symbol.
|
|
21
|
-
- [x] Supports JavaScript
|
|
22
|
-
- [x]
|
|
23
|
-
- [x] Features multiple [reporters](#reporters) and supports [custom reporters](#custom-reporters).
|
|
24
|
+
- [x] Supports JavaScript ES Module-based projects without a `tsconfig.json`.
|
|
25
|
+
- [x] Features multiple [reporters][1] and supports [custom reporters][2].
|
|
24
26
|
|
|
25
|
-
Knip really shines in larger projects
|
|
26
|
-
|
|
27
|
-
results it's essential to configure entry files. A comparison with similar toos answers the question
|
|
28
|
-
[Why yet another unused file/dependency/export finder?](#why-yet-another-unused-filedependencyexport-finder)
|
|
27
|
+
Knip really shines in larger projects. A little bit of configuration will pay off, I promise. A comparison with similar
|
|
28
|
+
tools answers the question [why another unused file/dependency/export finder?][3]
|
|
29
29
|
|
|
30
30
|
Knip is a fresh take on keeping your projects clean & tidy!
|
|
31
31
|
|
|
32
|
-
[![An orange cow with scissors, Van Gogh style]
|
|
33
|
-
|
|
32
|
+
[![An orange cow with scissors, Van Gogh style][5]][4] <sup>_“An orange cow with scissors, Van Gogh style” - generated
|
|
33
|
+
with OpenAI_</sup>
|
|
34
34
|
|
|
35
35
|
## Installation
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
npm install -D knip
|
|
38
|
+
|
|
39
|
+
Knip requires at least Node.js v16.17 or v18. Knip is _cutting edge!_
|
|
40
40
|
|
|
41
41
|
## Usage
|
|
42
42
|
|
|
@@ -54,112 +54,127 @@ all files it should match them against, including potentially unused files.
|
|
|
54
54
|
|
|
55
55
|
Then run the checks:
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
npx knip
|
|
59
|
-
```
|
|
57
|
+
npx knip
|
|
60
58
|
|
|
61
59
|
This will analyze the project and output unused files, exports, types and duplicate exports.
|
|
62
60
|
|
|
63
|
-
Use `--include files` when configuring knip the first time for faster initial results.
|
|
64
|
-
|
|
65
61
|
## How It Works
|
|
66
62
|
|
|
67
63
|
Knip works by creating two sets of files:
|
|
68
64
|
|
|
69
|
-
1.
|
|
70
|
-
2.
|
|
71
|
-
3.
|
|
72
|
-
4.
|
|
73
|
-
|
|
74
|
-

|
|
65
|
+
1. Production code is the set of files resolved from the `entryFiles`.
|
|
66
|
+
2. They are matched against the set of `projectFiles`.
|
|
67
|
+
3. The subset of project files that is not production code will be reported as unused files (in red).
|
|
68
|
+
4. Then the production code (in blue) will be analyzed for unused exports.
|
|
75
69
|
|
|
76
|
-
|
|
70
|
+
![How it works][6]
|
|
77
71
|
|
|
78
72
|
## Options
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
$ knip
|
|
106
|
-
$ knip --
|
|
107
|
-
$ knip
|
|
108
|
-
$ knip --
|
|
109
|
-
$ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
|
|
110
|
-
|
|
111
|
-
More info: https://github.com/webpro/knip
|
|
112
|
-
```
|
|
74
|
+
❯ npx knip
|
|
75
|
+
knip [options]
|
|
76
|
+
|
|
77
|
+
Options:
|
|
78
|
+
-c/--config [file] Configuration file path (default: ./knip.json or package.json#knip)
|
|
79
|
+
-t/--tsConfig [file] TypeScript configuration path (default: ./tsconfig.json)
|
|
80
|
+
--dir Working directory (default: current working directory)
|
|
81
|
+
--include Report only listed issue type(s) (see below)
|
|
82
|
+
--exclude Exclude issue type(s) from report (see below)
|
|
83
|
+
--ignore Ignore files matching this glob pattern (can be set multiple times)
|
|
84
|
+
--no-gitignore Don't use .gitignore
|
|
85
|
+
--dev Include `devDependencies` in report(s)
|
|
86
|
+
--no-progress Don't show dynamic progress updates
|
|
87
|
+
--max-issues Maximum number of issues before non-zero exit code (default: 0)
|
|
88
|
+
--reporter Select reporter: symbols, compact, codeowners (default: symbols)
|
|
89
|
+
--reporter-options Pass extra options to the reporter (as JSON string, see example)
|
|
90
|
+
--jsdoc Enable JSDoc parsing, with options: public
|
|
91
|
+
--debug Show debug output
|
|
92
|
+
--debug-level Set verbosity of debug output (default: 1, max: 2)
|
|
93
|
+
|
|
94
|
+
Issue types: files, dependencies, unlisted, exports, nsExports, types, nsTypes, duplicates
|
|
95
|
+
|
|
96
|
+
Examples:
|
|
97
|
+
|
|
98
|
+
$ knip
|
|
99
|
+
$ knip --dir packages/client --include files
|
|
100
|
+
$ knip -c ./knip.js --reporter compact --jsdoc public
|
|
101
|
+
$ knip --ignore 'lib/**/*.ts' --ignore build
|
|
102
|
+
$ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
|
|
113
103
|
|
|
114
|
-
|
|
104
|
+
More info: https://github.com/webpro/knip
|
|
105
|
+
|
|
106
|
+
## Performance
|
|
107
|
+
|
|
108
|
+
🚀 Knip is considerably faster when only the `files` and/or `duplicates` types are included. Finding unused exports
|
|
109
|
+
requires deeper analysis (`exports`, `nsExports`, `types`, `nsTypes`). The following example commands do the same:
|
|
110
|
+
|
|
111
|
+
knip --include files --include duplicates
|
|
112
|
+
knip --include files,duplicates
|
|
115
113
|
|
|
116
114
|
## Reading the report
|
|
117
115
|
|
|
118
116
|
After analyzing all the files resolved from the `entryFiles` against the `projectFiles`, the report contains the
|
|
119
|
-
following
|
|
117
|
+
following types of issues:
|
|
120
118
|
|
|
121
119
|
- `files` - Unused files: did not find references to this file
|
|
122
120
|
- `dependencies` - Unused dependencies: did not find references to this dependency
|
|
123
|
-
- `unlisted` - Unlisted dependencies:
|
|
121
|
+
- `unlisted` - Unlisted dependencies: imported dependencies, but not listed in package.json (1)
|
|
124
122
|
- `exports` - Unused exports: did not find references to this exported variable
|
|
125
123
|
- `nsExports` - Unused exports in namespaces: did not find direct references to this exported variable (2)
|
|
126
124
|
- `types` - Unused types: did not find references to this exported type
|
|
127
125
|
- `nsTypes` - Unused types in namespaces: did not find direct references to this exported variable (2)
|
|
128
|
-
- `duplicates` - Duplicate exports: the same thing is exported more than once with different names
|
|
126
|
+
- `duplicates` - Duplicate exports: the same thing is exported more than once with different names from the same file
|
|
129
127
|
|
|
130
|
-
|
|
128
|
+
1. This may also include dependencies that could not be resolved properly (such as non-relative `local/dir/file.ts` not
|
|
129
|
+
and `local` not being in `node_modules`).
|
|
130
|
+
2. The variable or type is not referenced directly, and has become a member of a namespace. That's why Knip is not sure
|
|
131
|
+
whether this export can be removed, so please look into it:
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
whether this export can be removed, so please look into it:
|
|
133
|
+
You can `--include` or `--exclude` any of the types to slice & dice the report to your needs. Alternatively, they can be
|
|
134
|
+
added to the configuration (e.g. `"exclude": ["dependencies"]`).
|
|
135
135
|
|
|
136
136
|
## Now what?
|
|
137
137
|
|
|
138
138
|
As always, make sure to backup files or use Git before deleting files or making changes. Run tests to verify results.
|
|
139
139
|
|
|
140
|
-
- Unused files can be
|
|
140
|
+
- Unused files can be removed.
|
|
141
141
|
- Unused dependencies can be removed from `package.json`.
|
|
142
142
|
- Unlisted dependencies should be added to `package.json`.
|
|
143
|
-
- Unused exports and types: remove the `export` keyword in front of unused exports. Then you (or tools such as
|
|
144
|
-
can see whether the variable or type is used within
|
|
143
|
+
- Unused exports and types: remove the `export` keyword in front of unused exports. Then you (or tools such as the
|
|
144
|
+
TypeScript language server in VS Code and/or ESLint) can see whether the variable or type is used within the same
|
|
145
|
+
file. If this is not the case, it can be removed.
|
|
146
|
+
|
|
147
|
+
🔁 Repeat the process to reveal new unused files and exports. Sometimes it's so liberating to remove things!
|
|
148
|
+
|
|
149
|
+
## Production versus non-production code
|
|
145
150
|
|
|
146
|
-
|
|
151
|
+
Feels like you're getting too many false positives? Let's talk about `entryFiles` and `projectFiles`.
|
|
147
152
|
|
|
148
|
-
|
|
153
|
+
### Production code
|
|
149
154
|
|
|
150
|
-
The default configuration for Knip is very strict and targets production code.
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
The default configuration for Knip is very strict and targets production code. Non-production files such as tests should
|
|
156
|
+
not be part of the `entryFiles` and `projectFiles`. Here's why: test and other non-production files often import
|
|
157
|
+
production files, which will prevent the production files from being reported as unused. For best results:
|
|
153
158
|
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
- Include only production entry files to the `entryFiles`.
|
|
160
|
+
- Include only and all production files to the `projectFiles`.
|
|
161
|
+
- If necessary, add globs to exclude non-production files from the `projectFiles` (using negation pattern).
|
|
156
162
|
|
|
157
|
-
|
|
163
|
+
This will ensure Knip understands what production code can be removed.
|
|
158
164
|
|
|
159
|
-
|
|
165
|
+
### Non-production code
|
|
160
166
|
|
|
161
|
-
|
|
162
|
-
|
|
167
|
+
Non-production code includes files such as unit tests, end-to-end tests, tooling, scripts, Storybook stories, etc. Think
|
|
168
|
+
of it the same way as the convention to split `dependencies` and `devDependencies` in `package.json`.
|
|
169
|
+
|
|
170
|
+
To analyze the project as a whole:
|
|
171
|
+
|
|
172
|
+
- Include both production entry files and test files to the `entryFiles`.
|
|
173
|
+
- Include all production files to the `projectFiles`.
|
|
174
|
+
- If necessary, add globs for non-production files to the `projectFiles`.
|
|
175
|
+
- Set `dev: true` in the configuration or add `--dev` as a command line flag (to add `devDependencies`).
|
|
176
|
+
|
|
177
|
+
Here's an example:
|
|
163
178
|
|
|
164
179
|
```json
|
|
165
180
|
{
|
|
@@ -169,7 +184,7 @@ and add `dev: true` to a file named such as `knip.dev.json`:
|
|
|
169
184
|
}
|
|
170
185
|
```
|
|
171
186
|
|
|
172
|
-
Now use `-c knip.dev.json` to find unused files and exports for the
|
|
187
|
+
Now use `-c knip.dev.json` to find unused files, dependencies and exports for the project as a whole.
|
|
173
188
|
|
|
174
189
|
An alternative way to store `dev` configuration is in this example `package.json`:
|
|
175
190
|
|
|
@@ -190,7 +205,9 @@ An alternative way to store `dev` configuration is in this example `package.json
|
|
|
190
205
|
}
|
|
191
206
|
```
|
|
192
207
|
|
|
193
|
-
|
|
208
|
+
Using the `--dev` flag will now switch to the non-production analysis.
|
|
209
|
+
|
|
210
|
+
Depending on the complexity of the project, be aware that it might require some fine-tuning on your end.
|
|
194
211
|
|
|
195
212
|
## More configuration examples
|
|
196
213
|
|
|
@@ -198,7 +215,7 @@ This way, the `--dev` flag will use the `dev` options (and also add `devDependen
|
|
|
198
215
|
|
|
199
216
|
#### Separate packages
|
|
200
217
|
|
|
201
|
-
In repos with multiple (
|
|
218
|
+
In repos with multiple (publishable) packages, the `--dir` option comes in handy. With similar package structures, the
|
|
202
219
|
packages can be configured using globs:
|
|
203
220
|
|
|
204
221
|
```json
|
|
@@ -212,18 +229,18 @@ packages can be configured using globs:
|
|
|
212
229
|
|
|
213
230
|
Packages can also be explicitly configured per package directory.
|
|
214
231
|
|
|
215
|
-
To
|
|
232
|
+
To analyze the packages separately, using the matching pattern from the configuration file:
|
|
216
233
|
|
|
217
|
-
|
|
218
|
-
knip --dir packages/
|
|
219
|
-
knip --dir packages/services
|
|
220
|
-
```
|
|
234
|
+
knip --dir packages/client
|
|
235
|
+
knip --dir packages/services
|
|
221
236
|
|
|
222
237
|
#### Connected projects
|
|
223
238
|
|
|
224
|
-
A good example of a large project setup is a monorepo
|
|
225
|
-
|
|
226
|
-
|
|
239
|
+
A good example of a large project setup is a monorepo. Let's take an example (Nx) project configuration using Next.js,
|
|
240
|
+
Jest and Storybook, which has multiple apps and libs. They are not published separately and don't have their own
|
|
241
|
+
`package.json`.
|
|
242
|
+
|
|
243
|
+
This configuration file can also be a JavaScript file, which allows to add logic and/or comments (e.g. `knip.js`):
|
|
227
244
|
|
|
228
245
|
```js
|
|
229
246
|
const entryFiles = ['apps/**/pages/**/*.{js,ts,tsx}'];
|
|
@@ -245,8 +262,8 @@ const projectFiles = [
|
|
|
245
262
|
module.exports = { entryFiles, projectFiles };
|
|
246
263
|
```
|
|
247
264
|
|
|
248
|
-
This should give good results about unused files and exports for the monorepo. After the first run, the
|
|
249
|
-
can be tweaked further to the project structure.
|
|
265
|
+
This should give good results about unused files, dependencies and exports for the monorepo. After the first run, the
|
|
266
|
+
configuration can be tweaked further to the project structure.
|
|
250
267
|
|
|
251
268
|
## Reporters
|
|
252
269
|
|
|
@@ -281,95 +298,88 @@ The data can then be used to write issues to `stdout`, a JSON or CSV file, or se
|
|
|
281
298
|
|
|
282
299
|
The default reporter shows the sorted symbols first:
|
|
283
300
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
src/
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
type
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
ProductsList, default src/components/Products.tsx
|
|
307
|
-
```
|
|
301
|
+
$ knip
|
|
302
|
+
--- UNUSED FILES (2)
|
|
303
|
+
src/chat/helpers.ts
|
|
304
|
+
src/components/SideBar.tsx
|
|
305
|
+
--- UNUSED DEPENDENCIES (1)
|
|
306
|
+
moment
|
|
307
|
+
--- UNLISTED DEPENDENCIES (1)
|
|
308
|
+
react
|
|
309
|
+
--- UNUSED EXPORTS (5)
|
|
310
|
+
lowercaseFirstLetter src/common/src/string/index.ts
|
|
311
|
+
RegistrationBox src/components/Registration.tsx
|
|
312
|
+
clamp src/css.ts
|
|
313
|
+
restoreSession src/services/authentication.ts
|
|
314
|
+
PREFIX src/services/authentication.ts
|
|
315
|
+
--- UNUSED TYPES (4)
|
|
316
|
+
enum RegistrationServices src/components/Registration/registrationMachine.ts
|
|
317
|
+
type RegistrationAction src/components/Registration/registrationMachine.ts
|
|
318
|
+
type ComponentProps src/components/Registration.tsx
|
|
319
|
+
interface ProductDetail src/types/Product.ts
|
|
320
|
+
--- DUPLICATE EXPORTS (2)
|
|
321
|
+
Registration, default src/components/Registration.tsx
|
|
322
|
+
ProductsList, default src/components/Products.tsx
|
|
308
323
|
|
|
309
324
|
#### Compact
|
|
310
325
|
|
|
311
326
|
The compact reporter shows the sorted files first, and then a list of symbols:
|
|
312
327
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
src/
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
src/
|
|
324
|
-
src/
|
|
325
|
-
src/
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
src/components/Registration
|
|
329
|
-
src/
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
src/components/
|
|
333
|
-
src/components/Products.tsx: ProductsList, default
|
|
334
|
-
```
|
|
328
|
+
$ knip --reporter compact
|
|
329
|
+
--- UNUSED FILES (2)
|
|
330
|
+
src/chat/helpers.ts
|
|
331
|
+
src/components/SideBar.tsx
|
|
332
|
+
--- UNUSED DEPENDENCIES (1)
|
|
333
|
+
moment
|
|
334
|
+
--- UNLISTED DEPENDENCIES (1)
|
|
335
|
+
react
|
|
336
|
+
--- UNUSED EXPORTS (4)
|
|
337
|
+
src/common/src/string/index.ts: lowercaseFirstLetter
|
|
338
|
+
src/components/Registration.tsx: RegistrationBox
|
|
339
|
+
src/css.ts: clamp
|
|
340
|
+
src/services/authentication.ts: restoreSession, PREFIX
|
|
341
|
+
--- UNUSED TYPES (3)
|
|
342
|
+
src/components/Registration/registrationMachine.ts: RegistrationServices, RegistrationAction
|
|
343
|
+
src/components/Registration.tsx: ComponentProps
|
|
344
|
+
src/types/Product.ts: ProductDetail
|
|
345
|
+
--- DUPLICATE EXPORTS (2)
|
|
346
|
+
src/components/Registration.tsx: Registration, default
|
|
347
|
+
src/components/Products.tsx: ProductsList, default
|
|
335
348
|
|
|
336
349
|
#### Code Owners
|
|
337
350
|
|
|
338
351
|
The `codeowners` reporter is like `compact`, but shows the sorted code owners (according to `.github/CODEOWNERS`) first:
|
|
339
352
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
@org/
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
@org/
|
|
351
|
-
@org/owner src/
|
|
352
|
-
@org/owner src/
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
@org/owner src/components/Registration
|
|
356
|
-
@org/owner src/
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
@org/owner src/components/
|
|
360
|
-
@org/owner src/components/Products.tsx: ProductsList, default
|
|
361
|
-
```
|
|
353
|
+
$ knip --reporter codeowners
|
|
354
|
+
--- UNUSED FILES (2)
|
|
355
|
+
@org/team src/chat/helpers.ts
|
|
356
|
+
@org/owner src/components/SideBar.tsx
|
|
357
|
+
--- UNUSED DEPENDENCIES (1)
|
|
358
|
+
@org/admin moment
|
|
359
|
+
--- UNLISTED DEPENDENCIES (1)
|
|
360
|
+
@org/owner src/components/Registration.tsx react
|
|
361
|
+
--- UNUSED EXPORTS (4)
|
|
362
|
+
@org/team src/common/src/string/index.ts: lowercaseFirstLetter
|
|
363
|
+
@org/owner src/components/Registration.tsx: RegistrationBox
|
|
364
|
+
@org/owner src/css.ts: clamp
|
|
365
|
+
@org/owner src/services/authentication.ts: restoreSession, PREFIX
|
|
366
|
+
--- UNUSED TYPES (3)
|
|
367
|
+
@org/owner src/components/Registration/registrationMachine.ts: RegistrationServices, RegistrationAction
|
|
368
|
+
@org/owner src/components/Registration.tsx: ComponentProps
|
|
369
|
+
@org/owner src/types/Product.ts: ProductDetail
|
|
370
|
+
--- DUPLICATE EXPORTS (2)
|
|
371
|
+
@org/owner src/components/Registration.tsx: Registration, default
|
|
372
|
+
@org/owner src/components/Products.tsx: ProductsList, default
|
|
362
373
|
|
|
363
374
|
The owner of `package.json` is considered the owner of unused (dev) dependencies.
|
|
364
375
|
|
|
365
376
|
Use `--reporter-options '{"path":".github/CODEOWNERS"}'` to pass another location for the code owners file.
|
|
366
377
|
|
|
367
|
-
##
|
|
378
|
+
## Really, another unused file/dependency/export finder?
|
|
379
|
+
|
|
380
|
+
There are already some great packages available if you want to find unused dependencies OR unused exports.
|
|
368
381
|
|
|
369
|
-
|
|
370
|
-
exports is not trivial. Repositories don't seem to get any smaller and with the rise of monorepos even more so. Tools
|
|
371
|
-
like this need to analyze potentially many and/or large files, which is memory and time-consuming. Although I normally
|
|
372
|
-
try to stick to the Unix philosophy, here I believe it's efficient to merge these issue reports into a single tool. When
|
|
382
|
+
Although I love the Unix philosophy, here I believe it's efficient to handle multiple concerns in a single tool. When
|
|
373
383
|
building a dependency graph of the project, an abstract syntax tree for each file, and traversing all of this, why not
|
|
374
384
|
collect the various issues in one go?
|
|
375
385
|
|
|
@@ -377,35 +387,64 @@ collect the various issues in one go?
|
|
|
377
387
|
|
|
378
388
|
This table is a work in progress, but here's a first impression. Based on their docs (please report any mistakes):
|
|
379
389
|
|
|
380
|
-
| Feature
|
|
381
|
-
|
|
|
382
|
-
| Unused files
|
|
383
|
-
| Unused dependencies
|
|
384
|
-
| Unlisted dependencies
|
|
385
|
-
| Custom dependency resolvers
|
|
386
|
-
| Unused exports
|
|
387
|
-
| Duplicate exports
|
|
388
|
-
| Search namespaces
|
|
389
|
-
| Custom reporters
|
|
390
|
-
| Pure JavaScript/ESM
|
|
391
|
-
| Configure entry files
|
|
392
|
-
| Support
|
|
393
|
-
| ESLint plugin available
|
|
390
|
+
| Feature | **knip** | [depcheck][7] | [unimported][8] | [ts-unused-exports][9] | [ts-prune][10] | [find-unused-exports][11] |
|
|
391
|
+
| --------------------------------- | :------: | :-----------: | :-------------: | :--------------------: | :------------: | :-----------------------: |
|
|
392
|
+
| Unused files | ✅ | - | ✅ | - | - | - |
|
|
393
|
+
| Unused dependencies | ✅ | ✅ | ✅ | - | - | - |
|
|
394
|
+
| Unlisted dependencies | ✅ | ✅ | ✅ | - | - | - |
|
|
395
|
+
| [Custom dependency resolvers][12] | ❌ | ✅ | ❌ | - | - | - |
|
|
396
|
+
| Unused exports | ✅ | - | - | ✅ | ✅ | ✅ |
|
|
397
|
+
| Duplicate exports | ✅ | - | - | ❌ | ❌ | ❌ |
|
|
398
|
+
| Search namespaces | ✅ | - | - | ✅ | ❌ | ❌ |
|
|
399
|
+
| Custom reporters | ✅ | - | - | - | - | - |
|
|
400
|
+
| Pure JavaScript/ESM | ✅ | ✅ | ✅ | - | - | ✅ |
|
|
401
|
+
| Configure entry files | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
|
402
|
+
| [Support monorepos][13] | 🟠 | - | - | - | - | - |
|
|
403
|
+
| ESLint plugin available | - | - | - | ✅ | - | - |
|
|
394
404
|
|
|
395
405
|
✅ = Supported, ❌ = Not supported, - = Out of scope
|
|
396
406
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
407
|
+
## Monorepos
|
|
408
|
+
|
|
409
|
+
Knip wants to [support monorepos][14] properly, the first steps in this direction are implemented.
|
|
410
|
+
|
|
411
|
+
## Custom dependency resolvers
|
|
412
|
+
|
|
413
|
+
Using a string like `"plugin:cypress/recommended"` in the `extends` property of a `.eslintrc.json` in a package
|
|
414
|
+
directory of a monorepo is nice for DX. But Knip will need some help to find it and to understand this _resolves to_ the
|
|
415
|
+
`eslint-plugin-cypress` _dependency_. Or see it is not listed in `package.json`. Or that the dependency is still listed,
|
|
416
|
+
but no longer in use. Many popular projects reference plugins in similar ways, such as Babel, Webpack and Storybook.
|
|
417
|
+
|
|
418
|
+
Big compliments to [depcheck][15] which already does this! They call this "specials". [Knip has this ambition][16], too.
|
|
419
|
+
|
|
420
|
+
unimported is strict in this regard and works based on production files and `dependencies`, so does not have custom
|
|
421
|
+
dependency resolvers which are usually only needed for `devDependencies`.
|
|
422
|
+
|
|
423
|
+
## TypeScript language services
|
|
424
|
+
|
|
425
|
+
TypeScript language services could play a major role in most of the "unused" areas, as they have an overview of the
|
|
426
|
+
project as a whole. This powers things in VS Code like "Find references" or the "Module "./some" declares 'Thing'
|
|
427
|
+
locally, but it is not exported" message. I think features like "duplicate exports" or "custom dependency resolvers" are
|
|
428
|
+
userland territory, much like code linters.
|
|
400
429
|
|
|
401
430
|
## Knip?!
|
|
402
431
|
|
|
403
432
|
Knip is Dutch for a "cut". A Dutch expression is "to be ge**knip**t for something", which means to be perfectly suited
|
|
404
433
|
for the job. I'm motivated to make knip perfectly suited for the job of cutting projects to perfection! ✂️
|
|
405
434
|
|
|
406
|
-
[1]:
|
|
407
|
-
[2]:
|
|
408
|
-
[3]:
|
|
409
|
-
[4]: https://
|
|
410
|
-
[5]:
|
|
411
|
-
[6]:
|
|
435
|
+
[1]: #reporters
|
|
436
|
+
[2]: #custom-reporters
|
|
437
|
+
[3]: #why-yet-another-unused-filedependencyexport-finder
|
|
438
|
+
[4]: https://labs.openai.com/s/xZQACaLepaKya0PRUPtIN5dC
|
|
439
|
+
[5]: ./assets/cow-with-orange-scissors-van-gogh-style.webp
|
|
440
|
+
[6]: ./assets/how-it-works.drawio.svg
|
|
441
|
+
[7]: https://github.com/depcheck/depcheck
|
|
442
|
+
[8]: https://github.com/smeijer/unimported
|
|
443
|
+
[9]: https://github.com/pzavolinsky/ts-unused-exports
|
|
444
|
+
[10]: https://github.com/nadeesha/ts-prune
|
|
445
|
+
[11]: https://github.com/jaydenseric/find-unused-exports
|
|
446
|
+
[12]: #custom-dependency-resolvers
|
|
447
|
+
[13]: #monorepos-1
|
|
448
|
+
[14]: #monorepos
|
|
449
|
+
[15]: https://github.com/depcheck/depcheck#special
|
|
450
|
+
[16]: https://github.com/webpro/knip/issues/7
|
package/dist/help.js
CHANGED
|
@@ -8,8 +8,8 @@ Options:
|
|
|
8
8
|
-c/--config [file] Configuration file path (default: ./knip.json or package.json#knip)
|
|
9
9
|
-t/--tsConfig [file] TypeScript configuration path (default: ./tsconfig.json)
|
|
10
10
|
--dir Working directory (default: current working directory)
|
|
11
|
-
--include Report only listed issue
|
|
12
|
-
--exclude Exclude issue
|
|
11
|
+
--include Report only listed issue type(s) (see below)
|
|
12
|
+
--exclude Exclude issue type(s) from report (see below)
|
|
13
13
|
--ignore Ignore files matching this glob pattern (can be set multiple times)
|
|
14
14
|
--no-gitignore Don't use .gitignore
|
|
15
15
|
--dev Include \`devDependencies\` in report(s)
|
|
@@ -21,7 +21,7 @@ Options:
|
|
|
21
21
|
--debug Show debug output
|
|
22
22
|
--debug-level Set verbosity of debug output (default: 1, max: 2)
|
|
23
23
|
|
|
24
|
-
Issue
|
|
24
|
+
Issue types: files, dependencies, unlisted, exports, nsExports, types, nsTypes, duplicates
|
|
25
25
|
|
|
26
26
|
Examples:
|
|
27
27
|
|
package/dist/util/debug.js
CHANGED
|
@@ -9,7 +9,7 @@ const logArray = (collection) => console.log(node_util_1.default.inspect(collect
|
|
|
9
9
|
const debugLogObject = (config, minimumLevel, name, obj) => {
|
|
10
10
|
if (minimumLevel > config.debug.level)
|
|
11
11
|
return;
|
|
12
|
-
console.log(`[
|
|
12
|
+
console.log(`[knip] ${name}:`);
|
|
13
13
|
console.log(node_util_1.default.inspect(obj, { depth: null, colors: true }));
|
|
14
14
|
};
|
|
15
15
|
exports.debugLogObject = debugLogObject;
|
|
@@ -18,11 +18,11 @@ const debugLogFiles = (config, minimumLevel, name, filePaths) => {
|
|
|
18
18
|
return;
|
|
19
19
|
const { debug } = config;
|
|
20
20
|
if (debug.level > 1) {
|
|
21
|
-
console.debug(`[
|
|
21
|
+
console.debug(`[knip] ${name} (${filePaths.length}):`);
|
|
22
22
|
logArray(filePaths);
|
|
23
23
|
}
|
|
24
24
|
else {
|
|
25
|
-
console.debug(`[
|
|
25
|
+
console.debug(`[knip] ${name} (${filePaths.length})`);
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
exports.debugLogFiles = debugLogFiles;
|
|
@@ -31,11 +31,11 @@ const debugLogSourceFiles = (config, minimumLevel, name, sourceFiles) => {
|
|
|
31
31
|
return;
|
|
32
32
|
const { debug } = config;
|
|
33
33
|
if (debug.level > 1) {
|
|
34
|
-
console.debug(`[
|
|
34
|
+
console.debug(`[knip] ${name} (${sourceFiles.length}):`);
|
|
35
35
|
logArray(sourceFiles.map(sourceFile => sourceFile.getFilePath()));
|
|
36
36
|
}
|
|
37
37
|
else {
|
|
38
|
-
console.debug(`[
|
|
38
|
+
console.debug(`[knip] ${name} (${sourceFiles.length})`);
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
exports.debugLogSourceFiles = debugLogSourceFiles;
|
|
@@ -44,11 +44,11 @@ const debugLogDiff = (config, minimumLevel, name, arrA, arrB) => {
|
|
|
44
44
|
return;
|
|
45
45
|
const onlyInA = arrA.filter(itemA => !arrB.includes(itemA)).sort();
|
|
46
46
|
const onlyInB = arrB.filter(itemB => !arrA.includes(itemB)).sort();
|
|
47
|
-
console.log(`[
|
|
48
|
-
console.log(`[
|
|
47
|
+
console.log(`[knip] ${name}`);
|
|
48
|
+
console.log(`[knip] Only in left:`);
|
|
49
49
|
logArray(onlyInA);
|
|
50
50
|
console.log();
|
|
51
|
-
console.log(`[
|
|
51
|
+
console.log(`[knip] Only in right:`);
|
|
52
52
|
logArray(onlyInB);
|
|
53
53
|
};
|
|
54
54
|
exports.debugLogDiff = debugLogDiff;
|