knip 1.0.0-beta.7 → 1.0.0-beta.9

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 (52) hide show
  1. package/README.md +85 -80
  2. package/dist/manifest/helpers.js +2 -0
  3. package/dist/plugins/_template/index.js +2 -1
  4. package/dist/plugins/babel/index.d.ts +3 -1
  5. package/dist/plugins/babel/index.js +4 -3
  6. package/dist/plugins/capacitor/index.d.ts +1 -1
  7. package/dist/plugins/capacitor/index.js +3 -2
  8. package/dist/plugins/changesets/index.js +2 -1
  9. package/dist/plugins/commitlint/index.js +2 -1
  10. package/dist/plugins/cypress/index.js +2 -1
  11. package/dist/plugins/eslint/index.js +2 -1
  12. package/dist/plugins/gatsby/index.js +2 -1
  13. package/dist/plugins/index.d.ts +2 -0
  14. package/dist/plugins/index.js +2 -0
  15. package/dist/plugins/jest/index.js +2 -1
  16. package/dist/plugins/lint-staged/index.d.ts +6 -0
  17. package/dist/plugins/lint-staged/index.js +32 -0
  18. package/dist/plugins/lint-staged/types.d.ts +5 -0
  19. package/dist/plugins/lint-staged/types.js +1 -0
  20. package/dist/plugins/mocha/index.js +2 -1
  21. package/dist/plugins/next/index.js +2 -1
  22. package/dist/plugins/nx/index.d.ts +1 -1
  23. package/dist/plugins/nx/index.js +3 -2
  24. package/dist/plugins/nyc/index.js +2 -1
  25. package/dist/plugins/playwright/index.js +2 -1
  26. package/dist/plugins/postcss/index.js +2 -1
  27. package/dist/plugins/prettier/index.js +2 -1
  28. package/dist/plugins/release-it/index.d.ts +6 -0
  29. package/dist/plugins/release-it/index.js +19 -0
  30. package/dist/plugins/release-it/types.d.ts +3 -0
  31. package/dist/plugins/release-it/types.js +1 -0
  32. package/dist/plugins/remark/index.js +2 -1
  33. package/dist/plugins/remix/index.d.ts +1 -1
  34. package/dist/plugins/remix/index.js +3 -2
  35. package/dist/plugins/rollup/index.js +2 -1
  36. package/dist/plugins/sentry/index.d.ts +1 -1
  37. package/dist/plugins/sentry/index.js +3 -11
  38. package/dist/plugins/storybook/index.d.ts +1 -1
  39. package/dist/plugins/storybook/index.js +8 -4
  40. package/dist/plugins/storybook/types.d.ts +3 -1
  41. package/dist/plugins/stryker/index.js +2 -1
  42. package/dist/plugins/typescript/index.js +2 -1
  43. package/dist/plugins/webpack/index.js +26 -11
  44. package/dist/plugins/webpack/types.d.ts +10 -0
  45. package/dist/plugins/webpack/types.js +1 -0
  46. package/dist/types/plugins.d.ts +2 -1
  47. package/dist/util/modules.js +2 -2
  48. package/dist/util/plugin.d.ts +1 -0
  49. package/dist/util/plugin.js +12 -0
  50. package/dist/workspace-worker.js +1 -0
  51. package/package.json +3 -3
  52. package/schema.json +8 -0
package/README.md CHANGED
@@ -36,16 +36,11 @@ with OpenAI_</sup>
36
36
 
37
37
  ## Migrating to v1.0.0
38
38
 
39
- When coming from version v0.13.3 or before, here are the breaking changes:
40
-
41
- - The `entryFiles` and `projectFiles` options have been renamed to `entry` and `project`.
42
- - The `--dev` argument and `dev: true` option are gone, this is now the default mode (see [production mode][7]).
43
- - Workspaces have been moved from the root of the config to the `workspaces` key (see [workspaces][8]).
44
- - The `--dir` argument has been renamed to `--workspace`.
39
+ When coming from version v0.13.3 or before, please see [migration to v1][7].
45
40
 
46
41
  ## Issues
47
42
 
48
- Please report any false positives by [opening an issue in this repo][9]. Bonus points for linking to a public repository
43
+ Please report any false positives by [opening an issue in this repo][8]. Bonus points for linking to a public repository
49
44
  using Knip, or even opening a pull request with a directory and example files in `test/fixtures`. Correctness and bug
50
45
  fixes have priority over performance and new features.
51
46
 
@@ -72,13 +67,19 @@ with a configuration file (or a `knip` property in `package.json`). Let's name t
72
67
  The `entry` files target the starting point(s) to resolve the rest of the imported code. The `project` files should
73
68
  contain all files to match against the files resolved from the entry files, including potentially unused files.
74
69
 
75
- Then run the checks:
70
+ Then run the checks with `npx knip`, or add a script to `package.json`:
76
71
 
77
- npx knip
72
+ ```json
73
+ {
74
+ "scripts": {
75
+ "knip": "knip"
76
+ }
77
+ }
78
+ ```
78
79
 
79
- This will analyze the project and output unused files, dependencies and exports.
80
+ Use `npm run knip` to analyze the project and output unused files, dependencies and exports.
80
81
 
81
- ## Options
82
+ ## Command-line options
82
83
 
83
84
  $ npx knip --help
84
85
  knip [options]
@@ -182,24 +183,18 @@ As always, make sure to backup files or use Git before deleting files or making
182
183
  ## Workspaces & Monorepos
183
184
 
184
185
  Workspaces and monorepos are handled out-of-the-box by Knip. Every workspace that is part of the Knip configuration will
185
- be part of the analysis. Here's a simple example:
186
+ be part of the analysis. Here's an example:
186
187
 
187
188
  ```jsonc
188
189
  {
189
- "ignore": "**/fixtures/**",
190
- "ignoreBinaries": ["rm", "docker-compose"],
191
190
  "ignoreWorkspaces": ["packages/ignore-me"],
192
191
  "workspaces": {
193
192
  "packages/*": {
194
- "entry": "{index,cli}.ts!",
193
+ "entry": "{index,cli}.ts",
195
194
  "project": "**/*.ts"
196
195
  },
197
- "packages/exception": {
198
- "entry": "something/different.js"
199
- },
200
- "not-a-workspace/in-package.json/but-has-package.json": {
201
- "entry": ["src/index.ts"],
202
- "project": "src/**/*.ts"
196
+ "packages/my-lib": {
197
+ "entry": "main.js"
203
198
  }
204
199
  }
205
200
  }
@@ -219,14 +214,15 @@ Here's a small output example when running Knip in a workspace:
219
214
 
220
215
  Knip contains a growing list of plugins:
221
216
 
222
- - [Babel][10]
223
- - [Capacitor][11]
224
- - [Changesets][12]
225
- - [commitlint][13]
226
- - [Cypress][14]
227
- - [ESLint][15]
228
- - [Gatsby][16]
229
- - [Jest][17]
217
+ - [Babel][9]
218
+ - [Capacitor][10]
219
+ - [Changesets][11]
220
+ - [commitlint][12]
221
+ - [Cypress][13]
222
+ - [ESLint][14]
223
+ - [Gatsby][15]
224
+ - [Jest][16]
225
+ - [lint-staged][17]
230
226
  - [Mocha][18]
231
227
  - [Next.js][19]
232
228
  - [Nx][20]
@@ -234,14 +230,15 @@ Knip contains a growing list of plugins:
234
230
  - [Playwright][22]
235
231
  - [PostCSS][23]
236
232
  - [Prettier][24]
237
- - [Remark][25]
238
- - [Remix][26]
239
- - [Rollup][27]
240
- - [Sentry][28]
241
- - [Storybook][29]
242
- - [Stryker][30]
243
- - [TypeScript][31]
244
- - [Webpack][32]
233
+ - [Release It][25]
234
+ - [Remark][26]
235
+ - [Remix][27]
236
+ - [Rollup][28]
237
+ - [Sentry][29]
238
+ - [Storybook][30]
239
+ - [Stryker][31]
240
+ - [TypeScript][32]
241
+ - [Webpack][33]
245
242
 
246
243
  Plugins are automatically activated, no need to enable anything. Each plugin is automatically enabled based on simple
247
244
  heuristics. Most of them check whether one or one of a few (dev) dependencies are listed in `package.json`. Once
@@ -249,9 +246,11 @@ enabled, they add a set of configuration and/or entry files for Knip to analyze.
249
246
 
250
247
  Most plugins use one or both of the following file types:
251
248
 
252
- - `config` - custom dependency resolvers are applied to the [config files][33]
249
+ - `config` - custom dependency resolvers are applied to the [config files][34]
253
250
  - `entry` - files to include with the analysis of the rest of the source code
254
251
 
252
+ See each plugin's documentation for its default values.
253
+
255
254
  ### `config`
256
255
 
257
256
  Plugins may include `config` files. They are parsed by custom dependency resolvers. Here are some examples to get an
@@ -272,6 +271,10 @@ rest to find which of those dependencies are unused or missing.
272
271
  Other configuration files use `require` or `import` statements to use dependencies, so they can be analyzed like the
273
272
  rest of the source files. These configuration files are also considered `entry` files.
274
273
 
274
+ ### Disable a plugin
275
+
276
+ In case a plugin causes issues, it can be disabled by using `false` as its value (e.g. `"webpack": false`).
277
+
275
278
  ### Create a new plugin
276
279
 
277
280
  Getting false positives because a plugin is missing? Want to help out? Feel free to add your own plugin! Get started:
@@ -341,10 +344,10 @@ locations. The more plugins Knip will have, the more projects can be analyzed ou
341
344
 
342
345
  Knip provides the following built-in reporters:
343
346
 
344
- - [`codeowners`][34]
345
- - [`compact`][35]
346
- - [`json`][36]
347
- - [`symbol`][37] (default)
347
+ - [`codeowners`][35]
348
+ - [`compact`][36]
349
+ - [`json`][37]
350
+ - [`symbol`][38] (default)
348
351
 
349
352
  The `compact` reporter shows the sorted files first, and then a list of symbols:
350
353
 
@@ -352,7 +355,7 @@ The `compact` reporter shows the sorted files first, and then a list of symbols:
352
355
 
353
356
  ### Custom Reporters
354
357
 
355
- When the provided built-in reporters are not quite sufficient, a custom reporter can be implemented.
358
+ When the provided built-in reporters are not sufficient, a custom reporter can be implemented.
356
359
 
357
360
  Pass `--reporter ./my-reporter`, with the default export of that module having this interface:
358
361
 
@@ -371,7 +374,7 @@ type ReporterOptions = {
371
374
 
372
375
  The data can then be used to write issues to `stdout`, a JSON or CSV file, or sent to a service.
373
376
 
374
- Find more details and ideas in [custom reporters][38].
377
+ Find more details and ideas in [custom reporters][39].
375
378
 
376
379
  ## Really, another unused file/dependency/export finder?
377
380
 
@@ -385,12 +388,12 @@ all of this, why not collect the various issues in one go?
385
388
 
386
389
  This table is an ongoing comparison. Based on their docs (please report any mistakes):
387
390
 
388
- | Feature | **knip** | [depcheck][39] | [unimported][40] | [ts-unused-exports][41] | [ts-prune][42] | [find-unused-exports][43] |
391
+ | Feature | **knip** | [depcheck][40] | [unimported][41] | [ts-unused-exports][42] | [ts-prune][43] | [find-unused-exports][44] |
389
392
  | :--------------------------------- | :------: | :------------: | :--------------: | :---------------------: | :------------: | :-----------------------: |
390
393
  | Unused files | ✅ | - | ✅ | - | - | - |
391
394
  | Unused dependencies | ✅ | ✅ | ✅ | - | - | - |
392
395
  | Unlisted dependencies | ✅ | ✅ | ✅ | - | - | - |
393
- | [Custom dependency resolvers][44] | ✅ | ✅ | ❌ | - | - | - |
396
+ | [Custom dependency resolvers][45] | ✅ | ✅ | ❌ | - | - | - |
394
397
  | Unused exports | ✅ | - | - | ✅ | ✅ | ✅ |
395
398
  | Unused class members | ✅ | - | - | - | - | - |
396
399
  | Unused enum members | ✅ | - | - | - | - | - |
@@ -399,7 +402,7 @@ This table is an ongoing comparison. Based on their docs (please report any mist
399
402
  | Custom reporters | ✅ | - | - | - | - | - |
400
403
  | JavaScript support | ✅ | ✅ | ✅ | - | - | ✅ |
401
404
  | Configure entry files | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
402
- | [Support workspaces/monorepos][45] | ✅ | ❌ | ❌ | - | - | - |
405
+ | [Support workspaces/monorepos][46] | ✅ | ❌ | ❌ | - | - | - |
403
406
  | ESLint plugin available | - | - | - | ✅ | - | - |
404
407
 
405
408
  ✅ = Supported, ❌ = Not supported, - = Out of scope
@@ -422,7 +425,7 @@ The following commands are similar:
422
425
  unimported
423
426
  knip --production --include files,dependencies,unlisted
424
427
 
425
- See [production mode][7].
428
+ See [production mode][47].
426
429
 
427
430
  ## TypeScript language services
428
431
 
@@ -442,17 +445,17 @@ for the job. I'm motivated to make knip perfectly suited for the job of cutting
442
445
  [4]: #really-another-unused-filedependencyexport-finder
443
446
  [5]: https://labs.openai.com/s/xZQACaLepaKya0PRUPtIN5dC
444
447
  [6]: ./assets/cow-with-orange-scissors-van-gogh-style.webp
445
- [7]: #production-mode
446
- [8]: #workspaces--monorepos
447
- [9]: https://github.com/webpro/knip/issues
448
- [10]: ./src/plugins/babel
449
- [11]: ./src/plugins/capacitor
450
- [12]: ./src/plugins/changesets
451
- [13]: ./src/plugins/commitlint
452
- [14]: ./src/plugins/cypress
453
- [15]: ./src/plugins/eslint
454
- [16]: ./src/plugins/gatsby
455
- [17]: ./src/plugins/jest
448
+ [7]: ./docs/migration-to-v1.md
449
+ [8]: https://github.com/webpro/knip/issues
450
+ [9]: ./src/plugins/babel
451
+ [10]: ./src/plugins/capacitor
452
+ [11]: ./src/plugins/changesets
453
+ [12]: ./src/plugins/commitlint
454
+ [13]: ./src/plugins/cypress
455
+ [14]: ./src/plugins/eslint
456
+ [15]: ./src/plugins/gatsby
457
+ [16]: ./src/plugins/jest
458
+ [17]: ./src/plugins/lint-staged
456
459
  [18]: ./src/plugins/mocha
457
460
  [19]: ./src/plugins/next
458
461
  [20]: ./src/plugins/nx
@@ -460,24 +463,26 @@ for the job. I'm motivated to make knip perfectly suited for the job of cutting
460
463
  [22]: ./src/plugins/playwright
461
464
  [23]: ./src/plugins/postcss
462
465
  [24]: ./src/plugins/prettier
463
- [25]: ./src/plugins/remark
464
- [26]: ./src/plugins/remix
465
- [27]: ./src/plugins/rollup
466
- [28]: ./src/plugins/sentry
467
- [29]: ./src/plugins/storybook
468
- [30]: ./src/plugins/stryker
469
- [31]: ./src/plugins/typescript
470
- [32]: ./src/plugins/webpack
471
- [33]: #config
472
- [34]: #code-owners
473
- [35]: #compact
474
- [36]: #json
475
- [37]: #symbol-default
476
- [38]: ./docs/custom-reporters.md
477
- [39]: https://github.com/depcheck/depcheck
478
- [40]: https://github.com/smeijer/unimported
479
- [41]: https://github.com/pzavolinsky/ts-unused-exports
480
- [42]: https://github.com/nadeesha/ts-prune
481
- [43]: https://github.com/jaydenseric/find-unused-exports
482
- [44]: #custom-dependency-resolvers
483
- [45]: #workspaces--monorepos
466
+ [25]: ./src/plugins/release-it
467
+ [26]: ./src/plugins/remark
468
+ [27]: ./src/plugins/remix
469
+ [28]: ./src/plugins/rollup
470
+ [29]: ./src/plugins/sentry
471
+ [30]: ./src/plugins/storybook
472
+ [31]: ./src/plugins/stryker
473
+ [32]: ./src/plugins/typescript
474
+ [33]: ./src/plugins/webpack
475
+ [34]: #config
476
+ [35]: #code-owners
477
+ [36]: #compact
478
+ [37]: #json
479
+ [38]: #symbol-default
480
+ [39]: ./docs/custom-reporters.md
481
+ [40]: https://github.com/depcheck/depcheck
482
+ [41]: https://github.com/smeijer/unimported
483
+ [42]: https://github.com/pzavolinsky/ts-unused-exports
484
+ [43]: https://github.com/nadeesha/ts-prune
485
+ [44]: https://github.com/jaydenseric/find-unused-exports
486
+ [45]: #custom-dependency-resolvers
487
+ [46]: #workspaces--monorepos
488
+ [47]: #production-mode
@@ -28,6 +28,8 @@ export const getBinariesFromScripts = (npmScripts) => Array.from(npmScripts.redu
28
28
  .map(stripEnvironmentVariables)
29
29
  .flatMap(command => {
30
30
  const [binary, ...args] = command.trim().split(' ');
31
+ if (binary === 'npx' && /-y|--yes/.test(args[0]))
32
+ return [binary];
31
33
  const firstArgument = FIRST_ARGUMENT_AS_BINARY_EXCEPTIONS.includes(binary) && args.find(arg => !arg.startsWith('-'));
32
34
  const dependenciesFromArguments = getDependenciesFromLoaderArguments(args);
33
35
  return [binary, firstArgument, ...dependenciesFromArguments];
@@ -1,8 +1,9 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = '';
4
5
  export const ENABLERS = [''];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = [];
7
8
  export const ENTRY_FILE_PATTERNS = [];
8
9
  export const PRODUCTION_ENTRY_FILE_PATTERNS = [];
@@ -1,6 +1,8 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ import type { BabelConfig } from './types.js';
2
3
  export declare const NAME = "Babel";
3
- export declare const ENABLERS: string[];
4
+ export declare const ENABLERS: RegExp[];
4
5
  export declare const isEnabled: IsPluginEnabledCallback;
5
6
  export declare const CONFIG_FILE_PATTERNS: string[];
7
+ export declare const getDependenciesFromConfig: (config: BabelConfig) => string[];
6
8
  export declare const findDependencies: GenericPluginCallback;
@@ -2,10 +2,11 @@ import { compact } from '../../util/array.js';
2
2
  import { _load } from '../../util/loader.js';
3
3
  import { getPackageName } from '../../util/modules.js';
4
4
  import { timerify } from '../../util/performance.js';
5
+ import { hasDependency } from '../../util/plugin.js';
5
6
  import { resolvePresetName, resolvePluginName } from './helpers.js';
6
7
  export const NAME = 'Babel';
7
- export const ENABLERS = ['@babel/cli', '@babel/core', '@babel/preset-env', '@babel/register'];
8
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
8
+ export const ENABLERS = [/^@babel\//];
9
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
9
10
  export const CONFIG_FILE_PATTERNS = [
10
11
  'babel.config.json',
11
12
  'babel.config.js',
@@ -17,7 +18,7 @@ export const CONFIG_FILE_PATTERNS = [
17
18
  const api = {
18
19
  caller: () => true,
19
20
  };
20
- const getDependenciesFromConfig = (config) => {
21
+ export const getDependenciesFromConfig = (config) => {
21
22
  const presets = config.presets?.map(preset => (typeof preset === 'string' ? preset : preset[0])).map(resolvePresetName) ?? [];
22
23
  const plugins = config.plugins?.map(plugin => (typeof plugin === 'string' ? plugin : plugin[0])).map(resolvePluginName) ?? [];
23
24
  const nested = config.env ? Object.values(config.env).flatMap(getDependenciesFromConfig) : [];
@@ -1,6 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
2
  export declare const NAME = "Capacitor";
3
- export declare const ENABLERS: string[];
3
+ export declare const ENABLERS: RegExp[];
4
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
5
  export declare const CONFIG_FILE_PATTERNS: string[];
6
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,8 +1,9 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = 'Capacitor';
4
- export const ENABLERS = ['@capacitor/core', '@capacitor/cli'];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
5
+ export const ENABLERS = [/^@capacitor\//];
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = ['capacitor.config.ts'];
7
8
  const findCapacitorDependencies = async (configFilePath) => {
8
9
  const config = await _load(configFilePath);
@@ -1,8 +1,9 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = 'Changesets';
4
5
  export const ENABLERS = ['@changesets/cli'];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = ['.changeset/config.json'];
7
8
  const findChangesetsDependencies = async (configFilePath) => {
8
9
  const config = await _load(configFilePath);
@@ -1,8 +1,9 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = 'commitlint';
4
5
  export const ENABLERS = ['@commitlint/cli'];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = ['commitlint.config.{js,ts}'];
7
8
  const findCommitLintDependencies = async (configFilePath) => {
8
9
  const config = await _load(configFilePath);
@@ -1,6 +1,7 @@
1
+ import { hasDependency } from '../../util/plugin.js';
1
2
  export const NAME = 'Cypress';
2
3
  export const ENABLERS = ['cypress'];
3
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
4
5
  export const ENTRY_FILE_PATTERNS = [
5
6
  'cypress.config.{js,ts,mjs,cjs}',
6
7
  'cypress/support/e2e.{js,jsx,ts,tsx}',
@@ -5,10 +5,11 @@ import { _firstGlob } from '../../util/glob.js';
5
5
  import { _load } from '../../util/loader.js';
6
6
  import { getPackageName } from '../../util/modules.js';
7
7
  import { timerify } from '../../util/performance.js';
8
+ import { hasDependency } from '../../util/plugin.js';
8
9
  import { resolvePluginPackageName, customResolvePluginPackageNames, getDependenciesFromSettings } from './helpers.js';
9
10
  export const NAME = 'ESLint';
10
11
  export const ENABLERS = ['eslint'];
11
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
12
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
12
13
  export const CONFIG_FILE_PATTERNS = ['.eslintrc', '.eslintrc.{js,json,cjs}', '.eslintrc.{yml,yaml}', 'package.json'];
13
14
  export const ENTRY_FILE_PATTERNS = ['eslint.config.js'];
14
15
  const findESLintDependencies = async (configFilePath, { cwd, manifest, workspaceConfig }) => {
@@ -1,8 +1,9 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = 'Gatsby';
4
5
  export const ENABLERS = ['gatsby', 'gatsby-cli'];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = ['gatsby-{config,node}.{js,jsx,ts,tsx}'];
7
8
  export const PRODUCTION_ENTRY_FILE_PATTERNS = [
8
9
  'gatsby-{browser,ssr}.{js,jsx,ts,tsx}',
@@ -6,6 +6,7 @@ export * as cypress from './cypress/index.js';
6
6
  export * as eslint from './eslint/index.js';
7
7
  export * as gatsby from './gatsby/index.js';
8
8
  export * as jest from './jest/index.js';
9
+ export * as lintStaged from './lint-staged/index.js';
9
10
  export * as mocha from './mocha/index.js';
10
11
  export * as next from './next/index.js';
11
12
  export * as nx from './nx/index.js';
@@ -13,6 +14,7 @@ export * as nyc from './nyc/index.js';
13
14
  export * as playwright from './playwright/index.js';
14
15
  export * as postcss from './postcss/index.js';
15
16
  export * as prettier from './prettier/index.js';
17
+ export * as releaseIt from './release-it/index.js';
16
18
  export * as remark from './remark/index.js';
17
19
  export * as remix from './remix/index.js';
18
20
  export * as rollup from './rollup/index.js';
@@ -6,6 +6,7 @@ export * as cypress from './cypress/index.js';
6
6
  export * as eslint from './eslint/index.js';
7
7
  export * as gatsby from './gatsby/index.js';
8
8
  export * as jest from './jest/index.js';
9
+ export * as lintStaged from './lint-staged/index.js';
9
10
  export * as mocha from './mocha/index.js';
10
11
  export * as next from './next/index.js';
11
12
  export * as nx from './nx/index.js';
@@ -13,6 +14,7 @@ export * as nyc from './nyc/index.js';
13
14
  export * as playwright from './playwright/index.js';
14
15
  export * as postcss from './postcss/index.js';
15
16
  export * as prettier from './prettier/index.js';
17
+ export * as releaseIt from './release-it/index.js';
16
18
  export * as remark from './remark/index.js';
17
19
  export * as remix from './remix/index.js';
18
20
  export * as rollup from './rollup/index.js';
@@ -2,9 +2,10 @@ import path from 'node:path';
2
2
  import { _load } from '../../util/loader.js';
3
3
  import { getPackageName } from '../../util/modules.js';
4
4
  import { timerify } from '../../util/performance.js';
5
+ import { hasDependency } from '../../util/plugin.js';
5
6
  export const NAME = 'Jest';
6
7
  export const ENABLERS = ['jest'];
7
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
8
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
8
9
  export const CONFIG_FILE_PATTERNS = ['jest.config.{js,ts,mjs,cjs,json}'];
9
10
  export const ENTRY_FILE_PATTERNS = ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'];
10
11
  const resolveExtensibleConfig = async (configFilePath) => {
@@ -0,0 +1,6 @@
1
+ import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "lint-staged";
3
+ export declare const ENABLERS: string[];
4
+ export declare const isEnabled: IsPluginEnabledCallback;
5
+ export declare const CONFIG_FILE_PATTERNS: string[];
6
+ export declare const findDependencies: GenericPluginCallback;
@@ -0,0 +1,32 @@
1
+ import { getBinariesFromScripts } from '../../manifest/helpers.js';
2
+ import { _load } from '../../util/loader.js';
3
+ import { timerify } from '../../util/performance.js';
4
+ import { hasDependency } from '../../util/plugin.js';
5
+ export const NAME = 'lint-staged';
6
+ export const ENABLERS = ['lint-staged'];
7
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
8
+ export const CONFIG_FILE_PATTERNS = [
9
+ '.lintstagedrc',
10
+ '.lintstagedrc.json',
11
+ '.lintstagedrc.{yml,yaml}',
12
+ '.lintstagedrc.{js,mjs,cjs}',
13
+ 'lint-staged.config.{js,mjs,cjs}',
14
+ 'package.json',
15
+ ];
16
+ const findLintStagedDependencies = async (configFilePath, { manifest }) => {
17
+ let config = configFilePath.endsWith('package.json')
18
+ ? manifest['lint-staged']
19
+ : await _load(configFilePath);
20
+ if (!config)
21
+ return [];
22
+ if (typeof config === 'function') {
23
+ config = config();
24
+ }
25
+ const binaries = new Set();
26
+ for (const entry of Object.values(config).flat()) {
27
+ const scripts = [typeof entry === 'function' ? await entry([]) : entry].flat();
28
+ getBinariesFromScripts(scripts).forEach(binary => binaries.add(binary));
29
+ }
30
+ return Array.from(binaries);
31
+ };
32
+ export const findDependencies = timerify(findLintStagedDependencies);
@@ -0,0 +1,5 @@
1
+ type Script = string | string[];
2
+ type Entry = Script | ((filenames: string[]) => Script | Promise<Script>);
3
+ type Config = Record<string, Entry>;
4
+ export type LintStagedConfig = Config | (() => Config);
5
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,10 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { getPackageName } from '../../util/modules.js';
3
3
  import { timerify } from '../../util/performance.js';
4
+ import { hasDependency } from '../../util/plugin.js';
4
5
  export const NAME = 'Mocha';
5
6
  export const ENABLERS = ['mocha'];
6
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
7
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
7
8
  export const CONFIG_FILE_PATTERNS = ['.mocharc.{js,cjs,json,jsonc,yml,yaml}', 'package.json'];
8
9
  export const ENTRY_FILE_PATTERNS = ['test/**/*.{js,cjs,mjs}'];
9
10
  const findMochaDependencies = async (configFilePath, { manifest }) => {
@@ -1,5 +1,6 @@
1
+ import { hasDependency } from '../../util/plugin.js';
1
2
  export const NAME = 'Next.js';
2
3
  export const ENABLERS = ['next'];
3
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
4
5
  export const ENTRY_FILE_PATTERNS = ['next.config.{js,ts}'];
5
6
  export const PRODUCTION_ENTRY_FILE_PATTERNS = ['pages/**/*.{js,jsx,ts,tsx}', 'src/pages/**/*.{js,jsx,ts,tsx}'];
@@ -1,6 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
2
  export declare const NAME = "Nx";
3
- export declare const ENABLERS: string[];
3
+ export declare const ENABLERS: RegExp[];
4
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
5
  export declare const CONFIG_FILE_PATTERNS: string[];
6
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,9 +1,10 @@
1
1
  import { compact } from '../../util/array.js';
2
2
  import { _load } from '../../util/loader.js';
3
3
  import { timerify } from '../../util/performance.js';
4
+ import { hasDependency } from '../../util/plugin.js';
4
5
  export const NAME = 'Nx';
5
- export const ENABLERS = ['@nrwl/workspace'];
6
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const ENABLERS = [/^@nrwl\//];
7
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
7
8
  export const CONFIG_FILE_PATTERNS = ['{apps,libs}/**/project.json'];
8
9
  const findNxDependencies = async (configFilePath) => {
9
10
  const config = await _load(configFilePath);
@@ -1,8 +1,9 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = 'nyc';
4
5
  export const ENABLERS = ['nyc'];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = ['.nycrc', '.nycrc.json', '.nycrc.{yml,yaml}', 'nyc.config.js'];
7
8
  const findNycDependencies = async (configFilePath) => {
8
9
  const config = await _load(configFilePath);
@@ -1,4 +1,5 @@
1
+ import { hasDependency } from '../../util/plugin.js';
1
2
  export const NAME = 'Playwright';
2
3
  export const ENABLERS = ['@playwright/test'];
3
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
4
5
  export const ENTRY_FILE_PATTERNS = ['playwright.config.{js,ts}', '.*{test,spec}.{js,ts,mjs}'];
@@ -1,9 +1,10 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { getPackageName } from '../../util/modules.js';
3
3
  import { timerify } from '../../util/performance.js';
4
+ import { hasDependency } from '../../util/plugin.js';
4
5
  export const NAME = 'PostCSS';
5
6
  export const ENABLERS = ['postcss'];
6
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
7
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
7
8
  export const CONFIG_FILE_PATTERNS = ['postcss.config.js', 'package.json'];
8
9
  const findPostCSSDependencies = async (configFilePath, { manifest }) => {
9
10
  const config = configFilePath.endsWith('package.json')
@@ -1,9 +1,10 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { getPackageName } from '../../util/modules.js';
3
3
  import { timerify } from '../../util/performance.js';
4
+ import { hasDependency } from '../../util/plugin.js';
4
5
  export const NAME = 'Prettier';
5
6
  export const ENABLERS = ['prettier'];
6
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
7
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
7
8
  export const CONFIG_FILE_PATTERNS = [
8
9
  '.prettierrc',
9
10
  '.prettierrc.{json,js,cjs,yml,yaml}',
@@ -0,0 +1,6 @@
1
+ import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Release It";
3
+ export declare const ENABLERS: string[];
4
+ export declare const isEnabled: IsPluginEnabledCallback;
5
+ export declare const CONFIG_FILE_PATTERNS: string[];
6
+ export declare const findDependencies: GenericPluginCallback;
@@ -0,0 +1,19 @@
1
+ import { _load } from '../../util/loader.js';
2
+ import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
4
+ export const NAME = 'Release It';
5
+ export const ENABLERS = ['release-it'];
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
7
+ export const CONFIG_FILE_PATTERNS = [
8
+ '.release-it.json',
9
+ '.release-it.{js,cjs}',
10
+ '.release-it.{yml,yaml}',
11
+ 'package.json',
12
+ ];
13
+ const findReleaseItDependencies = async (configFilePath, { manifest }) => {
14
+ const config = configFilePath.endsWith('package.json')
15
+ ? manifest['release-it']
16
+ : await _load(configFilePath);
17
+ return config?.plugins ? Object.keys(config.plugins) : [];
18
+ };
19
+ export const findDependencies = timerify(findReleaseItDependencies);
@@ -0,0 +1,3 @@
1
+ export type ReleaseItConfig = {
2
+ plugins?: Record<string, unknown>;
3
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,9 @@
1
1
  import { load } from 'js-yaml';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = 'Remark';
4
5
  export const ENABLERS = ['remark-cli'];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = [
7
8
  'package.json',
8
9
  '.remarkrc',
@@ -1,6 +1,6 @@
1
1
  import type { IsPluginEnabledCallback } from '../../types/plugins.js';
2
2
  export declare const NAME = "Remix";
3
- export declare const ENABLERS: string[];
3
+ export declare const ENABLERS: RegExp[];
4
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
5
  export declare const ENTRY_FILE_PATTERNS: string[];
6
6
  export declare const PRODUCTION_ENTRY_FILE_PATTERNS: string[];
@@ -1,6 +1,7 @@
1
+ import { hasDependency } from '../../util/plugin.js';
1
2
  export const NAME = 'Remix';
2
- export const ENABLERS = ['@remix-run/dev'];
3
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
3
+ export const ENABLERS = [/^@remix-run\//];
4
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
4
5
  export const ENTRY_FILE_PATTERNS = ['remix.config.js', 'remix.init/index.js'];
5
6
  export const PRODUCTION_ENTRY_FILE_PATTERNS = [
6
7
  'app/root.tsx',
@@ -1,4 +1,5 @@
1
+ import { hasDependency } from '../../util/plugin.js';
1
2
  export const NAME = 'Rollup';
2
3
  export const ENABLERS = ['rollup'];
3
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
4
5
  export const ENTRY_FILE_PATTERNS = ['rollup.config.{js,mjs,ts}'];
@@ -1,5 +1,5 @@
1
1
  import type { IsPluginEnabledCallback } from '../../types/plugins.js';
2
2
  export declare const NAME = "Sentry";
3
- export declare const ENABLERS: string[];
3
+ export declare const ENABLERS: RegExp[];
4
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
5
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -1,13 +1,5 @@
1
+ import { hasDependency } from '../../util/plugin.js';
1
2
  export const NAME = 'Sentry';
2
- export const ENABLERS = [
3
- '@sentry/browser',
4
- '@sentry/electron',
5
- '@sentry/ember',
6
- '@sentry/gatsby',
7
- '@sentry/nextjs',
8
- '@sentry/remix',
9
- '@sentry/replay',
10
- '@sentry/tracing',
11
- ];
12
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
3
+ export const ENABLERS = [/^@sentry\//];
4
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
13
5
  export const ENTRY_FILE_PATTERNS = ['sentry.{client,server}.config.{js,ts}'];
@@ -1,6 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
2
  export declare const NAME = "Storybook";
3
- export declare const ENABLERS: string[];
3
+ export declare const ENABLERS: (string | RegExp)[];
4
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
5
  export declare const CONFIG_FILE_PATTERNS: string[];
6
6
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -3,17 +3,21 @@ import path from 'node:path';
3
3
  import { _load } from '../../util/loader.js';
4
4
  import { getPackageName } from '../../util/modules.js';
5
5
  import { timerify } from '../../util/performance.js';
6
+ import { hasDependency } from '../../util/plugin.js';
6
7
  const require = createRequire(process.cwd());
7
8
  export const NAME = 'Storybook';
8
- export const ENABLERS = ['@storybook/core', '@nrwl/storybook'];
9
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
9
+ export const ENABLERS = [/^@storybook\//, '@nrwl/storybook'];
10
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
10
11
  export const CONFIG_FILE_PATTERNS = ['.storybook/{main,manager}.{js,ts}'];
11
12
  export const ENTRY_FILE_PATTERNS = ['.storybook/preview.{js,jsx,ts,tsx}', '**/*.stories.{js,jsx,ts,tsx}'];
12
- export const PROJECT_FILE_PATTERNS = ['.storybook/**/*.{js,ts,tsx}'];
13
+ export const PROJECT_FILE_PATTERNS = ['.storybook/**/*.{js,ts,tsx}', '**/*.stories.{js,jsx,ts,tsx}'];
13
14
  const findStorybookDependencies = async (configFilePath) => {
14
15
  const config = await _load(configFilePath);
15
16
  if (config) {
16
- const addons = config.addons?.map(addon => addon.startsWith('.') ? require.resolve(path.join(path.dirname(configFilePath), addon)) : addon) ?? [];
17
+ const addons = config.addons?.map(addon => {
18
+ const name = typeof addon === 'string' ? addon : addon.name;
19
+ return name.startsWith('.') ? require.resolve(path.join(path.dirname(configFilePath), name)) : name;
20
+ }) ?? [];
17
21
  const builder = config?.core?.builder;
18
22
  const builderPackages = builder && /webpack/.test(builder) ? [`@storybook/builder-${builder}`, `@storybook/manager-${builder}`] : [];
19
23
  return [...addons, ...builderPackages].map(getPackageName);
@@ -1,5 +1,7 @@
1
1
  export type StorybookConfig = {
2
- addons?: string[];
2
+ addons?: (string | {
3
+ name: string;
4
+ })[];
3
5
  core?: {
4
6
  builder?: string;
5
7
  };
@@ -1,8 +1,9 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ import { hasDependency } from '../../util/plugin.js';
3
4
  export const NAME = 'Stryker';
4
5
  export const ENABLERS = ['@stryker-mutator/core'];
5
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
6
7
  export const CONFIG_FILE_PATTERNS = ['?(.)stryker.{conf,config}.{js,mjs,json}'];
7
8
  const findStrykerDependencies = async (configFilePath) => {
8
9
  const config = await _load(configFilePath);
@@ -2,9 +2,10 @@ import { compact } from '../../util/array.js';
2
2
  import { _load } from '../../util/loader.js';
3
3
  import { getPackageName } from '../../util/modules.js';
4
4
  import { timerify } from '../../util/performance.js';
5
+ import { hasDependency } from '../../util/plugin.js';
5
6
  export const NAME = 'TypeScript';
6
7
  export const ENABLERS = ['typescript'];
7
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
8
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
8
9
  export const CONFIG_FILE_PATTERNS = ['tsconfig.json'];
9
10
  const findTypeScriptDependencies = async (configFilePath) => {
10
11
  const config = await _load(configFilePath);
@@ -1,18 +1,31 @@
1
1
  import { compact } from '../../util/array.js';
2
2
  import { _load } from '../../util/loader.js';
3
3
  import { timerify } from '../../util/performance.js';
4
+ import { hasDependency } from '../../util/plugin.js';
5
+ import { getDependenciesFromConfig } from '../babel/index.js';
4
6
  export const NAME = 'Webpack';
5
7
  export const ENABLERS = ['webpack'];
6
- export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
8
+ export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
7
9
  export const CONFIG_FILE_PATTERNS = ['webpack.config*.{js,ts}'];
8
- const resolveRuleSetLoaders = (rule) => {
10
+ const hasBabelOptions = (use) => Boolean(use) &&
11
+ typeof use !== 'string' &&
12
+ 'loader' in use &&
13
+ typeof use.loader === 'string' &&
14
+ use.loader === 'babel-loader' &&
15
+ typeof use.options === 'object';
16
+ const resolveRuleSetDependencies = (rule) => {
9
17
  if (!rule || typeof rule === 'string')
10
18
  return [];
11
19
  if (typeof rule.use === 'string')
12
20
  return [rule.use];
13
- if (Array.isArray(rule.use))
14
- return rule.use.flatMap(resolveUseItemLoader);
15
- return rule.use && typeof rule.use !== 'function' ? resolveUseItemLoader(rule.use) : [];
21
+ if (!rule.use || typeof rule.use === 'function')
22
+ return [];
23
+ return [rule.use].flat().flatMap((use) => {
24
+ if (hasBabelOptions(use)) {
25
+ return [...resolveUseItemLoader(use), ...getDependenciesFromConfig(use.options)];
26
+ }
27
+ return resolveUseItemLoader(use);
28
+ });
16
29
  };
17
30
  const resolveUseItemLoader = (use) => {
18
31
  if (!use)
@@ -23,17 +36,19 @@ const resolveUseItemLoader = (use) => {
23
36
  return [use.loader];
24
37
  return [];
25
38
  };
26
- const findWebpackDependencies = async (configFilePath, { manifest }) => {
39
+ const findWebpackDependencies = async (configFilePath, { manifest, isProduction }) => {
27
40
  let config = await _load(configFilePath);
28
41
  if (typeof config === 'function') {
29
- config = config();
42
+ config = config({ production: isProduction }, { mode: isProduction ? 'production' : 'development' });
30
43
  }
31
- const loaders = (config.module?.rules?.flatMap(resolveRuleSetLoaders) ?? [])
32
- .map(loader => loader.replace(/\?.*/, ''))
33
- .filter(loader => !loader.startsWith('/'));
44
+ const dependencies = [config].flat().flatMap(config => {
45
+ return (config.module?.rules?.flatMap(resolveRuleSetDependencies) ?? [])
46
+ .map(loader => loader.replace(/\?.*/, ''))
47
+ .filter(loader => !loader.startsWith('/'));
48
+ });
34
49
  const scripts = Object.values(manifest.scripts ?? {});
35
50
  const webpackCLI = scripts.some(script => script?.includes('webpack ')) ? ['webpack-cli'] : [];
36
51
  const webpackDevServer = scripts.some(script => script?.includes('webpack serve')) ? ['webpack-dev-server'] : [];
37
- return compact([...loaders, ...webpackCLI, ...webpackDevServer]);
52
+ return compact([...dependencies, ...webpackCLI, ...webpackDevServer]);
38
53
  };
39
54
  export const findDependencies = timerify(findWebpackDependencies);
@@ -0,0 +1,10 @@
1
+ import type { Configuration } from 'webpack';
2
+ type Mode = 'none' | 'development' | 'production';
3
+ type Env = {
4
+ production: boolean;
5
+ };
6
+ type Argv = {
7
+ mode: Mode;
8
+ };
9
+ export type WebpackConfig = Configuration | ((env: Env, argv: Argv) => Configuration);
10
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -10,6 +10,7 @@ type GenericPluginCallbackOptions = {
10
10
  manifest: PackageJson;
11
11
  config: PluginConfiguration;
12
12
  workspaceConfig: WorkspaceConfiguration;
13
+ isProduction: boolean;
13
14
  };
14
- export type GenericPluginCallback = (configFilePath: string, { cwd, manifest, config, workspaceConfig }: GenericPluginCallbackOptions) => Promise<string[]> | string[];
15
+ export type GenericPluginCallback = (configFilePath: string, { cwd, manifest, config, workspaceConfig, isProduction }: GenericPluginCallbackOptions) => Promise<string[]> | string[];
15
16
  export {};
@@ -4,9 +4,9 @@ export const getPackageNameFromModuleSpecifier = (moduleSpecifier) => {
4
4
  return moduleSpecifier.startsWith('@') ? parts.join('/') : parts[0];
5
5
  };
6
6
  export const getPackageName = (value) => {
7
- const match = ensurePosixPath(value).match(/(?<=node_modules\/)(@[^/]+\/[^/]+|[^/]+)/);
7
+ const match = ensurePosixPath(value).match(/(?<=node_modules\/)(@[^/]+\/[^/]+|[^/]+)/g);
8
8
  if (match)
9
- return match[1];
9
+ return match[match.length - 1];
10
10
  if (value.startsWith('@')) {
11
11
  const [scope, packageName] = value.split('/');
12
12
  return [scope, packageName].join('/');
@@ -0,0 +1 @@
1
+ export declare const hasDependency: (dependencies: Set<string>, values: (string | RegExp)[]) => boolean;
@@ -0,0 +1,12 @@
1
+ export const hasDependency = (dependencies, values) => values.some(value => {
2
+ if (typeof value === 'string') {
3
+ return dependencies.has(value);
4
+ }
5
+ else if (value instanceof RegExp) {
6
+ for (const dependency of dependencies) {
7
+ if (value.test(dependency))
8
+ return true;
9
+ }
10
+ }
11
+ return false;
12
+ });
@@ -230,6 +230,7 @@ export default class WorkspaceWorker {
230
230
  manifest: this.manifest,
231
231
  config: pluginConfig,
232
232
  workspaceConfig: this.config,
233
+ isProduction: this.isProduction,
233
234
  });
234
235
  return dependencies.map(symbol => ({ type: 'unlisted', filePath: configFilePath, symbol }));
235
236
  }))).flat();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0-beta.9",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript project",
5
5
  "keywords": [
6
6
  "find",
@@ -35,14 +35,14 @@
35
35
  "knip": "node ./dist/cli.js",
36
36
  "lint": "eslint src",
37
37
  "lint:fix": "eslint src --fix",
38
- "test": "globstar -- node --loader tsx --test \"test/**/*.spec.ts\"",
38
+ "test": "globstar -- node --loader tsx --test \"test/**/*.test.ts\"",
39
39
  "watch": "tsc --watch",
40
40
  "prebuild": "rm -rf dist",
41
41
  "build": "tsc",
42
42
  "docs": "npm run docs:cli && npm run docs:plugins && npm run docs:format",
43
43
  "docs:cli": "tsx ./scripts/update-cli-usage-in-readme.ts",
44
44
  "docs:plugins": "tsx ./scripts/generate-plugin-docs.ts",
45
- "docs:format": "remark README.md src/plugins/*/README.md -o",
45
+ "docs:format": "remark README.md docs/*.md src/plugins/*/README.md -o",
46
46
  "release": "release-it",
47
47
  "postinstall": "patch-package",
48
48
  "create-plugin": "tsx ./scripts/create-new-plugin.ts"
package/schema.json CHANGED
@@ -188,6 +188,10 @@
188
188
  "title": "Jest plugin configuration (https://github.com/webpro/knip/blob/next/src/plugins/jest/README.md)",
189
189
  "$ref": "#/definitions/plugin"
190
190
  },
191
+ "lint-staged": {
192
+ "title": "lint-staged plugin configuration (https://github.com/webpro/knip/blob/next/src/plugins/lint-staged/README.md)",
193
+ "$ref": "#/definitions/plugin"
194
+ },
191
195
  "mocha": {
192
196
  "title": "Mocha plugin configuration (https://github.com/webpro/knip/blob/next/src/plugins/mocha/README.md)",
193
197
  "$ref": "#/definitions/plugin"
@@ -216,6 +220,10 @@
216
220
  "title": "Prettier plugin configuration (https://github.com/webpro/knip/blob/next/src/plugins/prettier/README.md)",
217
221
  "$ref": "#/definitions/plugin"
218
222
  },
223
+ "release-it": {
224
+ "title": "Release It plugin configuration (https://github.com/webpro/knip/blob/next/src/plugins/release-it/README.md)",
225
+ "$ref": "#/definitions/plugin"
226
+ },
219
227
  "remark": {
220
228
  "title": "Remark plugin configuration (https://github.com/webpro/knip/blob/next/src/plugins/remark/README.md)",
221
229
  "$ref": "#/definitions/plugin"