@knip/mcp 0.0.20 → 0.0.22
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/package.json +2 -2
- package/src/docs/docs/blog/brief-history.md +29 -0
- package/src/docs/docs/blog/for-editors-and-agents.md +130 -0
- package/src/docs/docs/blog/knip-v3.mdx +88 -0
- package/src/docs/docs/blog/knip-v4.mdx +149 -0
- package/src/docs/docs/blog/knip-v5.mdx +190 -0
- package/src/docs/docs/blog/migration-to-v1.md +65 -0
- package/src/docs/docs/blog/release-notes-v2.md +46 -0
- package/src/docs/docs/blog/slim-down-to-speed-up.md +269 -0
- package/src/docs/docs/blog/state-of-knip.md +191 -0
- package/src/docs/docs/blog/two-years.mdx +107 -0
- package/src/docs/docs/explanations/comparison-and-migration.md +133 -0
- package/src/docs/docs/explanations/entry-files.md +70 -0
- package/src/docs/docs/explanations/plugins.md +347 -0
- package/src/docs/docs/explanations/why-use-knip.md +128 -0
- package/src/docs/docs/features/auto-fix.mdx +348 -0
- package/src/docs/docs/features/compilers.md +172 -0
- package/src/docs/docs/features/integrated-monorepos.md +61 -0
- package/src/docs/docs/features/monorepos-and-workspaces.md +149 -0
- package/src/docs/docs/features/production-mode.md +95 -0
- package/src/docs/docs/features/reporters.md +304 -0
- package/src/docs/docs/features/rules-and-filters.md +102 -0
- package/src/docs/docs/features/script-parser.md +156 -0
- package/src/docs/docs/features/source-mapping.md +100 -0
- package/src/docs/docs/guides/configuring-project-files.md +205 -0
- package/src/docs/docs/guides/contributing.md +24 -0
- package/src/docs/docs/guides/handling-issues.mdx +708 -0
- package/src/docs/docs/guides/issue-reproduction.md +99 -0
- package/src/docs/docs/guides/namespace-imports.md +125 -0
- package/src/docs/docs/guides/performance.md +108 -0
- package/src/docs/docs/guides/troubleshooting.md +133 -0
- package/src/docs/docs/guides/using-knip-in-ci.md +50 -0
- package/src/docs/docs/guides/working-with-commonjs.md +72 -0
- package/src/docs/docs/index.mdx +160 -0
- package/src/docs/docs/overview/configuration.md +104 -0
- package/src/docs/docs/overview/features.md +66 -0
- package/src/docs/docs/overview/getting-started.mdx +205 -0
- package/src/docs/docs/overview/screenshots-videos.md +42 -0
- package/src/docs/docs/playground.mdx +38 -0
- package/src/docs/docs/reference/cli.md +511 -0
- package/src/docs/docs/reference/configuration-hints.md +146 -0
- package/src/docs/docs/reference/configuration.md +430 -0
- package/src/docs/docs/reference/dynamic-configuration.mdx +72 -0
- package/src/docs/docs/reference/faq.md +493 -0
- package/src/docs/docs/reference/integrations.md +104 -0
- package/src/docs/docs/reference/issue-types.md +45 -0
- package/src/docs/docs/reference/jsdoc-tsdoc-tags.md +133 -0
- package/src/docs/docs/reference/known-issues.md +86 -0
- package/src/docs/docs/reference/plugins/.gitkeep +0 -0
- package/src/docs/docs/reference/plugins/angular.md +34 -0
- package/src/docs/docs/reference/plugins/astro-db.md +34 -0
- package/src/docs/docs/reference/plugins/astro-og-canvas.md +15 -0
- package/src/docs/docs/reference/plugins/astro.md +44 -0
- package/src/docs/docs/reference/plugins/ava.md +46 -0
- package/src/docs/docs/reference/plugins/babel.md +41 -0
- package/src/docs/docs/reference/plugins/biome.md +34 -0
- package/src/docs/docs/reference/plugins/bumpp.md +41 -0
- package/src/docs/docs/reference/plugins/bun.md +34 -0
- package/src/docs/docs/reference/plugins/c8.md +29 -0
- package/src/docs/docs/reference/plugins/capacitor.md +36 -0
- package/src/docs/docs/reference/plugins/changelogen.md +41 -0
- package/src/docs/docs/reference/plugins/changelogithub.md +41 -0
- package/src/docs/docs/reference/plugins/changesets.md +34 -0
- package/src/docs/docs/reference/plugins/commitizen.md +34 -0
- package/src/docs/docs/reference/plugins/commitlint.md +42 -0
- package/src/docs/docs/reference/plugins/convex.md +34 -0
- package/src/docs/docs/reference/plugins/create-typescript-app.md +34 -0
- package/src/docs/docs/reference/plugins/cspell.md +39 -0
- package/src/docs/docs/reference/plugins/cucumber.md +35 -0
- package/src/docs/docs/reference/plugins/cypress.md +41 -0
- package/src/docs/docs/reference/plugins/danger.md +34 -0
- package/src/docs/docs/reference/plugins/dependency-cruiser.md +46 -0
- package/src/docs/docs/reference/plugins/docusaurus.md +40 -0
- package/src/docs/docs/reference/plugins/dotenv.md +32 -0
- package/src/docs/docs/reference/plugins/drizzle.md +34 -0
- package/src/docs/docs/reference/plugins/eleventy.md +35 -0
- package/src/docs/docs/reference/plugins/eslint.md +86 -0
- package/src/docs/docs/reference/plugins/execa.md +15 -0
- package/src/docs/docs/reference/plugins/expo.md +35 -0
- package/src/docs/docs/reference/plugins/expressive-code.md +40 -0
- package/src/docs/docs/reference/plugins/gatsby.md +49 -0
- package/src/docs/docs/reference/plugins/github-action.md +34 -0
- package/src/docs/docs/reference/plugins/github-actions.md +34 -0
- package/src/docs/docs/reference/plugins/glob.md +29 -0
- package/src/docs/docs/reference/plugins/graphql-codegen.md +46 -0
- package/src/docs/docs/reference/plugins/hardhat.md +34 -0
- package/src/docs/docs/reference/plugins/husky.md +40 -0
- package/src/docs/docs/reference/plugins/i18next-parser.md +46 -0
- package/src/docs/docs/reference/plugins/jest.md +51 -0
- package/src/docs/docs/reference/plugins/karma.md +39 -0
- package/src/docs/docs/reference/plugins/knex.md +34 -0
- package/src/docs/docs/reference/plugins/ladle.md +39 -0
- package/src/docs/docs/reference/plugins/lefthook.md +46 -0
- package/src/docs/docs/reference/plugins/lint-staged.md +48 -0
- package/src/docs/docs/reference/plugins/linthtml.md +41 -0
- package/src/docs/docs/reference/plugins/lockfile-lint.md +41 -0
- package/src/docs/docs/reference/plugins/lost-pixel.md +34 -0
- package/src/docs/docs/reference/plugins/markdownlint.md +34 -0
- package/src/docs/docs/reference/plugins/mdx.md +38 -0
- package/src/docs/docs/reference/plugins/mdxlint.md +38 -0
- package/src/docs/docs/reference/plugins/metro.md +46 -0
- package/src/docs/docs/reference/plugins/mocha.md +47 -0
- package/src/docs/docs/reference/plugins/moonrepo.md +34 -0
- package/src/docs/docs/reference/plugins/msw.md +35 -0
- package/src/docs/docs/reference/plugins/nano-staged.md +39 -0
- package/src/docs/docs/reference/plugins/nest.md +36 -0
- package/src/docs/docs/reference/plugins/netlify.md +41 -0
- package/src/docs/docs/reference/plugins/next-intl.md +34 -0
- package/src/docs/docs/reference/plugins/next-mdx.md +35 -0
- package/src/docs/docs/reference/plugins/next.md +52 -0
- package/src/docs/docs/reference/plugins/nitro.md +52 -0
- package/src/docs/docs/reference/plugins/node-modules-inspector.md +49 -0
- package/src/docs/docs/reference/plugins/node.md +50 -0
- package/src/docs/docs/reference/plugins/nodemon.md +30 -0
- package/src/docs/docs/reference/plugins/npm-package-json-lint.md +41 -0
- package/src/docs/docs/reference/plugins/nuxt.md +55 -0
- package/src/docs/docs/reference/plugins/nx.md +62 -0
- package/src/docs/docs/reference/plugins/nyc.md +39 -0
- package/src/docs/docs/reference/plugins/oclif.md +34 -0
- package/src/docs/docs/reference/plugins/openapi-ts.md +41 -0
- package/src/docs/docs/reference/plugins/oxfmt.md +46 -0
- package/src/docs/docs/reference/plugins/oxlint.md +46 -0
- package/src/docs/docs/reference/plugins/parcel.md +38 -0
- package/src/docs/docs/reference/plugins/payload.md +40 -0
- package/src/docs/docs/reference/plugins/playwright-ct.md +40 -0
- package/src/docs/docs/reference/plugins/playwright-test.md +29 -0
- package/src/docs/docs/reference/plugins/playwright.md +49 -0
- package/src/docs/docs/reference/plugins/plop.md +34 -0
- package/src/docs/docs/reference/plugins/pm2.md +37 -0
- package/src/docs/docs/reference/plugins/pnpm.md +34 -0
- package/src/docs/docs/reference/plugins/postcss.md +46 -0
- package/src/docs/docs/reference/plugins/preconstruct.md +34 -0
- package/src/docs/docs/reference/plugins/prettier.md +39 -0
- package/src/docs/docs/reference/plugins/prisma.md +62 -0
- package/src/docs/docs/reference/plugins/qwik.md +40 -0
- package/src/docs/docs/reference/plugins/raycast.md +34 -0
- package/src/docs/docs/reference/plugins/react-cosmos.md +40 -0
- package/src/docs/docs/reference/plugins/react-native.md +34 -0
- package/src/docs/docs/reference/plugins/react-router.md +37 -0
- package/src/docs/docs/reference/plugins/relay.md +53 -0
- package/src/docs/docs/reference/plugins/release-it.md +34 -0
- package/src/docs/docs/reference/plugins/remark.md +40 -0
- package/src/docs/docs/reference/plugins/remix.md +43 -0
- package/src/docs/docs/reference/plugins/rollup.md +49 -0
- package/src/docs/docs/reference/plugins/rsbuild.md +34 -0
- package/src/docs/docs/reference/plugins/rslib.md +34 -0
- package/src/docs/docs/reference/plugins/rspack.md +34 -0
- package/src/docs/docs/reference/plugins/rstest.md +34 -0
- package/src/docs/docs/reference/plugins/sanity.md +38 -0
- package/src/docs/docs/reference/plugins/semantic-release.md +41 -0
- package/src/docs/docs/reference/plugins/sentry.md +36 -0
- package/src/docs/docs/reference/plugins/simple-git-hooks.md +38 -0
- package/src/docs/docs/reference/plugins/size-limit.md +38 -0
- package/src/docs/docs/reference/plugins/sst.md +34 -0
- package/src/docs/docs/reference/plugins/starlight.md +34 -0
- package/src/docs/docs/reference/plugins/storybook.md +43 -0
- package/src/docs/docs/reference/plugins/stryker.md +34 -0
- package/src/docs/docs/reference/plugins/stylelint.md +41 -0
- package/src/docs/docs/reference/plugins/svelte.md +34 -0
- package/src/docs/docs/reference/plugins/sveltekit.md +34 -0
- package/src/docs/docs/reference/plugins/svgo.md +38 -0
- package/src/docs/docs/reference/plugins/svgr.md +43 -0
- package/src/docs/docs/reference/plugins/swc.md +34 -0
- package/src/docs/docs/reference/plugins/syncpack.md +41 -0
- package/src/docs/docs/reference/plugins/tailwind.md +34 -0
- package/src/docs/docs/reference/plugins/tanstack-router.md +47 -0
- package/src/docs/docs/reference/plugins/taskfile.md +43 -0
- package/src/docs/docs/reference/plugins/travis.md +34 -0
- package/src/docs/docs/reference/plugins/ts-node.md +30 -0
- package/src/docs/docs/reference/plugins/tsdown.md +46 -0
- package/src/docs/docs/reference/plugins/tsup.md +46 -0
- package/src/docs/docs/reference/plugins/tsx.md +48 -0
- package/src/docs/docs/reference/plugins/typedoc.md +53 -0
- package/src/docs/docs/reference/plugins/typescript.md +57 -0
- package/src/docs/docs/reference/plugins/unbuild.md +34 -0
- package/src/docs/docs/reference/plugins/unocss.md +39 -0
- package/src/docs/docs/reference/plugins/vercel-og.md +41 -0
- package/src/docs/docs/reference/plugins/vike.md +37 -0
- package/src/docs/docs/reference/plugins/vite.md +50 -0
- package/src/docs/docs/reference/plugins/vitepress.md +37 -0
- package/src/docs/docs/reference/plugins/vitest.md +72 -0
- package/src/docs/docs/reference/plugins/vue.md +34 -0
- package/src/docs/docs/reference/plugins/webdriver-io.md +34 -0
- package/src/docs/docs/reference/plugins/webpack.md +55 -0
- package/src/docs/docs/reference/plugins/wireit.md +34 -0
- package/src/docs/docs/reference/plugins/wrangler.md +34 -0
- package/src/docs/docs/reference/plugins/xo.md +40 -0
- package/src/docs/docs/reference/plugins/yarn.md +35 -0
- package/src/docs/docs/reference/plugins/yorkie.md +34 -0
- package/src/docs/docs/reference/plugins/zx.md +15 -0
- package/src/docs/docs/reference/plugins.md +146 -0
- package/src/docs/docs/reference/related-tooling.md +46 -0
- package/src/docs/docs/sponsors.mdx +64 -0
- package/src/docs/docs/typescript/unused-dependencies.md +86 -0
- package/src/docs/docs/typescript/unused-exports.md +87 -0
- package/src/docs/docs/writing-a-plugin/argument-parsing.md +201 -0
- package/src/docs/docs/writing-a-plugin/index.md +391 -0
- package/src/docs/docs/writing-a-plugin/inputs.md +162 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Writing A Plugin
|
|
3
|
+
sidebar:
|
|
4
|
+
order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Plugins provide Knip with entry files and dependencies it would be unable to
|
|
8
|
+
find otherwise. Plugins always do at least one of the following:
|
|
9
|
+
|
|
10
|
+
1. Define entry file patterns
|
|
11
|
+
2. Find dependencies in configuration files
|
|
12
|
+
|
|
13
|
+
Knip v5.1.0 introduced a new plugin API, which makes them a breeze to write and
|
|
14
|
+
maintain.
|
|
15
|
+
|
|
16
|
+
:::tip[The new plugin API]
|
|
17
|
+
|
|
18
|
+
Easy things should be easy, and complex things possible.
|
|
19
|
+
|
|
20
|
+
:::
|
|
21
|
+
|
|
22
|
+
This tutorial walks through example plugins so you'll be ready to write your
|
|
23
|
+
own! The following examples demonstrate the elements a plugin can implement.
|
|
24
|
+
|
|
25
|
+
There's a handy command available to easily [create a new plugin][1] and get
|
|
26
|
+
started right away.
|
|
27
|
+
|
|
28
|
+
## Example 1: entry
|
|
29
|
+
|
|
30
|
+
Let's dive right in. Here's the entire source code of the Tailwind plugin:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import type { IsPluginEnabled, Plugin } from '../../types/config.js';
|
|
34
|
+
import { hasDependency } from '../../util/plugin.js';
|
|
35
|
+
|
|
36
|
+
const title = 'Tailwind';
|
|
37
|
+
|
|
38
|
+
const enablers = ['tailwindcss'];
|
|
39
|
+
|
|
40
|
+
const isEnabled: IsPluginEnabled = ({ dependencies }) =>
|
|
41
|
+
hasDependency(dependencies, enablers);
|
|
42
|
+
|
|
43
|
+
const entry = ['tailwind.config.{js,cjs,mjs,ts}'];
|
|
44
|
+
|
|
45
|
+
const plugin: Plugin {
|
|
46
|
+
title,
|
|
47
|
+
enablers,
|
|
48
|
+
isEnabled,
|
|
49
|
+
entry,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default plugin;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Yes, that's the entire plugin! Let's go over each item one by one:
|
|
56
|
+
|
|
57
|
+
### 1. `title`
|
|
58
|
+
|
|
59
|
+
The title of the plugin displayed in the [list of plugins][2] and in debug
|
|
60
|
+
output.
|
|
61
|
+
|
|
62
|
+
### 2. `enablers`
|
|
63
|
+
|
|
64
|
+
An array of strings to match one or more dependencies in `package.json` so the
|
|
65
|
+
`isEnabled` function can determine whether the plugin should be enabled or not.
|
|
66
|
+
Regular expressions are allowed as well.
|
|
67
|
+
|
|
68
|
+
### 3. `isEnabled`
|
|
69
|
+
|
|
70
|
+
This function checks whether a match is found in the `dependencies` or
|
|
71
|
+
`devDependencies` in `package.json`. The plugin is enabled if the dependency is
|
|
72
|
+
listed in `package.json`.
|
|
73
|
+
|
|
74
|
+
This function can be kept straightforward with the `hasDependency` helper.
|
|
75
|
+
|
|
76
|
+
### 4. `entry`
|
|
77
|
+
|
|
78
|
+
This plugin exports `entry` file patterns. This means that if the Tailwind
|
|
79
|
+
plugin is enabled, then `tailwind.config.*` files are added as entry files. A
|
|
80
|
+
Tailwind configuration file does not contain anything particular, so adding it
|
|
81
|
+
as an `entry` to treat it as a regular source file is enough.
|
|
82
|
+
|
|
83
|
+
The next example shows how to handle a tool that has its own particular
|
|
84
|
+
configuration object.
|
|
85
|
+
|
|
86
|
+
## Example 2: config
|
|
87
|
+
|
|
88
|
+
Here's the full source code of the `nyc` plugin:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { toDeferResolve } from '../../util/input.js';
|
|
92
|
+
import { hasDependency } from '../../util/plugin.js';
|
|
93
|
+
import type { NycConfig } from './types.js';
|
|
94
|
+
import type {
|
|
95
|
+
IsPluginEnabled,
|
|
96
|
+
Plugin,
|
|
97
|
+
ResolveConfig,
|
|
98
|
+
} from '../../types/config.js';
|
|
99
|
+
|
|
100
|
+
const title = 'nyc';
|
|
101
|
+
|
|
102
|
+
const enablers = ['nyc'];
|
|
103
|
+
|
|
104
|
+
const isEnabled: IsPluginEnabled = ({ dependencies }) =>
|
|
105
|
+
hasDependency(dependencies, enablers);
|
|
106
|
+
|
|
107
|
+
const config = [
|
|
108
|
+
'.nycrc',
|
|
109
|
+
'.nycrc.{json,yml,yaml}',
|
|
110
|
+
'nyc.config.js',
|
|
111
|
+
'package.json',
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const resolveConfig: ResolveConfig<NycConfig> = config => {
|
|
115
|
+
const extend = config?.extends ?? [];
|
|
116
|
+
const requires = config?.require ?? [];
|
|
117
|
+
return [extend, requires].flat().map(id => toDeferResolve(id));
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const plugin: Plugin {
|
|
121
|
+
title,
|
|
122
|
+
enablers,
|
|
123
|
+
isEnabled,
|
|
124
|
+
config,
|
|
125
|
+
resolveConfig
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export default plugin;
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Here's an example `config` file that will be handled by this plugin:
|
|
132
|
+
|
|
133
|
+
```json title=".nycrc.json"
|
|
134
|
+
{
|
|
135
|
+
"extends": "@istanbuljs/nyc-config-typescript",
|
|
136
|
+
"check-coverage": true
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Compared to the first example, this plugin has two new variables:
|
|
141
|
+
|
|
142
|
+
### 5. `config`
|
|
143
|
+
|
|
144
|
+
The `config` array contains all possible locations of the config file for the
|
|
145
|
+
tool. Knip loads matching files and passes the results (i.e. its default export)
|
|
146
|
+
into the `resolveConfig` function:
|
|
147
|
+
|
|
148
|
+
### 6. `resolveConfig`
|
|
149
|
+
|
|
150
|
+
This function receives the exported value of the `config` file, and executes the
|
|
151
|
+
`resolveConfig` function with this object. The plugin should return the entry
|
|
152
|
+
paths and dependencies referenced in this object.
|
|
153
|
+
|
|
154
|
+
Knip supports JSON, YAML, TOML, JavaScript and TypeScript config files. Files
|
|
155
|
+
without an extension are provided as plain text strings.
|
|
156
|
+
|
|
157
|
+
:::tip[Should I implement resolveConfig?]
|
|
158
|
+
|
|
159
|
+
You should implement `resolveConfig` if any of these are true:
|
|
160
|
+
|
|
161
|
+
- The `config` file contains one or more options that represent [entry
|
|
162
|
+
points][3]
|
|
163
|
+
- The `config` file references dependencies by strings (not import statements)
|
|
164
|
+
|
|
165
|
+
:::
|
|
166
|
+
|
|
167
|
+
## Example 3: entry paths
|
|
168
|
+
|
|
169
|
+
### 7. entry and production
|
|
170
|
+
|
|
171
|
+
Some tools operate mostly on entry files, some examples:
|
|
172
|
+
|
|
173
|
+
- Mocha looks for test files at `test/*.{js,cjs,mjs}`
|
|
174
|
+
- Storybook looks for stories at `*.stories.@(mdx|js|jsx|tsx)`
|
|
175
|
+
|
|
176
|
+
And some of those tools allow to configure those locations and patterns in
|
|
177
|
+
configuration files, such as `next.config.js` or `vite.config.ts`. If that's the
|
|
178
|
+
case we can define `resolveConfig` in our plugin to take this from the
|
|
179
|
+
configuration object and return it to Knip:
|
|
180
|
+
|
|
181
|
+
Here's an example from the Mocha plugin:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
const entry = ['**/test/*.{js,cjs,mjs}'];
|
|
185
|
+
|
|
186
|
+
const resolveConfig: ResolveConfig<MochaConfig> = localConfig => {
|
|
187
|
+
const entryPatterns = localConfig.spec ? [localConfig.spec].flat() : entry;
|
|
188
|
+
return entryPatterns.map(id => toEntry(id));
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export default {
|
|
192
|
+
entry,
|
|
193
|
+
resolveConfig,
|
|
194
|
+
};
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
With Mocha, you can configure `spec` file patterns. The result of implementing
|
|
198
|
+
`resolveConfig` is that users don't need to duplicate this configuration in both
|
|
199
|
+
the tool (e.g. Mocha) and Knip.
|
|
200
|
+
|
|
201
|
+
Use `production` entries to target source files that represent production code.
|
|
202
|
+
|
|
203
|
+
:::tip
|
|
204
|
+
|
|
205
|
+
Regardless of the presence of `resolveConfig`, add `entry` and `production` to
|
|
206
|
+
the default export so they will be displayed in the plugin's documentation as
|
|
207
|
+
default values.
|
|
208
|
+
|
|
209
|
+
:::
|
|
210
|
+
|
|
211
|
+
## Example 4: Use the AST directly
|
|
212
|
+
|
|
213
|
+
If the `resolveFromConfig` function is implemented, Knip loads the configuration
|
|
214
|
+
file and passes the default-exported object to this plugin function. However,
|
|
215
|
+
that object might then not contain the information we need.
|
|
216
|
+
|
|
217
|
+
Here's an example `astro.config.ts` configuration file with a Starlight
|
|
218
|
+
integration:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import starlight from '@astrojs/starlight';
|
|
222
|
+
import { defineConfig } from 'astro/config';
|
|
223
|
+
|
|
224
|
+
export default defineConfig({
|
|
225
|
+
integrations: [
|
|
226
|
+
starlight({
|
|
227
|
+
components: {
|
|
228
|
+
Head: './src/components/Head.astro',
|
|
229
|
+
Footer: './src/components/Footer.astro',
|
|
230
|
+
},
|
|
231
|
+
}),
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
With Starlight, components can be defined to override the default internal ones.
|
|
237
|
+
They're not otherwise referenced in your source code, so you'd have to manually
|
|
238
|
+
add them as entry files ([Knip itself did this][4]).
|
|
239
|
+
|
|
240
|
+
In the Astro plugin, there's no way to access this object containing
|
|
241
|
+
`components` to add the component files as entry files if we were to try:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
const resolveConfig: ResolveConfig<AstroConfig> = async config => {
|
|
245
|
+
console.log(config); // ¯\_(ツ)_/¯
|
|
246
|
+
};
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
This is why plugins can implement the `resolveFromAST` function.
|
|
250
|
+
|
|
251
|
+
### 8. resolveFromAST
|
|
252
|
+
|
|
253
|
+
Let's take a look at the Astro plugin implementation. This example assumes some
|
|
254
|
+
familiarity with Abstract Syntax Trees (AST) and the TypeScript compiler API.
|
|
255
|
+
Knip will provide more and more AST helpers to make implementing plugins more
|
|
256
|
+
fun and a little less tedious.
|
|
257
|
+
|
|
258
|
+
Anyway, let's dive in. Here's how we're adding the Starlight `components` paths
|
|
259
|
+
to the default `production` file patterns:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
import ts from 'typescript';
|
|
263
|
+
import {
|
|
264
|
+
getDefaultImportName,
|
|
265
|
+
getImportMap,
|
|
266
|
+
getPropertyValues,
|
|
267
|
+
} from '../../typescript/ast-helpers.js';
|
|
268
|
+
|
|
269
|
+
const title = 'Astro';
|
|
270
|
+
|
|
271
|
+
const production = [
|
|
272
|
+
'src/pages/**/*.{astro,mdx,js,ts}',
|
|
273
|
+
'src/content/**/*.mdx',
|
|
274
|
+
'src/middleware.{js,ts}',
|
|
275
|
+
'src/actions/index.{js,ts}',
|
|
276
|
+
];
|
|
277
|
+
|
|
278
|
+
const getComponentPathsFromSourceFile = (sourceFile: ts.SourceFile) => {
|
|
279
|
+
const componentPaths: Set<string> = new Set();
|
|
280
|
+
const importMap = getImportMap(sourceFile);
|
|
281
|
+
const importName = getDefaultImportName(importMap, '@astrojs/starlight');
|
|
282
|
+
|
|
283
|
+
function visit(node: ts.Node) {
|
|
284
|
+
if (
|
|
285
|
+
ts.isCallExpression(node) &&
|
|
286
|
+
ts.isIdentifier(node.expression) &&
|
|
287
|
+
node.expression.text === importName // match the starlight() function call
|
|
288
|
+
) {
|
|
289
|
+
const starlightConfig = node.arguments[0];
|
|
290
|
+
if (ts.isObjectLiteralExpression(starlightConfig)) {
|
|
291
|
+
const values = getPropertyValues(starlightConfig, 'components');
|
|
292
|
+
for (const value of values) componentPaths.add(value);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
ts.forEachChild(node, visit);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
visit(sourceFile);
|
|
300
|
+
|
|
301
|
+
return componentPaths;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const resolveFromAST: ResolveFromAST = (sourceFile: ts.SourceFile) => {
|
|
305
|
+
// Include './src/components/Head.astro' and './src/components/Footer.astro'
|
|
306
|
+
// as production entry files so they're also part of the analysis
|
|
307
|
+
const componentPaths = getComponentPathsFromSourceFile(sourceFile);
|
|
308
|
+
return [...production, ...componentPaths].map(id => toProductionEntry(id));
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const plugin: Plugin {
|
|
312
|
+
title,
|
|
313
|
+
production,
|
|
314
|
+
resolveFromAST,
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export default plugin;
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## None Of The Above
|
|
321
|
+
|
|
322
|
+
### 9. `resolve`
|
|
323
|
+
|
|
324
|
+
If there is no configuration file to parse or there is a need for customization,
|
|
325
|
+
use `resolve`:
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
const resolve: Resolve = async options => {
|
|
329
|
+
return toDependency('troublesome', { optional: true });
|
|
330
|
+
};
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Inputs
|
|
334
|
+
|
|
335
|
+
You may have noticed functions like `toDeferResolve` and `toEntry`. They're a
|
|
336
|
+
way for plugins to tell what they've found and how Knip should handle those. The
|
|
337
|
+
more precision a plugin can provide here, the better results and performance
|
|
338
|
+
will be.
|
|
339
|
+
|
|
340
|
+
Find all the details over at [Writing A Plugin → Inputs][5].
|
|
341
|
+
|
|
342
|
+
## Argument Parsing
|
|
343
|
+
|
|
344
|
+
As part of the [script parser][6], Knip parses command-line arguments. Plugins
|
|
345
|
+
can implement the `arg` object to add custom argument parsing tailored to the
|
|
346
|
+
tool.
|
|
347
|
+
|
|
348
|
+
Read more in [Writing A Plugin → Argument Parsing][7].
|
|
349
|
+
|
|
350
|
+
## Create a new plugin
|
|
351
|
+
|
|
352
|
+
The easiest way to create a new plugin is to use the `create-plugin` script:
|
|
353
|
+
|
|
354
|
+
```sh
|
|
355
|
+
cd packages/knip
|
|
356
|
+
pnpm create-plugin --name tool
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
This adds source and test files and fixtures to get you started. Keep fixtures
|
|
360
|
+
tidy, remove clutter that isn't required to test the plugin properly. E.g. using
|
|
361
|
+
a starterkit, script or wizard often creates more than what we need here.
|
|
362
|
+
|
|
363
|
+
The script adds the plugin to the JSON Schema and type definitions.
|
|
364
|
+
|
|
365
|
+
Run the test for your new plugin using one of the following commands:
|
|
366
|
+
|
|
367
|
+
```sh
|
|
368
|
+
node --test test/plugins/tool.test.ts
|
|
369
|
+
bun test test/plugins/tool.test.ts
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
You're ready to implement and submit a new Knip plugin! 🆕 🎉
|
|
373
|
+
|
|
374
|
+
## Wrapping Up
|
|
375
|
+
|
|
376
|
+
Feel free to check out the implementation of other similar plugins, and borrow
|
|
377
|
+
ideas and code from those!
|
|
378
|
+
|
|
379
|
+
The documentation website takes care of generating the [plugin list and the
|
|
380
|
+
individual plugin pages][2] from the exported plugin values.
|
|
381
|
+
|
|
382
|
+
Thanks for reading. If you have been following this guide to create a new
|
|
383
|
+
plugin, this might be the right time to open a pull request!
|
|
384
|
+
|
|
385
|
+
[1]: #create-a-new-plugin
|
|
386
|
+
[2]: ../reference/plugins.md
|
|
387
|
+
[3]: ../explanations/plugins.md#entry-files-from-config-files
|
|
388
|
+
[4]: https://github.com/webpro-nl/knip/blob/6a6954386b33ee8a2919005230a4bc094e11bc03/knip.json#L12
|
|
389
|
+
[5]: ./inputs.md
|
|
390
|
+
[6]: ../features/script-parser.md
|
|
391
|
+
[7]: ./argument-parsing.md
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inputs
|
|
3
|
+
sidebar:
|
|
4
|
+
order: 2
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You may have noticed functions like `toDeferResolve` and `toEntry`. They're a
|
|
8
|
+
way for plugins to tell what they've found and how Knip should handle those. The
|
|
9
|
+
more precise a plugin can be, the better it is for results and performance.
|
|
10
|
+
Here's an overview of all input type functions:
|
|
11
|
+
|
|
12
|
+
- [toEntry][1]
|
|
13
|
+
- [toProductionEntry][2]
|
|
14
|
+
- [toProject][3]
|
|
15
|
+
- [toDependency][4]
|
|
16
|
+
- [toProductionDependency][5]
|
|
17
|
+
- [toDeferResolve][6]
|
|
18
|
+
- [toDeferResolveEntry][7]
|
|
19
|
+
- [toConfig][8]
|
|
20
|
+
- [toBinary][9]
|
|
21
|
+
- [toAlias][10]
|
|
22
|
+
- [Options][11]
|
|
23
|
+
|
|
24
|
+
## toEntry
|
|
25
|
+
|
|
26
|
+
An `entry` input is just like an `entry` in the configuration. It should either
|
|
27
|
+
be an absolute or relative path, and glob patterns are allowed.
|
|
28
|
+
|
|
29
|
+
## toProductionEntry
|
|
30
|
+
|
|
31
|
+
A production `entry` input is just like an `production` in the configuration. It
|
|
32
|
+
should either be an absolute or relative path, and it can have glob patterns.
|
|
33
|
+
|
|
34
|
+
## toProject
|
|
35
|
+
|
|
36
|
+
A `project` input is the equivalent of `project` patterns in the configuration.
|
|
37
|
+
It should either be an absolute or relative path, and (negated) glob patterns
|
|
38
|
+
are allowed.
|
|
39
|
+
|
|
40
|
+
## toDependency
|
|
41
|
+
|
|
42
|
+
The `dependency` indicates the entry is a dependency, belonging in either the
|
|
43
|
+
`"dependencies"` or `"devDependencies"` section of `package.json`.
|
|
44
|
+
|
|
45
|
+
## toProductionDependency
|
|
46
|
+
|
|
47
|
+
The production `dependency` indicates the entry is a production dependency,
|
|
48
|
+
expected to be listed in `"dependencies"`.
|
|
49
|
+
|
|
50
|
+
## toDeferResolve
|
|
51
|
+
|
|
52
|
+
The `deferResolve` input type is used to defer the resolution of a specifier.
|
|
53
|
+
This could be resolved to a dependency or an entry file. For instance, the
|
|
54
|
+
specifier `"input"` could be resolved to `"input.js"`, `"input.tsx"`,
|
|
55
|
+
`"input/index.js"` or the `"input"` package name. Local files are added as entry
|
|
56
|
+
files, package names are external dependencies.
|
|
57
|
+
|
|
58
|
+
If this does not lead to a resolution, the specifier will be reported under
|
|
59
|
+
"unresolved imports".
|
|
60
|
+
|
|
61
|
+
## toDeferResolveEntry
|
|
62
|
+
|
|
63
|
+
The `deferResolveEntry` input type is similar to `deferResolve`, but it's used
|
|
64
|
+
for entry files only (not dependencies) and unresolved inputs are ignored. It's
|
|
65
|
+
different from `toEntry` as glob patterns are not supported.
|
|
66
|
+
|
|
67
|
+
## toConfig
|
|
68
|
+
|
|
69
|
+
The `config` input type is a way for plugins to reference a configuration file
|
|
70
|
+
that should be handled by a different plugin. For instance, Angular
|
|
71
|
+
configurations might contain references to `tsConfig` and `karmaConfig` files,
|
|
72
|
+
so these `config` files can then be handled by the TypeScript and Karma plugins,
|
|
73
|
+
respectively.
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
toConfig('typescript', './path/to/tsconfig.json');
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For instance, the Angular plugin uses this to tell Knip about its `tsConfig`
|
|
82
|
+
value in `angular.json` projects.
|
|
83
|
+
|
|
84
|
+
## toBinary
|
|
85
|
+
|
|
86
|
+
The `binary` input type isn't used by plugins directly, but by the shell script
|
|
87
|
+
parser (through the `getInputsFromScripts` helper). Think of GitHub Actions
|
|
88
|
+
workflow YAML files or husky scripts. Using this input type, a binary is
|
|
89
|
+
"assigned" to the dependency that has it as a `"bin"` in their `package.json`.
|
|
90
|
+
|
|
91
|
+
## toAlias
|
|
92
|
+
|
|
93
|
+
The `alias` input type adds path aliases to the core module resolver. They're
|
|
94
|
+
added to `compilerOptions.paths` so the syntax is identical.
|
|
95
|
+
|
|
96
|
+
## Options
|
|
97
|
+
|
|
98
|
+
When creating inputs from specifiers, an extra `options` object as the second
|
|
99
|
+
argument can be provided.
|
|
100
|
+
|
|
101
|
+
### dir
|
|
102
|
+
|
|
103
|
+
The optional `dir` option assigns the input to a different workspace. For
|
|
104
|
+
instance, GitHub Action workflows are always stored in the root workspace, and
|
|
105
|
+
support `working-directory` in job steps. For example:
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
jobs:
|
|
109
|
+
stylelint:
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
steps:
|
|
112
|
+
- run: npx esbuild
|
|
113
|
+
working-directory: packages/app
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The GitHub Action plugin understands `working-directory` and adds this `dir` to
|
|
117
|
+
the input:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
toDependency('esbuild', { dir: 'packages/app' });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Knip now understands `esbuild` is a dependency of the workspace in the
|
|
124
|
+
`packages/app` directory.
|
|
125
|
+
|
|
126
|
+
### optional
|
|
127
|
+
|
|
128
|
+
Use the `optional` flag to indicate the dependency is optional. Then, a
|
|
129
|
+
dependency won't be flagged as unlisted if it isn't.
|
|
130
|
+
|
|
131
|
+
### allowIncludeExports
|
|
132
|
+
|
|
133
|
+
By default, exports of entry files such as `src/index.ts` or the files in
|
|
134
|
+
`package.json#exports` are not reported as unused. When using the
|
|
135
|
+
`--include-entry-exports` flag or `isIncludeExports: true` option, unused
|
|
136
|
+
exports on such entry files are also reported.
|
|
137
|
+
|
|
138
|
+
Exports of entry files coming from plugins are not included in the analysis,
|
|
139
|
+
even with the option enabled. This is because certain tools and frameworks
|
|
140
|
+
consume named exports from entry files, causing false positives.
|
|
141
|
+
|
|
142
|
+
The `allowIncludeExports` option allows the exports of entry files to be
|
|
143
|
+
reported as unused when using `--include-entry-exports`. This option is
|
|
144
|
+
typically used with the [toProductionEntry][2] input type.
|
|
145
|
+
|
|
146
|
+
Example:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
toProductionEntry('./entry.ts', { allowIncludeExports: true });
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
[1]: #toentry
|
|
153
|
+
[2]: #toproductionentry
|
|
154
|
+
[3]: #toproject
|
|
155
|
+
[4]: #todependency
|
|
156
|
+
[5]: #toproductiondependency
|
|
157
|
+
[6]: #todeferresolve
|
|
158
|
+
[7]: #todeferresolveentry
|
|
159
|
+
[8]: #toconfig
|
|
160
|
+
[9]: #tobinary
|
|
161
|
+
[10]: #toalias
|
|
162
|
+
[11]: #options
|