knip 1.12.2 → 1.12.3

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/dist/index.js CHANGED
@@ -186,16 +186,16 @@ export const main = async (unresolvedConfiguration) => {
186
186
  if (report.dependencies || report.unlisted || report.files) {
187
187
  await worker.findDependenciesByPlugins();
188
188
  const { referencedDependencyIssues, peerDependencies, installedBinaries, entryFiles, enabledPlugins } = worker.getFinalDependencies();
189
+ deputy.addPeerDependencies(name, peerDependencies);
190
+ deputy.setInstalledBinaries(name, installedBinaries);
191
+ principal.addEntryPaths(entryFiles);
192
+ enabledPluginsStore.set(name, enabledPlugins);
189
193
  referencedDependencyIssues.forEach(issue => {
190
194
  const workspace = { name, dir, config, ancestors };
191
195
  const unlistedDependency = deputy.maybeAddListedReferencedDependency(workspace, issue.symbol);
192
196
  if (unlistedDependency)
193
197
  collector.addIssue(issue);
194
198
  });
195
- deputy.addPeerDependencies(name, peerDependencies);
196
- deputy.setInstalledBinaries(name, installedBinaries);
197
- principal.addEntryPaths(entryFiles);
198
- enabledPluginsStore.set(name, enabledPlugins);
199
199
  }
200
200
  }
201
201
  }
@@ -0,0 +1,5 @@
1
+ type Options = {
2
+ cwd: string;
3
+ };
4
+ export declare const fallback: (configFilePath: string, { cwd }: Options) => Promise<string[]>;
5
+ export {};
@@ -0,0 +1,20 @@
1
+ import { ESLint } from 'eslint';
2
+ import { compact } from '../../util/array.js';
3
+ import { getPackageName } from '../../util/modules.js';
4
+ import { resolvePluginPackageName, getDependenciesFromSettings } from './helpers.js';
5
+ export const fallback = async (configFilePath, { cwd }) => {
6
+ const engine = new ESLint({ cwd, overrideConfigFile: configFilePath, useEslintrc: false });
7
+ const jsConfig = await engine.calculateConfigForFile('__placeholder__.js');
8
+ const tsConfig = await engine.calculateConfigForFile('__placeholder__.ts');
9
+ const tsxConfig = await engine.calculateConfigForFile('__placeholder__.tsx');
10
+ const dependencies = [jsConfig, tsConfig, tsxConfig].map(config => {
11
+ if (!config)
12
+ return [];
13
+ const plugins = config.plugins?.map(resolvePluginPackageName) ?? [];
14
+ const parsers = config.parser ? [config.parser] : [];
15
+ const extraParsers = config.parserOptions?.babelOptions?.presets ?? [];
16
+ const settings = config.settings ? getDependenciesFromSettings(config.settings) : [];
17
+ return [...parsers, ...extraParsers, ...plugins, ...settings].map(getPackageName);
18
+ });
19
+ return compact(dependencies.flat());
20
+ };
@@ -1,4 +1,4 @@
1
1
  import type { ESLintConfig } from './types.js';
2
+ export declare const getDependenciesDeep: (configFilePath: string, dependencies?: Set<string>) => Promise<Set<string>>;
2
3
  export declare const resolvePluginPackageName: (pluginName: string) => string;
3
- export declare const customResolvePluginPackageNames: (extend: string) => string | undefined;
4
4
  export declare const getDependenciesFromSettings: (settings?: ESLintConfig['settings']) => string[];
@@ -1,5 +1,35 @@
1
+ import path from 'node:path';
1
2
  import { compact } from '../../util/array.js';
3
+ import { _load } from '../../util/loader.js';
2
4
  import { getPackageName } from '../../util/modules.js';
5
+ import { require } from '../../util/require.js';
6
+ const getDependencies = (config) => {
7
+ const extend = config.extends ? [config.extends].flat().map(customResolvePluginPackageNames) : [];
8
+ if (extend.includes('eslint-plugin-prettier'))
9
+ extend.push('eslint-config-prettier');
10
+ const plugins = config.plugins ? config.plugins.map(resolvePluginPackageName) : [];
11
+ const parser = config.parser;
12
+ const extraParsers = config.parserOptions?.babelOptions?.presets ?? [];
13
+ const settings = config.settings ? getDependenciesFromSettings(config.settings) : [];
14
+ return compact([...extend, ...plugins, parser, ...extraParsers, ...settings]).map(getPackageName);
15
+ };
16
+ export const getDependenciesDeep = async (configFilePath, dependencies = new Set()) => {
17
+ const addAll = (deps) => deps.forEach(dependency => dependencies.add(dependency));
18
+ const config = await _load(configFilePath);
19
+ if (config.extends) {
20
+ for (const extend of [config.extends].flat()) {
21
+ if (extend.startsWith('.') || (extend.startsWith('/') && !extend.includes('/node_modules/'))) {
22
+ const extendConfigFilePath = require.resolve(path.join(path.dirname(configFilePath), extend));
23
+ addAll(await getDependenciesDeep(extendConfigFilePath));
24
+ }
25
+ }
26
+ }
27
+ if (config.overrides)
28
+ for (const override of config.overrides)
29
+ addAll(getDependencies(override));
30
+ addAll(getDependencies(config));
31
+ return dependencies;
32
+ };
3
33
  const resolvePackageName = (namespace, pluginName) => {
4
34
  return pluginName.startsWith('@')
5
35
  ? pluginName.includes('/')
@@ -8,7 +38,7 @@ const resolvePackageName = (namespace, pluginName) => {
8
38
  : `${namespace}-${pluginName}`;
9
39
  };
10
40
  export const resolvePluginPackageName = (pluginName) => resolvePackageName('eslint-plugin', pluginName);
11
- export const customResolvePluginPackageNames = (extend) => {
41
+ const customResolvePluginPackageNames = (extend) => {
12
42
  if (extend.includes('/node_modules/'))
13
43
  return getPackageName(extend);
14
44
  if (extend.startsWith('/') || extend.startsWith('.'))
@@ -1,51 +1,29 @@
1
- import { ESLint } from 'eslint';
2
- import { compact } from '../../util/array.js';
3
- import { debugLogFiles, debugLogObject } from '../../util/debug.js';
4
- import { _firstGlob } from '../../util/glob.js';
5
1
  import { _load } from '../../util/loader.js';
6
- import { getPackageName } from '../../util/modules.js';
7
2
  import { timerify } from '../../util/performance.js';
8
3
  import { hasDependency } from '../../util/plugin.js';
9
- import { resolvePluginPackageName, customResolvePluginPackageNames, getDependenciesFromSettings } from './helpers.js';
4
+ import { fallback } from './fallback.js';
5
+ import { getDependenciesDeep } from './helpers.js';
10
6
  export const NAME = 'ESLint';
11
7
  export const ENABLERS = ['eslint'];
12
8
  export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
13
9
  export const CONFIG_FILE_PATTERNS = ['.eslintrc', '.eslintrc.{js,json,cjs}', '.eslintrc.{yml,yaml}', 'package.json'];
14
10
  export const ENTRY_FILE_PATTERNS = ['eslint.config.js'];
15
- const findESLintDependencies = async (configFilePath, { cwd, manifest, workspaceConfig }) => {
16
- if (configFilePath.endsWith('package.json') && !manifest.eslintConfig)
17
- return [];
11
+ const findESLintDependencies = async (configFilePath, { cwd, manifest }) => {
18
12
  let config = undefined;
19
13
  try {
20
14
  config = configFilePath.endsWith('package.json') ? manifest.eslintConfig : await _load(configFilePath);
21
15
  }
22
16
  catch (error) {
23
- if (error instanceof Error && error.cause instanceof Error && !/Failed to patch ESLint/.test(error.cause.message)) {
17
+ if (error instanceof Error && error.cause instanceof Error && /Failed to patch ESLint/.test(error.cause.message)) {
18
+ return fallback(configFilePath, { cwd });
19
+ }
20
+ else {
24
21
  throw error;
25
22
  }
26
23
  }
27
- const rootExtends = config?.extends ? [config.extends].flat().map(customResolvePluginPackageNames) : [];
28
- if (rootExtends.includes('eslint-plugin-prettier'))
29
- rootExtends.push('eslint-config-prettier');
30
- const patterns = compact([
31
- workspaceConfig.entry,
32
- ...(config?.overrides?.map(overrides => [overrides.files].flat()) ?? []),
33
- ]);
34
- debugLogObject('ESLint overrides file patterns', patterns);
35
- const samples = await Promise.all(patterns.map(patterns => _firstGlob({ patterns, cwd })));
36
- const sampleFilePaths = compact(samples.filter((filePath) => typeof filePath !== 'undefined').map(String));
37
- debugLogFiles('ESLint overrides sample files', sampleFilePaths);
38
- const engine = new ESLint({ cwd, overrideConfigFile: configFilePath, useEslintrc: false });
39
- const calculateConfigForFile = async (sampleFile) => await engine.calculateConfigForFile(sampleFile);
40
- const dependencies = await Promise.all(sampleFilePaths.map(calculateConfigForFile)).then(configs => configs.flatMap(config => {
41
- if (!config)
42
- return [];
43
- const plugins = config.plugins?.map(resolvePluginPackageName) ?? [];
44
- const parsers = config.parser ? [config.parser] : [];
45
- const extraParsers = config.parserOptions?.babelOptions?.presets ?? [];
46
- const settings = config.settings ? getDependenciesFromSettings(config.settings) : [];
47
- return [...parsers, ...extraParsers, ...plugins, ...settings].map(getPackageName);
48
- }));
49
- return compact([...rootExtends, ...dependencies.flat()]);
24
+ if (!config)
25
+ return [];
26
+ const dependencies = await getDependenciesDeep(configFilePath);
27
+ return Array.from(dependencies);
50
28
  };
51
29
  export const findDependencies = timerify(findESLintDependencies);
@@ -1,14 +1,25 @@
1
- export type ESLintConfig = {
1
+ type ParserOptions = {
2
+ project?: string;
3
+ babelOptions?: {
4
+ presets: string[];
5
+ };
6
+ };
7
+ type Settings = Record<string, Record<string, unknown>>;
8
+ type Rules = Record<string, string | number>;
9
+ type BaseConfig = {
2
10
  extends?: string | string[];
3
11
  parser?: string;
4
- parserOptions?: {
5
- babelOptions?: {
6
- presets: string[];
7
- };
8
- };
12
+ parserOptions?: ParserOptions;
13
+ processor?: string;
9
14
  plugins?: string[];
10
- settings?: Record<string, Record<string, unknown>>;
11
- overrides?: {
12
- files: string[];
13
- }[];
15
+ settings?: Settings;
16
+ rules?: Rules;
17
+ };
18
+ type OverrideConfig = BaseConfig & {
19
+ files: string[];
20
+ };
21
+ export type ESLintConfig = BaseConfig & {
22
+ env?: Record<string, boolean>;
23
+ overrides?: OverrideConfig[];
14
24
  };
25
+ export {};
@@ -1,4 +1,4 @@
1
- import { Configuration, PluginConfiguration, WorkspaceConfiguration } from './config.js';
1
+ import type { Configuration, PluginConfiguration, WorkspaceConfiguration } from './config.js';
2
2
  import type { PackageJson } from 'type-fest';
3
3
  type IsPluginEnabledCallbackOptions = {
4
4
  cwd: string;
@@ -1,2 +1,2 @@
1
- import type { GetBinariesFromScripts } from './types.js';
2
- export declare const _getReferencesFromScripts: GetBinariesFromScripts;
1
+ import type { GetReferencesFromScripts } from './types.js';
2
+ export declare const _getReferencesFromScripts: GetReferencesFromScripts;
@@ -5,7 +5,7 @@ type Options = {
5
5
  ignore?: string[];
6
6
  knownGlobalsOnly?: boolean;
7
7
  };
8
- export type GetBinariesFromScripts = (npmScripts: string | string[], options?: Options) => {
8
+ export type GetReferencesFromScripts = (npmScripts: string | string[], options?: Options) => {
9
9
  entryFiles: string[];
10
10
  binaries: string[];
11
11
  };
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "1.12.2";
1
+ export declare const version = "1.12.3";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.12.2';
1
+ export const version = '1.12.3';
@@ -43,11 +43,10 @@ export default class WorkspaceWorker {
43
43
  const dependencies = new Set([Object.keys(manifest?.dependencies ?? {}), Object.keys(manifest?.devDependencies ?? {})].flat());
44
44
  const pluginEntries = Object.entries(plugins);
45
45
  for (const [pluginName, plugin] of pluginEntries) {
46
- const hasIsEnabled = typeof plugin.isEnabled === 'function';
46
+ const isEnabled = this.config[pluginName] !== false;
47
+ const isEnabledInAncestor = enabledPluginsInAncestors.includes(pluginName);
47
48
  this.enabled[pluginName] =
48
- this.config[pluginName] !== false &&
49
- (enabledPluginsInAncestors.includes(pluginName) ||
50
- (hasIsEnabled && (await plugin.isEnabled({ cwd: this.dir, manifest: this.manifest, dependencies }))));
49
+ isEnabled && (isEnabledInAncestor || (await plugin.isEnabled({ cwd: this.dir, manifest, dependencies })));
51
50
  }
52
51
  this.enabledPlugins = pluginEntries.filter(([name]) => this.enabled[name]).map(([name]) => name);
53
52
  const enabledPluginNames = this.enabledPlugins.map(name => plugins[name].NAME);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "1.12.2",
3
+ "version": "1.12.3",
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",