knip 5.2.2 → 5.3.1
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/ConfigurationChief.js +2 -2
- package/dist/ProjectPrincipal.d.ts +2 -1
- package/dist/ProjectPrincipal.js +15 -0
- package/dist/cli.js +2 -1
- package/dist/index.js +15 -51
- package/dist/types/cli.d.ts +1 -0
- package/dist/typescript/getImportsAndExports.d.ts +1 -0
- package/dist/typescript/visitors/exports/exportKeyword.js +15 -13
- package/dist/util/cli-arguments.d.ts +3 -1
- package/dist/util/cli-arguments.js +4 -0
- package/dist/util/get-included-issue-types.d.ts +1 -0
- package/dist/util/get-included-issue-types.js +4 -2
- package/dist/util/handleReferencedDependency.d.ts +5 -0
- package/dist/util/handleReferencedDependency.js +48 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@ import { toRegexOrString } from './util/regex.js';
|
|
|
21
21
|
import { _require } from './util/require.js';
|
|
22
22
|
import { unwrapFunction } from './util/unwrap-function.js';
|
|
23
23
|
import { byPathDepth } from './util/workspace.js';
|
|
24
|
-
const { config: rawConfigArg, workspace: rawWorkspaceArg, include = [], exclude = [], dependencies = false, exports = false, } = parsedArgValues;
|
|
24
|
+
const { config: rawConfigArg, workspace: rawWorkspaceArg, include = [], exclude = [], dependencies = false, exports = false, files = false, } = parsedArgValues;
|
|
25
25
|
const workspaceArg = rawWorkspaceArg ? toPosix(rawWorkspaceArg).replace(/^\.\//, '').replace(/\/$/, '') : undefined;
|
|
26
26
|
const getDefaultWorkspaceConfig = (extensions) => {
|
|
27
27
|
const exts = [...DEFAULT_EXTENSIONS, ...(extensions ?? [])].map(ext => ext.slice(1)).join(',');
|
|
@@ -352,7 +352,7 @@ export class ConfigurationChief {
|
|
|
352
352
|
return { entry, project, paths, ignore, isIncludeEntryExports, ...plugins };
|
|
353
353
|
}
|
|
354
354
|
getIncludedIssueTypes() {
|
|
355
|
-
const cliArgs = { include, exclude, dependencies, exports };
|
|
355
|
+
const cliArgs = { include, exclude, dependencies, exports, files };
|
|
356
356
|
const excludesFromRules = getKeysByValue(this.config.rules, 'off');
|
|
357
357
|
const config = {
|
|
358
358
|
include: this.config.include ?? [],
|
|
@@ -4,7 +4,7 @@ import { createCustomModuleResolver } from './typescript/resolveModuleNames.js';
|
|
|
4
4
|
import { SourceFileManager } from './typescript/SourceFileManager.js';
|
|
5
5
|
import type { SyncCompilers, AsyncCompilers } from './compilers/types.js';
|
|
6
6
|
import type { PrincipalOptions } from './PrincipalFactory.js';
|
|
7
|
-
import type { SerializableExportMember } from './types/exports.js';
|
|
7
|
+
import type { SerializableExport, SerializableExportMember } from './types/exports.js';
|
|
8
8
|
import type { UnresolvedImport } from './types/imports.js';
|
|
9
9
|
import type { ProgramMaybe53 } from './typescript/SourceFile.js';
|
|
10
10
|
import type { ReferencedDependencies } from './WorkspaceWorker.js';
|
|
@@ -61,4 +61,5 @@ export declare class ProjectPrincipal {
|
|
|
61
61
|
};
|
|
62
62
|
resolveModule(specifier: string, filePath?: string): ts.ResolvedModuleFull | undefined;
|
|
63
63
|
findUnusedMembers(filePath: string, members: SerializableExportMember[]): SerializableExportMember[];
|
|
64
|
+
hasReferences(filePath: string, exportedItem: SerializableExport): boolean;
|
|
64
65
|
}
|
package/dist/ProjectPrincipal.js
CHANGED
|
@@ -203,4 +203,19 @@ export class ProjectPrincipal {
|
|
|
203
203
|
return externalRefs.length === 0 && internalRefs.length === 0;
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
|
+
hasReferences(filePath, exportedItem) {
|
|
207
|
+
if (exportedItem.jsDocTags.includes('@public'))
|
|
208
|
+
return false;
|
|
209
|
+
if (!this.findReferences) {
|
|
210
|
+
const languageService = ts.createLanguageService(this.backend.languageServiceHost, ts.createDocumentRegistry());
|
|
211
|
+
this.findReferences = timerify(languageService.findReferences);
|
|
212
|
+
}
|
|
213
|
+
const referencedSymbols = this.findReferences(filePath, exportedItem.pos);
|
|
214
|
+
const files = (referencedSymbols ?? [])
|
|
215
|
+
.flatMap(refs => refs.references)
|
|
216
|
+
.filter(ref => !ref.isDefinition)
|
|
217
|
+
.map(ref => ref.fileName);
|
|
218
|
+
const externalRefs = files.filter(f => f !== filePath);
|
|
219
|
+
return externalRefs.length > 0;
|
|
220
|
+
}
|
|
206
221
|
}
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import { runPreprocessors, runReporters } from './util/reporter.js';
|
|
|
9
9
|
import { splitTags } from './util/tag.js';
|
|
10
10
|
import { version } from './version.js';
|
|
11
11
|
import { main } from './index.js';
|
|
12
|
-
const { debug: isDebug = false, trace: isTrace = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-config-hints': noConfigHints = false, 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = isDebug || isTrace || false, 'include-entry-exports': isIncludeEntryExports = false, 'isolate-workspaces': isIsolateWorkspaces = false, performance: isObservePerf = false, production: isProduction = false, 'reporter-options': reporterOptions = '', 'preprocessor-options': preprocessorOptions = '', strict: isStrict = false, fix: isFix = false, 'fix-type': fixTypes = [], tsConfig, version: isVersion, 'experimental-tags': experimentalTags = [], tags = [], } = parsedArgValues;
|
|
12
|
+
const { debug: isDebug = false, trace: isTrace = false, help: isHelp, 'max-issues': maxIssues = '0', 'no-config-hints': noConfigHints = false, 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': isNoProgress = isDebug || isTrace || false, 'include-entry-exports': isIncludeEntryExports = false, 'include-libs': isIncludeLibs = false, 'isolate-workspaces': isIsolateWorkspaces = false, performance: isObservePerf = false, production: isProduction = false, 'reporter-options': reporterOptions = '', 'preprocessor-options': preprocessorOptions = '', strict: isStrict = false, fix: isFix = false, 'fix-type': fixTypes = [], tsConfig, version: isVersion, 'experimental-tags': experimentalTags = [], tags = [], } = parsedArgValues;
|
|
13
13
|
if (isHelp) {
|
|
14
14
|
console.log(helpText);
|
|
15
15
|
process.exit(0);
|
|
@@ -30,6 +30,7 @@ const run = async () => {
|
|
|
30
30
|
isStrict,
|
|
31
31
|
isShowProgress,
|
|
32
32
|
isIncludeEntryExports,
|
|
33
|
+
isIncludeLibs,
|
|
33
34
|
isIsolateWorkspaces,
|
|
34
35
|
tags: tags.length > 0 ? splitTags(tags) : splitTags(experimentalTags),
|
|
35
36
|
isFix: isFix || fixTypes.length > 0,
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import micromatch from 'micromatch';
|
|
2
1
|
import { _getDependenciesFromScripts } from './binaries/index.js';
|
|
3
2
|
import { getCompilerExtensions, getIncludedCompilers } from './compilers/index.js';
|
|
4
3
|
import { ConfigurationChief } from './ConfigurationChief.js';
|
|
@@ -12,16 +11,15 @@ import { ProjectPrincipal } from './ProjectPrincipal.js';
|
|
|
12
11
|
import { debugLogObject, debugLogArray, debugLog, exportLookupLog } from './util/debug.js';
|
|
13
12
|
import { _glob, negate } from './util/glob.js';
|
|
14
13
|
import { getGitIgnoredFn } from './util/globby.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { _resolveSpecifier } from './util/require.js';
|
|
14
|
+
import { getHandler } from './util/handleReferencedDependency.js';
|
|
15
|
+
import { getEntryPathFromManifest, getPackageNameFromModuleSpecifier } from './util/modules.js';
|
|
16
|
+
import { dirname, join } from './util/path.js';
|
|
19
17
|
import { shouldIgnore } from './util/tag.js';
|
|
20
18
|
import { loadTSConfig } from './util/tsconfig-loader.js';
|
|
21
19
|
import { getType, getHasStrictlyNsReferences } from './util/type.js';
|
|
22
20
|
import { WorkspaceWorker } from './WorkspaceWorker.js';
|
|
23
21
|
export const main = async (unresolvedConfiguration) => {
|
|
24
|
-
const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIncludeEntryExports, isIsolateWorkspaces, tags, isFix, fixTypes, } = unresolvedConfiguration;
|
|
22
|
+
const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIncludeEntryExports, isIncludeLibs, isIsolateWorkspaces, tags, isFix, fixTypes, } = unresolvedConfiguration;
|
|
25
23
|
debugLogObject('*', 'Unresolved configuration (from CLI arguments)', unresolvedConfiguration);
|
|
26
24
|
const chief = new ConfigurationChief({ cwd, isProduction, isStrict, isIncludeEntryExports });
|
|
27
25
|
const deputy = new DependencyDeputy({ isProduction, isStrict });
|
|
@@ -40,54 +38,13 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
40
38
|
const isReportValues = report.exports || report.nsExports || report.classMembers;
|
|
41
39
|
const isReportTypes = report.types || report.nsTypes || report.enumMembers;
|
|
42
40
|
const isReportClassMembers = report.classMembers;
|
|
41
|
+
const isSkipLibs = !isIncludeLibs && !isReportClassMembers;
|
|
43
42
|
const collector = new IssueCollector({ cwd, rules, filters });
|
|
44
43
|
const enabledPluginsStore = new Map();
|
|
45
44
|
deputy.setIgnored(chief.config.ignoreBinaries, chief.config.ignoreDependencies);
|
|
46
45
|
const o = () => workspaces.map(w => ({ pkgName: w.pkgName, name: w.name, config: w.config, ancestors: w.ancestors }));
|
|
47
46
|
debugLogObject('*', 'Included workspaces', () => workspaces.map(w => w.pkgName));
|
|
48
47
|
debugLogObject('*', 'Included workspace configs', o);
|
|
49
|
-
const handleReferencedDependency = ({ specifier, containingFilePath, principal, workspace, }) => {
|
|
50
|
-
if (isInternal(specifier)) {
|
|
51
|
-
const filePath = principal.resolveModule(specifier, containingFilePath)?.resolvedFileName;
|
|
52
|
-
if (filePath) {
|
|
53
|
-
const ignorePatterns = workspace.config?.ignore.map(pattern => join(workspace.dir, pattern)) ?? [];
|
|
54
|
-
const isIgnored = micromatch.isMatch(filePath, ignorePatterns);
|
|
55
|
-
if (!isIgnored)
|
|
56
|
-
principal.addEntryPath(filePath);
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
collector.addIssue({ type: 'unresolved', filePath: containingFilePath, symbol: specifier });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
if (isBinary(specifier)) {
|
|
64
|
-
const binaryName = fromBinary(specifier);
|
|
65
|
-
const isHandled = deputy.maybeAddReferencedBinary(workspace, binaryName);
|
|
66
|
-
if (!isHandled)
|
|
67
|
-
collector.addIssue({ type: 'binaries', filePath: containingFilePath, symbol: binaryName });
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
const packageName = isInNodeModules(specifier)
|
|
71
|
-
? getPackageNameFromFilePath(specifier)
|
|
72
|
-
: getPackageNameFromModuleSpecifier(specifier);
|
|
73
|
-
const isHandled = packageName && deputy.maybeAddReferencedExternalDependency(workspace, packageName);
|
|
74
|
-
if (!isHandled)
|
|
75
|
-
collector.addIssue({ type: 'unlisted', filePath: containingFilePath, symbol: specifier });
|
|
76
|
-
if (packageName && specifier !== packageName) {
|
|
77
|
-
const otherWorkspace = chief.availableWorkspaceManifests.find(w => w.manifest.name === packageName);
|
|
78
|
-
if (otherWorkspace) {
|
|
79
|
-
const filePath = _resolveSpecifier(otherWorkspace.dir, normalizeSpecifierFromFilePath(specifier));
|
|
80
|
-
if (filePath) {
|
|
81
|
-
principal.addEntryPath(filePath, { skipExportsAnalysis: true });
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
collector.addIssue({ type: 'unresolved', filePath: containingFilePath, symbol: specifier });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
48
|
for (const workspace of workspaces) {
|
|
92
49
|
const { name, dir, ancestors, pkgName, manifestPath } = workspace;
|
|
93
50
|
streamer.cast(`Analyzing workspace ${name}...`);
|
|
@@ -112,7 +69,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
112
69
|
pkgName,
|
|
113
70
|
isGitIgnored,
|
|
114
71
|
isIsolateWorkspaces,
|
|
115
|
-
isSkipLibs
|
|
72
|
+
isSkipLibs,
|
|
116
73
|
});
|
|
117
74
|
const worker = new WorkspaceWorker({
|
|
118
75
|
name,
|
|
@@ -213,10 +170,11 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
213
170
|
const exportedClasses = new Set();
|
|
214
171
|
for (const principal of principals) {
|
|
215
172
|
principal.init();
|
|
173
|
+
const handleReferencedDependency = getHandler(collector, deputy, chief);
|
|
216
174
|
principal.referencedDependencies.forEach(([containingFilePath, specifier, workspaceName]) => {
|
|
217
175
|
const workspace = chief.findWorkspaceByName(workspaceName);
|
|
218
176
|
if (workspace)
|
|
219
|
-
handleReferencedDependency(
|
|
177
|
+
handleReferencedDependency(specifier, containingFilePath, workspace, principal);
|
|
220
178
|
});
|
|
221
179
|
const specifierFilePaths = new Set();
|
|
222
180
|
const analyzeSourceFile = (filePath, _principal = principal) => {
|
|
@@ -227,6 +185,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
227
185
|
isFixExports: fixer.isEnabled && fixer.isFixUnusedExports,
|
|
228
186
|
isFixTypes: fixer.isEnabled && fixer.isFixUnusedTypes,
|
|
229
187
|
ignoreExportsUsedInFile: Boolean(chief.config.ignoreExportsUsedInFile),
|
|
188
|
+
isReportClassMembers,
|
|
230
189
|
tags,
|
|
231
190
|
});
|
|
232
191
|
const { internal, external, unresolved } = imports;
|
|
@@ -287,7 +246,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
287
246
|
manifestScriptNames: new Set(),
|
|
288
247
|
dependencies: deputy.getDependencies(workspace.name),
|
|
289
248
|
}).forEach(specifier => {
|
|
290
|
-
handleReferencedDependency(
|
|
249
|
+
handleReferencedDependency(specifier, filePath, workspace, _principal);
|
|
291
250
|
});
|
|
292
251
|
}
|
|
293
252
|
};
|
|
@@ -467,6 +426,11 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
467
426
|
if (hasStrictlyNsReferences && ((!report.nsTypes && isType) || (!report.nsExports && !isType)))
|
|
468
427
|
continue;
|
|
469
428
|
if (!isExportedItemReferenced(exportedItem)) {
|
|
429
|
+
if (!isSkipLibs) {
|
|
430
|
+
const principal = factory.getPrincipalByPackageName(workspace.pkgName);
|
|
431
|
+
if (principal?.hasReferences(filePath, exportedItem))
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
470
434
|
const type = getType(hasStrictlyNsReferences, isType);
|
|
471
435
|
collector.addIssue({
|
|
472
436
|
type,
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { SymbolType } from '../../../types/issues.js';
|
|
|
3
3
|
import { compact } from '../../../util/array.js';
|
|
4
4
|
import { isGetOrSetAccessorDeclaration, isPrivateMember, stripQuotes } from '../../ast-helpers.js';
|
|
5
5
|
import { exportVisitor as visit } from '../index.js';
|
|
6
|
-
export default visit(() => true, (node, { isFixExports, isFixTypes }) => {
|
|
6
|
+
export default visit(() => true, (node, { isFixExports, isFixTypes, isReportClassMembers }) => {
|
|
7
7
|
const exportKeyword = node.modifiers?.find(mod => mod.kind === ts.SyntaxKind.ExportKeyword);
|
|
8
8
|
if (exportKeyword) {
|
|
9
9
|
if (ts.isVariableStatement(node)) {
|
|
@@ -67,18 +67,20 @@ export default visit(() => true, (node, { isFixExports, isFixTypes }) => {
|
|
|
67
67
|
if (ts.isClassDeclaration(node) && node.name) {
|
|
68
68
|
const identifier = defaultKeyword ? 'default' : node.name.getText();
|
|
69
69
|
const pos = (node.name ?? node).getStart();
|
|
70
|
-
const members =
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
const members = isReportClassMembers
|
|
71
|
+
? node.members
|
|
72
|
+
.filter((member) => (ts.isPropertyDeclaration(member) ||
|
|
73
|
+
ts.isMethodDeclaration(member) ||
|
|
74
|
+
isGetOrSetAccessorDeclaration(member)) &&
|
|
75
|
+
!isPrivateMember(member))
|
|
76
|
+
.map(member => ({
|
|
77
|
+
node: member,
|
|
78
|
+
identifier: member.name.getText(),
|
|
79
|
+
pos: member.name.getStart() + (ts.isComputedPropertyName(member.name) ? 1 : 0),
|
|
80
|
+
type: SymbolType.MEMBER,
|
|
81
|
+
fix: undefined,
|
|
82
|
+
}))
|
|
83
|
+
: [];
|
|
82
84
|
const fix = isFixExports
|
|
83
85
|
? [exportKeyword.getStart(), (defaultKeyword ?? exportKeyword).getEnd() + 1]
|
|
84
86
|
: undefined;
|
|
@@ -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 -W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)\n --directory [dir] Run process from a different directory (default: cwd)\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,binaries,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --fix Fix issues\n --fix-type Fix only issues of type, can be comma-separated or repeated (2)\n --include-entry-exports Include entry files when reporting unused exports\n --isolate-workspaces Isolate workspaces into separate programs (default: false)\n -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)\n --preprocessor Preprocess the results before providing it to the reporter(s), can be repeated\n --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)\n --reporter Select reporter: symbols, compact, codeowners, json, can be repeated (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --tags Include or exclude tagged exports\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 --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(2) Fixable issue types: dependencies, exports, types\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 --tags=-knipignore\n\nWebsite: https://knip.dev";
|
|
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 -W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)\n --directory [dir] Run process from a different directory (default: cwd)\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,binaries,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --files Shortcut for --include files\n --fix Fix issues\n --fix-type Fix only issues of type, can be comma-separated or repeated (2)\n --include-libs Include type definitions from dependencies (default: false; implied with classMembers)\n --include-entry-exports Include entry files when reporting unused exports\n --isolate-workspaces Isolate workspaces into separate programs (default: false)\n -n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)\n --preprocessor Preprocess the results before providing it to the reporter(s), can be repeated\n --preprocessor-options Pass extra options to the preprocessor (as JSON string, see --reporter-options example)\n --reporter Select reporter: symbols, compact, codeowners, json, can be repeated (default: symbols)\n --reporter-options Pass extra options to the reporter (as JSON string, see example)\n --tags Include or exclude tagged exports\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 --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(2) Fixable issue types: dependencies, exports, types\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 --tags=-knipignore\n\nWebsite: https://knip.dev";
|
|
2
2
|
declare const _default: {
|
|
3
3
|
config: string | undefined;
|
|
4
4
|
debug: boolean | undefined;
|
|
@@ -8,11 +8,13 @@ declare const _default: {
|
|
|
8
8
|
exports: boolean | undefined;
|
|
9
9
|
tags: string[] | undefined;
|
|
10
10
|
'experimental-tags': string[] | undefined;
|
|
11
|
+
files: boolean | undefined;
|
|
11
12
|
fix: boolean | undefined;
|
|
12
13
|
'fix-type': string[] | undefined;
|
|
13
14
|
help: boolean | undefined;
|
|
14
15
|
'ignore-internal': boolean | undefined;
|
|
15
16
|
include: string[] | undefined;
|
|
17
|
+
'include-libs': boolean | undefined;
|
|
16
18
|
'include-entry-exports': boolean | undefined;
|
|
17
19
|
'isolate-workspaces': boolean | undefined;
|
|
18
20
|
'max-issues': string | undefined;
|
|
@@ -15,8 +15,10 @@ Options:
|
|
|
15
15
|
--exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
|
|
16
16
|
--dependencies Shortcut for --include dependencies,unlisted,binaries,unresolved
|
|
17
17
|
--exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates
|
|
18
|
+
--files Shortcut for --include files
|
|
18
19
|
--fix Fix issues
|
|
19
20
|
--fix-type Fix only issues of type, can be comma-separated or repeated (2)
|
|
21
|
+
--include-libs Include type definitions from dependencies (default: false; implied with classMembers)
|
|
20
22
|
--include-entry-exports Include entry files when reporting unused exports
|
|
21
23
|
--isolate-workspaces Isolate workspaces into separate programs (default: false)
|
|
22
24
|
-n, --no-progress Don't show dynamic progress updates (automatically enabled in CI environments)
|
|
@@ -58,11 +60,13 @@ try {
|
|
|
58
60
|
exports: { type: 'boolean' },
|
|
59
61
|
tags: { type: 'string', multiple: true },
|
|
60
62
|
'experimental-tags': { type: 'string', multiple: true },
|
|
63
|
+
files: { type: 'boolean' },
|
|
61
64
|
fix: { type: 'boolean' },
|
|
62
65
|
'fix-type': { type: 'string', multiple: true },
|
|
63
66
|
help: { type: 'boolean', short: 'h' },
|
|
64
67
|
'ignore-internal': { type: 'boolean' },
|
|
65
68
|
include: { type: 'string', multiple: true },
|
|
69
|
+
'include-libs': { type: 'boolean' },
|
|
66
70
|
'include-entry-exports': { type: 'boolean' },
|
|
67
71
|
'isolate-workspaces': { type: 'boolean' },
|
|
68
72
|
'max-issues': { type: 'string' },
|
|
@@ -16,8 +16,10 @@ export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isP
|
|
|
16
16
|
incl = [...incl, 'dependencies', 'optionalPeerDependencies', 'unlisted', 'binaries', 'unresolved'];
|
|
17
17
|
}
|
|
18
18
|
if (cliArgs.exports) {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
incl = [...incl, 'exports', 'nsExports', 'classMembers', 'types', 'nsTypes', 'enumMembers', 'duplicates'];
|
|
20
|
+
}
|
|
21
|
+
if (cliArgs.files) {
|
|
22
|
+
incl = [...incl, 'files'];
|
|
21
23
|
}
|
|
22
24
|
const _include = [...incl, ...includes];
|
|
23
25
|
const _exclude = [...excl, ...excludes];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ProjectPrincipal } from '../ProjectPrincipal.js';
|
|
2
|
+
import type { ConfigurationChief, Workspace } from '../ConfigurationChief.js';
|
|
3
|
+
import type { DependencyDeputy } from '../DependencyDeputy.js';
|
|
4
|
+
import type { IssueCollector } from '../IssueCollector.js';
|
|
5
|
+
export declare const getHandler: (collector: IssueCollector, deputy: DependencyDeputy, chief: ConfigurationChief) => (specifier: string, containingFilePath: string, workspace: Workspace, principal: ProjectPrincipal) => void;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import micromatch from 'micromatch';
|
|
2
|
+
import { ProjectPrincipal } from '../ProjectPrincipal.js';
|
|
3
|
+
import { getPackageNameFromFilePath, getPackageNameFromModuleSpecifier, normalizeSpecifierFromFilePath, } from './modules.js';
|
|
4
|
+
import { isInNodeModules, join, isInternal } from './path.js';
|
|
5
|
+
import { fromBinary, isBinary } from './protocols.js';
|
|
6
|
+
import { _resolveSpecifier } from './require.js';
|
|
7
|
+
export const getHandler = (collector, deputy, chief) => (specifier, containingFilePath, workspace, principal) => {
|
|
8
|
+
if (isInternal(specifier)) {
|
|
9
|
+
const filePath = principal.resolveModule(specifier, containingFilePath)?.resolvedFileName;
|
|
10
|
+
if (filePath) {
|
|
11
|
+
const ignorePatterns = workspace.config?.ignore.map(pattern => join(workspace.dir, pattern)) ?? [];
|
|
12
|
+
const isIgnored = micromatch.isMatch(filePath, ignorePatterns);
|
|
13
|
+
if (!isIgnored)
|
|
14
|
+
principal.addEntryPath(filePath);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
collector.addIssue({ type: 'unresolved', filePath: containingFilePath, symbol: specifier });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
if (isBinary(specifier)) {
|
|
22
|
+
const binaryName = fromBinary(specifier);
|
|
23
|
+
const isHandled = deputy.maybeAddReferencedBinary(workspace, binaryName);
|
|
24
|
+
if (!isHandled)
|
|
25
|
+
collector.addIssue({ type: 'binaries', filePath: containingFilePath, symbol: binaryName });
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const packageName = isInNodeModules(specifier)
|
|
29
|
+
? getPackageNameFromFilePath(specifier)
|
|
30
|
+
: getPackageNameFromModuleSpecifier(specifier);
|
|
31
|
+
const isHandled = packageName && deputy.maybeAddReferencedExternalDependency(workspace, packageName);
|
|
32
|
+
if (!isHandled)
|
|
33
|
+
collector.addIssue({ type: 'unlisted', filePath: containingFilePath, symbol: specifier });
|
|
34
|
+
if (packageName && specifier !== packageName) {
|
|
35
|
+
const otherWorkspace = chief.availableWorkspaceManifests.find(w => w.manifest.name === packageName);
|
|
36
|
+
if (otherWorkspace) {
|
|
37
|
+
const filePath = _resolveSpecifier(otherWorkspace.dir, normalizeSpecifierFromFilePath(specifier));
|
|
38
|
+
if (filePath) {
|
|
39
|
+
principal.addEntryPath(filePath, { skipExportsAnalysis: true });
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
collector.addIssue({ type: 'unresolved', filePath: containingFilePath, symbol: specifier });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "5.
|
|
1
|
+
export declare const version = "5.3.1";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '5.
|
|
1
|
+
export const version = '5.3.1';
|