knip 6.17.2 → 6.18.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.
@@ -1017,4 +1017,5 @@ export declare class ConfigurationChief {
1017
1017
  };
1018
1018
  findWorkspaceByFilePath(filePath: string): Workspace | undefined;
1019
1019
  getUnusedIgnoredWorkspaces(): string[];
1020
+ getUnusedConfiguredWorkspaces(): string[];
1020
1021
  }
@@ -392,4 +392,27 @@ export class ConfigurationChief {
392
392
  return !isDirectory(dir) || isFile(dir, 'package.json');
393
393
  });
394
394
  }
395
+ getUnusedConfiguredWorkspaces() {
396
+ if (!this.rawConfig?.workspaces)
397
+ return [];
398
+ const unused = [];
399
+ for (const key of Object.keys(this.rawConfig.workspaces)) {
400
+ if (key.includes('*')) {
401
+ const isMatch = picomatch(key);
402
+ let isUsed = false;
403
+ for (const name of this.workspacePackages.keys()) {
404
+ if (isMatch(name)) {
405
+ isUsed = true;
406
+ break;
407
+ }
408
+ }
409
+ if (!isUsed)
410
+ unused.push(key);
411
+ }
412
+ else if (!this.workspacePackages.has(key)) {
413
+ unused.push(key);
414
+ }
415
+ }
416
+ return unused;
417
+ }
395
418
  }
@@ -15,7 +15,8 @@ export const resolve = (_binary, args, options) => {
15
15
  const command = parsed.call ? fromArgs([parsed.call]) : [];
16
16
  const restArgs = argsFrom(args, packageSpecifier);
17
17
  const isBinary = specifier && !packageSpecifier.includes('@') && !isInternal(specifier);
18
- const dependency = isBinary ? toBinary(specifier) : toDependency(specifier, { optional: !parsed.no });
18
+ const opts = parsed.no ? undefined : { optional: true };
19
+ const dependency = isBinary ? toBinary(specifier, opts) : toDependency(specifier, opts);
19
20
  const specifiers = dependency && !parsed.yes ? [dependency] : [];
20
21
  return [
21
22
  ...specifiers,
@@ -233,6 +233,10 @@ export const analyze = async ({ analyzedFiles, counselor, chief, collector, depu
233
233
  const catalogIssues = await counselor.settleCatalogIssues(options);
234
234
  for (const issue of catalogIssues)
235
235
  collector.addIssue(issue);
236
+ const unusedConfiguredWorkspaces = chief.getUnusedConfiguredWorkspaces();
237
+ for (const identifier of unusedConfiguredWorkspaces) {
238
+ collector.addConfigurationHint({ type: 'workspaces', identifier });
239
+ }
236
240
  const unusedIgnoredWorkspaces = chief.getUnusedIgnoredWorkspaces();
237
241
  for (const identifier of unusedIgnoredWorkspaces) {
238
242
  collector.addConfigurationHint({ type: 'ignoreWorkspaces', identifier });
@@ -59,7 +59,7 @@ export async function build({ chief, collector, counselor, deputy, principal, is
59
59
  const dependencies = deputy.getDependencies(name);
60
60
  const baseConfig = chief.getConfigForWorkspace(name);
61
61
  const tsConfigFilePath = join(dir, options.tsConfigFile ?? 'tsconfig.json');
62
- const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs } = await loadTSConfig(tsConfigFilePath);
62
+ const { isFile, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths: tsConfigPaths, } = await loadTSConfig(tsConfigFilePath);
63
63
  const [definitionPaths, tscSourcePaths] = partition(fileNames, filePath => IS_DTS.test(filePath));
64
64
  const worker = new WorkspaceWorker({
65
65
  name,
@@ -129,6 +129,8 @@ export async function build({ chief, collector, counselor, deputy, principal, is
129
129
  for (const dep of getManifestImportDependencies(manifest))
130
130
  deputy.addReferencedDependency(name, dep);
131
131
  principal.addPaths(config.paths, dir, dir);
132
+ if (tsConfigPaths)
133
+ principal.addPaths(tsConfigPaths, dir, dir);
132
134
  principal.addRootDirs(compilerOptions.rootDirs, dir);
133
135
  const inputsFromPlugins = await worker.runPlugins();
134
136
  for (const id of inputsFromPlugins)
@@ -4,7 +4,11 @@ import { toCosmiconfig } from '../../util/plugin-config.js';
4
4
  const title = 'commitlint';
5
5
  const enablers = ['@commitlint/cli'];
6
6
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
7
- const config = ['package.json', 'package.yaml', ...toCosmiconfig('commitlint', { additionalExtensions: ['cts', 'mts'] })];
7
+ const config = [
8
+ 'package.json',
9
+ 'package.yaml',
10
+ ...toCosmiconfig('commitlint', { additionalExtensions: ['cts', 'mts'] }),
11
+ ];
8
12
  const resolveConfig = async (config) => {
9
13
  const extendsConfigs = config.extends
10
14
  ? [config.extends]
@@ -9,7 +9,7 @@ const enablers = ['jest'];
9
9
  const isEnabled = ({ dependencies, manifest }) => hasDependency(dependencies, enablers) || Boolean(manifest.name?.startsWith('jest-presets'));
10
10
  const config = ['jest.config.{js,ts,mjs,cjs,mts,cts,json}', 'package.json'];
11
11
  const mocks = ['**/__mocks__/**/*.[jt]s?(x)'];
12
- const entry = ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)', ...mocks];
12
+ const entry = ['**/__tests__/**/*.?(c|m)[jt]s?(x)', '**/?(*.)+(spec|test).?(c|m)[jt]s?(x)', ...mocks];
13
13
  const rootDirRe = /<rootDir>/;
14
14
  const resolveDependencies = async (config, rootDir, options) => {
15
15
  const { configFileDir } = options;
@@ -89,7 +89,9 @@ const resolveConfig = async (localConfig, options) => {
89
89
  const replaceRootDir = (name) => name.replace(rootDirRe, rootDir);
90
90
  const inputs = await resolveDependencies(localConfig, rootDir, options);
91
91
  const entries = localConfig.testMatch
92
- ? arrayify(localConfig.testMatch).map(replaceRootDir).map(id => toEntry(id))
92
+ ? arrayify(localConfig.testMatch)
93
+ .map(replaceRootDir)
94
+ .map(id => toEntry(id))
93
95
  : entry.map(id => toEntry(id));
94
96
  if (localConfig.testMatch && !options.config.entry)
95
97
  entries.push(...mocks.map(id => toEntry(id)));
@@ -1,6 +1,6 @@
1
1
  import { compact } from '../../util/array.js';
2
- import { toAlias, toConfig, toDeferResolve, toProductionDependency } from '../../util/input.js';
3
- import { dirname, join } from '../../util/path.js';
2
+ import { toConfig, toDeferResolve, toProductionDependency } from '../../util/input.js';
3
+ import { join } from '../../util/path.js';
4
4
  import { hasDependency } from '../../util/plugin.js';
5
5
  const title = 'TypeScript';
6
6
  const enablers = ['typescript', '@typescript/native-preview'];
@@ -24,18 +24,12 @@ const resolveConfig = async (localConfig, options) => {
24
24
  ? compilerOptions.plugins.map(plugin => (typeof plugin === 'object' && 'name' in plugin ? plugin.name : ''))
25
25
  : [];
26
26
  const importHelpers = compilerOptions?.importHelpers ? ['tslib'] : [];
27
- const paths = compilerOptions.paths;
28
- const configFileDir = dirname(options.configFilePath);
29
- const aliases = paths && configFileDir !== options.cwd
30
- ? Object.entries(paths).map(([key, prefixes]) => toAlias(key, prefixes, { dir: join(configFileDir, compilerOptions.baseUrl ?? '.') }))
31
- : [];
32
27
  return compact([
33
28
  ...extend,
34
29
  ...references,
35
30
  ...types.map(id => toDeferResolve(id, { isTypeOnly: true, dir: options.cwd })),
36
31
  ...[...plugins, ...importHelpers].map(id => toDeferResolve(id)),
37
32
  ...jsx,
38
- ...aliases,
39
33
  ]);
40
34
  };
41
35
  const args = {
@@ -9,7 +9,7 @@ const title = 'Vitest';
9
9
  const enablers = ['vitest'];
10
10
  const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
11
11
  const config = ['vitest.config.{js,mjs,ts,cjs,mts,cts}', 'vitest.{workspace,projects}.{js,mjs,ts,cjs,mts,cts,json}'];
12
- const mocks = ['**/__mocks__/**/*.[jt]s?(x)'];
12
+ const mocks = ['**/__mocks__/**/*.?(c|m)[jt]s?(x)'];
13
13
  const entry = ['**/*.{bench,test,test-d,spec,spec-d}.?(c|m)[jt]s?(x)', ...mocks];
14
14
  const findConfigDependencies = (localConfig, options, vitestRoot) => {
15
15
  const { configFileDir: dir } = options;
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: ({ report, issues, cwd }: ReporterOptions) => Promise<void>;
3
2
  export default _default;
3
+ declare function _default({ report, issues, cwd }: ReporterOptions): Promise<void>;
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: ({ report, issues, isShowProgress, options, cwd }: ReporterOptions) => void;
3
2
  export default _default;
3
+ declare function _default({ report, issues, isShowProgress, options, cwd }: ReporterOptions): void;
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: ({ report, issues, isShowProgress, cwd }: ReporterOptions) => void;
3
2
  export default _default;
3
+ declare function _default({ report, issues, isShowProgress, cwd }: ReporterOptions): void;
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: ({ report, issues, cwd }: ReporterOptions) => void;
3
2
  export default _default;
3
+ declare function _default({ report, issues, cwd }: ReporterOptions): void;
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: ({ report, issues, cwd, configurationHints, tagHints, isDisableConfigHints, isDisableTagHints, isTreatConfigHintsAsErrors, isTreatTagHintsAsErrors, configFilePath, }: ReporterOptions) => void;
3
2
  export default _default;
3
+ declare function _default({ report, issues, cwd, configurationHints, tagHints, isDisableConfigHints, isDisableTagHints, isTreatConfigHintsAsErrors, isTreatTagHintsAsErrors, configFilePath, }: ReporterOptions): void;
@@ -30,5 +30,5 @@ export type JSONReportEntry = {
30
30
  export type JSONReport = {
31
31
  issues: Array<JSONReportEntry>;
32
32
  };
33
- declare const _default: ({ report, issues, options, cwd }: ReporterOptions) => Promise<void>;
34
33
  export default _default;
34
+ declare function _default({ report, issues, options, cwd }: ReporterOptions): Promise<void>;
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: ({ report, issues, cwd }: ReporterOptions) => void;
3
2
  export default _default;
3
+ declare function _default({ report, issues, cwd }: ReporterOptions): void;
@@ -1,3 +1,3 @@
1
1
  import type { ReporterOptions } from '../types/issues.ts';
2
- declare const _default: (options: ReporterOptions) => void;
3
2
  export default _default;
3
+ declare function _default(options: ReporterOptions): void;
@@ -10,5 +10,5 @@ interface TraceReporterOptions {
10
10
  workspaceFilePathFilter: WorkspaceFilePathFilter;
11
11
  issues: Issues;
12
12
  }
13
- declare const _default: ({ graph, explorer, options, workspaceFilePathFilter, issues }: TraceReporterOptions) => void;
14
13
  export default _default;
14
+ declare function _default({ graph, explorer, options, workspaceFilePathFilter, issues }: TraceReporterOptions): void;
@@ -46,6 +46,7 @@ export const hintPrinters = new Map([
46
46
  ['ignoreBinaries', { print: unused }],
47
47
  ['ignoreDependencies', { print: unused }],
48
48
  ['ignoreUnresolved', { print: unused }],
49
+ ['workspaces', { print: unused }],
49
50
  ['ignoreWorkspaces', { print: unused }],
50
51
  ['entry-empty', { print: empty }],
51
52
  ['project-empty', { print: empty }],
@@ -61,6 +62,7 @@ export const hintPrinters = new Map([
61
62
  const hintTypesOrder = [
62
63
  ['top-level-unconfigured', 'workspace-unconfigured'],
63
64
  ['entry-top-level', 'project-top-level'],
65
+ ['workspaces'],
64
66
  ['ignore', 'ignoreFiles'],
65
67
  ['ignoreWorkspaces'],
66
68
  ['ignoreDependencies'],
@@ -7,5 +7,5 @@ interface WatchReporter {
7
7
  duration?: number;
8
8
  size: number;
9
9
  }
10
- declare const _default: (options: MainOptions, { issues, streamer, duration, size }: WatchReporter) => void;
11
10
  export default _default;
11
+ declare function _default(options: MainOptions, { issues, streamer, duration, size }: WatchReporter): void;
@@ -72,7 +72,7 @@ export type Preprocessor = (options: ReporterOptions) => ReporterOptions;
72
72
  export type IssueSeverity = 'error' | 'warn' | 'off';
73
73
  export type Rules = Record<IssueType, IssueSeverity>;
74
74
  export type ConfigurationHints = Map<string, ConfigurationHint>;
75
- export type ConfigurationHintType = 'ignore' | 'ignoreFiles' | 'ignoreBinaries' | 'ignoreDependencies' | 'ignoreUnresolved' | 'ignoreWorkspaces' | 'entry-redundant' | 'project-redundant' | 'entry-top-level' | 'project-top-level' | 'entry-empty' | 'project-empty' | 'project-extension-unregistered' | 'package-entry' | 'top-level-unconfigured' | 'workspace-unconfigured';
75
+ export type ConfigurationHintType = 'ignore' | 'ignoreFiles' | 'ignoreBinaries' | 'ignoreDependencies' | 'ignoreUnresolved' | 'workspaces' | 'ignoreWorkspaces' | 'entry-redundant' | 'project-redundant' | 'entry-top-level' | 'project-top-level' | 'entry-empty' | 'project-empty' | 'project-extension-unregistered' | 'package-entry' | 'top-level-unconfigured' | 'workspace-unconfigured';
76
76
  export type ConfigurationHint = {
77
77
  type: ConfigurationHintType;
78
78
  identifier: string | RegExp;
@@ -7,6 +7,7 @@ interface TSConfigInfo {
7
7
  include: string[] | undefined;
8
8
  exclude: string[] | undefined;
9
9
  sourceMapPairs: SourceMap[];
10
+ paths: Record<string, string[]> | undefined;
10
11
  }
11
12
  export declare const loadTSConfig: (tsConfigFilePath: string) => Promise<TSConfigInfo>;
12
13
  export {};
@@ -1,4 +1,5 @@
1
1
  import { parseTsconfig } from 'get-tsconfig';
2
+ import { compact } from './array.js';
2
3
  import { isFile } from './fs.js';
3
4
  import { _syncGlob } from './glob.js';
4
5
  import { dirname, isAbsolute, join, toAbsolute } from './path.js';
@@ -16,6 +17,15 @@ const resolvePatterns = (patterns, dir, expandDirs = false) => {
16
17
  return expandDirs && !hasGlobChar(p) && !hasExtension(p) ? join(resolved, '**/*') : resolved;
17
18
  });
18
19
  };
20
+ const pathsBaseDir = (baseUrl, dir) => (baseUrl ? toAbsolute(baseUrl, dir) : dir);
21
+ const collectPaths = (acc, paths, baseDir) => {
22
+ if (!paths)
23
+ return;
24
+ for (const key in paths) {
25
+ const resolved = paths[key].map(p => toAbsolute(p, baseDir));
26
+ acc[key] = key in acc ? compact([...acc[key], ...resolved]) : resolved;
27
+ }
28
+ };
19
29
  const DEFAULT_INCLUDE = ['**/*'];
20
30
  const TS_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs']);
21
31
  const isDtsExt = /\.d\.(m|c)?ts$/;
@@ -53,7 +63,7 @@ const resolveReference = (refPath, dir) => {
53
63
  return isFile(withTsconfig) ? withTsconfig : undefined;
54
64
  };
55
65
  const absDir = (path, dir) => toAbsolute(path, dir).replace(/\/+$/, '');
56
- const walkReferences = (target, references, dir, visited, pairs) => {
66
+ const walkReferences = (target, references, dir, visited, pairs, paths) => {
57
67
  if (!references?.length)
58
68
  return;
59
69
  for (const ref of references) {
@@ -64,6 +74,7 @@ const walkReferences = (target, references, dir, visited, pairs) => {
64
74
  const refConfig = parseTsconfig(refPath);
65
75
  const refDir = dirname(refPath);
66
76
  const refOpts = refConfig.compilerOptions;
77
+ collectPaths(paths, refOpts?.paths, pathsBaseDir(refOpts?.baseUrl, refDir));
67
78
  const refOutDir = refOpts?.outDir ? absDir(refOpts.outDir, refDir) : undefined;
68
79
  const refRootDir = refOpts?.rootDir ? absDir(refOpts.rootDir, refDir) : undefined;
69
80
  if (refOutDir && refRootDir && refOutDir !== refRootDir)
@@ -73,7 +84,7 @@ const walkReferences = (target, references, dir, visited, pairs) => {
73
84
  if (refRootDir && !target.rootDir)
74
85
  target.rootDir = refRootDir;
75
86
  if (!refOutDir || !refRootDir)
76
- walkReferences(target, refConfig.references, refDir, visited, pairs);
87
+ walkReferences(target, refConfig.references, refDir, visited, pairs, paths);
77
88
  }
78
89
  };
79
90
  const EMPTY = {
@@ -82,6 +93,7 @@ const EMPTY = {
82
93
  include: undefined,
83
94
  exclude: undefined,
84
95
  sourceMapPairs: [],
96
+ paths: undefined,
85
97
  };
86
98
  export const loadTSConfig = async (tsConfigFilePath) => {
87
99
  if (!isFile(tsConfigFilePath))
@@ -96,15 +108,18 @@ export const loadTSConfig = async (tsConfigFilePath) => {
96
108
  compilerOptions.rootDir = absDir(compilerOptions.rootDir, dir);
97
109
  if (compilerOptions.rootDirs)
98
110
  compilerOptions.rootDirs = compilerOptions.rootDirs.map(d => absDir(d, dir));
111
+ const tsconfigPaths = {};
112
+ collectPaths(tsconfigPaths, compilerOptions.paths, pathsBaseDir(compilerOptions.baseUrl, dir));
99
113
  const sourceMapPairs = [];
100
114
  if (config.references?.length) {
101
- walkReferences(compilerOptions, config.references, dir, new Set([tsConfigFilePath]), sourceMapPairs);
115
+ walkReferences(compilerOptions, config.references, dir, new Set([tsConfigFilePath]), sourceMapPairs, tsconfigPaths);
102
116
  }
103
117
  const include = resolvePatterns(config.include, dir, true);
104
118
  const exclude = resolvePatterns(config.exclude, dir, true);
105
119
  const files = resolvePatterns(config.files, dir);
106
120
  const fileNames = expandFileNames(dir, compilerOptions, include, exclude, files);
107
- return { isFile: true, compilerOptions, fileNames, include, exclude, sourceMapPairs };
121
+ const paths = Object.keys(tsconfigPaths).length > 0 ? tsconfigPaths : undefined;
122
+ return { isFile: true, compilerOptions, fileNames, include, exclude, sourceMapPairs, paths };
108
123
  }
109
124
  catch {
110
125
  return { isFile: true, ...EMPTY };
@@ -8,6 +8,6 @@ export type WorkspaceManifestHandler = (filePath: string) => {
8
8
  } | undefined;
9
9
  export declare const getWorkspaceManifestHandler: (chief: ConfigurationChief) => WorkspaceManifestHandler;
10
10
  export declare const getModuleSourcePathHandler: (chief: ConfigurationChief) => (filePath: string) => string | undefined;
11
- export declare const getToSourcePathsHandler: (chief: ConfigurationChief) => (specifiers: Set<string>, dir: string, extensions: (string | undefined) | undefined, label: string) => Promise<string[]>;
11
+ export declare const getToSourcePathsHandler: (chief: ConfigurationChief) => (specifiers: Set<string>, dir: string, extensions: string | undefined, label: string) => Promise<string[]>;
12
12
  export declare const toSourceMappedSpecifiers: (ws: Workspace | undefined, absSpecifier: string, extensions?: string) => string[];
13
13
  export type ToSourceFilePath = ReturnType<typeof getModuleSourcePathHandler>;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "6.17.2";
1
+ export declare const version = "6.18.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '6.17.2';
1
+ export const version = '6.18.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "knip",
3
- "version": "6.17.2",
3
+ "version": "6.18.0",
4
4
  "description": "Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects",
5
5
  "keywords": [
6
6
  "analysis",
@@ -81,8 +81,8 @@
81
81
  "formatly": "^0.3.0",
82
82
  "get-tsconfig": "4.14.0",
83
83
  "jiti": "^2.7.0",
84
- "oxc-parser": "^0.135.0",
85
- "oxc-resolver": "^11.20.0",
84
+ "oxc-parser": "^0.137.0",
85
+ "oxc-resolver": "11.21.3",
86
86
  "picomatch": "^4.0.4",
87
87
  "smol-toml": "^1.6.1",
88
88
  "strip-json-comments": "5.0.3",
@@ -96,7 +96,7 @@
96
96
  "@types/bun": "^1.3.14",
97
97
  "@types/picomatch": "^4.0.3",
98
98
  "@types/webpack": "^5.28.5",
99
- "@typescript/native-preview": "7.0.0-dev.20260612.1",
99
+ "@typescript/native-preview": "7.0.0-dev.20260619.1",
100
100
  "codeclimate-types": "^0.3.1",
101
101
  "prettier": "^3.8.4",
102
102
  "tsx": "^4.22.4"