knip 2.21.0 → 2.21.2

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
@@ -624,7 +624,7 @@ Tip: back up files or use an VCS like Git before deleting files or making change
624
624
 
625
625
  Repeat the process to reveal new unused files and exports. It's so liberating to remove unused things!
626
626
 
627
- Getting too many reported issues and false positives? Read more about [handling issues][50] describing potential causes
627
+ Getting too many reported issues and false positives? Read more about [handling issues][48] describing potential causes
628
628
  for false positives, and how to handle them.
629
629
 
630
630
  ## Command Line Options
@@ -675,13 +675,13 @@ for false positives, and how to handle them.
675
675
 
676
676
  ## Potential boost with `--no-gitignore`
677
677
 
678
- To increase performance in a large monorepo, check out [Potential boost with `--no-gitignore`][51].
678
+ To increase performance in a large monorepo, check out [Potential boost with `--no-gitignore`][50].
679
679
 
680
680
  ## Comparison & Migration
681
681
 
682
682
  This table is an ongoing comparison. Based on their docs (please report any mistakes):
683
683
 
684
- | Feature | **knip** | [depcheck][52] | [unimported][53] | [ts-unused-exports][54] | [ts-prune][55] |
684
+ | Feature | **knip** | [depcheck][51] | [unimported][52] | [ts-unused-exports][53] | [ts-prune][54] |
685
685
  | :---------------------- | :------: | :------------: | :--------------: | :---------------------: | :------------: |
686
686
  | Unused files | ✅ | - | ✅ | - | - |
687
687
  | Unused dependencies | ✅ | ✅ | ✅ | - | - |
@@ -739,25 +739,25 @@ The following commands are similar:
739
739
 
740
740
  Many thanks to some of the early adopters of Knip:
741
741
 
742
- - [Block Protocol][56]
743
- - [DeepmergeTS][57]
744
- - [eslint-plugin-functional][58]
745
- - [freeCodeCamp.org][59]
746
- - [is-immutable-type][60]
747
- - [IsaacScript][61]
748
- - [Nuxt][62]
749
- - [Owncast][63]
750
- - [release-it][64]
751
- - [Template TypeScript Node Package][65]
752
- - [Tipi][66]
742
+ - [Block Protocol][55]
743
+ - [DeepmergeTS][56]
744
+ - [eslint-plugin-functional][57]
745
+ - [freeCodeCamp.org][58]
746
+ - [is-immutable-type][59]
747
+ - [IsaacScript][60]
748
+ - [Nuxt][61]
749
+ - [Owncast][62]
750
+ - [release-it][63]
751
+ - [Template TypeScript Node Package][64]
752
+ - [Tipi][65]
753
753
 
754
754
  ## Articles, etc.
755
755
 
756
756
  - Discord: hang out in [The Knip Barn][9]
757
- - Ask your questions in the [Knip knowledge base][67] (powered by OpenAI and [7-docs][68], experimental!)
758
- - Smashing Magazine: [Knip: An Automated Tool For Finding Unused Files, Exports, And Dependencies][69]
759
- - Effective TypeScript: [Recommendation Update: ✂️ Use knip to detect dead code and types][70]
760
- - Josh Goldberg: [Speeding Up Centered Part 4: Unused Code Bloat][71]
757
+ - Ask your questions in the [Knip knowledge base][66] (powered by OpenAI and [7-docs][67], experimental!)
758
+ - Smashing Magazine: [Knip: An Automated Tool For Finding Unused Files, Exports, And Dependencies][68]
759
+ - Effective TypeScript: [Recommendation Update: ✂️ Use knip to detect dead code and types][69]
760
+ - Josh Goldberg: [Speeding Up Centered Part 4: Unused Code Bloat][70]
761
761
 
762
762
  ## Why "Knip"?
763
763
 
@@ -775,7 +775,7 @@ each file, and traversing all of this, why not collect the various issues in one
775
775
 
776
776
  Special thanks to the wonderful people who have contributed to this project:
777
777
 
778
- [![Contributors][73]][72]
778
+ [![Contributors][72]][71]
779
779
 
780
780
  [1]: #workspaces
781
781
  [2]: #plugins
@@ -824,32 +824,31 @@ Special thanks to the wonderful people who have contributed to this project:
824
824
  [45]: https://nx.dev/concepts/integrated-vs-package-based
825
825
  [46]: ./docs/writing-a-plugin.md
826
826
  [47]: ./docs/compilers.md
827
- [48]: #handling-issues
827
+ [48]: ./docs/handling-issues.md
828
828
  [49]: ./docs/reporters-and-preprocessors.md
829
- [50]: ./docs/handling-issues.md
830
- [51]: ./docs/perf-boost-with-no-gitignore.md
831
- [52]: https://github.com/depcheck/depcheck
832
- [53]: https://github.com/smeijer/unimported
833
- [54]: https://github.com/pzavolinsky/ts-unused-exports
834
- [55]: https://github.com/nadeesha/ts-prune
835
- [56]: https://github.com/blockprotocol/blockprotocol
836
- [57]: https://github.com/RebeccaStevens/deepmerge-ts
837
- [58]: https://github.com/eslint-functional/eslint-plugin-functional
838
- [59]: https://github.com/freeCodeCamp/freeCodeCamp
839
- [60]: https://github.com/RebeccaStevens/is-immutable-type
840
- [61]: https://github.com/IsaacScript/isaacscript
841
- [62]: https://github.com/nuxt/nuxt
842
- [63]: https://github.com/owncast/owncast
843
- [64]: https://github.com/release-it/release-it
844
- [65]: https://github.com/JoshuaKGoldberg/template-typescript-node-package
845
- [66]: https://github.com/meienberger/runtipi
846
- [67]: https://knip.deno.dev
847
- [68]: https://github.com/7-docs/7-docs
848
- [69]: https://www.smashingmagazine.com/2023/08/knip-automated-tool-find-unused-files-exports-dependencies/
849
- [70]: https://effectivetypescript.com/2023/07/29/knip/
850
- [71]: https://www.joshuakgoldberg.com/blog/speeding-up-centered-part-4-unused-code-bloat/
851
- [72]: https://github.com/webpro/knip/graphs/contributors
852
- [73]: https://contrib.rocks/image?repo=webpro/knip
829
+ [50]: ./docs/perf-boost-with-no-gitignore.md
830
+ [51]: https://github.com/depcheck/depcheck
831
+ [52]: https://github.com/smeijer/unimported
832
+ [53]: https://github.com/pzavolinsky/ts-unused-exports
833
+ [54]: https://github.com/nadeesha/ts-prune
834
+ [55]: https://github.com/blockprotocol/blockprotocol
835
+ [56]: https://github.com/RebeccaStevens/deepmerge-ts
836
+ [57]: https://github.com/eslint-functional/eslint-plugin-functional
837
+ [58]: https://github.com/freeCodeCamp/freeCodeCamp
838
+ [59]: https://github.com/RebeccaStevens/is-immutable-type
839
+ [60]: https://github.com/IsaacScript/isaacscript
840
+ [61]: https://github.com/nuxt/nuxt
841
+ [62]: https://github.com/owncast/owncast
842
+ [63]: https://github.com/release-it/release-it
843
+ [64]: https://github.com/JoshuaKGoldberg/template-typescript-node-package
844
+ [65]: https://github.com/meienberger/runtipi
845
+ [66]: https://knip.deno.dev
846
+ [67]: https://github.com/7-docs/7-docs
847
+ [68]: https://www.smashingmagazine.com/2023/08/knip-automated-tool-find-unused-files-exports-dependencies/
848
+ [69]: https://effectivetypescript.com/2023/07/29/knip/
849
+ [70]: https://www.joshuakgoldberg.com/blog/speeding-up-centered-part-4-unused-code-bloat/
850
+ [71]: https://github.com/webpro/knip/graphs/contributors
851
+ [72]: https://contrib.rocks/image?repo=webpro/knip
853
852
  [plugin-ava]: ./src/plugins/ava
854
853
  [plugin-babel]: ./src/plugins/babel
855
854
  [plugin-capacitor]: ./src/plugins/capacitor
@@ -22,8 +22,8 @@ export declare class ConfigurationChief {
22
22
  ignoredWorkspacePatterns: string[];
23
23
  manifestWorkspaces: Map<string, string>;
24
24
  additionalWorkspaceNames: Set<string>;
25
- enabledWorkspaceNames: string[];
26
- enabledWorkspaceDirs: string[];
25
+ availableWorkspaceNames: string[];
26
+ availableWorkspaceDirs: string[];
27
27
  enabledWorkspaces: Workspace[];
28
28
  localWorkspaces: Set<string>;
29
29
  resolvedConfigFilePath?: string;
@@ -37,7 +37,7 @@ export declare class ConfigurationChief {
37
37
  private getIgnoredWorkspacePatterns;
38
38
  private getManifestWorkspaces;
39
39
  private getAdditionalWorkspaceNames;
40
- private getEnabledWorkspaceNames;
40
+ private getAvailableWorkspaceNames;
41
41
  private getEnabledWorkspaces;
42
42
  getWorkspaces(): Workspace[];
43
43
  private getDescendentWorkspaces;
@@ -55,8 +55,8 @@ export class ConfigurationChief {
55
55
  ignoredWorkspacePatterns = [];
56
56
  manifestWorkspaces = new Map();
57
57
  additionalWorkspaceNames = new Set();
58
- enabledWorkspaceNames = [];
59
- enabledWorkspaceDirs = [];
58
+ availableWorkspaceNames = [];
59
+ availableWorkspaceDirs = [];
60
60
  enabledWorkspaces = [];
61
61
  localWorkspaces = new Set();
62
62
  resolvedConfigFilePath;
@@ -170,12 +170,12 @@ export class ConfigurationChief {
170
170
  this.ignoredWorkspacePatterns = this.getIgnoredWorkspacePatterns();
171
171
  this.manifestWorkspaces = await this.getManifestWorkspaces();
172
172
  this.additionalWorkspaceNames = await this.getAdditionalWorkspaceNames();
173
- this.enabledWorkspaceNames = this.getEnabledWorkspaceNames();
174
- this.enabledWorkspaces = this.getEnabledWorkspaces();
175
- this.enabledWorkspaceDirs = this.enabledWorkspaceNames
173
+ this.availableWorkspaceNames = this.getAvailableWorkspaceNames();
174
+ this.availableWorkspaceDirs = this.availableWorkspaceNames
176
175
  .sort(byPathDepth)
177
176
  .reverse()
178
177
  .map(dir => join(this.cwd, dir));
178
+ this.enabledWorkspaces = this.getEnabledWorkspaces();
179
179
  this.localWorkspaces = new Set(compact(this.enabledWorkspaces.map(w => w.pkgName)));
180
180
  }
181
181
  getListedWorkspaces() {
@@ -211,16 +211,13 @@ export class ConfigurationChief {
211
211
  !this.manifestWorkspaces.has(name) &&
212
212
  !micromatch.isMatch(name, this.ignoredWorkspacePatterns)));
213
213
  }
214
- getEnabledWorkspaceNames() {
214
+ getAvailableWorkspaceNames() {
215
215
  return [ROOT_WORKSPACE_NAME, ...this.manifestWorkspaces.keys(), ...this.additionalWorkspaceNames].filter(name => !micromatch.isMatch(name, this.ignoredWorkspacePatterns));
216
216
  }
217
217
  getEnabledWorkspaces() {
218
218
  if (workspaceArg && !existsSync(workspaceArg)) {
219
219
  throw new ConfigurationError(`Directory does not exist: ${workspaceArg}`);
220
220
  }
221
- const workspaceNames = workspaceArg
222
- ? this.enabledWorkspaceNames.filter(name => name === workspaceArg)
223
- : this.enabledWorkspaceNames;
224
221
  const getAncestors = (name) => (ancestors, ancestorName) => {
225
222
  if (name === ancestorName)
226
223
  return ancestors;
@@ -228,19 +225,25 @@ export class ConfigurationChief {
228
225
  ancestors.push(ancestorName);
229
226
  return ancestors;
230
227
  };
228
+ const workspaceNames = workspaceArg
229
+ ? [
230
+ ...this.availableWorkspaceNames.reduce(getAncestors(workspaceArg), []),
231
+ ...this.availableWorkspaceNames.filter(name => name === workspaceArg),
232
+ ]
233
+ : this.availableWorkspaceNames;
231
234
  return workspaceNames.sort(byPathDepth).map((name) => ({
232
235
  name,
233
236
  pkgName: this.manifestWorkspaces.get(name) ?? this.manifest?.name,
234
237
  dir: join(this.cwd, name),
235
238
  config: this.getConfigForWorkspace(name),
236
- ancestors: workspaceNames.reduce(getAncestors(name), []),
239
+ ancestors: this.availableWorkspaceNames.reduce(getAncestors(name), []),
237
240
  }));
238
241
  }
239
242
  getWorkspaces() {
240
243
  return this.enabledWorkspaces;
241
244
  }
242
245
  getDescendentWorkspaces(name) {
243
- return this.enabledWorkspaceNames
246
+ return this.availableWorkspaceNames
244
247
  .filter(workspaceName => workspaceName !== name)
245
248
  .filter(workspaceName => name === ROOT_WORKSPACE_NAME || workspaceName.startsWith(name + '/'));
246
249
  }
@@ -280,7 +283,7 @@ export class ConfigurationChief {
280
283
  return getIncludedIssueTypes(cliArgs, config);
281
284
  }
282
285
  findWorkspaceByFilePath(filePath) {
283
- const workspaceDir = this.enabledWorkspaceDirs.find(workspaceDir => filePath.startsWith(workspaceDir + '/'));
286
+ const workspaceDir = this.availableWorkspaceDirs.find(workspaceDir => filePath.startsWith(workspaceDir + '/'));
284
287
  return this.enabledWorkspaces.find(workspace => workspace.dir === workspaceDir);
285
288
  }
286
289
  findWorkspaceByPackageName(packageName) {
package/dist/index.js CHANGED
@@ -244,6 +244,15 @@ export const main = async (unresolvedConfiguration) => {
244
244
  const unusedFiles = principal.getUnreferencedFiles();
245
245
  collector.addFilesIssues(unusedFiles);
246
246
  collector.addFileCounts({ processed: analyzedFiles.size, unused: unusedFiles.length });
247
+ const isSymbolImported = (symbol, importingModule) => {
248
+ if (!importingModule)
249
+ return false;
250
+ if (importingModule.symbols.has(symbol))
251
+ return true;
252
+ const { isReExport, isReExportedBy } = importingModule;
253
+ const hasSymbol = (file) => isSymbolImported(symbol, importedSymbols.get(file));
254
+ return isReExport ? Array.from(isReExportedBy).some(hasSymbol) : false;
255
+ };
247
256
  const isExportedInEntryFile = (importedModule) => {
248
257
  if (!importedModule)
249
258
  return false;
@@ -265,15 +274,15 @@ export const main = async (unresolvedConfiguration) => {
265
274
  for (const [filePath, exportItems] of exportedSymbols.entries()) {
266
275
  if (!isIncludeEntryExports && principal.entryPaths.has(filePath))
267
276
  continue;
268
- const importedModule = importedSymbols.get(filePath);
277
+ const importingModule = importedSymbols.get(filePath);
269
278
  for (const [symbol, exportedItem] of exportItems.entries()) {
270
279
  const jsDocTags = principal.getJSDocTags(exportedItem);
271
280
  if (jsDocTags.includes('@public') || jsDocTags.includes('@beta'))
272
281
  continue;
273
282
  if (isIgnoreInternal && jsDocTags.includes('@internal'))
274
283
  continue;
275
- if (importedModule?.symbols.has(symbol)) {
276
- if (importedModule.isReExport && isExportedInEntryFile(importedModule))
284
+ if (importingModule && isSymbolImported(symbol, importingModule)) {
285
+ if (importingModule.isReExport && isExportedInEntryFile(importingModule))
277
286
  continue;
278
287
  if (report.enumMembers && exportedItem.type === 'enum' && exportedItem.members) {
279
288
  if (isProduction)
@@ -289,8 +298,8 @@ export const main = async (unresolvedConfiguration) => {
289
298
  }
290
299
  continue;
291
300
  }
292
- const isStar = Boolean(importedModule?.isStar);
293
- const isReExportedByEntryFile = !isIncludeEntryExports && isStar && isExportedInEntryFile(importedModule);
301
+ const isStar = Boolean(importingModule?.isStar);
302
+ const isReExportedByEntryFile = !isIncludeEntryExports && isStar && isExportedInEntryFile(importingModule);
294
303
  if (!isReExportedByEntryFile && !isExportedItemReferenced(exportedItem, filePath)) {
295
304
  if (['enum', 'type', 'interface'].includes(exportedItem.type)) {
296
305
  if (isProduction)
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "2.21.0";
1
+ export declare const version = "2.21.2";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '2.21.0';
1
+ export const version = '2.21.2';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "2.21.0",
3
+ "version": "2.21.2",
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",
@@ -65,16 +65,16 @@
65
65
  "@npmcli/package-json": "5.0.0",
66
66
  "@release-it/bumper": "5.1.0",
67
67
  "@swc/cli": "0.1.62",
68
- "@swc/core": "1.3.80",
68
+ "@swc/core": "1.3.82",
69
69
  "@types/eslint": "8.44.2",
70
70
  "@types/js-yaml": "4.0.5",
71
71
  "@types/micromatch": "4.0.2",
72
72
  "@types/minimist": "1.2.2",
73
- "@types/node": "20.5.7",
73
+ "@types/node": "20.5.9",
74
74
  "@types/npmcli__map-workspaces": "3.0.1",
75
75
  "@types/webpack": "5.28.2",
76
- "@typescript-eslint/eslint-plugin": "6.5.0",
77
- "@typescript-eslint/parser": "6.5.0",
76
+ "@typescript-eslint/eslint-plugin": "6.6.0",
77
+ "@typescript-eslint/parser": "6.6.0",
78
78
  "c8": "8.0.1",
79
79
  "eslint": "8.48.0",
80
80
  "eslint-import-resolver-typescript": "3.6.0",
@@ -84,7 +84,7 @@
84
84
  "release-it": "16.1.5",
85
85
  "remark-cli": "11.0.0",
86
86
  "remark-preset-webpro": "0.0.3",
87
- "tsx": "3.12.7",
87
+ "tsx": "3.12.8",
88
88
  "type-fest": "4.3.1"
89
89
  },
90
90
  "engines": {