knip 2.14.0-next.0 → 2.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -142,7 +142,7 @@ Using workspaces in a monorepo? Please see [workspaces][1] for more details abou
142
142
  --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
143
143
  --dependencies Shortcut for --include dependencies,unlisted,unresolved
144
144
  --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates
145
- --include-entry-exports Include entry files when reporting unused exports
145
+ --include-entry-exports Include entry files when reporting unused exports
146
146
  -n, --no-progress Don't show dynamic progress updates
147
147
  --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
148
148
  --reporter-options Pass extra options to the reporter (as JSON string, see example)
@@ -579,6 +579,15 @@ export const split = function () {};
579
579
 
580
580
  Knip does not report public exports and types as unused.
581
581
 
582
+ ## Include exports in entry files
583
+
584
+ When a repository is self-contained or private, you may want to include entry files when reporting unused exports:
585
+
586
+ knip --include-entry-exports
587
+
588
+ Knip will also report unused exports in entry source files and scripts (such as those referenced in `package.json`). But
589
+ not in entry and configuration files from plugins, such as `next.config.js` or `src/routes/+page.svelte`.
590
+
582
591
  ## Handling Issues
583
592
 
584
593
  How to handle a long list of reported issues? Seeing too many false positives? Read more about [handling issues][17]
@@ -10,6 +10,7 @@ type ProjectPrincipalOptions = {
10
10
  export declare class ProjectPrincipal {
11
11
  entryPaths: Set<string>;
12
12
  projectPaths: Set<string>;
13
+ skipExportsAnalysis: Set<string>;
13
14
  cwd: string;
14
15
  compilerOptions: ts.CompilerOptions;
15
16
  extensions: Set<string>;
@@ -25,8 +26,12 @@ export declare class ProjectPrincipal {
25
26
  constructor({ compilerOptions, cwd, compilers }: ProjectPrincipalOptions);
26
27
  private createProgram;
27
28
  private hasAcceptedExtension;
28
- addEntryPath(filePath: string): void;
29
- addEntryPaths(filePaths: Set<string> | string[]): void;
29
+ addEntryPath(filePath: string, options?: {
30
+ skipExportsAnalysis: boolean;
31
+ }): void;
32
+ addEntryPaths(filePaths: Set<string> | string[], options?: {
33
+ skipExportsAnalysis: boolean;
34
+ }): void;
30
35
  addProjectPath(filePath: string): void;
31
36
  runAsyncCompilers(): Promise<void>;
32
37
  getUsedResolvedFiles(): string[];
@@ -22,6 +22,7 @@ const tsCreateProgram = timerify(ts.createProgram);
22
22
  export class ProjectPrincipal {
23
23
  entryPaths = new Set();
24
24
  projectPaths = new Set();
25
+ skipExportsAnalysis = new Set();
25
26
  cwd;
26
27
  compilerOptions;
27
28
  extensions;
@@ -62,14 +63,16 @@ export class ProjectPrincipal {
62
63
  hasAcceptedExtension(filePath) {
63
64
  return this.extensions.has(extname(filePath));
64
65
  }
65
- addEntryPath(filePath) {
66
+ addEntryPath(filePath, options) {
66
67
  if (!isInNodeModules(filePath) && this.hasAcceptedExtension(filePath)) {
67
68
  this.entryPaths.add(filePath);
68
69
  this.projectPaths.add(filePath);
70
+ if (options?.skipExportsAnalysis)
71
+ this.skipExportsAnalysis.add(filePath);
69
72
  }
70
73
  }
71
- addEntryPaths(filePaths) {
72
- filePaths.forEach(filePath => this.addEntryPath(filePath));
74
+ addEntryPaths(filePaths, options) {
75
+ filePaths.forEach(filePath => this.addEntryPath(filePath, options));
73
76
  }
74
77
  addProjectPath(filePath) {
75
78
  if (!isInNodeModules(filePath) && this.hasAcceptedExtension(filePath)) {
@@ -101,7 +104,8 @@ export class ProjectPrincipal {
101
104
  const sourceFile = this.backend.program?.getSourceFile(filePath);
102
105
  if (!sourceFile)
103
106
  throw new Error(`Unable to find ${filePath}`);
104
- const { imports, exports, scripts } = getImportsAndExports(sourceFile, { skipTypeOnly });
107
+ const skipExports = this.skipExportsAnalysis.has(filePath);
108
+ const { imports, exports, scripts } = getImportsAndExports(sourceFile, { skipTypeOnly, skipExports });
105
109
  const { internal, unresolved, external } = imports;
106
110
  const unresolvedImports = new Set();
107
111
  unresolved.forEach(specifier => {
@@ -114,7 +118,7 @@ export class ProjectPrincipal {
114
118
  external.add(specifier);
115
119
  }
116
120
  else {
117
- this.addEntryPath(resolvedModule.resolvedFileName);
121
+ this.addEntryPath(resolvedModule.resolvedFileName, { skipExportsAnalysis: true });
118
122
  }
119
123
  }
120
124
  else {
package/dist/index.js CHANGED
@@ -71,7 +71,7 @@ export const main = async (unresolvedConfiguration) => {
71
71
  if (otherWorkspace) {
72
72
  const filePath = _resolveSpecifier(otherWorkspace.dir, specifier);
73
73
  if (filePath) {
74
- principal.addEntryPath(filePath);
74
+ principal.addEntryPath(filePath, { skipExportsAnalysis: true });
75
75
  }
76
76
  else {
77
77
  collector.addIssue({ type: 'unresolved', filePath: containingFilePath, symbol: specifier });
@@ -121,7 +121,7 @@ export const main = async (unresolvedConfiguration) => {
121
121
  const patterns = worker.getProductionPluginEntryFilePatterns();
122
122
  const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
123
123
  debugLogArray(`Found production plugin entry paths (${name})`, pluginWorkspaceEntryPaths);
124
- principal.addEntryPaths(pluginWorkspaceEntryPaths);
124
+ principal.addEntryPaths(pluginWorkspaceEntryPaths, { skipExportsAnalysis: true });
125
125
  }
126
126
  {
127
127
  const patterns = worker.getProductionProjectFilePatterns();
@@ -147,7 +147,7 @@ export const main = async (unresolvedConfiguration) => {
147
147
  const patterns = worker.getPluginEntryFilePatterns();
148
148
  const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
149
149
  debugLogArray(`Found plugin entry paths (${name})`, pluginWorkspaceEntryPaths);
150
- principal.addEntryPaths(pluginWorkspaceEntryPaths);
150
+ principal.addEntryPaths(pluginWorkspaceEntryPaths, { skipExportsAnalysis: true });
151
151
  }
152
152
  {
153
153
  const patterns = worker.getPluginProjectFilePatterns();
@@ -159,11 +159,11 @@ export const main = async (unresolvedConfiguration) => {
159
159
  const patterns = compact(worker.getPluginConfigPatterns());
160
160
  const configurationEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
161
161
  debugLogArray(`Found plugin configuration paths (${name})`, configurationEntryPaths);
162
- principal.addEntryPaths(configurationEntryPaths);
162
+ principal.addEntryPaths(configurationEntryPaths, { skipExportsAnalysis: true });
163
163
  }
164
164
  }
165
165
  if (chief.resolvedConfigFilePath)
166
- principal.addEntryPath(chief.resolvedConfigFilePath);
166
+ principal.addEntryPath(chief.resolvedConfigFilePath, { skipExportsAnalysis: true });
167
167
  const dependencies = await worker.findAllDependencies();
168
168
  const { referencedDependencies, peerDependencies, installedBinaries, enabledPlugins } = dependencies;
169
169
  deputy.addPeerDependencies(name, peerDependencies);
@@ -288,7 +288,7 @@ export const main = async (unresolvedConfiguration) => {
288
288
  continue;
289
289
  }
290
290
  const isStar = Boolean(importedModule?.isStar);
291
- const isReExportedByEntryFile = isStar && isExportedInEntryFile(importedModule);
291
+ const isReExportedByEntryFile = !isIncludeEntryExports && isStar && isExportedInEntryFile(importedModule);
292
292
  if (!isReExportedByEntryFile && !isExportedItemReferenced(exportedItem, filePath)) {
293
293
  if (['enum', 'type', 'interface'].includes(exportedItem.type)) {
294
294
  if (isProduction)
@@ -22,6 +22,8 @@ const resolveRuleSetDependencies = (rule) => {
22
22
  if (typeof useItem === 'function')
23
23
  useItem = useItem(info);
24
24
  return [useItem].flat().flatMap((useItem) => {
25
+ if (!useItem)
26
+ return [];
25
27
  if (hasBabelOptions(useItem)) {
26
28
  return [
27
29
  ...resolveUseItem(useItem),
@@ -4,6 +4,7 @@ import type { ExportItems as Exports, ExportItem } from '../types/exports.js';
4
4
  import type { Imports } from '../types/imports.js';
5
5
  export type GetImportsAndExportsOptions = {
6
6
  skipTypeOnly: boolean;
7
+ skipExports: boolean;
7
8
  };
8
9
  export type AddImportOptions = {
9
10
  specifier: string;
@@ -86,6 +86,8 @@ export const getImportsAndExports = (sourceFile, options) => {
86
86
  }
87
87
  };
88
88
  const addExport = ({ node, identifier, type, pos, members }) => {
89
+ if (options.skipExports)
90
+ return;
89
91
  if (exports.has(identifier)) {
90
92
  const item = exports.get(identifier);
91
93
  exports.set(identifier, { ...item, node, type, pos, members });
@@ -1,4 +1,4 @@
1
- export declare const helpText = "\u2702\uFE0F Find unused files, dependencies and exports in your JavaScript and TypeScript projects\n\nUsage: knip [options]\n\nOptions:\n -c, --config [file] Configuration file path (default: [.]knip.json[c], knip.js, knip.ts 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 --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 --dependencies Shortcut for --include dependencies,unlisted,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --include-entry-exports Include entry files when reporting unused exports\n -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-config-hints Suppress configuration hints\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 -d, --debug Show debug output\n --debug-file-filter Filter for files in debug output (regex as string)\n --performance Measure count and running time of expensive functions and display stats table\n --h, --help Print this help text\n --V, version Print version\n\n(1) Issue types: files, dependencies, unlisted, unresolved, 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 documentation and bug reports: https://github.com/webpro/knip";
1
+ export declare const helpText = "\u2702\uFE0F Find unused files, dependencies and exports in your JavaScript and TypeScript projects\n\nUsage: knip [options]\n\nOptions:\n -c, --config [file] Configuration file path (default: [.]knip.json[c], knip.js, knip.ts 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 --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 --dependencies Shortcut for --include dependencies,unlisted,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --include-entry-exports Include entry files when reporting unused exports\n -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-config-hints Suppress configuration hints\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 -d, --debug Show debug output\n --debug-file-filter Filter for files in debug output (regex as string)\n --performance Measure count and running time of expensive functions and display stats table\n --h, --help Print this help text\n --V, version Print version\n\n(1) Issue types: files, dependencies, unlisted, unresolved, 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 documentation and bug reports: https://github.com/webpro/knip";
2
2
  declare const _default: {
3
3
  config: string | undefined;
4
4
  debug: boolean | undefined;
@@ -14,7 +14,7 @@ Options:
14
14
  --exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
15
15
  --dependencies Shortcut for --include dependencies,unlisted,unresolved
16
16
  --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates
17
- --include-entry-exports Include entry files when reporting unused exports
17
+ --include-entry-exports Include entry files when reporting unused exports
18
18
  -n, --no-progress Don't show dynamic progress updates
19
19
  --reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
20
20
  --reporter-options Pass extra options to the reporter (as JSON string, see example)
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "2.14.0-next.0";
1
+ export declare const version = "2.14.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '2.14.0-next.0';
1
+ export const version = '2.14.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "2.14.0-next.0",
3
+ "version": "2.14.0",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
5
5
  "homepage": "https://github.com/webpro/knip",
6
6
  "repository": "github:webpro/knip",