@knip/mcp 0.0.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 +53 -0
- package/docs/blog/brief-history.md +30 -0
- package/docs/blog/knip-v3.mdx +88 -0
- package/docs/blog/knip-v4.mdx +149 -0
- package/docs/blog/knip-v5.mdx +190 -0
- package/docs/blog/migration-to-v1.md +65 -0
- package/docs/blog/release-notes-v2.md +46 -0
- package/docs/blog/slim-down-to-speed-up.md +269 -0
- package/docs/blog/state-of-knip.md +191 -0
- package/docs/blog/two-years.mdx +107 -0
- package/docs/docs/blog/brief-history.md +30 -0
- package/docs/docs/blog/for-editors-and-agents.md +109 -0
- package/docs/docs/blog/knip-v3.mdx +88 -0
- package/docs/docs/blog/knip-v4.mdx +149 -0
- package/docs/docs/blog/knip-v5.mdx +190 -0
- package/docs/docs/blog/migration-to-v1.md +65 -0
- package/docs/docs/blog/release-notes-v2.md +46 -0
- package/docs/docs/blog/slim-down-to-speed-up.md +269 -0
- package/docs/docs/blog/state-of-knip.md +191 -0
- package/docs/docs/blog/two-years.mdx +107 -0
- package/docs/docs/explanations/comparison-and-migration.md +129 -0
- package/docs/docs/explanations/entry-files.md +70 -0
- package/docs/docs/explanations/plugins.md +318 -0
- package/docs/docs/explanations/why-use-knip.md +128 -0
- package/docs/docs/features/auto-fix.mdx +333 -0
- package/docs/docs/features/compilers.md +172 -0
- package/docs/docs/features/integrated-monorepos.md +52 -0
- package/docs/docs/features/monorepos-and-workspaces.md +134 -0
- package/docs/docs/features/production-mode.md +95 -0
- package/docs/docs/features/reporters.md +302 -0
- package/docs/docs/features/rules-and-filters.md +102 -0
- package/docs/docs/features/script-parser.md +156 -0
- package/docs/docs/features/source-mapping.md +100 -0
- package/docs/docs/guides/configuring-project-files.md +205 -0
- package/docs/docs/guides/contributing.md +24 -0
- package/docs/docs/guides/handling-issues.mdx +646 -0
- package/docs/docs/guides/issue-reproduction.md +94 -0
- package/docs/docs/guides/namespace-imports.md +125 -0
- package/docs/docs/guides/performance.md +97 -0
- package/docs/docs/guides/troubleshooting.md +127 -0
- package/docs/docs/guides/using-knip-in-ci.md +54 -0
- package/docs/docs/guides/working-with-commonjs.md +72 -0
- package/docs/docs/index.mdx +160 -0
- package/docs/docs/overview/configuration.md +104 -0
- package/docs/docs/overview/features.md +66 -0
- package/docs/docs/overview/getting-started.mdx +195 -0
- package/docs/docs/overview/screenshots-videos.md +42 -0
- package/docs/docs/playground.mdx +38 -0
- package/docs/docs/reference/cli.md +481 -0
- package/docs/docs/reference/configuration.md +413 -0
- package/docs/docs/reference/dynamic-configuration.mdx +72 -0
- package/docs/docs/reference/faq.md +441 -0
- package/docs/docs/reference/issue-types.md +43 -0
- package/docs/docs/reference/jsdoc-tsdoc-tags.md +122 -0
- package/docs/docs/reference/known-issues.md +64 -0
- package/docs/docs/reference/plugins/.gitkeep +0 -0
- package/docs/docs/reference/plugins.md +238 -0
- package/docs/docs/reference/related-tooling.md +46 -0
- package/docs/docs/sponsors.mdx +65 -0
- package/docs/docs/typescript/unused-dependencies.md +86 -0
- package/docs/docs/typescript/unused-exports.md +87 -0
- package/docs/docs/writing-a-plugin/argument-parsing.md +202 -0
- package/docs/docs/writing-a-plugin/index.md +376 -0
- package/docs/docs/writing-a-plugin/inputs.md +162 -0
- package/docs/explanations/comparison-and-migration.md +129 -0
- package/docs/explanations/entry-files.md +70 -0
- package/docs/explanations/plugins.md +318 -0
- package/docs/explanations/why-use-knip.md +128 -0
- package/docs/features/auto-fix.mdx +333 -0
- package/docs/features/compilers.md +172 -0
- package/docs/features/integrated-monorepos.md +52 -0
- package/docs/features/monorepos-and-workspaces.md +134 -0
- package/docs/features/production-mode.md +95 -0
- package/docs/features/reporters.md +302 -0
- package/docs/features/rules-and-filters.md +102 -0
- package/docs/features/script-parser.md +156 -0
- package/docs/features/source-mapping.md +100 -0
- package/docs/guides/configuring-project-files.md +205 -0
- package/docs/guides/contributing.md +24 -0
- package/docs/guides/handling-issues.mdx +646 -0
- package/docs/guides/issue-reproduction.md +94 -0
- package/docs/guides/namespace-imports.md +125 -0
- package/docs/guides/performance.md +97 -0
- package/docs/guides/troubleshooting.md +127 -0
- package/docs/guides/using-knip-in-ci.md +54 -0
- package/docs/guides/working-with-commonjs.md +72 -0
- package/docs/index.mdx +156 -0
- package/docs/overview/configuration.md +104 -0
- package/docs/overview/features.md +66 -0
- package/docs/overview/getting-started.mdx +195 -0
- package/docs/overview/screenshots-videos.md +42 -0
- package/docs/playground.mdx +38 -0
- package/docs/reference/cli.md +481 -0
- package/docs/reference/configuration.md +413 -0
- package/docs/reference/dynamic-configuration.mdx +72 -0
- package/docs/reference/faq.md +441 -0
- package/docs/reference/issue-types.md +43 -0
- package/docs/reference/jsdoc-tsdoc-tags.md +122 -0
- package/docs/reference/known-issues.md +64 -0
- package/docs/reference/plugins/.gitkeep +0 -0
- package/docs/reference/plugins.md +238 -0
- package/docs/reference/related-tooling.md +46 -0
- package/docs/sponsors.mdx +65 -0
- package/docs/typescript/unused-dependencies.md +86 -0
- package/docs/typescript/unused-exports.md +87 -0
- package/docs/writing-a-plugin/argument-parsing.md +202 -0
- package/docs/writing-a-plugin/index.md +376 -0
- package/docs/writing-a-plugin/inputs.md +162 -0
- package/license +15 -0
- package/package.json +38 -0
- package/src/cli.js +13 -0
- package/src/curated-resources.js +62 -0
- package/src/server.js +129 -0
- package/src/texts.js +76 -0
- package/src/tools.js +68 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Why use Knip?
|
|
3
|
+
sidebar:
|
|
4
|
+
order: 3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The value of removing clutter is clear, but finding it manually is tedious. This
|
|
8
|
+
is where Knip comes in: comprehensive and accurate results at any scale.
|
|
9
|
+
|
|
10
|
+
:::tip[TL;DR]
|
|
11
|
+
|
|
12
|
+
Knip finds and fixes unused dependencies, exports and files.
|
|
13
|
+
|
|
14
|
+
Deep analysis from [fine-grained entry points][1] based on the actual frameworks
|
|
15
|
+
and tooling in [(mono)repos][2] for accurate and actionable results. Advanced
|
|
16
|
+
features for maximum coverage:
|
|
17
|
+
|
|
18
|
+
- [Custom module resolution][3]
|
|
19
|
+
- [Configuration file parsers][4]
|
|
20
|
+
- [Advanced shell script parser][5]
|
|
21
|
+
- [Built-in and custom compilers][6]
|
|
22
|
+
- [Auto-fix most issues][7]
|
|
23
|
+
|
|
24
|
+
:::
|
|
25
|
+
|
|
26
|
+
## Less is more
|
|
27
|
+
|
|
28
|
+
There are plenty of reasons to delete unused files, dependencies and "dead
|
|
29
|
+
code":
|
|
30
|
+
|
|
31
|
+
- Easier maintenance: things are easier to manage when there's less of it.
|
|
32
|
+
- Improved performance: startup time, build time and/or bundle size can be
|
|
33
|
+
negatively impacted when unused code, files and/or dependencies are included.
|
|
34
|
+
Relying on tree-shaking when bundling code helps, but it's not a silver
|
|
35
|
+
bullet.
|
|
36
|
+
- Easier onboarding: there should be no doubts about whether files, dependencies
|
|
37
|
+
and exports are actually in use or not. Especially for people new to the
|
|
38
|
+
project and/or taking over responsibilities this is harder to grasp.
|
|
39
|
+
- Prevent regressions: tools like TypeScript, ESLint and Prettier do all sorts
|
|
40
|
+
of checks and linting to report violations and prevent regressions. Knip does
|
|
41
|
+
the same for dependencies, exports and files that are obsolete.
|
|
42
|
+
- Keeping dead code around has a negative value on readability, as it can be
|
|
43
|
+
misleading and distracting. Even if it serves no purpose it will need to be
|
|
44
|
+
maintained (source: [Safe dead code removal → YAGNI][8]).
|
|
45
|
+
- Also see [Why are unused dependencies a problem?][9] and [Why are unused
|
|
46
|
+
exports a problem?][10].
|
|
47
|
+
|
|
48
|
+
## Automation
|
|
49
|
+
|
|
50
|
+
Code and dependency management is usually not the most exciting task for most of
|
|
51
|
+
us. Knip's mission is to automate finding clutter. This is such a tedious job if
|
|
52
|
+
you were to do it manually, and where would you even start? Knip applies many
|
|
53
|
+
techniques and heuristics to report what you need and save a lot of time.
|
|
54
|
+
|
|
55
|
+
:::tip
|
|
56
|
+
|
|
57
|
+
Knip not only finds clutter, it can also [remove clutter][7]!
|
|
58
|
+
|
|
59
|
+
Use Knip next to a linter like ESLint or Biome: after removing unused variables
|
|
60
|
+
inside files, Knip might find even more unused code. Rinse and repeat!
|
|
61
|
+
|
|
62
|
+
:::
|
|
63
|
+
|
|
64
|
+
## Comprehensive
|
|
65
|
+
|
|
66
|
+
You can use alternative tools that do the same. However, the advantage of a
|
|
67
|
+
strategy that addresses all of dependencies, exports and files is in their
|
|
68
|
+
synergy:
|
|
69
|
+
|
|
70
|
+
- Utilizing plugins to find their dependencies includes the capacity to find
|
|
71
|
+
additional entry and configuration files. This results in more resolved and
|
|
72
|
+
used files. Better coverage gives better insights into unused files and
|
|
73
|
+
exports.
|
|
74
|
+
- Analyzing more files reveals more unused exports and dependency usage,
|
|
75
|
+
refining the list of both unused and unlisted dependencies.
|
|
76
|
+
- This approach is amplified in a monorepo setting. In fact, files and internal
|
|
77
|
+
dependencies can recursively reference each other (across workspaces).
|
|
78
|
+
|
|
79
|
+
## Greenfield or Legacy
|
|
80
|
+
|
|
81
|
+
Installing Knip in greenfield projects ensures the project stays neat and tidy
|
|
82
|
+
from the start. Add it to your CI workflow and prevent any regressions from
|
|
83
|
+
entering the codebase.
|
|
84
|
+
|
|
85
|
+
:::tip
|
|
86
|
+
|
|
87
|
+
Use Knip in a CI environment to prevent future regressions.
|
|
88
|
+
|
|
89
|
+
:::
|
|
90
|
+
|
|
91
|
+
In large and/or legacy projects, Knip may report false positives and require
|
|
92
|
+
some configuration. It aims to be a great assistant when cleaning up parts of
|
|
93
|
+
the project or doing large refactors. Even a list of results with a few false
|
|
94
|
+
positives is many times better and faster than if you were to do it manually.
|
|
95
|
+
|
|
96
|
+
## Unobtrusive
|
|
97
|
+
|
|
98
|
+
Knip does not introduce new syntax for you to learn. This may sound obvious, but
|
|
99
|
+
consider comments like the following:
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
// eslint-disable-next-line
|
|
103
|
+
// prettier-ignore
|
|
104
|
+
// @ts-expect-error
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Maybe you wonder why Knip does not have similar comments like `// knip-ignore`
|
|
108
|
+
so you can get rid of false positives? A variety of reasons:
|
|
109
|
+
|
|
110
|
+
1. A false positive may be a bug in Knip, and should be reported, not dismissed.
|
|
111
|
+
2. Instead of proprietary comments, use [standardized annotations][11] that also
|
|
112
|
+
serve as documentation.
|
|
113
|
+
3. In the event you want to remove Knip, just uninstall `knip` without having to
|
|
114
|
+
remove useless comments scattered throughout the codebase.
|
|
115
|
+
|
|
116
|
+
Tip: use `@lintignore` in JSDoc comments, so other linters can use the same.
|
|
117
|
+
|
|
118
|
+
[1]: ./entry-files.md
|
|
119
|
+
[2]: ../features/monorepos-and-workspaces.md
|
|
120
|
+
[3]: ../reference/faq.md#why-doesnt-knip-use-an-existing-module-resolver
|
|
121
|
+
[4]: ./plugins.md#configuration-files
|
|
122
|
+
[5]: ../features/script-parser.md
|
|
123
|
+
[6]: ../features/compilers.md
|
|
124
|
+
[7]: ../features/auto-fix.mdx
|
|
125
|
+
[8]: https://jfmengels.net/safe-dead-code-removal/#yagni-you-arent-gonna-need-it
|
|
126
|
+
[9]: ../typescript/unused-dependencies.md#why-are-unused-dependencies-a-problem
|
|
127
|
+
[10]: ../typescript/unused-exports.md#why-are-unused-exports-a-problem
|
|
128
|
+
[11]: ../reference/jsdoc-tsdoc-tags.md
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Auto-fix
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
|
6
|
+
import { Badge } from '@astrojs/starlight/components';
|
|
7
|
+
|
|
8
|
+
Run Knip as you normally would, and if the report looks good then run it again
|
|
9
|
+
with the `--fix` flag to let Knip automatically apply fixes. It fixes the
|
|
10
|
+
following [issue types][1]:
|
|
11
|
+
|
|
12
|
+
- Remove `export` keyword for unused exports and exported types
|
|
13
|
+
- Remove `export default` keywords for unused default exports
|
|
14
|
+
- Remove exports, re-exports and exported types
|
|
15
|
+
- Remove unused enum members
|
|
16
|
+
- Remove unused class members (disabled by default)
|
|
17
|
+
- Remove unused `dependencies` and `devDependencies` from `package.json`
|
|
18
|
+
- Remove unused files
|
|
19
|
+
|
|
20
|
+
:::caution
|
|
21
|
+
|
|
22
|
+
Use a VCS (version control system) like Git to review and undo changes as
|
|
23
|
+
necessary.
|
|
24
|
+
|
|
25
|
+
:::
|
|
26
|
+
|
|
27
|
+
## Flags
|
|
28
|
+
|
|
29
|
+
### Fix
|
|
30
|
+
|
|
31
|
+
Add the `--fix` flag to remove unused exports and dependencies:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
knip --fix
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Add `--allow-remove-files` to allow Knip to remove unused files:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
knip --fix --allow-remove-files
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Use `--fix-type` to fix only specific issue types:
|
|
44
|
+
|
|
45
|
+
- `files`
|
|
46
|
+
- `exports`
|
|
47
|
+
- `types`
|
|
48
|
+
- `dependencies`
|
|
49
|
+
- `catalog`
|
|
50
|
+
|
|
51
|
+
Example:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
knip --fix-type exports,types
|
|
55
|
+
knip --fix-type exports --fix-type types # same as above
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Format
|
|
59
|
+
|
|
60
|
+
Add `--format` to format the modified files using the formatter and
|
|
61
|
+
configuration in your project. Supports Biome, deno fmt, dprint and Prettier
|
|
62
|
+
(using [Formatly][2]):
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
knip --fix --format
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Demo
|
|
69
|
+
|
|
70
|
+
<video controls width="500">
|
|
71
|
+
<source src="/screenshots/fix.mp4" type="video/mp4" />
|
|
72
|
+
|
|
73
|
+
<source src="/screenshots/fix.webm" type="video/webm" />
|
|
74
|
+
</video>
|
|
75
|
+
|
|
76
|
+
## Post-fix
|
|
77
|
+
|
|
78
|
+
After Knip has fixed issues, there are four things to consider:
|
|
79
|
+
|
|
80
|
+
### 1. Use a formatter
|
|
81
|
+
|
|
82
|
+
Use a tool like Prettier or Biome if the code needs formatting. Knip removes the
|
|
83
|
+
minimum amount of code while leaving it in a working state.
|
|
84
|
+
|
|
85
|
+
:::tip
|
|
86
|
+
|
|
87
|
+
Add the `--format` flag to format the modified files using the formatter and
|
|
88
|
+
configuration in your project.
|
|
89
|
+
|
|
90
|
+
:::
|
|
91
|
+
|
|
92
|
+
### 2. Unused variables
|
|
93
|
+
|
|
94
|
+
Use a tool like ESLint or Biome to find and remove unused variables inside
|
|
95
|
+
files. Even better, try [remove-unused-vars][3] to remove unused variables
|
|
96
|
+
within files.
|
|
97
|
+
|
|
98
|
+
This may result in more deleted code, and Knip may then find more unused code.
|
|
99
|
+
Rinse and repeat!
|
|
100
|
+
|
|
101
|
+
### 3. Unused dependencies
|
|
102
|
+
|
|
103
|
+
Verify changes in `package.json` and update dependencies using your package
|
|
104
|
+
manager.
|
|
105
|
+
|
|
106
|
+
<Tabs syncKey="pm">
|
|
107
|
+
<TabItem label="npm">
|
|
108
|
+
```shell
|
|
109
|
+
npm install
|
|
110
|
+
```
|
|
111
|
+
</TabItem>
|
|
112
|
+
|
|
113
|
+
<TabItem label="pnpm">
|
|
114
|
+
```shell
|
|
115
|
+
pnpm install
|
|
116
|
+
```
|
|
117
|
+
</TabItem>
|
|
118
|
+
|
|
119
|
+
<TabItem label="bun">
|
|
120
|
+
```shell
|
|
121
|
+
bun install
|
|
122
|
+
```
|
|
123
|
+
</TabItem>
|
|
124
|
+
|
|
125
|
+
<TabItem label="yarn">
|
|
126
|
+
```shell
|
|
127
|
+
yarn
|
|
128
|
+
```
|
|
129
|
+
</TabItem>
|
|
130
|
+
</Tabs>
|
|
131
|
+
|
|
132
|
+
### 4. Install unlisted dependencies
|
|
133
|
+
|
|
134
|
+
If Knip reports unlisted dependencies or binaries, they should be installed
|
|
135
|
+
using the package manager in the project, for example:
|
|
136
|
+
|
|
137
|
+
<Tabs syncKey="pm">
|
|
138
|
+
<TabItem label="npm">
|
|
139
|
+
```shell
|
|
140
|
+
npm install unlisted-package
|
|
141
|
+
```
|
|
142
|
+
</TabItem>
|
|
143
|
+
|
|
144
|
+
<TabItem label="pnpm">
|
|
145
|
+
```shell
|
|
146
|
+
pnpm add unlisted-package
|
|
147
|
+
```
|
|
148
|
+
</TabItem>
|
|
149
|
+
|
|
150
|
+
<TabItem label="bun">
|
|
151
|
+
```shell
|
|
152
|
+
bun add unlisted-package
|
|
153
|
+
```
|
|
154
|
+
</TabItem>
|
|
155
|
+
|
|
156
|
+
<TabItem label="yarn">
|
|
157
|
+
```shell
|
|
158
|
+
yarn add unlisted-package
|
|
159
|
+
```
|
|
160
|
+
</TabItem>
|
|
161
|
+
</Tabs>
|
|
162
|
+
|
|
163
|
+
## Example results
|
|
164
|
+
|
|
165
|
+
### Exports
|
|
166
|
+
|
|
167
|
+
The `export` keyword for unused exports is removed:
|
|
168
|
+
|
|
169
|
+
```diff title="module.ts"
|
|
170
|
+
-export const unused = 1;
|
|
171
|
+
-export default class MyClass {}
|
|
172
|
+
+const unused = 1;
|
|
173
|
+
+class MyClass {}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The `default` keyword was also removed here.
|
|
177
|
+
|
|
178
|
+
Knip removes the whole or part of export declarations:
|
|
179
|
+
|
|
180
|
+
```diff title="module.ts"
|
|
181
|
+
type Snake = 'python' | 'anaconda';
|
|
182
|
+
const Owl = 'Hedwig';
|
|
183
|
+
const Hawk = 'Tony';
|
|
184
|
+
-export type { Snake };
|
|
185
|
+
-export { Owl, Hawk };
|
|
186
|
+
+;
|
|
187
|
+
+;
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Re-exports
|
|
191
|
+
|
|
192
|
+
Knip removes the whole or part of re-exports:
|
|
193
|
+
|
|
194
|
+
```diff title="file.js"
|
|
195
|
+
-export { Cat, Dog } from './pets';
|
|
196
|
+
-export { Lion, Elephant } from './jungle';
|
|
197
|
+
+export { Elephant } from './jungle'
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Also across any chain of re-exports:
|
|
201
|
+
|
|
202
|
+
<Tabs>
|
|
203
|
+
<TabItem label="module.ts">
|
|
204
|
+
```diff
|
|
205
|
+
export const Hawk = 'Tony';
|
|
206
|
+
-export const Owl = 'Hedwig';
|
|
207
|
+
+const Owl = 'Hedwig';
|
|
208
|
+
```
|
|
209
|
+
</TabItem>
|
|
210
|
+
|
|
211
|
+
<TabItem label="barrel.ts">
|
|
212
|
+
```diff
|
|
213
|
+
export * from './module.js';
|
|
214
|
+
```
|
|
215
|
+
</TabItem>
|
|
216
|
+
|
|
217
|
+
<TabItem label="index.ts">
|
|
218
|
+
```diff
|
|
219
|
+
-export { Hawk, Owl } from './barrel.js';
|
|
220
|
+
+export { Hawk } from './barrel.js'
|
|
221
|
+
```
|
|
222
|
+
</TabItem>
|
|
223
|
+
</Tabs>
|
|
224
|
+
|
|
225
|
+
### Export assignments
|
|
226
|
+
|
|
227
|
+
Knip removes individual exported items in "export assignments", but does not
|
|
228
|
+
remove the entire export declaration if it's empty:
|
|
229
|
+
|
|
230
|
+
```diff title="file.js"
|
|
231
|
+
-export const { a, b } = fn();
|
|
232
|
+
+export const { } = fn();
|
|
233
|
+
|
|
234
|
+
-export const [c, d] = [c, d];
|
|
235
|
+
+export const [, ] = [c, d];
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Reason: the right-hand side of the assignment might have side-effects. It's not
|
|
239
|
+
safe to always remove the whole declaration. This could be improved in the
|
|
240
|
+
future (feel free to open an issue/RFC).
|
|
241
|
+
|
|
242
|
+
### Enum members
|
|
243
|
+
|
|
244
|
+
Unused members of enums are removed:
|
|
245
|
+
|
|
246
|
+
```diff title="file.ts"
|
|
247
|
+
export enum Directions {
|
|
248
|
+
North = 1,
|
|
249
|
+
East = 2,
|
|
250
|
+
- South = 3,
|
|
251
|
+
West = 4,
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### CommonJS
|
|
256
|
+
|
|
257
|
+
Knip supports CommonJS and removes unused exports:
|
|
258
|
+
|
|
259
|
+
```diff title="common.js"
|
|
260
|
+
-module.exports = { identifier, unused };
|
|
261
|
+
+module.exports = { identifier, };
|
|
262
|
+
|
|
263
|
+
-module.exports.UNUSED = 1;
|
|
264
|
+
-module.exports['ACCESS'] = 1;
|
|
265
|
+
+
|
|
266
|
+
+
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Warning: the right-hand side of such an assignment might have side-effects. Knip
|
|
270
|
+
currently removes the whole declaration (feel free to open an issue/RFC).
|
|
271
|
+
|
|
272
|
+
### Dependencies
|
|
273
|
+
|
|
274
|
+
Unused dependencies are removed from `package.json`:
|
|
275
|
+
|
|
276
|
+
```diff title="package.json"
|
|
277
|
+
{
|
|
278
|
+
"name": "my-package",
|
|
279
|
+
"dependencies": {
|
|
280
|
+
- "rimraf": "*",
|
|
281
|
+
- "unused-dependency": "*"
|
|
282
|
+
+ "rimraf": "*"
|
|
283
|
+
},
|
|
284
|
+
- "devDependencies": {
|
|
285
|
+
- "unreferenced-package": "5.3.3"
|
|
286
|
+
- }
|
|
287
|
+
+ "devDependencies": {}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Class members <Badge text="experimental" variant="caution" />
|
|
292
|
+
|
|
293
|
+
Unused members of classes can be removed:
|
|
294
|
+
|
|
295
|
+
```diff title="file.ts"
|
|
296
|
+
export class Rectangle {
|
|
297
|
+
constructor(public width: number, public height: number) {}
|
|
298
|
+
|
|
299
|
+
- static Key = 1;
|
|
300
|
+
+
|
|
301
|
+
|
|
302
|
+
area() {
|
|
303
|
+
return this.width * this.height;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
- public get unusedGetter(): string {
|
|
307
|
+
- return 'unusedGetter';
|
|
308
|
+
- }
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Currently Knip might be too eager removing class members when they're not
|
|
313
|
+
referenced internally but meant to be called by an external library. For
|
|
314
|
+
instance, Knip might think `componentDidMount` and `render` in React class
|
|
315
|
+
component are unused and will remove those.
|
|
316
|
+
|
|
317
|
+
Note that [`classMembers` aren't included by default][4].
|
|
318
|
+
|
|
319
|
+
## What's not included
|
|
320
|
+
|
|
321
|
+
Operations that auto-fix does not (yet) perform and why:
|
|
322
|
+
|
|
323
|
+
- Add unlisted (dev) dependencies to `package.json` (should it go into
|
|
324
|
+
`dependencies` or `devDependencies`? For monorepos in current workspace or
|
|
325
|
+
root?)
|
|
326
|
+
- Add unlisted binaries (which package and package version contains the used
|
|
327
|
+
binary?)
|
|
328
|
+
- Fix duplicate exports (which one should be removed?)
|
|
329
|
+
|
|
330
|
+
[1]: ../reference/issue-types.md
|
|
331
|
+
[2]: https://github.com/JoshuaKGoldberg/formatly
|
|
332
|
+
[3]: https://github.com/webpro-nl/remove-unused-vars
|
|
333
|
+
[4]: ../guides/handling-issues.mdx#class-members
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Compilers
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Projects may have source files that are not JavaScript or TypeScript, and thus
|
|
6
|
+
require compilation (or transpilation, or pre-processing, you name it). Files
|
|
7
|
+
like `.mdx`, `.astro`, `.vue` and `.svelte` may also import other source files
|
|
8
|
+
and external dependencies. So ideally, these files are included when linting the
|
|
9
|
+
project. That's why Knip supports compilers.
|
|
10
|
+
|
|
11
|
+
## Built-in compilers
|
|
12
|
+
|
|
13
|
+
Knip has built-in "compilers" for the following file extensions:
|
|
14
|
+
|
|
15
|
+
- `.astro`
|
|
16
|
+
- `.css` (only enabled by `tailwindcss`)
|
|
17
|
+
- `.mdx`
|
|
18
|
+
- `.prisma`
|
|
19
|
+
- `.sass` + `.scss`
|
|
20
|
+
- `.svelte`
|
|
21
|
+
- `.vue`
|
|
22
|
+
|
|
23
|
+
Knip does not include real compilers for those files, but regular expressions to
|
|
24
|
+
collect `import` statements. This is fast, requires no dependencies, and enough
|
|
25
|
+
for Knip to build the module graph.
|
|
26
|
+
|
|
27
|
+
On the other hand, real compilers may expose their own challenges in the context
|
|
28
|
+
of Knip. For instance, the Svelte compiler keeps `exports` intact, while they
|
|
29
|
+
might represent component properties. This results in those exports being
|
|
30
|
+
reported as unused by Knip.
|
|
31
|
+
|
|
32
|
+
The built-in functions seem to do a decent job, but override them however you
|
|
33
|
+
like.
|
|
34
|
+
|
|
35
|
+
Compilers are enabled only if certain dependencies are found. If that's not
|
|
36
|
+
working for your project, set `true` and enable any compiler manually:
|
|
37
|
+
|
|
38
|
+
```ts title="knip.ts"
|
|
39
|
+
export default {
|
|
40
|
+
compilers: {
|
|
41
|
+
mdx: true,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Custom compilers
|
|
47
|
+
|
|
48
|
+
Built-in compilers can be overridden, and additional compilers can be added.
|
|
49
|
+
Since compilers are functions, the Knip configuration file must be a dynamic
|
|
50
|
+
`.js` or `.ts` file.
|
|
51
|
+
|
|
52
|
+
### Interface
|
|
53
|
+
|
|
54
|
+
The compiler function interface is straightforward. Text in, text out:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
(source: string, filename: string) => string;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This may also be an `async` function.
|
|
61
|
+
|
|
62
|
+
:::tip[Note]
|
|
63
|
+
|
|
64
|
+
Compilers will automatically have their extension added as a default extension
|
|
65
|
+
to Knip. This means you don't need to add something like `**/*.{ts,vue}` to the
|
|
66
|
+
`entry` or `project` file patterns manually.
|
|
67
|
+
|
|
68
|
+
:::
|
|
69
|
+
|
|
70
|
+
### Examples
|
|
71
|
+
|
|
72
|
+
- [CSS][1]
|
|
73
|
+
- [MDX][2]
|
|
74
|
+
- [Svelte][3]
|
|
75
|
+
- [Vue][4]
|
|
76
|
+
|
|
77
|
+
#### CSS
|
|
78
|
+
|
|
79
|
+
Here's an example, minimal compiler for CSS files:
|
|
80
|
+
|
|
81
|
+
```ts title="knip.ts"
|
|
82
|
+
export default {
|
|
83
|
+
compilers: {
|
|
84
|
+
css: (text: string) => [...text.matchAll(/(?<=@)import[^;]+/g)].join('\n'),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
You may wonder why the CSS compiler is not included by default. It's currently
|
|
90
|
+
not clear if it should be included. And if so, what would be the best way to
|
|
91
|
+
determine it should be enabled, and what syntax(es) it should support. Note that
|
|
92
|
+
Tailwind CSS and SASS/SCSS compilers are included.
|
|
93
|
+
|
|
94
|
+
#### MDX
|
|
95
|
+
|
|
96
|
+
Another example, in case the built-in MDX compiler is not enough:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { compile } from '@mdx-js/mdx';
|
|
100
|
+
|
|
101
|
+
export default {
|
|
102
|
+
compilers: {
|
|
103
|
+
mdx: async text => (await compile(text)).toString(),
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### Svelte
|
|
109
|
+
|
|
110
|
+
In a Svelte project, the compiler is automatically enabled. Override and use
|
|
111
|
+
Svelte's compiler for better results if the built-in "compiler" is not enough:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import type { KnipConfig } from 'knip';
|
|
115
|
+
import { compile } from 'svelte/compiler';
|
|
116
|
+
|
|
117
|
+
export default {
|
|
118
|
+
compilers: {
|
|
119
|
+
svelte: (source: string) => compile(source, {}).js.code,
|
|
120
|
+
},
|
|
121
|
+
} satisfies KnipConfig;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Vue
|
|
125
|
+
|
|
126
|
+
In a Vue project, the compiler is automatically enabled. Override and use Vue's
|
|
127
|
+
parser for better results if the built-in "compiler" is not enough:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import type { KnipConfig } from 'knip';
|
|
131
|
+
import {
|
|
132
|
+
parse,
|
|
133
|
+
type SFCScriptBlock,
|
|
134
|
+
type SFCStyleBlock,
|
|
135
|
+
} from 'vue/compiler-sfc';
|
|
136
|
+
|
|
137
|
+
function getScriptBlockContent(block: SFCScriptBlock | null): string[] {
|
|
138
|
+
if (!block) return [];
|
|
139
|
+
if (block.src) return [`import '${block.src}'`];
|
|
140
|
+
return [block.content];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getStyleBlockContent(block: SFCStyleBlock | null): string[] {
|
|
144
|
+
if (!block) return [];
|
|
145
|
+
if (block.src) return [`@import '${block.src}';`];
|
|
146
|
+
return [block.content];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function getStyleImports(content: string): string {
|
|
150
|
+
return [...content.matchAll(/(?<=@)import[^;]+/g)].join('\n');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const config = {
|
|
154
|
+
compilers: {
|
|
155
|
+
vue: (text: string, filename: string) => {
|
|
156
|
+
const { descriptor } = parse(text, { filename, sourceMap: false });
|
|
157
|
+
return [
|
|
158
|
+
...getScriptBlockContent(descriptor.script),
|
|
159
|
+
...getScriptBlockContent(descriptor.scriptSetup),
|
|
160
|
+
...descriptor.styles.flatMap(getStyleBlockContent).map(getStyleImports),
|
|
161
|
+
].join('\n');
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
} satisfies KnipConfig;
|
|
165
|
+
|
|
166
|
+
export default config;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
[1]: #css
|
|
170
|
+
[2]: #mdx
|
|
171
|
+
[3]: #svelte
|
|
172
|
+
[4]: #vue
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Integrated Monorepos
|
|
3
|
+
sidebar:
|
|
4
|
+
order: 3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Some repositories have a single `package.json`, but consist of multiple projects
|
|
8
|
+
with configuration files across the repository. A good example is the [Nx
|
|
9
|
+
integrated monorepo style][1].
|
|
10
|
+
|
|
11
|
+
:::tip
|
|
12
|
+
|
|
13
|
+
An integrated monorepo is a single workspace.
|
|
14
|
+
|
|
15
|
+
:::
|
|
16
|
+
|
|
17
|
+
## Entry Files
|
|
18
|
+
|
|
19
|
+
The default entrypoints files might not be enough. Here's an idea that might fit
|
|
20
|
+
this type of monorepo:
|
|
21
|
+
|
|
22
|
+
```json title="knip.json"
|
|
23
|
+
{
|
|
24
|
+
"entry": ["{apps,libs}/**/src/index.{ts,tsx}"],
|
|
25
|
+
"project": ["{apps,libs}/**/src/**/*.{ts,tsx}"]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Plugins
|
|
30
|
+
|
|
31
|
+
Let's assume some of these projects are applications ("apps") which have their
|
|
32
|
+
own ESLint configuration files and Cypress configuration and test files. This
|
|
33
|
+
may result in those files getting reported as unused, and consequently also the
|
|
34
|
+
dependencies they import and refer to.
|
|
35
|
+
|
|
36
|
+
In that case, we could configure the ESLint and Cypress plugins like this:
|
|
37
|
+
|
|
38
|
+
```json title="knip.json"
|
|
39
|
+
{
|
|
40
|
+
"eslint": {
|
|
41
|
+
"config": ["{apps,libs}/**/.eslintrc.json"]
|
|
42
|
+
},
|
|
43
|
+
"cypress": {
|
|
44
|
+
"entry": ["apps/**/cypress.config.ts", "apps/**/cypress/e2e/*.spec.ts"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Adapt the file patterns to your project, and the relevant `config` and `entry`
|
|
50
|
+
files and dependencies should no longer be reported as unused.
|
|
51
|
+
|
|
52
|
+
[1]: https://nx.dev/getting-started/tutorials/integrated-repo-tutorial
|