@knip/mcp 0.0.2 → 0.0.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.
Files changed (56) hide show
  1. package/docs/blog/for-editors-and-agents.md +50 -35
  2. package/docs/docs/blog/brief-history.md +30 -0
  3. package/docs/docs/blog/for-editors-and-agents.md +124 -0
  4. package/docs/docs/blog/knip-v3.mdx +88 -0
  5. package/docs/docs/blog/knip-v4.mdx +149 -0
  6. package/docs/docs/blog/knip-v5.mdx +190 -0
  7. package/docs/docs/blog/migration-to-v1.md +65 -0
  8. package/docs/docs/blog/release-notes-v2.md +46 -0
  9. package/docs/docs/blog/slim-down-to-speed-up.md +269 -0
  10. package/docs/docs/blog/state-of-knip.md +191 -0
  11. package/docs/docs/blog/two-years.mdx +107 -0
  12. package/docs/docs/explanations/comparison-and-migration.md +129 -0
  13. package/docs/docs/explanations/entry-files.md +70 -0
  14. package/docs/docs/explanations/plugins.md +318 -0
  15. package/docs/docs/explanations/why-use-knip.md +128 -0
  16. package/docs/docs/features/auto-fix.mdx +333 -0
  17. package/docs/docs/features/compilers.md +172 -0
  18. package/docs/docs/features/integrated-monorepos.md +52 -0
  19. package/docs/docs/features/monorepos-and-workspaces.md +134 -0
  20. package/docs/docs/features/production-mode.md +95 -0
  21. package/docs/docs/features/reporters.md +302 -0
  22. package/docs/docs/features/rules-and-filters.md +102 -0
  23. package/docs/docs/features/script-parser.md +156 -0
  24. package/docs/docs/features/source-mapping.md +100 -0
  25. package/docs/docs/guides/configuring-project-files.md +205 -0
  26. package/docs/docs/guides/contributing.md +24 -0
  27. package/docs/docs/guides/handling-issues.mdx +646 -0
  28. package/docs/docs/guides/issue-reproduction.md +94 -0
  29. package/docs/docs/guides/namespace-imports.md +125 -0
  30. package/docs/docs/guides/performance.md +97 -0
  31. package/docs/docs/guides/troubleshooting.md +127 -0
  32. package/docs/docs/guides/using-knip-in-ci.md +54 -0
  33. package/docs/docs/guides/working-with-commonjs.md +72 -0
  34. package/docs/docs/index.mdx +160 -0
  35. package/docs/docs/overview/configuration.md +104 -0
  36. package/docs/docs/overview/features.md +66 -0
  37. package/docs/docs/overview/getting-started.mdx +195 -0
  38. package/docs/docs/overview/screenshots-videos.md +42 -0
  39. package/docs/docs/playground.mdx +38 -0
  40. package/docs/docs/reference/cli.md +481 -0
  41. package/docs/docs/reference/configuration.md +413 -0
  42. package/docs/docs/reference/dynamic-configuration.mdx +72 -0
  43. package/docs/docs/reference/faq.md +441 -0
  44. package/docs/docs/reference/issue-types.md +43 -0
  45. package/docs/docs/reference/jsdoc-tsdoc-tags.md +122 -0
  46. package/docs/docs/reference/known-issues.md +64 -0
  47. package/docs/docs/reference/plugins/.gitkeep +0 -0
  48. package/docs/docs/reference/plugins.md +238 -0
  49. package/docs/docs/reference/related-tooling.md +46 -0
  50. package/docs/docs/sponsors.mdx +65 -0
  51. package/docs/docs/typescript/unused-dependencies.md +86 -0
  52. package/docs/docs/typescript/unused-exports.md +87 -0
  53. package/docs/docs/writing-a-plugin/argument-parsing.md +202 -0
  54. package/docs/docs/writing-a-plugin/index.md +376 -0
  55. package/docs/docs/writing-a-plugin/inputs.md +162 -0
  56. package/package.json +8 -6
@@ -0,0 +1,190 @@
1
+ ---
2
+ title: Announcing Knip v5
3
+ date: 2024-02-10
4
+ sidebar:
5
+ order: 4
6
+ ---
7
+
8
+ import { Tabs, TabItem } from '@astrojs/starlight/components';
9
+
10
+ _Published: 2024-02-10_
11
+
12
+ Today brings the smallest major release so far. Tiny yet mighty!
13
+
14
+ Below are two cases to demonstrate the change in how unused exports are
15
+ reported.
16
+
17
+ ## Case 1
18
+
19
+ The first case shows two exports with a namespaced import that references one of
20
+ those exports explicitly:
21
+
22
+ ```ts title="knip.js"
23
+ export const version = 'v5';
24
+ export const getRocket = () => '🚀';
25
+ ```
26
+
27
+ ```ts title="index.js"
28
+ import * as NS from './knip.js';
29
+
30
+ console.log(NS.version);
31
+ ```
32
+
33
+ In this case we see that `getRocket` is an unused export.
34
+
35
+ Previously it would go into the "Unused exports in namespaces" category
36
+ (`nsExports`). This issue has been moved to the "Unused exports" category
37
+ (`exports`).
38
+
39
+ ## Case 2
40
+
41
+ The second case is similar, but only the imported namespace itself is
42
+ referenced. None of the individual exports is referenced:
43
+
44
+ ```ts title="index.js"
45
+ import * as NS from './knip.js';
46
+ import send from 'stats';
47
+
48
+ send(NS);
49
+ ```
50
+
51
+ Are the `version` and `getRocket` exports used? We can't know. The same is true
52
+ for the spread object pattern:
53
+
54
+ ```ts title="index.js"
55
+ import * as NS from './knip.js';
56
+
57
+ const Spread = { ...NS };
58
+ ```
59
+
60
+ Previously those exports would go into the "Unused exports in namespaces"
61
+ category. This is still the case, but this category is no longer enabled by
62
+ default.
63
+
64
+ ## Include unused exports in namespaces
65
+
66
+ To enable this type of issues in Knip v5, add this argument to the command:
67
+
68
+ ```shell
69
+ knip --include nsExports
70
+ ```
71
+
72
+ Or in your configuration file:
73
+
74
+ ```json title="knip.json"
75
+ {
76
+ "include": ["nsExports", "nsTypes"]
77
+ }
78
+ ```
79
+
80
+ Now `version` and `getRocket` will be reported as "Unused exports in
81
+ namespaces".
82
+
83
+ Note that `nsExports` and `nsTypes` are split for more granular control.
84
+
85
+ ## Handling exports in namespaced imports
86
+
87
+ You have a few options to handle namespaced imports when it comes to unused
88
+ exports.
89
+
90
+ ### 1. Use named imports
91
+
92
+ Regardless of whether `nsExports` is enabled or not, it's often good practice to
93
+ replace the namespaced imports with named imports:
94
+
95
+ ```ts title="index.js"
96
+ import { version, getRocket } from './knip.js';
97
+
98
+ send({ version, getRocket });
99
+ ```
100
+
101
+ Whenever possible, explicit over implicit is often the better choice.
102
+
103
+ ### 2. Standardized JSDoc tags
104
+
105
+ Using one of the available JSDoc tags like `@public` or `@internal`:
106
+
107
+ ```ts title="knip.js"
108
+ export const version = 'v5';
109
+ /** @public */
110
+ export const getRocket = () => '🚀';
111
+ ```
112
+
113
+ Assuming only imported using a namespace (like in the example cases above), this
114
+ will exclude the `getRocket` export from the report, even though it isn't
115
+ explicitly referenced.
116
+
117
+ ### 3. Arbitrary JSDoc tags
118
+
119
+ Another solution is to tag individual exports arbitrarily:
120
+
121
+ ```ts title="knip.js"
122
+ export const version = 'v5';
123
+ /** @launch */
124
+ export const getRocket = () => '🚀';
125
+ ```
126
+
127
+ And then exclude the tag like so:
128
+
129
+ ```shell
130
+ $ knip --experimental-tags=-launch
131
+ Exports in used namespace (1)
132
+ version NS unknown knip.js:1:1
133
+ ```
134
+
135
+ Assuming only imported using a namespace (like in the example cases above), this
136
+ will exclude the `getRocket` export from the report, even though it isn't
137
+ explicitly referenced.
138
+
139
+ ## A better default
140
+
141
+ I believe this behavior in v5 is the better default: have all exports you want
142
+ to know about in a single category, and those you probably want to ignore in
143
+ another that's disabled by default.
144
+
145
+ Before the [v4 refactoring][1], this would be a lot harder to implement. That
146
+ refactoring turns out to be a better investment than expected. Combined with a
147
+ better understanding of how people write code and use Knip, this change is a
148
+ natural iteration.
149
+
150
+ Why the major bump? It's not breaking for the large majority of users, but for
151
+ some it may be breaking. For instance when relying on the [JSON reporter][2],
152
+ other reporter output, or custom [preprocessing][3]. It's not a bug fix, it's
153
+ not a new feature, but since semver is all about setting expectations I feel the
154
+ change is large enough to warrant a major bump.
155
+
156
+ ## Let's Go!
157
+
158
+ What are you waiting for? Start using Knip v5 today!
159
+
160
+ <Tabs syncKey="pm">
161
+ <TabItem label="npm">
162
+ ```shell
163
+ npm install -D knip
164
+ ```
165
+ </TabItem>
166
+
167
+ <TabItem label="pnpm">
168
+ ```shell
169
+ pnpm add -D knip
170
+ ```
171
+ </TabItem>
172
+
173
+ <TabItem label="bun">
174
+ ```shell
175
+ bun add -D knip
176
+ ```
177
+ </TabItem>
178
+
179
+ <TabItem label="yarn">
180
+ ```shell
181
+ yarn add -D knip
182
+ ```
183
+ </TabItem>
184
+ </Tabs>
185
+
186
+ Remember, Knip it before you ship it! Have a great day ☀️
187
+
188
+ [1]: ../blog/slim-down-to-speed-up.md
189
+ [2]: ../features/reporters.md#json
190
+ [3]: ../features/reporters.md#preprocessors
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Migration to v1
3
+ ---
4
+
5
+ _2023-01-04_
6
+
7
+ When coming from version v0.13.3 or before, there are some breaking changes:
8
+
9
+ - The `entryFiles` and `projectFiles` options have been renamed to `entry` and
10
+ `project`.
11
+ - The `--dev` argument and `dev: true` option are gone, this is now the default
12
+ mode (see [production mode][1]).
13
+ - Workspaces have been moved from the root of the config to the `workspaces` key
14
+ (see [workspaces][2]).
15
+ - The `--dir` argument has been renamed to `--workspace`.
16
+
17
+ ## Example
18
+
19
+ A configuration like this in v0.13.3 or before...
20
+
21
+ ```json
22
+ {
23
+ "entryFiles": ["src/index.ts"],
24
+ "projectFiles": ["src/**/*.ts", "!**/*.spec.ts"],
25
+ "dev": {
26
+ "entryFiles": ["src/index.ts", "src/**/*.spec.ts", "src/**/*.e2e.ts"],
27
+ "projectFiles": ["src/**/*.ts"]
28
+ }
29
+ }
30
+ ```
31
+
32
+ ...should become this for v1...
33
+
34
+ ```json
35
+ {
36
+ "entry": ["src/index.ts!"],
37
+ "project": ["src/**/*.ts!"]
38
+ }
39
+ ```
40
+
41
+ Much cleaner, right? For some more details:
42
+
43
+ - The `dev` property for the `--dev` flag is now the default mode.
44
+ - Use `--production` to analyze only the `entry` and `project` files suffixed
45
+ with `!`.
46
+ - The glob patterns for both types of test files (`*.spec.ts` and `*.e2e.ts`)
47
+ are no longer needed:
48
+ - Regular test files like `*.test.js` and `*.spec.ts` etc. are automatically
49
+ handled by Knip.
50
+ - The `*.e2e.ts` files is configured with the Cypress or other plugin. Note
51
+ that Cypress uses `*.cy.ts` for spec files, but this could be overridden
52
+ like so:
53
+
54
+ ```json
55
+ {
56
+ "entry": "src/index.ts!",
57
+ "project": "src/**/*.ts!",
58
+ "cypress": {
59
+ "entry": "src/**/*.e2e.ts"
60
+ }
61
+ }
62
+ ```
63
+
64
+ [1]: ../features/production-mode.md
65
+ [2]: ../features/monorepos-and-workspaces.md
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: Release Notes v2
3
+ sidebar:
4
+ order: 9
5
+ ---
6
+
7
+ _2023-03-22_
8
+
9
+ ## Breaking changes
10
+
11
+ When coming from v1, there are no breaking changes in terms of configuration.
12
+
13
+ ## Changes
14
+
15
+ There are some changes regarding CLI arguments and output:
16
+
17
+ - Knip now runs on every \[workspace]\[1] automatically (except for the ones in
18
+ `ignoreWorkspaces: []`).
19
+ - The "Unlisted or unresolved dependencies" is split in "Unlisted dependencies"
20
+ and "Unresolved imports".
21
+ - Bug fixes and increased correctness impact output (potentially causing CI to
22
+ now succeed or fail).
23
+
24
+ ## New features
25
+
26
+ Rewriting a major part of Knip's core from scratch allows for some new exciting
27
+ features:
28
+
29
+ - **Performance**. Files are read only once, and their ASTs are traversed only
30
+ once. Projects of any size will notice the difference. Total running time for
31
+ some projects decreases with 90%.
32
+ - **Compilers**. You can now include other file types such as `.mdx`, `.vue` and
33
+ `.svelte` in the analysis.
34
+
35
+ Internally, the `ts-morph` dependency is replaced by `typescript` itself.
36
+
37
+ ## Other improvements
38
+
39
+ - Improved support for workspaces.
40
+ - Improved module resolutions, self-referencing imports, and other things you
41
+ don't want to worry about.
42
+ - Configure `ignoreDependencies` and `ignoreBinaries` at the workspace level.
43
+ - Simplified plugins model: plugin dependency finder may now return any type of
44
+ dependency in a single array: npm packages, local workspace packages, local
45
+ files, etc. (module and path resolution are handled outside the plugin).
46
+ - Many bugfixes.
@@ -0,0 +1,269 @@
1
+ ---
2
+ title: Slim down to speed up
3
+ date: 2023-12-14
4
+ sidebar:
5
+ order: 6
6
+ ---
7
+
8
+ _Published: 2023-12-14_
9
+
10
+ **tl;dr;** Memory usage is up to 50% lower, runs are up to 60% faster and you
11
+ can start using v4 canary today. No "unused class members" for the time being,
12
+ but this feature is planned to be restored.
13
+
14
+ ## Introduction
15
+
16
+ Honestly, performance has always been a challenge for Knip. A longstanding
17
+ bottleneck has finally been eliminated and Knip is going to be a lot faster.
18
+ Skip straight to the bottom to install v4 canary and try it out! Or grab
19
+ yourself a nice drink and read on if you're interested in where we are coming
20
+ from, and where we are heading.
21
+
22
+ ## Projects & Workspaces
23
+
24
+ From the start, Knip has relied on TypeScript for its robust parser for
25
+ JavaScript and TypeScript files. And on lots of machinery important to Knip,
26
+ like module resolution and accurately finding references to exported values.
27
+ Parts of it can be customized, such as the (virtual) file system and the module
28
+ resolver.
29
+
30
+ In TypeScript terms, a "project" is like a workspace in a monorepo. Same as each
31
+ workspace has a `package.json`, each project has a `tsconfig.json`. The
32
+ `ts.createProgram()` method is used to create a program based on a
33
+ `tsconfig.json` and the machinery starts to read and parse source code files,
34
+ resolve modules, and so on.
35
+
36
+ Up until v2, when Knip wanted to find unused things in a monorepo, all programs
37
+ for all workspaces were loaded into memory. Workspaces often depend on each
38
+ other, so Knip couldn't load one project, analyze it and dispose it. This way,
39
+ connections across workspaces would be lost.
40
+
41
+ ## Shared Workspaces
42
+
43
+ Knip v2 said goodbye to this approach and implemented its own TypeScript backend
44
+ (after using `ts-morph` for this). Based on the compatibility of
45
+ `compilerOptions`, workspaces were merged into shared programs whenever
46
+ possible. Having less programs in memory led to significant performance
47
+ improvements. Yet ultimately it was still a stopgap, since everything was still
48
+ kept in memory for the duration of the process.
49
+
50
+ "Why does everything need to stay in memory?", you may wonder. The answer is
51
+ that Knip uses `findReferences` at the end of the process. Knip relied on this
52
+ TypeScript Language Server method for everything that's not easy to find. More
53
+ about that later in [the story of findReferences][1]
54
+
55
+ ## Serialization
56
+
57
+ Fortunately, everything that's imported and exported from source files
58
+ (including things like members of namespaces and enums) can be found relatively
59
+ easily during AST traversal. This way, references to exports don't have to be
60
+ "traced back" later on.
61
+
62
+ It's mostly class members that are harder to find due to their dynamic nature.
63
+ Without these, all information can be serialized for storage and retrieval (in
64
+ memory or on disk). Slimming down by taking class members out of the equation
65
+ simplifies things a lot and paves the way for all sorts of improvements.
66
+
67
+ ## We Have To Slim Down
68
+
69
+ The relevant part in the linting process can be summarized in 5 steps:
70
+
71
+ 1. Collect entry files and feed them to TypeScript
72
+ 2. Read files, resolve modules, and create ASTs
73
+ 3. Traverse ASTs and collect imports & exports
74
+ 4. Match exports against imports to determine what's unused
75
+ 5. Find references to hard-to-find exported values and members
76
+
77
+ If we would hold on to reporting unused class members, then especially steps 2
78
+ and 5 are hard to decouple. The program and the language service containing the
79
+ source files used to eventually trace back references can't really be decoupled.
80
+ So class members had to go. Sometimes you have to slim down to keep moving. One
81
+ step back, two steps forward.
82
+
83
+ If you rely on this feature, fear not. I plan to bring it back before the final
84
+ v4, but possibly behind a flag.
85
+
86
+ ## What's In Store?
87
+
88
+ So with this out of the way, everything becomes a lot clearer and we can finally
89
+ really start thinking about significant memory and performance improvements. So
90
+ what's in store here? A lot!
91
+
92
+ - We no longer need to keep everything in memory, so workspaces are read and
93
+ disposed in isolation, one at a time. Memory usage will be spread out more
94
+ even. This does not make it faster, but reducing "out of memory" issues is
95
+ definitely a Good Thing™️ in my book.
96
+ - Knip could recover from unexpected exits and continue from the last completed
97
+ workspace.
98
+ - The imports and exports are in a format that can be serialized for storage and
99
+ retrieval. This opens up interesting opportunities, such as local caching on
100
+ disk, skipping work in subsequent runs, remote caching, and so on.
101
+ - Handling workspaces in isolation and serialization result in parallelization
102
+ becoming a possibility. This becomes essential, as module resolution and AST
103
+ creation and traversal are now the slowest parts of the process and are not
104
+ easy to optimize significantly (unless perhaps switching to e.g Rust).
105
+ - No longer relying on `findReferences` speeds up the export/import matching
106
+ part part significantly. So far I've seen **improvements of up to 60% on total
107
+ runtime**, and my guess is that some larger codebases may profit even more.
108
+ - The serialization format is still being explored and there is no caching yet,
109
+ but having the steps more decoupled is another Good Thing™️ that future me
110
+ should be happy about.
111
+
112
+ ## Back It Up, Please
113
+
114
+ I heard you. Here's some example data. You can get it directly from Knip using
115
+ the `--performance` flag when running it on any codebase. Below we have some
116
+ data after linting the [Remix monorepo][2].
117
+
118
+ ### Knip v3
119
+
120
+ ```sh
121
+ $ knip --performance
122
+
123
+ Name size min max median sum
124
+ ----------------------------- ---- ------ ------- ------- -------
125
+ findReferences 223 0.55 2252.35 8.46 5826.95
126
+ createProgram 2 50.78 1959.92 1005.35 2010.70
127
+ getTypeChecker 2 5.04 667.45 336.24 672.48
128
+ getImportsAndExports 396 0.00 7.19 0.11 104.46
129
+
130
+ Total running time: 9.7s (mem: 1487.39MB)
131
+ ```
132
+
133
+ ### Knip v4
134
+
135
+ ```sh
136
+ $ knip --performance
137
+
138
+ ...
139
+
140
+ Name size min max median sum
141
+ ----------------------------- ---- ------ ------- ------- -------
142
+ createProgram 2 54.36 2138.45 1096.40 2192.81
143
+ getTypeChecker 2 7.40 664.83 336.12 672.23
144
+ getImportsAndExports 396 0.00 36.36 0.16 224.37
145
+ getSymbolAtLocation 2915 0.00 29.71 0.00 65.63
146
+
147
+ Total running time: 4.3s (mem: 729.67MB)
148
+ ```
149
+
150
+ ### Takeaways
151
+
152
+ The main takeaways here:
153
+
154
+ - In v3,`findReferences` is where Knip potentially spends most of its time
155
+ - In v4, total running time is down over 50%
156
+ - In v4, memory usage is down 50% (calculated using
157
+ `process.memoryUsage().heapUsage`)
158
+ - In v4, `getImportsAndExports` is more comprehensive to compensate for the
159
+ absence of `findReferences` - more on that below
160
+
161
+ Remember, unused class members are no longer reported by default in v4.
162
+
163
+ ## The story of `findReferences`
164
+
165
+ Did I mention Knip uses `findReferences`...? Knip relied on it for everything
166
+ that's not easy to find. Here's an example of an export/import match that **is**
167
+ easy to find:
168
+
169
+ ```ts title="import.ts"
170
+ import { MyThing } from './thing.ts';
171
+ ```
172
+
173
+ ```ts title="export.ts"
174
+ export const MyThing = 'cool';
175
+ ```
176
+
177
+ In v2 and v3, Knip collects many of such easy patterns. Other patterns are
178
+ harder to find with static analysis. This is especially true for class members.
179
+ Let's take a look at the next example:
180
+
181
+ ```ts title="MyClass.ts"
182
+ class MyClass {
183
+ constructor() {
184
+ this.method();
185
+ }
186
+ method() {}
187
+ do() {}
188
+ }
189
+
190
+ export const OtherName = MyClass;
191
+ ```
192
+
193
+ ```ts title="instance.ts"
194
+ import * as MyNamespace from './MyClass.ts';
195
+
196
+ const { OtherName } = MyNamespace;
197
+
198
+ const instance = new OtherName();
199
+
200
+ instance.do();
201
+ ```
202
+
203
+ Without a call or `new` expression to instantiate `OtherName`, its `method`
204
+ member would not be used (since the constructor would not be executed). To
205
+ figure this out using static analysis goes a long way. Through export
206
+ declarations, import declarations, aliases, initializers, call expressions...
207
+ the list goes on and on. Yet all this magic is exactly what happens when you use
208
+ "Find all references" or "Go to definition" in VS Code.
209
+
210
+ Knip used `findReferences` extensively, but it's what makes a part of Knip
211
+ rather slow. TypeScript needs to wire things up (through
212
+ `ts.createLanguageService` and `program.getTypeChecker`) before it can use this,
213
+ and then it tries hard to find all references to anything you throw at it. It
214
+ does this very well, but the more class members, enum members and namespaced
215
+ imports your codebase has, the longer it inevitably takes to complete the
216
+ process.
217
+
218
+ Besides letting go of class members, a slightly more comprehensive AST traversal
219
+ is required to compensate for the absence of `findReferences` (it's the
220
+ `getImportsAndExports` function in the metrics above). I'd like to give you an
221
+ idea of what "more comprehensive" means here.
222
+
223
+ In the following example, `referencedExport` was stored as export from
224
+ `namespace.ts`, but it was not imported directly as such:
225
+
226
+ ```ts title="namespace.ts"
227
+ export const referencedExport = () => {};
228
+ ```
229
+
230
+ ```ts title="index.ts"
231
+ import * as NS from './namespace.ts';
232
+
233
+ NS.referencedExport();
234
+ ```
235
+
236
+ Previously, Knip used `findReferences()` to "trace back" the usage of the
237
+ exported `referencedExport`.
238
+
239
+ The gist of the optimization is to pre-determine all imports and exports. During
240
+ AST traversal of `index.ts` , Knip sees that `referencedExport` is attached to
241
+ the imported `NS` namespace, and stores that as an imported identifier of
242
+ `namespace.ts`. When matching exports against imports, this lookup comes at no
243
+ extra cost. Additionally, this can be stored as strings, so it can be serialized
244
+ too. And that means it can be cached.
245
+
246
+ Knip already did this for trivial cases as shown in the first example of this
247
+ article. This has now been extended to cover more patterns. This is also what
248
+ needs to be tested more extensively before v4 can be released. Its own test
249
+ suite and the projects in the integration tests are already covered so we're
250
+ well on our way.
251
+
252
+ For the record, `findReferences` is an absolute gem of functionality provided by
253
+ TypeScript. Knip is still backed by TypeScript, and tries to speed things up by
254
+ shaking things off. In the end it's all about trade-offs.
255
+
256
+ ## Let's Go!
257
+
258
+ You can start using Knip v4 today, feel free to try it out! You might find a
259
+ false positive that wasn't there in v3, please [report this][3].
260
+
261
+ ```sh
262
+ npm install -D knip@canary
263
+ ```
264
+
265
+ Remember, Knip it before you ship it! Have a great day ☀️
266
+
267
+ [1]: #the-story-of-findreferences
268
+ [2]: https://github.com/remix-run/remix
269
+ [3]: https://github.com/webpro-nl/knip/issues