knip 1.0.0-beta.4 → 1.0.0-beta.6

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 (67) hide show
  1. package/README.md +28 -21
  2. package/dist/cli.js +5 -6
  3. package/dist/configuration-chief.d.ts +1 -3
  4. package/dist/configuration-chief.js +5 -8
  5. package/dist/index.js +4 -4
  6. package/dist/plugins/_template/index.d.ts +3 -1
  7. package/dist/plugins/_template/index.js +3 -3
  8. package/dist/plugins/babel/index.d.ts +3 -1
  9. package/dist/plugins/babel/index.js +3 -6
  10. package/dist/plugins/capacitor/index.d.ts +2 -0
  11. package/dist/plugins/capacitor/index.js +3 -3
  12. package/dist/plugins/changesets/index.d.ts +2 -0
  13. package/dist/plugins/changesets/index.js +3 -1
  14. package/dist/plugins/commitlint/index.d.ts +2 -0
  15. package/dist/plugins/commitlint/index.js +3 -1
  16. package/dist/plugins/cypress/index.d.ts +2 -0
  17. package/dist/plugins/cypress/index.js +3 -1
  18. package/dist/plugins/eslint/index.d.ts +2 -0
  19. package/dist/plugins/eslint/index.js +3 -1
  20. package/dist/plugins/gatsby/index.d.ts +2 -0
  21. package/dist/plugins/gatsby/index.js +3 -3
  22. package/dist/plugins/jest/index.d.ts +2 -0
  23. package/dist/plugins/jest/index.js +3 -3
  24. package/dist/plugins/mocha/index.d.ts +2 -0
  25. package/dist/plugins/mocha/index.js +3 -3
  26. package/dist/plugins/next/index.d.ts +2 -0
  27. package/dist/plugins/next/index.js +3 -3
  28. package/dist/plugins/nx/index.d.ts +2 -0
  29. package/dist/plugins/nx/index.js +3 -3
  30. package/dist/plugins/nyc/index.d.ts +2 -0
  31. package/dist/plugins/nyc/index.js +3 -1
  32. package/dist/plugins/playwright/index.d.ts +2 -0
  33. package/dist/plugins/playwright/index.js +3 -1
  34. package/dist/plugins/postcss/index.d.ts +2 -1
  35. package/dist/plugins/postcss/index.js +3 -2
  36. package/dist/plugins/prettier/index.d.ts +2 -1
  37. package/dist/plugins/prettier/index.js +3 -2
  38. package/dist/plugins/remark/index.d.ts +2 -0
  39. package/dist/plugins/remark/index.js +3 -1
  40. package/dist/plugins/remix/index.d.ts +2 -0
  41. package/dist/plugins/remix/index.js +3 -3
  42. package/dist/plugins/rollup/index.d.ts +2 -0
  43. package/dist/plugins/rollup/index.js +3 -1
  44. package/dist/plugins/sentry/index.d.ts +2 -0
  45. package/dist/plugins/sentry/index.js +3 -1
  46. package/dist/plugins/storybook/index.d.ts +2 -0
  47. package/dist/plugins/storybook/index.js +3 -3
  48. package/dist/plugins/stryker/index.d.ts +2 -0
  49. package/dist/plugins/stryker/index.js +3 -1
  50. package/dist/plugins/typescript/index.d.ts +3 -1
  51. package/dist/plugins/typescript/index.js +4 -2
  52. package/dist/plugins/webpack/index.d.ts +3 -2
  53. package/dist/plugins/webpack/index.js +3 -2
  54. package/dist/types/cli.d.ts +1 -1
  55. package/dist/util/cli-arguments.d.ts +26 -0
  56. package/dist/util/cli-arguments.js +58 -0
  57. package/dist/util/debug.js +1 -1
  58. package/dist/util/glob.js +6 -2
  59. package/dist/util/loader.js +1 -1
  60. package/dist/util/performance.js +1 -1
  61. package/dist/util/resolve-included-issue-types.d.ts +0 -1
  62. package/dist/workspace-worker.js +7 -6
  63. package/package.json +17 -8
  64. package/dist/util/help.d.ts +0 -1
  65. package/dist/util/help.js +0 -36
  66. package/dist/util/parseArgs.d.ts +0 -25
  67. package/dist/util/parseArgs.js +0 -24
package/README.md CHANGED
@@ -80,29 +80,30 @@ This will analyze the project and output unused files, dependencies and exports.
80
80
 
81
81
  ## Options
82
82
 
83
- npx knip
83
+ $ npx knip --help
84
84
  knip [options]
85
85
 
86
86
  Options:
87
- -c/--config [file] Configuration file path (default: ./knip.json, knip.jsonc or package.json#knip)
88
- -t/--tsConfig [file] TypeScript configuration path (default: ./tsconfig.json)
89
- --production Analyze only production source files (e.g. no tests, devDependencies, exported types)
90
- --strict Consider only direct dependencies of workspaces. Not devDependencies, not ancestor workspaces.
91
- --workspace Analyze a single workspace (default: analyze all configured workspaces)
92
- --include Report only listed issue type(s), can be comma-separated or repeated
93
- --exclude Exclude issue type(s) from report, can be comma-separated or repeated
94
- --ignore Ignore files matching this glob pattern, can be repeated
95
- --no-gitignore Don't use .gitignore
96
- --no-progress Don't show dynamic progress updates
97
- --no-exit-code Always exit with code zero (0)
98
- --max-issues Maximum number of issues before non-zero exit code (default: 0)
99
- --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
100
- --reporter-options Pass extra options to the reporter (as JSON string, see example)
101
- --debug Show debug output
102
- --debug-file-filter Filter for files in debug output (regex as string)
103
- --performance Measure running time of expensive functions and display stats table
104
-
105
- Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates
87
+ -c/--config [file] Configuration file path (default: knip.json, knip.jsonc or package.json#knip)
88
+ -t/--tsConfig [file] TypeScript configuration path (default: tsconfig.json)
89
+ --production Analyze only production source files (e.g. no tests, devDependencies, exported types)
90
+ --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)
91
+ --workspace Analyze a single workspace (default: analyze all configured workspaces)
92
+ --include-entry-exports Include unused exports in entry files (without `@public`)
93
+ --ignore Ignore files matching this glob pattern, can be repeated
94
+ --no-gitignore Don't use .gitignore
95
+ --include Report only provided issue type(s), can be comma-separated or repeated (1)
96
+ --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
97
+ --no-progress Don't show dynamic progress updates
98
+ --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
99
+ --reporter-options Pass extra options to the reporter (as JSON string, see example)
100
+ --no-exit-code Always exit with code zero (0)
101
+ --max-issues Maximum number of issues before non-zero exit code (default: 0)
102
+ --debug Show debug output
103
+ --debug-file-filter Filter for files in debug output (regex as string)
104
+ --performance Measure running time of expensive functions and display stats table
105
+
106
+ (1) Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates
106
107
 
107
108
  Examples:
108
109
 
@@ -271,6 +272,12 @@ rest to find which of those dependencies are unused or missing.
271
272
  Other configuration files use `require` or `import` statements to use dependencies, so they can be analyzed like the
272
273
  rest of the source files. These configuration files are also considered `entry` files.
273
274
 
275
+ ### Create a new plugin
276
+
277
+ Getting false positives because a plugin is missing? Want to help out? Feel free to add your own plugin! Get started:
278
+
279
+ npm run create-plugin -- --name [myplugin]
280
+
274
281
  ## Configuration
275
282
 
276
283
  ### Libraries versus Applications
@@ -407,7 +414,7 @@ The following commands are similar:
407
414
  unimported
408
415
  knip --production --include files,dependencies,unlisted
409
416
 
410
- See [production mode](#production-mode).
417
+ See [production mode][7].
411
418
 
412
419
  ## TypeScript language services
413
420
 
package/dist/cli.js CHANGED
@@ -2,15 +2,14 @@
2
2
  import path from 'node:path';
3
3
  import { register } from 'esbuild-register/dist/node.js';
4
4
  import reporters from './reporters/index.js';
5
+ import parsedArgs, { helpText } from './util/cli-arguments.js';
5
6
  import { ConfigurationError } from './util/errors.js';
6
- import { printHelp } from './util/help.js';
7
- import parsedArgs from './util/parseArgs.js';
8
7
  import { measure } from './util/performance.js';
9
8
  import { main } from './index.js';
10
9
  register();
11
- const { values: { debug: isDebug = false, help, 'ignore-entry-exports': isIgnoreEntryExports = false, 'max-issues': maxIssues = '0', 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': noProgress = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, }, } = parsedArgs;
10
+ const { values: { debug: isDebug = false, help, 'include-entry-exports': isIncludeEntryExports = false, 'max-issues': maxIssues = '0', 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': noProgress = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, }, } = parsedArgs;
12
11
  if (help) {
13
- printHelp();
12
+ console.log(helpText);
14
13
  process.exit(0);
15
14
  }
16
15
  const cwd = process.cwd();
@@ -25,7 +24,7 @@ const run = async () => {
25
24
  isStrict,
26
25
  isProduction,
27
26
  isShowProgress,
28
- isIgnoreEntryExports,
27
+ isIncludeEntryExports,
29
28
  });
30
29
  await printReport({ report, issues, cwd, isProduction, options: reporterOptions });
31
30
  const totalErrorCount = Object.keys(report)
@@ -39,7 +38,7 @@ const run = async () => {
39
38
  catch (error) {
40
39
  if (error instanceof ConfigurationError) {
41
40
  console.error(error.message + '\n');
42
- printHelp();
41
+ console.log(helpText);
43
42
  process.exit(1);
44
43
  }
45
44
  throw error;
@@ -5,18 +5,16 @@ import type { Configuration, WorkspaceConfiguration } from './types/config.js';
5
5
  import type { PackageJson } from '@npmcli/package-json';
6
6
  type ConfigurationManagerOptions = {
7
7
  cwd?: string;
8
- isStrict: boolean;
9
8
  isProduction: boolean;
10
9
  };
11
10
  export default class ConfigurationChief {
12
11
  cwd: string;
13
- isStrict: boolean;
14
12
  isProduction: boolean;
15
13
  config: Configuration;
16
14
  manifestPath: undefined | string;
17
15
  manifest: undefined | PackageJson;
18
16
  manifestWorkspaces: undefined | string[];
19
- constructor({ cwd, isStrict, isProduction }: ConfigurationManagerOptions);
17
+ constructor({ cwd, isProduction }: ConfigurationManagerOptions);
20
18
  loadLocalConfig(): Promise<void>;
21
19
  normalize(rawLocalConfig: z.infer<typeof ConfigurationValidator>): {
22
20
  include: string[];
@@ -5,10 +5,10 @@ import { ConfigurationValidator } from './configuration-validator.js';
5
5
  import { ROOT_WORKSPACE_NAME } from './constants.js';
6
6
  import * as plugins from './plugins/index.js';
7
7
  import { arrayify } from './util/array.js';
8
+ import parsedArgs from './util/cli-arguments.js';
8
9
  import { ConfigurationError } from './util/errors.js';
9
10
  import { findFile, loadJSON } from './util/fs.js';
10
11
  import { ensurePosixPath } from './util/glob.js';
11
- import parsedArgs from './util/parseArgs.js';
12
12
  import { resolveIncludedIssueTypes } from './util/resolve-included-issue-types.js';
13
13
  import { byPathDepth } from './util/workspace.js';
14
14
  const { values: { config: rawConfigArg, workspace: rawWorkspaceArg, include = [], exclude = [] }, } = parsedArgs;
@@ -31,15 +31,13 @@ const defaultConfig = {
31
31
  const PLUGIN_NAMES = Object.keys(plugins);
32
32
  export default class ConfigurationChief {
33
33
  cwd = process.cwd();
34
- isStrict = false;
35
34
  isProduction = false;
36
35
  config;
37
36
  manifestPath;
38
37
  manifest;
39
38
  manifestWorkspaces;
40
- constructor({ cwd, isStrict, isProduction }) {
39
+ constructor({ cwd, isProduction }) {
41
40
  this.cwd = cwd ?? this.cwd;
42
- this.isStrict = isStrict;
43
41
  this.isProduction = isProduction;
44
42
  this.config = defaultConfig;
45
43
  }
@@ -102,7 +100,7 @@ export default class ConfigurationChief {
102
100
  }
103
101
  else {
104
102
  const isObject = typeof pluginConfig !== 'string' && !Array.isArray(pluginConfig);
105
- const config = typeof pluginConfig === 'string' ? [pluginConfig] : isObject ? arrayify(pluginConfig.config) : null;
103
+ const config = isObject ? arrayify(pluginConfig.config) : pluginConfig ? arrayify(pluginConfig) : null;
106
104
  const entry = isObject && 'entry' in pluginConfig ? arrayify(pluginConfig.entry) : null;
107
105
  const project = isObject && 'project' in pluginConfig ? arrayify(pluginConfig.project) : entry;
108
106
  workspaces[workspaceName][pluginName] = {
@@ -150,7 +148,7 @@ export default class ConfigurationChief {
150
148
  ancestors: [],
151
149
  };
152
150
  const isOnlyRootWorkspace = (manifestWorkspaces.length === 0 && !rawWorkspaceArg) ||
153
- (rawWorkspaceArg && ['.', './'].includes(rawWorkspaceArg));
151
+ (rawWorkspaceArg && [ROOT_WORKSPACE_NAME, './'].includes(rawWorkspaceArg));
154
152
  if (isOnlyRootWorkspace)
155
153
  return [rootWorkspace];
156
154
  if (rawWorkspaceArg) {
@@ -160,7 +158,7 @@ export default class ConfigurationChief {
160
158
  config: this.getConfigForWorkspace(rawWorkspaceArg),
161
159
  ancestors: [ROOT_WORKSPACE_NAME],
162
160
  };
163
- return this.hasConfigForWorkspace('.') ? [rootWorkspace, workspace] : [workspace];
161
+ return this.hasConfigForWorkspace(ROOT_WORKSPACE_NAME) ? [rootWorkspace, workspace] : [workspace];
164
162
  }
165
163
  const workspaces = [...manifestWorkspaces, ...additionalWorkspaces];
166
164
  const activeWorkspaces = workspaces.filter(workspaceName => this.hasConfigForWorkspace(workspaceName));
@@ -215,7 +213,6 @@ export default class ConfigurationChief {
215
213
  include: this.config.include ?? [],
216
214
  exclude: this.config.exclude ?? [],
217
215
  isProduction: this.isProduction,
218
- isStrict: this.isStrict,
219
216
  });
220
217
  }
221
218
  }
package/dist/index.js CHANGED
@@ -16,8 +16,8 @@ import { loadTSConfig } from './util/tsconfig-loader.js';
16
16
  import { byPathDepth } from './util/workspace.js';
17
17
  import WorkspaceWorker from './workspace-worker.js';
18
18
  export const main = async (unresolvedConfiguration) => {
19
- const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIgnoreEntryExports } = unresolvedConfiguration;
20
- const chief = new ConfigurationChief({ cwd, isStrict, isProduction });
19
+ const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIncludeEntryExports } = unresolvedConfiguration;
20
+ const chief = new ConfigurationChief({ cwd, isProduction });
21
21
  debugLogObject('Unresolved configuration', unresolvedConfiguration);
22
22
  const collector = new IssueCollector({ cwd, isShowProgress });
23
23
  collector.updateMessage('Reading configuration and manifest files...');
@@ -81,7 +81,7 @@ export const main = async (unresolvedConfiguration) => {
81
81
  });
82
82
  debugLogFiles(`Globbed entry paths${suffix}`, workspaceEntryPaths);
83
83
  workspaceEntryPaths.forEach(entryPath => principal.addEntryPath(entryPath));
84
- if (isIgnoreEntryExports)
84
+ if (!isIncludeEntryExports)
85
85
  workspaceEntryPaths.forEach(entryPath => lab.skipExportsAnalysisFor(entryPath));
86
86
  collector.updateMessage(`Resolving production plugin entry files${suffix}...`);
87
87
  const pluginWorkspaceEntryPaths = await _glob({
@@ -122,7 +122,7 @@ export const main = async (unresolvedConfiguration) => {
122
122
  });
123
123
  debugLogFiles(`Globbed entry paths${suffix}`, workspaceEntryPaths);
124
124
  workspaceEntryPaths.forEach(entryPath => principal.addEntryPath(entryPath));
125
- if (isIgnoreEntryExports)
125
+ if (!isIncludeEntryExports)
126
126
  workspaceEntryPaths.forEach(entryPath => lab.skipExportsAnalysisFor(entryPath));
127
127
  }
128
128
  {
@@ -1,7 +1,9 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "";
3
+ export declare const ENABLERS: string[];
4
+ export declare const isEnabled: IsPluginEnabledCallback;
2
5
  export declare const CONFIG_FILE_PATTERNS: never[];
3
6
  export declare const ENTRY_FILE_PATTERNS: never[];
4
7
  export declare const PRODUCTION_ENTRY_FILE_PATTERNS: never[];
5
8
  export declare const PROJECT_FILE_PATTERNS: never[];
6
- export declare const isEnabled: IsPluginEnabledCallback;
7
9
  export declare const findDependencies: GenericPluginCallback;
@@ -1,12 +1,12 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
+ export const NAME = '';
4
+ export const ENABLERS = [''];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
3
6
  export const CONFIG_FILE_PATTERNS = [];
4
7
  export const ENTRY_FILE_PATTERNS = [];
5
8
  export const PRODUCTION_ENTRY_FILE_PATTERNS = [];
6
9
  export const PROJECT_FILE_PATTERNS = [];
7
- export const isEnabled = ({ dependencies }) => {
8
- return dependencies.has('[pkg]');
9
- };
10
10
  const findPluginDependencies = async (configFilePath, { manifest }) => {
11
11
  const config = configFilePath.endsWith('package.json') ? manifest.plugin : await _load(configFilePath);
12
12
  return config?.plugins ?? [];
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
- export declare const CONFIG_FILE_PATTERNS: string[];
2
+ export declare const NAME = "Babel";
3
+ export declare const ENABLERS: string[];
3
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
+ export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -3,6 +3,9 @@ import { _load } from '../../util/loader.js';
3
3
  import { getPackageName } from '../../util/modules.js';
4
4
  import { timerify } from '../../util/performance.js';
5
5
  import { resolvePresetName, resolvePluginName } from './helpers.js';
6
+ 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));
6
9
  export const CONFIG_FILE_PATTERNS = [
7
10
  'babel.config.json',
8
11
  'babel.config.js',
@@ -11,12 +14,6 @@ export const CONFIG_FILE_PATTERNS = [
11
14
  '.babelrc',
12
15
  'package.json',
13
16
  ];
14
- export const isEnabled = ({ dependencies }) => {
15
- return (dependencies.has('@babel/cli') ||
16
- dependencies.has('@babel/core') ||
17
- dependencies.has('@babel/preset-env') ||
18
- dependencies.has('@babel/register'));
19
- };
20
17
  const api = {
21
18
  caller: () => true,
22
19
  };
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Capacitor";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,8 +1,8 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => {
4
- return dependencies.has('@capacitor/core') || dependencies.has('@capacitor/cli');
5
- };
3
+ export const NAME = 'Capacitor';
4
+ export const ENABLERS = ['@capacitor/core', '@capacitor/cli'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
6
  export const CONFIG_FILE_PATTERNS = ['capacitor.config.ts'];
7
7
  const findCapacitorDependencies = async (configFilePath) => {
8
8
  const config = await _load(configFilePath);
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Changesets";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,6 +1,8 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => dependencies.has('@changesets/cli');
3
+ export const NAME = 'Changesets';
4
+ export const ENABLERS = ['@changesets/cli'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
6
  export const CONFIG_FILE_PATTERNS = ['.changeset/config.json'];
5
7
  const findChangesetsDependencies = async (configFilePath) => {
6
8
  const config = await _load(configFilePath);
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "commitlint";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,6 +1,8 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => dependencies.has('@commitlint/cli');
3
+ export const NAME = 'commitlint';
4
+ export const ENABLERS = ['@commitlint/cli'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
6
  export const CONFIG_FILE_PATTERNS = ['commitlint.config.{js,ts}'];
5
7
  const findCommitLintDependencies = async (configFilePath) => {
6
8
  const config = await _load(configFilePath);
@@ -1,3 +1,5 @@
1
1
  import type { IsPluginEnabledCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Cypress";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -1,4 +1,6 @@
1
- export const isEnabled = ({ dependencies }) => dependencies.has('cypress');
1
+ export const NAME = 'Cypress';
2
+ export const ENABLERS = ['cypress'];
3
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
2
4
  export const ENTRY_FILE_PATTERNS = [
3
5
  'cypress.config.{js,ts,mjs,cjs}',
4
6
  'cypress/support/e2e.{js,jsx,ts,tsx}',
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "ESLint";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -6,7 +6,9 @@ import { _load } from '../../util/loader.js';
6
6
  import { getPackageName } from '../../util/modules.js';
7
7
  import { timerify } from '../../util/performance.js';
8
8
  import { resolvePluginPackageName, customResolvePluginPackageNames, getDependenciesFromSettings } from './helpers.js';
9
- export const isEnabled = ({ dependencies }) => dependencies.has('eslint');
9
+ export const NAME = 'ESLint';
10
+ export const ENABLERS = ['eslint'];
11
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
10
12
  export const CONFIG_FILE_PATTERNS = ['.eslintrc', '.eslintrc.{js,json,cjs}', '.eslintrc.{yml,yaml}', 'package.json'];
11
13
  export const ENTRY_FILE_PATTERNS = ['eslint.config.js'];
12
14
  const findESLintDependencies = async (configFilePath, { cwd, manifest, workspaceConfig }) => {
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Gatsby";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const PRODUCTION_ENTRY_FILE_PATTERNS: string[];
@@ -1,8 +1,8 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => {
4
- return dependencies.has('gatsby') || dependencies.has('gatsby-cli');
5
- };
3
+ export const NAME = 'Gatsby';
4
+ export const ENABLERS = ['gatsby', 'gatsby-cli'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
6
6
  export const CONFIG_FILE_PATTERNS = ['gatsby-{config,node}.{js,jsx,ts,tsx}'];
7
7
  export const PRODUCTION_ENTRY_FILE_PATTERNS = [
8
8
  'gatsby-{browser,ssr}.{js,jsx,ts,tsx}',
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Jest";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -2,9 +2,9 @@ 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
- export const isEnabled = ({ dependencies }) => {
6
- return dependencies.has('jest');
7
- };
5
+ export const NAME = 'Jest';
6
+ export const ENABLERS = ['jest'];
7
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
8
8
  export const CONFIG_FILE_PATTERNS = ['jest.config.{js,ts,mjs,cjs,json}'];
9
9
  export const ENTRY_FILE_PATTERNS = ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'];
10
10
  const resolveExtensibleConfig = async (configFilePath) => {
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Mocha";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -1,9 +1,9 @@
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
- export const isEnabled = ({ dependencies }) => {
5
- return dependencies.has('mocha');
6
- };
4
+ export const NAME = 'Mocha';
5
+ export const ENABLERS = ['mocha'];
6
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
7
7
  export const CONFIG_FILE_PATTERNS = ['.mocharc.{js,cjs,json,jsonc,yml,yaml}', 'package.json'];
8
8
  export const ENTRY_FILE_PATTERNS = ['test/**/*.{js,cjs,mjs}'];
9
9
  const findMochaDependencies = async (configFilePath, { manifest }) => {
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Next.js";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const ENTRY_FILE_PATTERNS: string[];
4
6
  export declare const PRODUCTION_ENTRY_FILE_PATTERNS: string[];
@@ -1,5 +1,5 @@
1
- export const isEnabled = ({ dependencies }) => {
2
- return dependencies.has('next');
3
- };
1
+ export const NAME = 'Next.js';
2
+ export const ENABLERS = ['next'];
3
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
4
  export const ENTRY_FILE_PATTERNS = ['next.config.{js,ts}'];
5
5
  export const PRODUCTION_ENTRY_FILE_PATTERNS = ['pages/**/*.{js,jsx,ts,tsx}', 'src/pages/**/*.{js,jsx,ts,tsx}'];
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Nx";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,9 +1,9 @@
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
- export const isEnabled = ({ dependencies }) => {
5
- return dependencies.has('@nrwl/workspace');
6
- };
4
+ export const NAME = 'Nx';
5
+ export const ENABLERS = ['@nrwl/workspace'];
6
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
7
7
  export const CONFIG_FILE_PATTERNS = ['{apps,libs}/**/project.json'];
8
8
  const findNxDependencies = async (configFilePath) => {
9
9
  const config = await _load(configFilePath);
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "nyc";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,6 +1,8 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => dependencies.has('nyc');
3
+ export const NAME = 'nyc';
4
+ export const ENABLERS = ['nyc'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
6
  export const CONFIG_FILE_PATTERNS = ['.nycrc', '.nycrc.json', '.nycrc.{yml,yaml}', 'nyc.config.js'];
5
7
  const findNycDependencies = async (configFilePath) => {
6
8
  const config = await _load(configFilePath);
@@ -1,3 +1,5 @@
1
1
  import type { IsPluginEnabledCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Playwright";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -1,2 +1,4 @@
1
- export const isEnabled = ({ dependencies }) => dependencies.has('@playwright/test');
1
+ export const NAME = 'Playwright';
2
+ export const ENABLERS = ['@playwright/test'];
3
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
2
4
  export const ENTRY_FILE_PATTERNS = ['playwright.config.{js,ts}', '.*{test,spec}.{js,ts,mjs}'];
@@ -1,5 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "PostCSS";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
- export declare const ENTRY_FILE_PATTERNS: string[];
5
6
  export declare const findDependencies: GenericPluginCallback;
@@ -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
- export const isEnabled = ({ dependencies }) => dependencies.has('postcss');
4
+ export const NAME = 'PostCSS';
5
+ export const ENABLERS = ['postcss'];
6
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
5
7
  export const CONFIG_FILE_PATTERNS = ['postcss.config.js', 'package.json'];
6
- export const ENTRY_FILE_PATTERNS = ['postcss.config.js'];
7
8
  const findPostCSSDependencies = async (configFilePath, { manifest }) => {
8
9
  const config = configFilePath.endsWith('package.json')
9
10
  ? manifest?.postcss
@@ -1,5 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Prettier";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
- export declare const ENTRY_FILE_PATTERNS: string[];
5
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,14 +1,15 @@
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
- export const isEnabled = ({ dependencies }) => dependencies.has('prettier');
4
+ export const NAME = 'Prettier';
5
+ export const ENABLERS = ['prettier'];
6
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
5
7
  export const CONFIG_FILE_PATTERNS = [
6
8
  '.prettierrc',
7
9
  '.prettierrc.{json,js,cjs,yml,yaml}',
8
10
  'prettier.config.{js,cjs}',
9
11
  'package.json',
10
12
  ];
11
- export const ENTRY_FILE_PATTERNS = ['.prettierrc.{js,cjs}', 'prettier.config.{js,cjs}'];
12
13
  const findPrettierDependencies = async (configFilePath, { manifest }) => {
13
14
  const config = configFilePath.endsWith('package.json')
14
15
  ? manifest.prettier
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Remark";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,6 +1,8 @@
1
1
  import { load } from 'js-yaml';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => dependencies.has('remark-cli');
3
+ export const NAME = 'Remark';
4
+ export const ENABLERS = ['remark-cli'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
6
  export const CONFIG_FILE_PATTERNS = [
5
7
  'package.json',
6
8
  '.remarkrc',
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Remix";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const ENTRY_FILE_PATTERNS: string[];
4
6
  export declare const PRODUCTION_ENTRY_FILE_PATTERNS: string[];
@@ -1,6 +1,6 @@
1
- export const isEnabled = ({ dependencies }) => {
2
- return dependencies.has('@remix-run/dev');
3
- };
1
+ export const NAME = 'Remix';
2
+ export const ENABLERS = ['@remix-run/dev'];
3
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
4
  export const ENTRY_FILE_PATTERNS = ['remix.config.js', 'remix.init/index.js'];
5
5
  export const PRODUCTION_ENTRY_FILE_PATTERNS = [
6
6
  'app/root.tsx',
@@ -1,3 +1,5 @@
1
1
  import type { IsPluginEnabledCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Rollup";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -1,2 +1,4 @@
1
- export const isEnabled = ({ dependencies }) => dependencies.has('rollup');
1
+ export const NAME = 'Rollup';
2
+ export const ENABLERS = ['rollup'];
3
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
2
4
  export const ENTRY_FILE_PATTERNS = ['rollup.config.{js,mjs,ts}'];
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Sentry";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const ENTRY_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,6 +1,8 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => dependencies.has('@sentry/replay');
3
+ export const NAME = 'Sentry';
4
+ export const ENABLERS = ['@sentry/replay'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
6
  export const ENTRY_FILE_PATTERNS = ['sentry.{client,server}.config.{js,ts}'];
5
7
  const findNycDependencies = async (configFilePath) => {
6
8
  const config = await _load(configFilePath);
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Storybook";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const ENTRY_FILE_PATTERNS: string[];
@@ -4,9 +4,9 @@ import { _load } from '../../util/loader.js';
4
4
  import { getPackageName } from '../../util/modules.js';
5
5
  import { timerify } from '../../util/performance.js';
6
6
  const require = createRequire(process.cwd());
7
- export const isEnabled = ({ dependencies }) => {
8
- return dependencies.has('@storybook/core') || dependencies.has('@nrwl/storybook');
9
- };
7
+ export const NAME = 'Storybook';
8
+ export const ENABLERS = ['@storybook/core', '@nrwl/storybook'];
9
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
10
10
  export const CONFIG_FILE_PATTERNS = ['.storybook/{main,manager}.{js,ts}'];
11
11
  export const ENTRY_FILE_PATTERNS = ['.storybook/preview.{js,jsx,ts,tsx}', '**/*.stories.{js,jsx,ts,tsx}'];
12
12
  export const PROJECT_FILE_PATTERNS = ['.storybook/**/*.{js,ts,tsx}'];
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
+ export declare const NAME = "Stryker";
3
+ export declare const ENABLERS: string[];
2
4
  export declare const isEnabled: IsPluginEnabledCallback;
3
5
  export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -1,6 +1,8 @@
1
1
  import { _load } from '../../util/loader.js';
2
2
  import { timerify } from '../../util/performance.js';
3
- export const isEnabled = ({ dependencies }) => dependencies.has('@stryker-mutator/core');
3
+ export const NAME = 'Stryker';
4
+ export const ENABLERS = ['@stryker-mutator/core'];
5
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
6
  export const CONFIG_FILE_PATTERNS = ['?(.)stryker.{conf,config}.{js,mjs,json}'];
5
7
  const findStrykerDependencies = async (configFilePath) => {
6
8
  const config = await _load(configFilePath);
@@ -1,4 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
- export declare const CONFIG_FILE_PATTERNS: string[];
2
+ export declare const NAME = "TypeScript";
3
+ export declare const ENABLERS: string[];
3
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
+ export declare const CONFIG_FILE_PATTERNS: string[];
4
6
  export declare const findDependencies: GenericPluginCallback;
@@ -2,11 +2,13 @@ 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
+ export const NAME = 'TypeScript';
6
+ export const ENABLERS = ['typescript'];
7
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
5
8
  export const CONFIG_FILE_PATTERNS = ['tsconfig.json'];
6
- export const isEnabled = ({ dependencies }) => dependencies.has('typescript');
7
9
  const findTypeScriptDependencies = async (configFilePath) => {
8
10
  const config = await _load(configFilePath);
9
- const extend = config?.extends ? [getPackageName(config.extends)] : [];
11
+ const extend = config?.extends && !config.extends.startsWith('.') ? [getPackageName(config.extends)] : [];
10
12
  const plugins = compact(config?.compilerOptions?.plugins?.map(plugin => plugin.name) ?? []);
11
13
  return [...extend, ...plugins];
12
14
  };
@@ -1,5 +1,6 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
- export declare const CONFIG_FILE_PATTERNS: string[];
3
- export declare const ENTRY_FILE_PATTERNS: string[];
2
+ export declare const NAME = "Webpack";
3
+ export declare const ENABLERS: string[];
4
4
  export declare const isEnabled: IsPluginEnabledCallback;
5
+ export declare const CONFIG_FILE_PATTERNS: string[];
5
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
+ export const NAME = 'Webpack';
5
+ export const ENABLERS = ['webpack'];
6
+ export const isEnabled = ({ dependencies }) => ENABLERS.some(enabler => dependencies.has(enabler));
4
7
  export const CONFIG_FILE_PATTERNS = ['webpack.config*.js'];
5
- export const ENTRY_FILE_PATTERNS = ['webpack.config*.js'];
6
- export const isEnabled = ({ dependencies }) => dependencies.has('webpack');
7
8
  const resolveRuleSetLoaders = (rule) => {
8
9
  if (!rule || typeof rule === 'string')
9
10
  return [];
@@ -5,5 +5,5 @@ export interface CommandLineOptions {
5
5
  isStrict: boolean;
6
6
  isProduction: boolean;
7
7
  isShowProgress: boolean;
8
- isIgnoreEntryExports: boolean;
8
+ isIncludeEntryExports: boolean;
9
9
  }
@@ -0,0 +1,26 @@
1
+ export declare const helpText = "knip [options]\n\nOptions:\n -c/--config [file] Configuration file path (default: knip.json, knip.jsonc or package.json#knip)\n -t/--tsConfig [file] TypeScript configuration path (default: tsconfig.json)\n --production Analyze only production source files (e.g. no tests, devDependencies, exported types)\n --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)\n --workspace Analyze a single workspace (default: analyze all configured workspaces)\n --include-entry-exports Include unused exports in entry files (without `@public`)\n --ignore Ignore files matching this glob pattern, can be repeated\n --no-gitignore Don't use .gitignore\n --include Report only provided issue type(s), can be comma-separated or repeated (1)\n --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)\n --no-progress Don't show dynamic progress updates\n --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --no-exit-code Always exit with code zero (0)\n --max-issues Maximum number of issues before non-zero exit code (default: 0)\n --debug Show debug output\n --debug-file-filter Filter for files in debug output (regex as string)\n --performance Measure running time of expensive functions and display stats table\n\n(1) Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates\n\nExamples:\n\n$ knip\n$ knip --production\n$ knip --workspace packages/client --include files,dependencies\n$ knip -c ./config/knip.json --reporter compact\n$ knip --reporter codeowners --reporter-options '{\"path\":\".github/CODEOWNERS\"}'\n$ knip --debug --debug-file-filter '(specific|particular)-module'\n\nMore info: https://github.com/webpro/knip";
2
+ declare const _default: {
3
+ values: {
4
+ config: string | undefined;
5
+ debug: boolean | undefined;
6
+ 'debug-file-filter': string | undefined;
7
+ exclude: string[] | undefined;
8
+ help: boolean | undefined;
9
+ ignore: string[] | undefined;
10
+ 'include-entry-exports': boolean | undefined;
11
+ include: string[] | undefined;
12
+ 'max-issues': string | undefined;
13
+ 'no-exit-code': boolean | undefined;
14
+ 'no-gitignore': boolean | undefined;
15
+ 'no-progress': boolean | undefined;
16
+ performance: boolean | undefined;
17
+ production: boolean | undefined;
18
+ reporter: string | undefined;
19
+ 'reporter-options': string | undefined;
20
+ strict: boolean | undefined;
21
+ tsConfig: string | undefined;
22
+ workspace: string | undefined;
23
+ };
24
+ positionals: [];
25
+ };
26
+ export default _default;
@@ -0,0 +1,58 @@
1
+ import { parseArgs } from 'node:util';
2
+ export const helpText = `knip [options]
3
+
4
+ Options:
5
+ -c/--config [file] Configuration file path (default: knip.json, knip.jsonc or package.json#knip)
6
+ -t/--tsConfig [file] TypeScript configuration path (default: tsconfig.json)
7
+ --production Analyze only production source files (e.g. no tests, devDependencies, exported types)
8
+ --strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)
9
+ --workspace Analyze a single workspace (default: analyze all configured workspaces)
10
+ --include-entry-exports Include unused exports in entry files (without \`@public\`)
11
+ --ignore Ignore files matching this glob pattern, can be repeated
12
+ --no-gitignore Don't use .gitignore
13
+ --include Report only provided issue type(s), can be comma-separated or repeated (1)
14
+ --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
15
+ --no-progress Don't show dynamic progress updates
16
+ --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
17
+ --reporter-options Pass extra options to the reporter (as JSON string, see example)
18
+ --no-exit-code Always exit with code zero (0)
19
+ --max-issues Maximum number of issues before non-zero exit code (default: 0)
20
+ --debug Show debug output
21
+ --debug-file-filter Filter for files in debug output (regex as string)
22
+ --performance Measure running time of expensive functions and display stats table
23
+
24
+ (1) Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates
25
+
26
+ Examples:
27
+
28
+ $ knip
29
+ $ knip --production
30
+ $ knip --workspace packages/client --include files,dependencies
31
+ $ knip -c ./config/knip.json --reporter compact
32
+ $ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
33
+ $ knip --debug --debug-file-filter '(specific|particular)-module'
34
+
35
+ More info: https://github.com/webpro/knip`;
36
+ export default parseArgs({
37
+ options: {
38
+ config: { type: 'string', short: 'c' },
39
+ debug: { type: 'boolean' },
40
+ 'debug-file-filter': { type: 'string' },
41
+ exclude: { type: 'string', multiple: true },
42
+ help: { type: 'boolean', short: 'h' },
43
+ ignore: { type: 'string', multiple: true },
44
+ 'include-entry-exports': { type: 'boolean' },
45
+ include: { type: 'string', multiple: true },
46
+ 'max-issues': { type: 'string' },
47
+ 'no-exit-code': { type: 'boolean' },
48
+ 'no-gitignore': { type: 'boolean' },
49
+ 'no-progress': { type: 'boolean' },
50
+ performance: { type: 'boolean' },
51
+ production: { type: 'boolean' },
52
+ reporter: { type: 'string' },
53
+ 'reporter-options': { type: 'string' },
54
+ strict: { type: 'boolean' },
55
+ tsConfig: { type: 'string', short: 't' },
56
+ workspace: { type: 'string' },
57
+ },
58
+ });
@@ -1,5 +1,5 @@
1
1
  import util from 'node:util';
2
- import parsedArgs from './parseArgs.js';
2
+ import parsedArgs from './cli-arguments.js';
3
3
  const { debug, 'debug-file-filter': debugFileFilter } = parsedArgs.values;
4
4
  const IS_ENABLED = debug ?? false;
5
5
  const FILE_FILTER = debugFileFilter;
package/dist/util/glob.js CHANGED
@@ -2,6 +2,7 @@ import path from 'node:path';
2
2
  import fg from 'fast-glob';
3
3
  import { globby } from 'globby';
4
4
  import memoize from 'nano-memoize';
5
+ import { ROOT_WORKSPACE_NAME } from '../constants.js';
5
6
  import { compact } from './array.js';
6
7
  import { debugLogObject } from './debug.js';
7
8
  import { timerify } from './performance.js';
@@ -22,8 +23,11 @@ const glob = async ({ cwd, workingDir = cwd, patterns, ignore = [], gitignore =
22
23
  const relativePath = path.posix.relative(cwdPosix, workingDirPosix);
23
24
  const prepend = (pattern) => prependDirToPattern(relativePath, pattern);
24
25
  const globPatterns = compact([patterns].flat().map(prepend).map(removeProductionSuffix)).sort(negatedLast);
25
- const ignorePatterns = [...ignore, '**/node_modules/**'];
26
- debugLogObject("Globbin'", { cwd, globPatterns, ignorePatterns });
26
+ const ignorePatterns = compact([
27
+ ...ignore.map(pattern => prependDirToPattern(relativePath, pattern)),
28
+ '**/node_modules/**',
29
+ ]);
30
+ debugLogObject(`Globbing (${relativePath || ROOT_WORKSPACE_NAME})`, { cwd, globPatterns, ignorePatterns });
27
31
  return globby(globPatterns, {
28
32
  cwd,
29
33
  ignore: ignorePatterns,
@@ -3,8 +3,8 @@ import { createRequire } from 'node:module';
3
3
  import path from 'node:path';
4
4
  import { load as esmLoad } from '@esbuild-kit/esm-loader';
5
5
  import yaml from 'js-yaml';
6
+ import parsedArgs from './cli-arguments.js';
6
7
  import { loadJSON } from './fs.js';
7
- import parsedArgs from './parseArgs.js';
8
8
  import { timerify } from './performance.js';
9
9
  const require = createRequire(process.cwd());
10
10
  const { values: { 'no-progress': noProgress = false }, } = parsedArgs;
@@ -1,7 +1,7 @@
1
1
  import { performance, PerformanceObserver } from 'node:perf_hooks';
2
2
  import EasyTable from 'easy-table';
3
3
  import prettyMilliseconds from 'pretty-ms';
4
- import parsedArgs from './parseArgs.js';
4
+ import parsedArgs from './cli-arguments.js';
5
5
  import Summary from 'summary';
6
6
  const { values } = parsedArgs;
7
7
  const { performance: isEnabled = false } = values;
@@ -1,7 +1,6 @@
1
1
  import type { Report } from '../types/issues.js';
2
2
  type Options = {
3
3
  isProduction?: boolean;
4
- isStrict?: boolean;
5
4
  include?: string[];
6
5
  exclude?: string[];
7
6
  };
@@ -47,14 +47,15 @@ export default class WorkspaceWorker {
47
47
  const dependencies = new Set([this.manifest, ...this.ancestorManifests]
48
48
  .flatMap(manifest => [Object.keys(manifest?.dependencies ?? {}), Object.keys(manifest?.devDependencies ?? {})])
49
49
  .flat());
50
- for (const [pluginName, plugin] of Object.entries(plugins)) {
50
+ const pluginEntries = Object.entries(plugins);
51
+ for (const [pluginName, plugin] of pluginEntries) {
51
52
  const hasIsEnabled = typeof plugin.isEnabled === 'function';
52
53
  this.enabled[pluginName] =
53
54
  this.config[pluginName] !== false &&
54
55
  hasIsEnabled &&
55
56
  plugin.isEnabled({ manifest: this.manifest, dependencies });
56
57
  }
57
- const enabledPlugins = Object.keys(this.enabled).filter(k => this.enabled[k]);
58
+ const enabledPlugins = pluginEntries.filter(([name]) => this.enabled[name]).map(([, plugin]) => plugin.NAME);
58
59
  debugLogObject(`Enabled plugins (${this.name})`, enabledPlugins);
59
60
  }
60
61
  async initReferencedDependencies() {
@@ -201,7 +202,7 @@ export default class WorkspaceWorker {
201
202
  if (this.enabled[pluginName] && isIncludePlugin) {
202
203
  const hasDependencyFinder = 'findDependencies' in plugin && typeof plugin.findDependencies === 'function';
203
204
  if (hasDependencyFinder) {
204
- const dependencies = await this.findDependenciesByPlugin(pluginName, plugin.findDependencies);
205
+ const dependencies = await this.findDependenciesByPlugin(pluginName, plugin.NAME, plugin.findDependencies);
205
206
  dependencies.forEach(dependency => this.referencedDependencyIssues.add(dependency));
206
207
  dependencies.forEach(dependency => this.referencedDependencies.add(dependency.symbol));
207
208
  }
@@ -212,7 +213,7 @@ export default class WorkspaceWorker {
212
213
  referencedDependencies: this.referencedDependencies,
213
214
  };
214
215
  }
215
- async findDependenciesByPlugin(pluginName, pluginCallback) {
216
+ async findDependenciesByPlugin(pluginName, pluginTitle, pluginCallback) {
216
217
  const pluginConfig = this.getConfigForPlugin(pluginName);
217
218
  if (!pluginConfig)
218
219
  return [];
@@ -220,7 +221,7 @@ export default class WorkspaceWorker {
220
221
  const cwd = this.dir;
221
222
  const ignore = this.getWorkspaceIgnorePatterns();
222
223
  const configFilePaths = await _pureGlob({ patterns, cwd, ignore });
223
- debugLogFiles(`Globbed ${pluginName} config file paths`, configFilePaths);
224
+ debugLogFiles(`Globbed ${pluginTitle} config file paths`, configFilePaths);
224
225
  if (configFilePaths.length === 0)
225
226
  return [];
226
227
  const referencedDependencyIssues = (await Promise.all(configFilePaths.map(async (configFilePath) => {
@@ -232,7 +233,7 @@ export default class WorkspaceWorker {
232
233
  });
233
234
  return dependencies.map(symbol => ({ type: 'unlisted', filePath: configFilePath, symbol }));
234
235
  }))).flat();
235
- debugLogIssues(`Dependencies used by ${pluginName} configuration`, referencedDependencyIssues);
236
+ debugLogIssues(`Dependencies used by ${pluginTitle} configuration`, referencedDependencyIssues);
236
237
  return referencedDependencyIssues;
237
238
  }
238
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "1.0.0-beta.4",
3
+ "version": "1.0.0-beta.6",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript project",
5
5
  "keywords": [
6
6
  "find",
@@ -32,19 +32,20 @@
32
32
  },
33
33
  "type": "module",
34
34
  "scripts": {
35
- "preknip": "npm run build",
36
35
  "knip": "node ./dist/cli.js",
37
36
  "lint": "eslint src",
38
37
  "lint:fix": "eslint src --fix",
39
38
  "test": "globstar -- node --loader tsx --test \"test/**/*.spec.ts\"",
40
39
  "watch": "tsc --watch",
41
- "build": "rm -rf dist && tsc",
42
- "prepublishOnly": "npm test && npm run build && npm run knip",
43
- "format": "remark README.md -o",
40
+ "prebuild": "rm -rf dist",
41
+ "build": "tsc",
42
+ "docs": "npm run docs:cli && npm run docs:plugins && npm run docs:format",
43
+ "docs:cli": "tsx ./scripts/update-cli-usage-in-readme.ts",
44
+ "docs:plugins": "tsx ./scripts/generate-plugin-docs.ts",
45
+ "docs:format": "remark README.md src/plugins/*/README.md -o",
44
46
  "release": "release-it",
45
47
  "postinstall": "patch-package",
46
- "add-plugin:help": "echo 'Usage: npm run add-plugin --name=[name] (and update README.md and schema.json)'",
47
- "add-plugin": "cp -R src/plugins/_template src/plugins/$npm_config_name && echo \"export * as $npm_config_name from \\\"./$npm_config_name/index.js\\\";\" >> src/plugins/index.ts"
48
+ "create-plugin": "tsx ./scripts/create-new-plugin.ts"
48
49
  },
49
50
  "files": [
50
51
  "dist",
@@ -63,7 +64,7 @@
63
64
  "easy-table": "1.2.0",
64
65
  "esbuild": "0.16.12",
65
66
  "esbuild-register": "3.4.2",
66
- "eslint": "8.30.0",
67
+ "eslint": "8.31.0",
67
68
  "fast-glob": "3.2.12",
68
69
  "globby": "13.1.3",
69
70
  "js-yaml": "4.1.0",
@@ -99,6 +100,14 @@
99
100
  "typescript": "4.9.4"
100
101
  },
101
102
  "release-it": {
103
+ "hooks": {
104
+ "before:init": [
105
+ "npm run build",
106
+ "npm run knip",
107
+ "npm run docs",
108
+ "npm test"
109
+ ]
110
+ },
102
111
  "github": {
103
112
  "release": true
104
113
  }
@@ -1 +0,0 @@
1
- export declare const printHelp: () => void;
package/dist/util/help.js DELETED
@@ -1,36 +0,0 @@
1
- export const printHelp = () => {
2
- console.log(`knip [options]
3
-
4
- Options:
5
- -c/--config [file] Configuration file path (default: ./knip.json, knip.jsonc or package.json#knip)
6
- -t/--tsConfig [file] TypeScript configuration path (default: ./tsconfig.json)
7
- --production Analyze only production source files (e.g. no tests, devDependencies, exported types)
8
- --strict Consider only direct dependencies of workspaces. Not devDependencies, not ancestor workspaces.
9
- --workspace Analyze a single workspace (default: analyze all configured workspaces)
10
- --include Report only listed issue type(s), can be comma-separated or repeated
11
- --exclude Exclude issue type(s) from report, can be comma-separated or repeated
12
- --ignore Ignore files matching this glob pattern, can be repeated
13
- --ignore-entry-exports Ignore exports from entry files
14
- --no-gitignore Don't use .gitignore
15
- --no-progress Don't show dynamic progress updates
16
- --no-exit-code Always exit with code zero (0)
17
- --max-issues Maximum number of issues before non-zero exit code (default: 0)
18
- --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
19
- --reporter-options Pass extra options to the reporter (as JSON string, see example)
20
- --debug Show debug output
21
- --debug-file-filter Filter for files in debug output (regex as string)
22
- --performance Measure running time of expensive functions and display stats table
23
-
24
- Issue types: files, dependencies, unlisted, exports, nsExports, classMembers, types, nsTypes, enumMembers, duplicates
25
-
26
- Examples:
27
-
28
- $ knip
29
- $ knip --production
30
- $ knip --workspace packages/client --include files,dependencies
31
- $ knip -c ./config/knip.json --reporter compact
32
- $ knip --reporter codeowners --reporter-options '{"path":".github/CODEOWNERS"}'
33
- $ knip --debug --debug-file-filter '(specific|particular)-module'
34
-
35
- More info: https://github.com/webpro/knip`);
36
- };
@@ -1,25 +0,0 @@
1
- declare const _default: {
2
- values: {
3
- config: string | undefined;
4
- debug: boolean | undefined;
5
- 'debug-file-filter': string | undefined;
6
- exclude: string[] | undefined;
7
- help: boolean | undefined;
8
- ignore: string[] | undefined;
9
- 'ignore-entry-exports': boolean | undefined;
10
- include: string[] | undefined;
11
- 'max-issues': string | undefined;
12
- 'no-exit-code': boolean | undefined;
13
- 'no-gitignore': boolean | undefined;
14
- 'no-progress': boolean | undefined;
15
- performance: boolean | undefined;
16
- production: boolean | undefined;
17
- reporter: string | undefined;
18
- 'reporter-options': string | undefined;
19
- strict: boolean | undefined;
20
- tsConfig: string | undefined;
21
- workspace: string | undefined;
22
- };
23
- positionals: [];
24
- };
25
- export default _default;
@@ -1,24 +0,0 @@
1
- import { parseArgs } from 'node:util';
2
- export default parseArgs({
3
- options: {
4
- config: { type: 'string', short: 'c' },
5
- debug: { type: 'boolean' },
6
- 'debug-file-filter': { type: 'string' },
7
- exclude: { type: 'string', multiple: true },
8
- help: { type: 'boolean', short: 'h' },
9
- ignore: { type: 'string', multiple: true },
10
- 'ignore-entry-exports': { type: 'boolean' },
11
- include: { type: 'string', multiple: true },
12
- 'max-issues': { type: 'string' },
13
- 'no-exit-code': { type: 'boolean' },
14
- 'no-gitignore': { type: 'boolean' },
15
- 'no-progress': { type: 'boolean' },
16
- performance: { type: 'boolean' },
17
- production: { type: 'boolean' },
18
- reporter: { type: 'string' },
19
- 'reporter-options': { type: 'string' },
20
- strict: { type: 'boolean' },
21
- tsConfig: { type: 'string', short: 't' },
22
- workspace: { type: 'string' },
23
- },
24
- });