knip 1.0.0-beta.3 → 1.0.0-beta.4
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 +3 -1
- package/dist/cli.js +2 -1
- package/dist/configuration-chief.js +12 -7
- package/dist/configuration-validator.d.ts +2 -2
- package/dist/index.js +7 -3
- package/dist/source-lab.js +6 -12
- package/dist/types/cli.d.ts +1 -0
- package/dist/util/glob.d.ts +1 -0
- package/dist/util/glob.js +1 -1
- package/dist/util/help.js +1 -0
- package/dist/util/members.d.ts +2 -3
- package/dist/util/members.js +8 -4
- package/dist/util/modules.js +2 -1
- package/dist/util/parseArgs.d.ts +1 -1
- package/dist/util/parseArgs.js +1 -1
- package/dist/util/path.js +2 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -57,7 +57,9 @@ Knip supports LTS versions of Node.js, and currently requires at least Node.js v
|
|
|
57
57
|
|
|
58
58
|
## Usage
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Knip has good defaults and you can run it without any configuration, but especially larger projects get more out of Knip
|
|
61
|
+
with a configuration file (or a `knip` property in `package.json`). Let's name this file `knip.json` with these contents
|
|
62
|
+
(you might want to adjust right away for your project):
|
|
61
63
|
|
|
62
64
|
```json
|
|
63
65
|
{
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import parsedArgs from './util/parseArgs.js';
|
|
|
8
8
|
import { measure } from './util/performance.js';
|
|
9
9
|
import { main } from './index.js';
|
|
10
10
|
register();
|
|
11
|
-
const { values: { debug: isDebug = false, help, 'max-issues': maxIssues = '0', 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': noProgress = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, }, } = parsedArgs;
|
|
11
|
+
const { values: { debug: isDebug = false, help, 'ignore-entry-exports': isIgnoreEntryExports = false, 'max-issues': maxIssues = '0', 'no-exit-code': noExitCode = false, 'no-gitignore': isNoGitIgnore = false, 'no-progress': noProgress = false, production: isProduction = false, reporter = 'symbols', 'reporter-options': reporterOptions = '', strict: isStrict = false, tsConfig, }, } = parsedArgs;
|
|
12
12
|
if (help) {
|
|
13
13
|
printHelp();
|
|
14
14
|
process.exit(0);
|
|
@@ -25,6 +25,7 @@ const run = async () => {
|
|
|
25
25
|
isStrict,
|
|
26
26
|
isProduction,
|
|
27
27
|
isShowProgress,
|
|
28
|
+
isIgnoreEntryExports,
|
|
28
29
|
});
|
|
29
30
|
await printReport({ report, issues, cwd, isProduction, options: reporterOptions });
|
|
30
31
|
const totalErrorCount = Object.keys(report)
|
|
@@ -7,6 +7,7 @@ import * as plugins from './plugins/index.js';
|
|
|
7
7
|
import { arrayify } from './util/array.js';
|
|
8
8
|
import { ConfigurationError } from './util/errors.js';
|
|
9
9
|
import { findFile, loadJSON } from './util/fs.js';
|
|
10
|
+
import { ensurePosixPath } from './util/glob.js';
|
|
10
11
|
import parsedArgs from './util/parseArgs.js';
|
|
11
12
|
import { resolveIncludedIssueTypes } from './util/resolve-included-issue-types.js';
|
|
12
13
|
import { byPathDepth } from './util/workspace.js';
|
|
@@ -84,13 +85,14 @@ export default class ConfigurationChief {
|
|
|
84
85
|
.reduce((workspaces, workspace) => {
|
|
85
86
|
const [workspaceName, workspaceConfig] = workspace;
|
|
86
87
|
const entry = workspaceConfig.entry ? arrayify(workspaceConfig.entry) : defaultWorkspaceConfig.entry;
|
|
88
|
+
const project = workspaceConfig.project
|
|
89
|
+
? arrayify(workspaceConfig.project)
|
|
90
|
+
: workspaceConfig.entry
|
|
91
|
+
? entry
|
|
92
|
+
: defaultWorkspaceConfig.project;
|
|
87
93
|
workspaces[workspaceName] = {
|
|
88
94
|
entry,
|
|
89
|
-
project
|
|
90
|
-
? arrayify(workspaceConfig.project)
|
|
91
|
-
: workspaceConfig.entry
|
|
92
|
-
? entry
|
|
93
|
-
: defaultWorkspaceConfig.project,
|
|
95
|
+
project,
|
|
94
96
|
ignore: arrayify(workspaceConfig.ignore),
|
|
95
97
|
};
|
|
96
98
|
for (const [pluginName, pluginConfig] of Object.entries(workspaceConfig)) {
|
|
@@ -125,7 +127,9 @@ export default class ConfigurationChief {
|
|
|
125
127
|
ignore: this.config.ignoreWorkspaces,
|
|
126
128
|
absolute: false,
|
|
127
129
|
});
|
|
128
|
-
this.manifestWorkspaces = Array.from(workspaces.values())
|
|
130
|
+
this.manifestWorkspaces = Array.from(workspaces.values())
|
|
131
|
+
.map(dir => path.relative(this.cwd, dir))
|
|
132
|
+
.map(ensurePosixPath);
|
|
129
133
|
return this.manifestWorkspaces;
|
|
130
134
|
}
|
|
131
135
|
return [];
|
|
@@ -185,8 +189,9 @@ export default class ConfigurationChief {
|
|
|
185
189
|
}
|
|
186
190
|
async getNegatedWorkspacePatterns(name) {
|
|
187
191
|
const descendentWorkspaces = await this.getDescendentWorkspaces(name);
|
|
192
|
+
const matchName = new RegExp(`^${name}/`);
|
|
188
193
|
return descendentWorkspaces
|
|
189
|
-
.map(workspaceName =>
|
|
194
|
+
.map(workspaceName => workspaceName.replace(matchName, ''))
|
|
190
195
|
.map(workspaceName => `!${workspaceName}`);
|
|
191
196
|
}
|
|
192
197
|
getConfigKeyForWorkspace(workspaceName) {
|
|
@@ -856,10 +856,10 @@ export declare const ConfigurationValidator: z.ZodObject<z.extendShape<z.extendS
|
|
|
856
856
|
}>, "strip", z.ZodTypeAny, {
|
|
857
857
|
exclude?: string[] | undefined;
|
|
858
858
|
ignore?: string | string[] | undefined;
|
|
859
|
-
ignoreBinaries?: string[] | undefined;
|
|
860
859
|
include?: string[] | undefined;
|
|
861
860
|
entry?: string | string[] | undefined;
|
|
862
861
|
project?: string | string[] | undefined;
|
|
862
|
+
ignoreBinaries?: string[] | undefined;
|
|
863
863
|
ignoreDependencies?: string[] | undefined;
|
|
864
864
|
ignoreWorkspaces?: string[] | undefined;
|
|
865
865
|
babel?: string | false | string[] | {
|
|
@@ -1100,10 +1100,10 @@ export declare const ConfigurationValidator: z.ZodObject<z.extendShape<z.extendS
|
|
|
1100
1100
|
}, {
|
|
1101
1101
|
exclude?: string[] | undefined;
|
|
1102
1102
|
ignore?: string | string[] | undefined;
|
|
1103
|
-
ignoreBinaries?: string[] | undefined;
|
|
1104
1103
|
include?: string[] | undefined;
|
|
1105
1104
|
entry?: string | string[] | undefined;
|
|
1106
1105
|
project?: string | string[] | undefined;
|
|
1106
|
+
ignoreBinaries?: string[] | undefined;
|
|
1107
1107
|
ignoreDependencies?: string[] | undefined;
|
|
1108
1108
|
ignoreWorkspaces?: string[] | undefined;
|
|
1109
1109
|
babel?: string | false | string[] | {
|
package/dist/index.js
CHANGED
|
@@ -9,14 +9,14 @@ import { compact } from './util/array.js';
|
|
|
9
9
|
import { debugLogObject, debugLogFiles } from './util/debug.js';
|
|
10
10
|
import { _findImportModuleSpecifiers } from './util/find-import-specifiers.js';
|
|
11
11
|
import { findFile, loadJSON } from './util/fs.js';
|
|
12
|
-
import { _glob } from './util/glob.js';
|
|
12
|
+
import { _glob, ensurePosixPath } from './util/glob.js';
|
|
13
13
|
import { getPackageNameFromModuleSpecifier } from './util/modules.js';
|
|
14
14
|
import { _findDuplicateExportedNames } from './util/project.js';
|
|
15
15
|
import { loadTSConfig } from './util/tsconfig-loader.js';
|
|
16
16
|
import { byPathDepth } from './util/workspace.js';
|
|
17
17
|
import WorkspaceWorker from './workspace-worker.js';
|
|
18
18
|
export const main = async (unresolvedConfiguration) => {
|
|
19
|
-
const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress } = unresolvedConfiguration;
|
|
19
|
+
const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress, isIgnoreEntryExports } = unresolvedConfiguration;
|
|
20
20
|
const chief = new ConfigurationChief({ cwd, isStrict, isProduction });
|
|
21
21
|
debugLogObject('Unresolved configuration', unresolvedConfiguration);
|
|
22
22
|
const collector = new IssueCollector({ cwd, isShowProgress });
|
|
@@ -81,6 +81,8 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
81
81
|
});
|
|
82
82
|
debugLogFiles(`Globbed entry paths${suffix}`, workspaceEntryPaths);
|
|
83
83
|
workspaceEntryPaths.forEach(entryPath => principal.addEntryPath(entryPath));
|
|
84
|
+
if (isIgnoreEntryExports)
|
|
85
|
+
workspaceEntryPaths.forEach(entryPath => lab.skipExportsAnalysisFor(entryPath));
|
|
84
86
|
collector.updateMessage(`Resolving production plugin entry files${suffix}...`);
|
|
85
87
|
const pluginWorkspaceEntryPaths = await _glob({
|
|
86
88
|
cwd,
|
|
@@ -120,6 +122,8 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
120
122
|
});
|
|
121
123
|
debugLogFiles(`Globbed entry paths${suffix}`, workspaceEntryPaths);
|
|
122
124
|
workspaceEntryPaths.forEach(entryPath => principal.addEntryPath(entryPath));
|
|
125
|
+
if (isIgnoreEntryExports)
|
|
126
|
+
workspaceEntryPaths.forEach(entryPath => lab.skipExportsAnalysisFor(entryPath));
|
|
123
127
|
}
|
|
124
128
|
{
|
|
125
129
|
collector.updateMessage(`Resolving project files${suffix}...`);
|
|
@@ -232,7 +236,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
232
236
|
const filePath = sourceFile.getFilePath();
|
|
233
237
|
if (report.dependencies || report.unlisted) {
|
|
234
238
|
const filePath = sourceFile.getFilePath();
|
|
235
|
-
const workspaceDir = workspaceDirs.find(workspaceDir => filePath.startsWith(workspaceDir));
|
|
239
|
+
const workspaceDir = workspaceDirs.find(workspaceDir => filePath.startsWith(ensurePosixPath(workspaceDir)));
|
|
236
240
|
const workspace = workspaces.find(workspace => workspace.dir === workspaceDir);
|
|
237
241
|
if (workspace) {
|
|
238
242
|
const [, externalModuleSpecifiers] = moduleSpecifierCache.get(sourceFile) ?? _findImportModuleSpecifiers(sourceFile, { skipInternal: true });
|
package/dist/source-lab.js
CHANGED
|
@@ -52,23 +52,17 @@ export default class SourceLab {
|
|
|
52
52
|
if (declaration.isKind(ts.SyntaxKind.EnumDeclaration)) {
|
|
53
53
|
identifier = declaration.getFirstChildByKind(ts.SyntaxKind.Identifier);
|
|
54
54
|
if (report.enumMembers) {
|
|
55
|
-
findUnusedEnumMembers(declaration, filePath).forEach(
|
|
56
|
-
type: 'enumMembers',
|
|
57
|
-
|
|
58
|
-
symbol: member.getName().replace(/['"`]/g, ''),
|
|
59
|
-
parentSymbol: identifier?.getText(),
|
|
60
|
-
}));
|
|
55
|
+
findUnusedEnumMembers(declaration, filePath).forEach(symbol => {
|
|
56
|
+
issues.add({ type: 'enumMembers', filePath, symbol, parentSymbol: identifier?.getText() });
|
|
57
|
+
});
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
else if (declaration.isKind(ts.SyntaxKind.ClassDeclaration)) {
|
|
64
61
|
identifier = declaration.getFirstChildByKind(ts.SyntaxKind.Identifier);
|
|
65
62
|
if (report.classMembers) {
|
|
66
|
-
findUnusedClassMembers(declaration, filePath).forEach(
|
|
67
|
-
type: 'classMembers',
|
|
68
|
-
|
|
69
|
-
symbol: member.getName(),
|
|
70
|
-
parentSymbol: identifier?.getText(),
|
|
71
|
-
}));
|
|
63
|
+
findUnusedClassMembers(declaration, filePath).forEach(symbol => {
|
|
64
|
+
issues.add({ type: 'classMembers', filePath, symbol, parentSymbol: identifier?.getText() });
|
|
65
|
+
});
|
|
72
66
|
}
|
|
73
67
|
}
|
|
74
68
|
if (Node.isExportGetable(declaration) &&
|
package/dist/types/cli.d.ts
CHANGED
package/dist/util/glob.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
/// <reference types="nano-memoize" />
|
|
3
|
+
export declare const ensurePosixPath: (value: string) => string;
|
|
3
4
|
export declare const negate: (pattern: string) => string;
|
|
4
5
|
export declare const hasProductionSuffix: (pattern: string) => boolean;
|
|
5
6
|
export declare const hasNoProductionSuffix: (pattern: string) => boolean;
|
package/dist/util/glob.js
CHANGED
|
@@ -5,7 +5,7 @@ import memoize from 'nano-memoize';
|
|
|
5
5
|
import { compact } from './array.js';
|
|
6
6
|
import { debugLogObject } from './debug.js';
|
|
7
7
|
import { timerify } from './performance.js';
|
|
8
|
-
const ensurePosixPath = (value) => value.split(path.sep).join(path.posix.sep);
|
|
8
|
+
export const ensurePosixPath = (value) => value.split(path.sep).join(path.posix.sep);
|
|
9
9
|
const prependDirToPattern = (workingDir, pattern) => {
|
|
10
10
|
if (pattern.startsWith('!'))
|
|
11
11
|
return '!' + path.posix.join(workingDir, pattern.slice(1));
|
package/dist/util/help.js
CHANGED
|
@@ -10,6 +10,7 @@ Options:
|
|
|
10
10
|
--include Report only listed issue type(s), can be comma-separated or repeated
|
|
11
11
|
--exclude Exclude issue type(s) from report, can be comma-separated or repeated
|
|
12
12
|
--ignore Ignore files matching this glob pattern, can be repeated
|
|
13
|
+
--ignore-entry-exports Ignore exports from entry files
|
|
13
14
|
--no-gitignore Don't use .gitignore
|
|
14
15
|
--no-progress Don't show dynamic progress updates
|
|
15
16
|
--no-exit-code Always exit with code zero (0)
|
package/dist/util/members.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { MethodDeclaration, PropertyDeclaration } from 'ts-morph';
|
|
2
1
|
import type { ClassDeclaration, EnumDeclaration } from 'ts-morph';
|
|
3
|
-
export declare const findUnusedClassMembers: (declaration: ClassDeclaration, filePath: string) =>
|
|
4
|
-
export declare const findUnusedEnumMembers: (declaration: EnumDeclaration, filePath: string) =>
|
|
2
|
+
export declare const findUnusedClassMembers: (declaration: ClassDeclaration, filePath: string) => string[];
|
|
3
|
+
export declare const findUnusedEnumMembers: (declaration: EnumDeclaration, filePath: string) => string[];
|
package/dist/util/members.js
CHANGED
|
@@ -2,7 +2,8 @@ import { ts } from 'ts-morph';
|
|
|
2
2
|
import { _findReferences, hasExternalReferences, hasInternalReferences } from './project.js';
|
|
3
3
|
export const findUnusedClassMembers = (declaration, filePath) => {
|
|
4
4
|
const members = declaration.getMembers();
|
|
5
|
-
return members
|
|
5
|
+
return members
|
|
6
|
+
.filter((member) => {
|
|
6
7
|
const isPrivate = Boolean(member.getCombinedModifierFlags() & ts.ModifierFlags.Private);
|
|
7
8
|
if (!isPrivate &&
|
|
8
9
|
(member.isKind(ts.SyntaxKind.PropertyDeclaration) || member.isKind(ts.SyntaxKind.MethodDeclaration))) {
|
|
@@ -10,12 +11,15 @@ export const findUnusedClassMembers = (declaration, filePath) => {
|
|
|
10
11
|
return !hasExternalReferences(refs, filePath) && !hasInternalReferences(refs);
|
|
11
12
|
}
|
|
12
13
|
return false;
|
|
13
|
-
})
|
|
14
|
+
})
|
|
15
|
+
.map(member => member.getName());
|
|
14
16
|
};
|
|
15
17
|
export const findUnusedEnumMembers = (declaration, filePath) => {
|
|
16
18
|
const members = declaration.getMembers();
|
|
17
|
-
return members
|
|
19
|
+
return members
|
|
20
|
+
.filter(member => {
|
|
18
21
|
const refs = _findReferences(member);
|
|
19
22
|
return !hasExternalReferences(refs, filePath) && !hasInternalReferences(refs);
|
|
20
|
-
})
|
|
23
|
+
})
|
|
24
|
+
.map(member => member.getName().replace(/['"`]/g, ''));
|
|
21
25
|
};
|
package/dist/util/modules.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { ensurePosixPath } from './glob.js';
|
|
1
2
|
export const getPackageNameFromModuleSpecifier = (moduleSpecifier) => {
|
|
2
3
|
const parts = moduleSpecifier.split('/').slice(0, 2);
|
|
3
4
|
return moduleSpecifier.startsWith('@') ? parts.join('/') : parts[0];
|
|
4
5
|
};
|
|
5
6
|
export const getPackageName = (value) => {
|
|
6
|
-
const match = value
|
|
7
|
+
const match = ensurePosixPath(value).match(/(?<=node_modules\/)(@[^/]+\/[^/]+|[^/]+)/);
|
|
7
8
|
if (match)
|
|
8
9
|
return match[1];
|
|
9
10
|
if (value.startsWith('@')) {
|
package/dist/util/parseArgs.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ declare const _default: {
|
|
|
6
6
|
exclude: string[] | undefined;
|
|
7
7
|
help: boolean | undefined;
|
|
8
8
|
ignore: string[] | undefined;
|
|
9
|
-
|
|
9
|
+
'ignore-entry-exports': boolean | undefined;
|
|
10
10
|
include: string[] | undefined;
|
|
11
11
|
'max-issues': string | undefined;
|
|
12
12
|
'no-exit-code': boolean | undefined;
|
package/dist/util/parseArgs.js
CHANGED
|
@@ -7,7 +7,7 @@ export default parseArgs({
|
|
|
7
7
|
exclude: { type: 'string', multiple: true },
|
|
8
8
|
help: { type: 'boolean', short: 'h' },
|
|
9
9
|
ignore: { type: 'string', multiple: true },
|
|
10
|
-
|
|
10
|
+
'ignore-entry-exports': { type: 'boolean' },
|
|
11
11
|
include: { type: 'string', multiple: true },
|
|
12
12
|
'max-issues': { type: 'string' },
|
|
13
13
|
'no-exit-code': { type: 'boolean' },
|
package/dist/util/path.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knip",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.4",
|
|
4
4
|
"description": "Find unused files, dependencies and exports in your TypeScript and JavaScript project",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"find",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@snyk/github-codeowners": "1.1.0",
|
|
62
62
|
"chalk": "5.2.0",
|
|
63
63
|
"easy-table": "1.2.0",
|
|
64
|
-
"esbuild": "0.16.
|
|
64
|
+
"esbuild": "0.16.12",
|
|
65
65
|
"esbuild-register": "3.4.2",
|
|
66
66
|
"eslint": "8.30.0",
|
|
67
67
|
"fast-glob": "3.2.12",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"eslint-import-resolver-typescript": "3.5.2",
|
|
92
92
|
"eslint-plugin-import": "2.26.0",
|
|
93
93
|
"globstar": "1.0.0",
|
|
94
|
-
"release-it": "15.
|
|
94
|
+
"release-it": "15.6.0",
|
|
95
95
|
"remark-cli": "11.0.0",
|
|
96
96
|
"remark-preset-webpro": "0.0.1",
|
|
97
97
|
"tsx": "3.12.1",
|