knip 1.0.0-beta.0 → 1.0.0-beta.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
@@ -368,25 +368,45 @@ all of this, why not collect the various issues in one go?
368
368
 
369
369
  This table is an ongoing comparison. Based on their docs (please report any mistakes):
370
370
 
371
- | Feature | **knip** | [depcheck][39] | [unimported][40] | [ts-unused-exports][41] | [ts-prune][42] | [find-unused-exports][43] |
372
- | :-------------------------------- | :------: | :------------: | :--------------: | :---------------------: | :------------: | :-----------------------: |
373
- | Unused files | ✅ | - | ✅ | - | - | - |
374
- | Unused dependencies | ✅ | ✅ | ✅ | - | - | - |
375
- | Unlisted dependencies | ✅ | ✅ | ✅ | - | - | - |
376
- | [Custom dependency resolvers][44] | ✅ | ✅ | ❌ | - | - | - |
377
- | Unused exports | ✅ | - | - | ✅ | ✅ | ✅ |
378
- | Unused class members | ✅ | - | - | - | - | - |
379
- | Unused enum members | ✅ | - | - | - | - | - |
380
- | Duplicate exports | ✅ | - | - | ❌ | ❌ | ❌ |
381
- | Search namespaces | ✅ | - | - | ✅ | ❌ | ❌ |
382
- | Custom reporters | ✅ | - | - | - | - | - |
383
- | JavaScript support | ✅ | ✅ | ✅ | - | - | ✅ |
384
- | Configure entry files | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
385
- | [Support monorepos][45] | ✅ | - | - | - | - | - |
386
- | ESLint plugin available | - | - | - | ✅ | - | - |
371
+ | Feature | **knip** | [depcheck][39] | [unimported][40] | [ts-unused-exports][41] | [ts-prune][42] | [find-unused-exports][43] |
372
+ | :--------------------------------- | :------: | :------------: | :--------------: | :---------------------: | :------------: | :-----------------------: |
373
+ | Unused files | ✅ | - | ✅ | - | - | - |
374
+ | Unused dependencies | ✅ | ✅ | ✅ | - | - | - |
375
+ | Unlisted dependencies | ✅ | ✅ | ✅ | - | - | - |
376
+ | [Custom dependency resolvers][44] | ✅ | ✅ | ❌ | - | - | - |
377
+ | Unused exports | ✅ | - | - | ✅ | ✅ | ✅ |
378
+ | Unused class members | ✅ | - | - | - | - | - |
379
+ | Unused enum members | ✅ | - | - | - | - | - |
380
+ | Duplicate exports | ✅ | - | - | ❌ | ❌ | ❌ |
381
+ | Search namespaces | ✅ | - | - | ✅ | ❌ | ❌ |
382
+ | Custom reporters | ✅ | - | - | - | - | - |
383
+ | JavaScript support | ✅ | ✅ | ✅ | - | - | ✅ |
384
+ | Configure entry files | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
385
+ | [Support workspaces/monorepos][45] | ✅ | | | - | - | - |
386
+ | ESLint plugin available | - | - | - | ✅ | - | - |
387
387
 
388
388
  ✅ = Supported, ❌ = Not supported, - = Out of scope
389
389
 
390
+ ### Migrating from other tools
391
+
392
+ WIP
393
+
394
+ ### depcheck
395
+
396
+ The following commands are similar:
397
+
398
+ depcheck
399
+ knip --include dependencies,unlisted
400
+
401
+ ### unimported
402
+
403
+ The following commands are similar:
404
+
405
+ unimported
406
+ knip --production --include files,dependencies,unlisted
407
+
408
+ See [production mode](#production-mode).
409
+
390
410
  ## TypeScript language services
391
411
 
392
412
  TypeScript language services could play a major role in most of the "unused" areas, as they have an overview of the
@@ -443,4 +463,4 @@ for the job. I'm motivated to make knip perfectly suited for the job of cutting
443
463
  [42]: https://github.com/nadeesha/ts-prune
444
464
  [43]: https://github.com/jaydenseric/find-unused-exports
445
465
  [44]: #custom-dependency-resolvers
446
- [45]: #monorepos-1
466
+ [45]: #workspaces--monorepos
@@ -99,8 +99,8 @@ export default class ConfigurationChief {
99
99
  }
100
100
  else {
101
101
  const isObject = typeof pluginConfig !== 'string' && !Array.isArray(pluginConfig);
102
- const config = isObject ? arrayify(pluginConfig.config) : arrayify(pluginConfig);
103
- const entry = isObject && 'entry' in pluginConfig ? arrayify(pluginConfig.entry) : [];
102
+ const config = typeof pluginConfig === 'string' ? [pluginConfig] : isObject ? arrayify(pluginConfig.config) : null;
103
+ const entry = isObject && 'entry' in pluginConfig ? arrayify(pluginConfig.entry) : null;
104
104
  const project = isObject && 'project' in pluginConfig ? arrayify(pluginConfig.project) : entry;
105
105
  workspaces[workspaceName][pluginName] = {
106
106
  config,
@@ -3,7 +3,7 @@ import { getPackageName } from '../../util/modules.js';
3
3
  const resolvePackageName = (namespace, pluginName) => {
4
4
  return pluginName.startsWith('@')
5
5
  ? pluginName.includes('/')
6
- ? pluginName
6
+ ? pluginName.replace(/\//, `/${namespace}-`)
7
7
  : `${pluginName}/${namespace}`
8
8
  : `${namespace}-${pluginName}`;
9
9
  };
@@ -7,7 +7,7 @@ import { getPackageName } from '../../util/modules.js';
7
7
  import { timerify } from '../../util/performance.js';
8
8
  import { resolvePluginPackageName, customResolvePluginPackageNames, getDependenciesFromSettings } from './helpers.js';
9
9
  export const isEnabled = ({ dependencies }) => dependencies.has('eslint');
10
- export const CONFIG_FILE_PATTERNS = ['.eslintrc', '.eslintrc.{js,json,cjs}', 'package.json'];
10
+ export const CONFIG_FILE_PATTERNS = ['.eslintrc', '.eslintrc.{js,json,cjs}', '.eslintrc.{yml,yaml}', 'package.json'];
11
11
  export const ENTRY_FILE_PATTERNS = ['eslint.config.js'];
12
12
  const findESLintDependencies = async (configFilePath, { cwd, manifest, workspaceConfig }) => {
13
13
  if (configFilePath.endsWith('package.json') && !manifest.eslintConfig)
@@ -1,4 +1,5 @@
1
1
  import type { IsPluginEnabledCallback, GenericPluginCallback } from '../../types/plugins.js';
2
2
  export declare const isEnabled: IsPluginEnabledCallback;
3
3
  export declare const CONFIG_FILE_PATTERNS: string[];
4
+ export declare const ENTRY_FILE_PATTERNS: string[];
4
5
  export declare const findDependencies: GenericPluginCallback;
@@ -3,12 +3,15 @@ import { getPackageName } from '../../util/modules.js';
3
3
  import { timerify } from '../../util/performance.js';
4
4
  export const isEnabled = ({ dependencies }) => dependencies.has('postcss');
5
5
  export const CONFIG_FILE_PATTERNS = ['postcss.config.js', 'package.json'];
6
+ export const ENTRY_FILE_PATTERNS = ['postcss.config.js'];
6
7
  const findPostCSSDependencies = async (configFilePath, { manifest }) => {
7
8
  const config = configFilePath.endsWith('package.json')
8
9
  ? manifest?.postcss
9
10
  : await _load(configFilePath);
10
11
  return config?.plugins
11
- ? (Array.isArray(config.plugins) ? config.plugins : Object.keys(config.plugins)).map(getPackageName)
12
+ ? (Array.isArray(config.plugins) ? config.plugins : Object.keys(config.plugins))
13
+ .filter(plugin => typeof plugin === 'string')
14
+ .map(getPackageName)
12
15
  : [];
13
16
  };
14
17
  export const findDependencies = timerify(findPostCSSDependencies);
@@ -1,8 +1,8 @@
1
1
  type NormalizedGlob = string[];
2
2
  export type PluginConfiguration = {
3
- config: NormalizedGlob;
4
- entry: NormalizedGlob;
5
- project: NormalizedGlob;
3
+ config: NormalizedGlob | null;
4
+ entry: NormalizedGlob | null;
5
+ project: NormalizedGlob | null;
6
6
  } | false;
7
7
  interface PluginsConfiguration {
8
8
  babel: PluginConfiguration;
package/dist/util/fs.js CHANGED
@@ -15,11 +15,6 @@ export const findFile = async (workingDir, fileName) => {
15
15
  return (await isFile(filePath)) ? filePath : undefined;
16
16
  };
17
17
  export const loadJSON = async (filePath) => {
18
- try {
19
- const contents = await fs.readFile(filePath);
20
- return JSON.parse(stripJsonComments(contents.toString()));
21
- }
22
- catch (error) {
23
- console.log(error?.toString());
24
- }
18
+ const contents = await fs.readFile(filePath);
19
+ return JSON.parse(stripJsonComments(contents.toString()));
25
20
  };
@@ -9,19 +9,13 @@ import { timerify } from './performance.js';
9
9
  const require = createRequire(process.cwd());
10
10
  const { values: { 'no-progress': noProgress = false }, } = parsedArgs;
11
11
  const load = async (filePath) => {
12
- if (path.extname(filePath) === '.json' || /rc$/.test(filePath)) {
13
- return loadJSON(filePath);
14
- }
15
- if (path.extname(filePath) === '.yaml' || path.extname(filePath) === '.yml') {
16
- try {
17
- return yaml.load((await fs.readFile(filePath)).toString());
12
+ try {
13
+ if (path.extname(filePath) === '.json' || /rc$/.test(filePath)) {
14
+ return loadJSON(filePath);
18
15
  }
19
- catch (error) {
20
- console.log('Failed to load ' + filePath);
21
- console.log(error?.toString());
16
+ if (path.extname(filePath) === '.yaml' || path.extname(filePath) === '.yml') {
17
+ return yaml.load((await fs.readFile(filePath)).toString());
22
18
  }
23
- }
24
- try {
25
19
  const imported = await esmLoad(filePath, {}, require);
26
20
  return imported.default ?? imported;
27
21
  }
@@ -37,7 +37,7 @@ export default class WorkspaceWorker {
37
37
  this.enabled = Object.keys(plugins).reduce((enabled, pluginName) => ({ ...enabled, [pluginName]: false }), {});
38
38
  }
39
39
  getConfigForPlugin(pluginName) {
40
- return this.config[pluginName] ?? { config: [], entry: [], project: [] };
40
+ return this.config[pluginName] ?? { config: null, entry: null, project: null };
41
41
  }
42
42
  async init() {
43
43
  this.setEnabledPlugins();
@@ -101,7 +101,7 @@ export default class WorkspaceWorker {
101
101
  if (this.enabled[pluginName] && pluginConfig) {
102
102
  const { entry } = pluginConfig;
103
103
  const defaultEntryFiles = 'ENTRY_FILE_PATTERNS' in plugin ? plugin.ENTRY_FILE_PATTERNS : [];
104
- patterns.push(...(entry.length > 0 ? entry : defaultEntryFiles));
104
+ patterns.push(...(entry ?? defaultEntryFiles));
105
105
  if (isIncludeProductionEntryFiles) {
106
106
  const entry = 'PRODUCTION_ENTRY_FILE_PATTERNS' in plugin ? plugin.PRODUCTION_ENTRY_FILE_PATTERNS : [];
107
107
  patterns.push(...entry);
@@ -116,15 +116,13 @@ export default class WorkspaceWorker {
116
116
  const pluginConfig = this.getConfigForPlugin(pluginName);
117
117
  if (this.enabled[pluginName] && pluginConfig) {
118
118
  const { entry, project } = pluginConfig;
119
- const defaultEntryFiles = 'ENTRY_FILE_PATTERNS' in plugin ? plugin.ENTRY_FILE_PATTERNS : [];
120
- const defaultProjectFiles = 'PROJECT_FILE_PATTERNS' in plugin ? plugin.PROJECT_FILE_PATTERNS : defaultEntryFiles;
121
- patterns.push(...(project.length > 0
122
- ? project
123
- : defaultProjectFiles.length > 0
124
- ? defaultProjectFiles
125
- : entry.length > 0
126
- ? entry
127
- : defaultEntryFiles));
119
+ patterns.push(...(project ??
120
+ entry ??
121
+ ('PROJECT_FILE_PATTERNS' in plugin
122
+ ? plugin.PROJECT_FILE_PATTERNS
123
+ : 'ENTRY_FILE_PATTERNS' in plugin
124
+ ? plugin.ENTRY_FILE_PATTERNS
125
+ : [])));
128
126
  }
129
127
  }
130
128
  return [patterns, this.isRoot ? this.negatedWorkspacePatterns : []].flat();
@@ -136,7 +134,7 @@ export default class WorkspaceWorker {
136
134
  if (this.enabled[pluginName] && pluginConfig) {
137
135
  const { config } = pluginConfig;
138
136
  const defaultConfigFiles = 'CONFIG_FILE_PATTERNS' in plugin ? plugin.CONFIG_FILE_PATTERNS : [];
139
- patterns.push(...(config.length > 0 ? config : defaultConfigFiles));
137
+ patterns.push(...(config ?? defaultConfigFiles));
140
138
  }
141
139
  }
142
140
  return patterns;
@@ -177,9 +175,7 @@ export default class WorkspaceWorker {
177
175
  const pluginConfig = this.getConfigForPlugin(pluginName);
178
176
  if (this.enabled[pluginName] && pluginConfig) {
179
177
  if ('PRODUCTION_ENTRY_FILE_PATTERNS' in plugin) {
180
- const { entry } = pluginConfig;
181
- const defaultEntryFiles = plugin.PRODUCTION_ENTRY_FILE_PATTERNS;
182
- patterns.push(...(entry.length > 0 ? entry : defaultEntryFiles));
178
+ patterns.push(...(pluginConfig.entry ?? plugin.PRODUCTION_ENTRY_FILE_PATTERNS));
183
179
  }
184
180
  }
185
181
  }
@@ -191,9 +187,8 @@ export default class WorkspaceWorker {
191
187
  const plugin = plugins[pluginName];
192
188
  const pluginConfig = this.getConfigForPlugin(pluginName);
193
189
  if (pluginConfig) {
194
- const { config } = pluginConfig;
195
190
  const defaultConfig = 'CONFIG_FILE_PATTERNS' in plugin ? plugin.CONFIG_FILE_PATTERNS : [];
196
- return config.length > 0 ? config : defaultConfig;
191
+ return pluginConfig.config ?? defaultConfig;
197
192
  }
198
193
  return [];
199
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "Find unused files, dependencies and exports in your TypeScript and JavaScript project",
5
5
  "keywords": [
6
6
  "find",
@@ -59,7 +59,7 @@
59
59
  "@snyk/github-codeowners": "1.1.0",
60
60
  "chalk": "5.2.0",
61
61
  "easy-table": "1.2.0",
62
- "esbuild": "0.16.8",
62
+ "esbuild": "0.16.10",
63
63
  "esbuild-register": "3.4.2",
64
64
  "eslint": "8.30.0",
65
65
  "fast-glob": "3.2.12",
@@ -81,11 +81,11 @@
81
81
  "@types/eslint": "8.4.10",
82
82
  "@types/js-yaml": "4.0.5",
83
83
  "@types/micromatch": "4.0.2",
84
- "@types/node": "18.11.16",
84
+ "@types/node": "18.11.17",
85
85
  "@types/npmcli__map-workspaces": "3.0.0",
86
86
  "@types/webpack": "5.28.0",
87
- "@typescript-eslint/eslint-plugin": "5.46.1",
88
- "@typescript-eslint/parser": "5.46.1",
87
+ "@typescript-eslint/eslint-plugin": "5.47.0",
88
+ "@typescript-eslint/parser": "5.47.0",
89
89
  "eslint-import-resolver-typescript": "3.5.2",
90
90
  "eslint-plugin-import": "2.26.0",
91
91
  "globstar": "1.0.0",