knip 1.6.0 → 1.7.0
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 +55 -41
- package/dist/constants.js +17 -1
- package/dist/plugins/babel/index.d.ts +1 -1
- package/dist/plugins/github-actions/index.js +1 -1
- package/dist/plugins/nx/index.js +14 -4
- package/dist/plugins/nx/types.d.ts +11 -0
- package/dist/plugins/nx/types.js +1 -0
- package/dist/plugins/vitest/index.js +2 -1
- package/package.json +24 -24
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ export const myVar = true;
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
ESLint handles files in isolation, so it does not know whether `myVar` is actually used somewhere else. Knip lints the
|
|
11
|
-
project as a whole, and finds unused exports, files and dependencies
|
|
11
|
+
project as a whole, and finds unused exports, files and dependencies.
|
|
12
12
|
|
|
13
13
|
It's only human to forget removing things that you no longer use. But how do you find out? Where to even start finding
|
|
14
14
|
things that can be removed?
|
|
@@ -26,25 +26,22 @@ The dots don't connect themselves. This is where Knip comes in:
|
|
|
26
26
|
- [x] Features multiple [reporters][2] and supports [custom reporters][3]
|
|
27
27
|
- [x] Run Knip as part of your CI environment to detect issues and prevent regressions
|
|
28
28
|
|
|
29
|
-
Knip shines in both small and large projects.
|
|
30
|
-
file/dependency/export finder?][4]
|
|
29
|
+
Knip shines in both small and large projects. It's a fresh take on keeping your projects clean & tidy!
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
[![An orange cow with scissors, Van Gogh style][6]][5] <sup>_“An orange cow with scissors, Van Gogh style” - generated
|
|
31
|
+
[![An orange cow with scissors, Van Gogh style][5]][4] <sup>_“An orange cow with scissors, Van Gogh style” - generated
|
|
35
32
|
with OpenAI_</sup>
|
|
36
33
|
|
|
37
34
|
## Migrating to v1.0.0
|
|
38
35
|
|
|
39
|
-
When coming from version v0.13.3 or before, please see [migration to v1][
|
|
36
|
+
When coming from version v0.13.3 or before, please see [migration to v1][6].
|
|
40
37
|
|
|
41
38
|
## Issues
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
using Knip, or even opening a pull request with a directory and example files in `test/fixtures`.
|
|
45
|
-
fixes have priority over performance and new features.
|
|
40
|
+
Are you seeing false positives? Please report them by [opening an issue in this repo][7]. Bonus points for linking to a
|
|
41
|
+
public repository using Knip, or even opening a pull request with a directory and example files in `test/fixtures`.
|
|
42
|
+
Correctness and bug fixes have priority over performance and new features.
|
|
46
43
|
|
|
47
|
-
Also see the [FAQ][
|
|
44
|
+
Also see the [FAQ][8].
|
|
48
45
|
|
|
49
46
|
## Installation
|
|
50
47
|
|
|
@@ -69,7 +66,7 @@ with a configuration file (or a `knip` property in `package.json`). Let's name t
|
|
|
69
66
|
The `entry` files target the starting point(s) to resolve the rest of the imported code. The `project` files should
|
|
70
67
|
contain all files to match against the files resolved from the entry files, including potentially unused files.
|
|
71
68
|
|
|
72
|
-
Then run the checks with `npx knip
|
|
69
|
+
Then run the checks with `npx knip`. Or first add this script to `package.json`:
|
|
73
70
|
|
|
74
71
|
```json
|
|
75
72
|
{
|
|
@@ -79,7 +76,8 @@ Then run the checks with `npx knip`, or add a script to `package.json`:
|
|
|
79
76
|
}
|
|
80
77
|
```
|
|
81
78
|
|
|
82
|
-
Use `npm run knip` to analyze the project and output unused files, dependencies and exports.
|
|
79
|
+
Use `npm run knip` to analyze the project and output unused files, dependencies and exports. Knip works just fine with
|
|
80
|
+
`yarn` or `pnpm` as well.
|
|
83
81
|
|
|
84
82
|
## Command-line options
|
|
85
83
|
|
|
@@ -146,6 +144,15 @@ The report contains the following types of issues:
|
|
|
146
144
|
- **Unused exported class members**: did not find references to this member of the exported class
|
|
147
145
|
- **Duplicate exports**: the same thing is exported more than once
|
|
148
146
|
|
|
147
|
+
When an issue type has zero issues, it is not shown.
|
|
148
|
+
|
|
149
|
+
_(1)_ This includes imports that could not be resolved.
|
|
150
|
+
|
|
151
|
+
_(2)_ The variable or type is not referenced directly, and has become a member of a namespace. Knip can't find a
|
|
152
|
+
reference to it, so you can _probably_ remove it.
|
|
153
|
+
|
|
154
|
+
### Output filters
|
|
155
|
+
|
|
149
156
|
You can `--include` or `--exclude` any of the types to slice & dice the report to your needs. Alternatively, they can be
|
|
150
157
|
added to the configuration (e.g. `"exclude": ["dependencies"]`).
|
|
151
158
|
|
|
@@ -164,18 +171,20 @@ Use `--exclude` to ignore reports you're not interested in:
|
|
|
164
171
|
Use `--dependencies` or `--exports` as shortcuts to combine groups of related types.
|
|
165
172
|
|
|
166
173
|
Still not happy with the results? Getting too much output/false positives? The [FAQ][9] may be useful. Feel free to open
|
|
167
|
-
an issue and I'm happy to look into it.
|
|
174
|
+
an issue and I'm happy to look into it. Also see the next section on how to [ignore][10] certain false positives:
|
|
168
175
|
|
|
169
|
-
|
|
176
|
+
## Ignore
|
|
170
177
|
|
|
171
|
-
|
|
178
|
+
There are a few ways to tell Knip to ignore certain packages, binaries, dependencies and workspaces. Some examples:
|
|
172
179
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"ignore": ["**/*.d.ts", "**/fixtures"],
|
|
183
|
+
"ignoreBinaries": ["zip", "docker-compose"],
|
|
184
|
+
"ignoreDependencies": ["hidden-package"],
|
|
185
|
+
"ignoreWorkspaces": ["packages/deno-lib"]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
179
188
|
|
|
180
189
|
## Now what?
|
|
181
190
|
|
|
@@ -218,7 +227,7 @@ analysis.
|
|
|
218
227
|
Extra "workspaces" not configured as a workspace in the root `package.json` can be configured as well, Knip is happy to
|
|
219
228
|
analyze unused dependencies and exports from any directory with a `package.json`.
|
|
220
229
|
|
|
221
|
-
Here's
|
|
230
|
+
Here's some example output when running Knip in a workspace:
|
|
222
231
|
|
|
223
232
|
<img src="./assets/screenshot-workspaces.png" alt="example output in workspaces" width="578">
|
|
224
233
|
|
|
@@ -226,7 +235,7 @@ Here's a small output example when running Knip in a workspace:
|
|
|
226
235
|
|
|
227
236
|
Knip contains a growing list of plugins:
|
|
228
237
|
|
|
229
|
-
- [Babel][
|
|
238
|
+
- [Babel][9]
|
|
230
239
|
- [Capacitor][11]
|
|
231
240
|
- [Changesets][12]
|
|
232
241
|
- [commitlint][13]
|
|
@@ -257,9 +266,9 @@ Knip contains a growing list of plugins:
|
|
|
257
266
|
- [Vitest][38]
|
|
258
267
|
- [Webpack][39]
|
|
259
268
|
|
|
260
|
-
Plugins are automatically activated
|
|
261
|
-
|
|
262
|
-
|
|
269
|
+
Plugins are automatically activated. Each plugin is automatically enabled based on simple heuristics. Most of them check
|
|
270
|
+
whether one or one of a few (dev) dependencies are listed in `package.json`. Once enabled, they add a set of
|
|
271
|
+
configuration and/or entry files for Knip to analyze. These defaults can be overriden.
|
|
263
272
|
|
|
264
273
|
Most plugins use one or both of the following file types:
|
|
265
274
|
|
|
@@ -270,7 +279,7 @@ See each plugin's documentation for its default values.
|
|
|
270
279
|
|
|
271
280
|
### `config`
|
|
272
281
|
|
|
273
|
-
Plugins may include `config` files. They are parsed by the plugin's custom dependency
|
|
282
|
+
Plugins may include `config` files. They are parsed by the plugin's custom dependency resolver. Here are some examples
|
|
274
283
|
to get an idea of how they work and why they are needed:
|
|
275
284
|
|
|
276
285
|
- The `eslint` plugin tells Knip that the `"prettier"` entry in the array of `plugins` means that the
|
|
@@ -429,10 +438,11 @@ all of this, why not collect the various issues in one go?
|
|
|
429
438
|
The structure and configuration of projects and their dependencies vary wildly, and no matter how well-balanced,
|
|
430
439
|
defaults only get you so far. Some implementations and some tools out there have smart or unconventional ways to import
|
|
431
440
|
code, making things more complicated. That's why Knip tends to require more configuration in larger projects, based on
|
|
432
|
-
how many dependencies are used and how much the project diverges from the defaults.
|
|
441
|
+
how many dependencies are used and how much the configuration in the project diverges from the defaults.
|
|
433
442
|
|
|
434
|
-
One important goal of Knip is to minimize the amount of configuration necessary.
|
|
435
|
-
infer things automatically, reducing the amount of configuration, please open
|
|
443
|
+
One important goal of Knip is to minimize the amount of configuration necessary. When you false positives are reported
|
|
444
|
+
and you think there are feasible ways to infer things automatically, reducing the amount of configuration, please open
|
|
445
|
+
an issue.
|
|
436
446
|
|
|
437
447
|
### How do I handle too many output/false positives?
|
|
438
448
|
|
|
@@ -457,17 +467,21 @@ When the dependencies don't have a Knip plugin yet, please file an issue or [cre
|
|
|
457
467
|
|
|
458
468
|
When the project is a library and the exports are meant to be used by consumers of the library, there are two options:
|
|
459
469
|
|
|
460
|
-
1. By default, unused exports of `entry` files are not reported
|
|
470
|
+
1. By default, unused exports of `entry` files are not reported. You could re-export from an existing entry file, or
|
|
471
|
+
add the containing file to the `entry` array in the configuration.
|
|
461
472
|
2. The exported values or types can be marked [using the JSDoc `@public` tag][47].
|
|
462
473
|
|
|
463
474
|
### How to start using Knip in CI while having too many issues to sort out?
|
|
464
475
|
|
|
465
476
|
Eventually this type of QA only really works when it's tied to an automated workflow. But with too many issues to
|
|
466
|
-
resolve this might not be feasible right away, especially in existing larger codebase. Here are a few options
|
|
477
|
+
resolve this might not be feasible right away, especially in existing larger codebase. Here are a few options that may
|
|
478
|
+
help:
|
|
467
479
|
|
|
468
480
|
- Use `--no-exit-code` for exit code 0 in CI.
|
|
469
|
-
- Use `--include` (or `--exclude`) to report only the issue types
|
|
481
|
+
- Use `--include` (or `--exclude`) to report only the issue types that have little or no errors.
|
|
482
|
+
- Use a separate `--dependencies` and/or `--exports` Knip command.
|
|
470
483
|
- Use `ignore` (for files and directories) and `ignoreDependencies` to filter out some problematic areas.
|
|
484
|
+
- Limit the number of workspaces configured to analyze in `knip.json`.
|
|
471
485
|
|
|
472
486
|
All of this is hiding problems, so please make sure to plan for fixing them and/or open issues here for false positives.
|
|
473
487
|
|
|
@@ -543,13 +557,13 @@ for the job. I'm motivated to make knip perfectly suited for the job of cutting
|
|
|
543
557
|
[1]: #plugins
|
|
544
558
|
[2]: #reporters
|
|
545
559
|
[3]: #custom-reporters
|
|
546
|
-
[4]:
|
|
547
|
-
[5]:
|
|
548
|
-
[6]: ./
|
|
549
|
-
[7]:
|
|
550
|
-
[8]:
|
|
551
|
-
[9]:
|
|
552
|
-
[10]:
|
|
560
|
+
[4]: https://labs.openai.com/s/xZQACaLepaKya0PRUPtIN5dC
|
|
561
|
+
[5]: ./assets/cow-with-orange-scissors-van-gogh-style.webp
|
|
562
|
+
[6]: ./docs/migration-to-v1.md
|
|
563
|
+
[7]: https://github.com/webpro/knip/issues
|
|
564
|
+
[8]: #faq
|
|
565
|
+
[9]: ./src/plugins/babel
|
|
566
|
+
[10]: #ignore
|
|
553
567
|
[11]: ./src/plugins/capacitor
|
|
554
568
|
[12]: ./src/plugins/changesets
|
|
555
569
|
[13]: ./src/plugins/commitlint
|
package/dist/constants.js
CHANGED
|
@@ -7,7 +7,23 @@ export const DEFAULT_WORKSPACE_CONFIG = {
|
|
|
7
7
|
ignore: [],
|
|
8
8
|
};
|
|
9
9
|
export const TEST_FILE_PATTERNS = ['**/*.{test,spec}.{js,jsx,ts,tsx}', '**/__tests__/**/*.{js,jsx,ts,tsx}'];
|
|
10
|
-
export const IGNORED_GLOBAL_BINARIES = [
|
|
10
|
+
export const IGNORED_GLOBAL_BINARIES = [
|
|
11
|
+
'deno',
|
|
12
|
+
'git',
|
|
13
|
+
'node',
|
|
14
|
+
'npm',
|
|
15
|
+
'npx',
|
|
16
|
+
'pnpm',
|
|
17
|
+
'yarn',
|
|
18
|
+
'cd',
|
|
19
|
+
'cp',
|
|
20
|
+
'echo',
|
|
21
|
+
'exit',
|
|
22
|
+
'mkdir',
|
|
23
|
+
'mv',
|
|
24
|
+
'rm',
|
|
25
|
+
'sudo',
|
|
26
|
+
];
|
|
11
27
|
export const IGNORE_DEFINITELY_TYPED = ['node'];
|
|
12
28
|
export const ISSUE_TYPES = [
|
|
13
29
|
'files',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
|
|
2
1
|
import type { BabelConfig } from './types.js';
|
|
2
|
+
import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
|
|
3
3
|
export declare const NAME = "Babel";
|
|
4
4
|
export declare const ENABLERS: RegExp[];
|
|
5
5
|
export declare const isEnabled: IsPluginEnabledCallback;
|
|
@@ -6,7 +6,7 @@ import { timerify } from '../../util/performance.js';
|
|
|
6
6
|
export const NAME = 'GitHub Actions';
|
|
7
7
|
export const ENABLERS = 'This plugin is enabled when a `.yml` file is found in the `.github/workflows` folder.';
|
|
8
8
|
export const isEnabled = async ({ cwd }) => Boolean(await _firstGlob({ cwd, patterns: ['.github/workflows/*.yml'] }));
|
|
9
|
-
export const CONFIG_FILE_PATTERNS = ['.github/workflows/*.yml'];
|
|
9
|
+
export const CONFIG_FILE_PATTERNS = ['.github/workflows/*.yml', '.github/**/action.{yml,yaml}'];
|
|
10
10
|
const findGithubActionsDependencies = async (configFilePath, { manifest, rootConfig }) => {
|
|
11
11
|
const config = await _load(configFilePath);
|
|
12
12
|
if (!config)
|
package/dist/plugins/nx/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { compact } from '../../util/array.js';
|
|
2
|
+
import { getBinariesFromScripts } from '../../util/binaries/index.js';
|
|
2
3
|
import { _load } from '../../util/loader.js';
|
|
3
4
|
import { timerify } from '../../util/performance.js';
|
|
4
5
|
import { hasDependency } from '../../util/plugin.js';
|
|
@@ -6,10 +7,19 @@ export const NAME = 'Nx';
|
|
|
6
7
|
export const ENABLERS = [/^@nrwl\//];
|
|
7
8
|
export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
|
|
8
9
|
export const CONFIG_FILE_PATTERNS = ['{apps,libs}/**/project.json'];
|
|
9
|
-
const findNxDependencies = async (configFilePath) => {
|
|
10
|
+
const findNxDependencies = async (configFilePath, { manifest }) => {
|
|
10
11
|
const config = await _load(configFilePath);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
if (!config)
|
|
13
|
+
return [];
|
|
14
|
+
const targets = config.targets ? Object.values(config.targets) : [];
|
|
15
|
+
const executors = compact(targets
|
|
16
|
+
.map(target => target?.executor)
|
|
17
|
+
.filter(executor => executor && !executor.startsWith('.'))
|
|
18
|
+
.map(executor => executor?.split(':')[0]));
|
|
19
|
+
const scripts = compact(targets
|
|
20
|
+
.filter(target => target.executor === 'nx:run-commands')
|
|
21
|
+
.flatMap(target => (target.options?.commands ?? target.options?.command ? [target.options.command] : [])));
|
|
22
|
+
const binaries = getBinariesFromScripts(scripts, { manifest, knownGlobalsOnly: true });
|
|
23
|
+
return [...executors, ...binaries];
|
|
14
24
|
};
|
|
15
25
|
export const findDependencies = timerify(findNxDependencies);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { compact } from '../../util/array.js';
|
|
1
2
|
import { _load } from '../../util/loader.js';
|
|
2
3
|
import { timerify } from '../../util/performance.js';
|
|
3
4
|
import { hasDependency } from '../../util/plugin.js';
|
|
@@ -15,6 +16,6 @@ const findVitestDependencies = async (configFilePath) => {
|
|
|
15
16
|
const environments = cfg.environment ? [getEnvPackageName(cfg.environment)] : [];
|
|
16
17
|
const reporters = getExternalReporters(cfg.reporters);
|
|
17
18
|
const coverage = cfg.coverage?.provider ? [`@vitest/coverage-${cfg.coverage.provider}`] : [];
|
|
18
|
-
return [...environments, ...reporters, ...coverage];
|
|
19
|
+
return compact([...environments, ...reporters, ...coverage]);
|
|
19
20
|
};
|
|
20
21
|
export const findDependencies = timerify(findVitestDependencies);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knip",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
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",
|
|
@@ -38,27 +38,27 @@
|
|
|
38
38
|
"schema.json"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@esbuild-kit/esm-loader": "2.5.4",
|
|
42
|
-
"@npmcli/map-workspaces": "3.0.1",
|
|
43
|
-
"@snyk/github-codeowners": "1.1.0",
|
|
44
|
-
"chalk": "5.2.0",
|
|
45
|
-
"easy-table": "1.2.0",
|
|
46
|
-
"esbuild": "0.17.
|
|
41
|
+
"@esbuild-kit/esm-loader": "^2.5.4",
|
|
42
|
+
"@npmcli/map-workspaces": "^3.0.1",
|
|
43
|
+
"@snyk/github-codeowners": "^1.1.0",
|
|
44
|
+
"chalk": "^5.2.0",
|
|
45
|
+
"easy-table": "^1.2.0",
|
|
46
|
+
"esbuild": "^0.17.3",
|
|
47
47
|
"esbuild-register": "3.4.2",
|
|
48
|
-
"eslint": "8.32.0",
|
|
49
|
-
"fast-glob": "3.2.12",
|
|
50
|
-
"get-tsconfig": "4.3.0",
|
|
51
|
-
"globby": "13.1.3",
|
|
52
|
-
"js-yaml": "4.1.0",
|
|
53
|
-
"micromatch": "4.0.5",
|
|
54
|
-
"nano-memoize": "2.0.0",
|
|
55
|
-
"patch-package": "6.5.1",
|
|
56
|
-
"pretty-ms": "8.0.0",
|
|
57
|
-
"strip-json-comments": "5.0.0",
|
|
58
|
-
"summary": "2.1.0",
|
|
59
|
-
"ts-morph": "17.0.1",
|
|
60
|
-
"ts-morph-helpers": "0.6.3",
|
|
61
|
-
"zod": "3.20.2"
|
|
48
|
+
"eslint": "^8.32.0",
|
|
49
|
+
"fast-glob": "^3.2.12",
|
|
50
|
+
"get-tsconfig": "^4.3.0",
|
|
51
|
+
"globby": "^13.1.3",
|
|
52
|
+
"js-yaml": "^4.1.0",
|
|
53
|
+
"micromatch": "^4.0.5",
|
|
54
|
+
"nano-memoize": "^2.0.0",
|
|
55
|
+
"patch-package": "^6.5.1",
|
|
56
|
+
"pretty-ms": "^8.0.0",
|
|
57
|
+
"strip-json-comments": "^5.0.0",
|
|
58
|
+
"summary": "^2.1.0",
|
|
59
|
+
"ts-morph": "^17.0.1",
|
|
60
|
+
"ts-morph-helpers": "^0.6.3",
|
|
61
|
+
"zod": "^3.20.2"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@jest/types": "29.3.1",
|
|
@@ -69,10 +69,10 @@
|
|
|
69
69
|
"@types/node": "18.11.18",
|
|
70
70
|
"@types/npmcli__map-workspaces": "3.0.0",
|
|
71
71
|
"@types/webpack": "5.28.0",
|
|
72
|
-
"@typescript-eslint/eslint-plugin": "5.48.
|
|
73
|
-
"@typescript-eslint/parser": "5.48.
|
|
72
|
+
"@typescript-eslint/eslint-plugin": "5.48.2",
|
|
73
|
+
"@typescript-eslint/parser": "5.48.2",
|
|
74
74
|
"eslint-import-resolver-typescript": "3.5.3",
|
|
75
|
-
"eslint-plugin-import": "2.
|
|
75
|
+
"eslint-plugin-import": "2.27.5",
|
|
76
76
|
"globstar": "1.0.0",
|
|
77
77
|
"release-it": "15.6.0",
|
|
78
78
|
"remark-cli": "11.0.0",
|