knip 2.21.2 → 2.22.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.
- package/README.md +1 -1
- package/dist/DependencyDeputy.d.ts +4 -0
- package/dist/DependencyDeputy.js +30 -3
- package/dist/ProjectPrincipal.d.ts +0 -2
- package/dist/ProjectPrincipal.js +2 -9
- package/dist/binaries/bash-parser.js +4 -2
- package/dist/binaries/resolvers/pnpm.js +1 -1
- package/dist/constants.js +2 -0
- package/dist/index.js +8 -6
- package/dist/plugins/eslint/helpers.js +1 -1
- package/dist/plugins/husky/index.js +3 -8
- package/dist/plugins/lefthook/index.js +17 -10
- package/dist/reporters/json.js +1 -0
- package/dist/types/exports.d.ts +2 -1
- package/dist/types/issues.d.ts +1 -0
- package/dist/types/workspace.d.ts +1 -0
- package/dist/typescript/ast-helpers.d.ts +1 -0
- package/dist/typescript/ast-helpers.js +1 -0
- package/dist/typescript/getImportsAndExports.js +13 -8
- package/dist/util/cli-arguments.d.ts +1 -1
- package/dist/util/cli-arguments.js +2 -2
- package/dist/util/get-included-issue-types.js +10 -3
- package/dist/util/git.d.ts +1 -0
- package/dist/util/git.js +20 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/dist/plugins/husky/helpers.d.ts +0 -1
- package/dist/plugins/husky/helpers.js +0 -9
package/README.md
CHANGED
|
@@ -640,7 +640,7 @@ for false positives, and how to handle them.
|
|
|
640
640
|
--production Analyze only production source files (e.g. no tests, devDependencies, exported types)
|
|
641
641
|
--strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)
|
|
642
642
|
--ignore-internal Ignore exports with tag @internal (JSDoc/TSDoc)
|
|
643
|
-
--workspace [dir]
|
|
643
|
+
-W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)
|
|
644
644
|
--no-gitignore Don't use .gitignore
|
|
645
645
|
--include Report only provided issue type(s), can be comma-separated or repeated (1)
|
|
646
646
|
--exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
|
|
@@ -32,6 +32,7 @@ export declare class DependencyDeputy {
|
|
|
32
32
|
scripts: string[];
|
|
33
33
|
dependencies: string[];
|
|
34
34
|
peerDependencies: string[];
|
|
35
|
+
optionalPeerDependencies: string[];
|
|
35
36
|
optionalDependencies: string[];
|
|
36
37
|
devDependencies: string[];
|
|
37
38
|
allDependencies: string[];
|
|
@@ -46,12 +47,15 @@ export declare class DependencyDeputy {
|
|
|
46
47
|
addReferencedBinary(workspaceName: string, binaryName: string): void;
|
|
47
48
|
addPeerDependencies(workspaceName: string, peerDependencies: Map<string, Set<string>>): void;
|
|
48
49
|
getPeerDependenciesOf(workspaceName: string, dependency: string): string[];
|
|
50
|
+
getPeerDependencies(workspaceName: string): string[];
|
|
51
|
+
getOptionalPeerDependencies(workspaceName: string): string[];
|
|
49
52
|
maybeAddReferencedExternalDependency(workspace: Workspace, packageName: string): boolean;
|
|
50
53
|
maybeAddReferencedBinary(workspace: Workspace, binaryName: string): boolean;
|
|
51
54
|
private isInDependencies;
|
|
52
55
|
settleDependencyIssues(): {
|
|
53
56
|
dependencyIssues: Issue[];
|
|
54
57
|
devDependencyIssues: Issue[];
|
|
58
|
+
optionalPeerDependencyIssues: Issue[];
|
|
55
59
|
};
|
|
56
60
|
getConfigurationHints(): {
|
|
57
61
|
configurationHints: ConfigurationHints;
|
package/dist/DependencyDeputy.js
CHANGED
|
@@ -22,6 +22,11 @@ export class DependencyDeputy {
|
|
|
22
22
|
const dependencies = Object.keys(manifest.dependencies ?? {});
|
|
23
23
|
const peerDependencies = Object.keys(manifest.peerDependencies ?? {});
|
|
24
24
|
const optionalDependencies = Object.keys(manifest.optionalDependencies ?? {});
|
|
25
|
+
const optionalPeerDependencies = manifest.peerDependenciesMeta
|
|
26
|
+
? peerDependencies.filter(peerDependency => manifest.peerDependenciesMeta &&
|
|
27
|
+
peerDependency in manifest.peerDependenciesMeta &&
|
|
28
|
+
manifest.peerDependenciesMeta[peerDependency].optional)
|
|
29
|
+
: [];
|
|
25
30
|
const devDependencies = Object.keys(manifest.devDependencies ?? {});
|
|
26
31
|
const allDependencies = [...dependencies, ...devDependencies, ...peerDependencies, ...optionalDependencies];
|
|
27
32
|
this._manifests.set(name, {
|
|
@@ -32,6 +37,7 @@ export class DependencyDeputy {
|
|
|
32
37
|
scripts,
|
|
33
38
|
dependencies,
|
|
34
39
|
peerDependencies,
|
|
40
|
+
optionalPeerDependencies,
|
|
35
41
|
optionalDependencies,
|
|
36
42
|
devDependencies,
|
|
37
43
|
allDependencies,
|
|
@@ -79,6 +85,18 @@ export class DependencyDeputy {
|
|
|
79
85
|
getPeerDependenciesOf(workspaceName, dependency) {
|
|
80
86
|
return Array.from(this.peerDependencies.get(workspaceName)?.get(dependency) ?? []);
|
|
81
87
|
}
|
|
88
|
+
getPeerDependencies(workspaceName) {
|
|
89
|
+
const manifest = this._manifests.get(workspaceName);
|
|
90
|
+
if (!manifest)
|
|
91
|
+
return [];
|
|
92
|
+
return manifest.peerDependencies;
|
|
93
|
+
}
|
|
94
|
+
getOptionalPeerDependencies(workspaceName) {
|
|
95
|
+
const manifest = this._manifests.get(workspaceName);
|
|
96
|
+
if (!manifest)
|
|
97
|
+
return [];
|
|
98
|
+
return manifest.optionalPeerDependencies;
|
|
99
|
+
}
|
|
82
100
|
maybeAddReferencedExternalDependency(workspace, packageName) {
|
|
83
101
|
if (isBuiltin(packageName))
|
|
84
102
|
return true;
|
|
@@ -133,6 +151,7 @@ export class DependencyDeputy {
|
|
|
133
151
|
settleDependencyIssues() {
|
|
134
152
|
const dependencyIssues = [];
|
|
135
153
|
const devDependencyIssues = [];
|
|
154
|
+
const optionalPeerDependencyIssues = [];
|
|
136
155
|
for (const [workspaceName, { manifestPath, ignoreDependencies, ignoreBinaries }] of this._manifests.entries()) {
|
|
137
156
|
const referencedDependencies = this.referencedDependencies.get(workspaceName);
|
|
138
157
|
const installedBinaries = this.getInstalledBinaries(workspaceName);
|
|
@@ -175,6 +194,7 @@ export class DependencyDeputy {
|
|
|
175
194
|
const isNotReferencedDependency = (dependency) => !isReferencedDependency(dependency);
|
|
176
195
|
const pd = this.getProductionDependencies(workspaceName);
|
|
177
196
|
const dd = this.getDevDependencies(workspaceName);
|
|
197
|
+
const od = this.getOptionalPeerDependencies(workspaceName);
|
|
178
198
|
pd.filter(isNotIgnoredDependency)
|
|
179
199
|
.filter(isNotIgnoredBinary)
|
|
180
200
|
.filter(isNotReferencedDependency)
|
|
@@ -183,8 +203,12 @@ export class DependencyDeputy {
|
|
|
183
203
|
.filter(isNotIgnoredBinary)
|
|
184
204
|
.filter(isNotReferencedDependency)
|
|
185
205
|
.forEach(symbol => devDependencyIssues.push({ type: 'devDependencies', filePath: manifestPath, symbol }));
|
|
206
|
+
od.filter(isNotIgnoredDependency)
|
|
207
|
+
.filter(isNotIgnoredBinary)
|
|
208
|
+
.filter(p => isReferencedDependency(p))
|
|
209
|
+
.forEach(symbol => optionalPeerDependencyIssues.push({ type: 'optionalPeerDependencies', filePath: manifestPath, symbol }));
|
|
186
210
|
}
|
|
187
|
-
return { dependencyIssues, devDependencyIssues };
|
|
211
|
+
return { dependencyIssues, devDependencyIssues, optionalPeerDependencyIssues };
|
|
188
212
|
}
|
|
189
213
|
getConfigurationHints() {
|
|
190
214
|
const configurationHints = new Set();
|
|
@@ -199,12 +223,13 @@ export class DependencyDeputy {
|
|
|
199
223
|
const dependencies = this.isStrict
|
|
200
224
|
? this.getProductionDependencies(workspaceName)
|
|
201
225
|
: [...this.getProductionDependencies(workspaceName), ...this.getDevDependencies(workspaceName)];
|
|
226
|
+
const peerDependencies = this.getPeerDependencies(workspaceName);
|
|
202
227
|
const isReferencedDep = (name) => referencedDependencies?.has(name) && dependencies.includes(name);
|
|
203
228
|
const isReferencedBin = (name) => referencedBinaries?.has(name) && installedBinaries?.has(name);
|
|
204
229
|
ignoreDependencies
|
|
205
230
|
.filter(packageName => IGNORED_DEPENDENCIES.includes(packageName) ||
|
|
206
231
|
(workspaceName !== ROOT_WORKSPACE_NAME && this.ignoreDependencies.includes(packageName)) ||
|
|
207
|
-
isReferencedDep(packageName))
|
|
232
|
+
(!peerDependencies.includes(packageName) && isReferencedDep(packageName)))
|
|
208
233
|
.forEach(identifier => configurationHints.add({ workspaceName, identifier, type: 'ignoreDependencies' }));
|
|
209
234
|
ignoreBinaries
|
|
210
235
|
.filter(binaryName => IGNORED_GLOBAL_BINARIES.includes(binaryName) ||
|
|
@@ -216,11 +241,13 @@ export class DependencyDeputy {
|
|
|
216
241
|
const dependencies = this.isStrict
|
|
217
242
|
? this.getProductionDependencies(ROOT_WORKSPACE_NAME)
|
|
218
243
|
: [...this.getProductionDependencies(ROOT_WORKSPACE_NAME), ...this.getDevDependencies(ROOT_WORKSPACE_NAME)];
|
|
244
|
+
const peerDependencies = this.getPeerDependencies(ROOT_WORKSPACE_NAME);
|
|
219
245
|
Object.keys(rootIgnoreBinaries)
|
|
220
246
|
.filter(key => IGNORED_GLOBAL_BINARIES.includes(key) || (rootIgnoreBinaries[key] !== 0 && installedBinaries?.has(key)))
|
|
221
247
|
.forEach(identifier => configurationHints.add({ workspaceName: ROOT_WORKSPACE_NAME, identifier, type: 'ignoreBinaries' }));
|
|
222
248
|
Object.keys(rootIgnoreDependencies)
|
|
223
|
-
.filter(key => IGNORED_DEPENDENCIES.includes(key) ||
|
|
249
|
+
.filter(key => IGNORED_DEPENDENCIES.includes(key) ||
|
|
250
|
+
(rootIgnoreDependencies[key] !== 0 && !peerDependencies.includes(key) && dependencies.includes(key)))
|
|
224
251
|
.forEach(identifier => configurationHints.add({ workspaceName: ROOT_WORKSPACE_NAME, identifier, type: 'ignoreDependencies' }));
|
|
225
252
|
return { configurationHints };
|
|
226
253
|
}
|
|
@@ -60,7 +60,5 @@ export declare class ProjectPrincipal {
|
|
|
60
60
|
};
|
|
61
61
|
findUnusedMembers(filePath: string, members: ExportItemMember[]): string[];
|
|
62
62
|
private findReferences;
|
|
63
|
-
isPublicExport(exportedItem: ExportItem): boolean;
|
|
64
|
-
getJSDocTags(exportedItem: ExportItem): string[];
|
|
65
63
|
}
|
|
66
64
|
export {};
|
package/dist/ProjectPrincipal.js
CHANGED
|
@@ -2,7 +2,7 @@ import { isGitIgnoredSync } from 'globby';
|
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
import { DEFAULT_EXTENSIONS } from './constants.js';
|
|
4
4
|
import { IGNORED_FILE_EXTENSIONS } from './constants.js';
|
|
5
|
-
import { isInModuleBlock } from './typescript/ast-helpers.js';
|
|
5
|
+
import { getJSDocTags, isInModuleBlock } from './typescript/ast-helpers.js';
|
|
6
6
|
import { createHosts } from './typescript/createHosts.js';
|
|
7
7
|
import { getImportsAndExports } from './typescript/getImportsAndExports.js';
|
|
8
8
|
import { SourceFileManager } from './typescript/SourceFileManager.js';
|
|
@@ -178,7 +178,7 @@ export class ProjectPrincipal {
|
|
|
178
178
|
findUnusedMembers(filePath, members) {
|
|
179
179
|
return members
|
|
180
180
|
.filter(member => {
|
|
181
|
-
if (
|
|
181
|
+
if (getJSDocTags(member.node).includes('@public'))
|
|
182
182
|
return false;
|
|
183
183
|
const referencedSymbols = this.findReferences(filePath, member.pos);
|
|
184
184
|
const files = referencedSymbols
|
|
@@ -194,11 +194,4 @@ export class ProjectPrincipal {
|
|
|
194
194
|
findReferences(filePath, pos) {
|
|
195
195
|
return this.backend.lsFindReferences(filePath, pos) ?? [];
|
|
196
196
|
}
|
|
197
|
-
isPublicExport(exportedItem) {
|
|
198
|
-
const tags = this.getJSDocTags(exportedItem);
|
|
199
|
-
return tags.includes('@public');
|
|
200
|
-
}
|
|
201
|
-
getJSDocTags(exportedItem) {
|
|
202
|
-
return ts.getJSDocTags(exportedItem.node).map(node => node.getText().match(/@\S+/)[0]);
|
|
203
|
-
}
|
|
204
197
|
}
|
|
@@ -15,7 +15,7 @@ export const getBinariesFromScript = (script, { cwd, manifest, knownGlobalsOnly
|
|
|
15
15
|
if (commandExpansions.length > 0) {
|
|
16
16
|
return commandExpansions.flatMap(expansion => getBinariesFromNodes(expansion.commandAST.commands)) ?? [];
|
|
17
17
|
}
|
|
18
|
-
if (!binary || binary === '.' || binary === 'source')
|
|
18
|
+
if (!binary || binary === '.' || binary === 'source' || binary === '[')
|
|
19
19
|
return [];
|
|
20
20
|
if (binary.startsWith('-') || binary.startsWith('"') || binary.startsWith('..'))
|
|
21
21
|
return [];
|
|
@@ -34,13 +34,15 @@ export const getBinariesFromScript = (script, { cwd, manifest, knownGlobalsOnly
|
|
|
34
34
|
case 'LogicalExpression':
|
|
35
35
|
return getBinariesFromNodes([node.left, node.right]);
|
|
36
36
|
case 'If':
|
|
37
|
-
return getBinariesFromNodes([
|
|
37
|
+
return getBinariesFromNodes([node.clause, node.then, ...(node.else ? [node.else] : [])]);
|
|
38
38
|
case 'For':
|
|
39
39
|
return getBinariesFromNodes(node.do.commands);
|
|
40
40
|
case 'CompoundList':
|
|
41
41
|
return getBinariesFromNodes(node.commands);
|
|
42
42
|
case 'Pipeline':
|
|
43
43
|
return getBinariesFromNodes(node.commands);
|
|
44
|
+
case 'Function':
|
|
45
|
+
return getBinariesFromNodes(node.body.commands);
|
|
44
46
|
default:
|
|
45
47
|
return [];
|
|
46
48
|
}
|
|
@@ -53,7 +53,7 @@ const commands = [
|
|
|
53
53
|
];
|
|
54
54
|
export const resolve = (_binary, args, { manifest }) => {
|
|
55
55
|
const scripts = manifest.scripts ? Object.keys(manifest.scripts) : [];
|
|
56
|
-
const parsed = parseArgs(args, {});
|
|
56
|
+
const parsed = parseArgs(args, { alias: { recursive: 'r' }, boolean: ['recursive'] });
|
|
57
57
|
const [command, binary] = parsed._;
|
|
58
58
|
if (scripts.includes(command) || commands.includes(command))
|
|
59
59
|
return [];
|
package/dist/constants.js
CHANGED
|
@@ -60,6 +60,7 @@ export const ISSUE_TYPES = [
|
|
|
60
60
|
'files',
|
|
61
61
|
'dependencies',
|
|
62
62
|
'devDependencies',
|
|
63
|
+
'optionalPeerDependencies',
|
|
63
64
|
'unlisted',
|
|
64
65
|
'binaries',
|
|
65
66
|
'unresolved',
|
|
@@ -75,6 +76,7 @@ export const ISSUE_TYPE_TITLE = {
|
|
|
75
76
|
files: 'Unused files',
|
|
76
77
|
dependencies: 'Unused dependencies',
|
|
77
78
|
devDependencies: 'Unused devDependencies',
|
|
79
|
+
optionalPeerDependencies: 'Referenced optional peerDependencies',
|
|
78
80
|
unlisted: 'Unlisted dependencies',
|
|
79
81
|
binaries: 'Unlisted binaries',
|
|
80
82
|
unresolved: 'Unresolved imports',
|
package/dist/index.js
CHANGED
|
@@ -208,8 +208,10 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
duplicate.forEach(symbols => {
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
if (symbols.length > 1) {
|
|
212
|
+
const symbol = symbols.join('|');
|
|
213
|
+
collector.addIssue({ type: 'duplicates', filePath, symbol, symbols });
|
|
214
|
+
}
|
|
213
215
|
});
|
|
214
216
|
external.forEach(specifier => {
|
|
215
217
|
const packageName = getPackageNameFromModuleSpecifier(specifier);
|
|
@@ -276,10 +278,9 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
276
278
|
continue;
|
|
277
279
|
const importingModule = importedSymbols.get(filePath);
|
|
278
280
|
for (const [symbol, exportedItem] of exportItems.entries()) {
|
|
279
|
-
|
|
280
|
-
if (jsDocTags.includes('@public') || jsDocTags.includes('@beta'))
|
|
281
|
+
if (exportedItem.jsDocTags.includes('@public') || exportedItem.jsDocTags.includes('@beta'))
|
|
281
282
|
continue;
|
|
282
|
-
if (isIgnoreInternal && jsDocTags.includes('@internal'))
|
|
283
|
+
if (isIgnoreInternal && exportedItem.jsDocTags.includes('@internal'))
|
|
283
284
|
continue;
|
|
284
285
|
if (importingModule && isSymbolImported(symbol, importingModule)) {
|
|
285
286
|
if (importingModule.isReExport && isExportedInEntryFile(importingModule))
|
|
@@ -317,11 +318,12 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
317
318
|
}
|
|
318
319
|
}
|
|
319
320
|
if (isReportDependencies) {
|
|
320
|
-
const { dependencyIssues, devDependencyIssues } = deputy.settleDependencyIssues();
|
|
321
|
+
const { dependencyIssues, devDependencyIssues, optionalPeerDependencyIssues } = deputy.settleDependencyIssues();
|
|
321
322
|
const { configurationHints } = deputy.getConfigurationHints();
|
|
322
323
|
dependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
323
324
|
if (!isProduction)
|
|
324
325
|
devDependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
326
|
+
optionalPeerDependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
325
327
|
configurationHints.forEach(hint => collector.addConfigurationHint(hint));
|
|
326
328
|
}
|
|
327
329
|
const unusedIgnoredWorkspaces = chief.getUnusedIgnoredWorkspaces();
|
|
@@ -5,7 +5,7 @@ import { _resolve } from '../../util/require.js';
|
|
|
5
5
|
import { fallback } from './fallback.js';
|
|
6
6
|
const getDependencies = (config) => {
|
|
7
7
|
const extendsSpecifiers = config.extends ? [config.extends].flat().map(resolveExtendSpecifier) : [];
|
|
8
|
-
if (extendsSpecifiers.
|
|
8
|
+
if (extendsSpecifiers.some(specifier => specifier?.startsWith('eslint-plugin-prettier')))
|
|
9
9
|
extendsSpecifiers.push('eslint-config-prettier');
|
|
10
10
|
const plugins = config.plugins ? config.plugins.map(resolvePluginSpecifier) : [];
|
|
11
11
|
const parser = config.parser;
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
2
|
import { _getDependenciesFromScripts } from '../../binaries/index.js';
|
|
3
|
+
import { getGitHookPaths } from '../../util/git.js';
|
|
3
4
|
import { timerify } from '../../util/Performance.js';
|
|
4
5
|
import { hasDependency } from '../../util/plugin.js';
|
|
5
|
-
import { getGitHooksPath } from './helpers.js';
|
|
6
6
|
export const NAME = 'husky';
|
|
7
7
|
export const ENABLERS = ['husky'];
|
|
8
8
|
export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
|
|
9
|
-
const
|
|
10
|
-
export const CONFIG_FILE_PATTERNS = [
|
|
11
|
-
`${gitHooksPath}/prepare-commit-msg`,
|
|
12
|
-
`${gitHooksPath}/commit-msg`,
|
|
13
|
-
`${gitHooksPath}/pre-{applypatch,commit,merge-commit,push,rebase,receive}`,
|
|
14
|
-
`${gitHooksPath}/post-{checkout,commit,merge,rewrite}`,
|
|
15
|
-
];
|
|
9
|
+
const gitHookPaths = getGitHookPaths('.husky');
|
|
10
|
+
export const CONFIG_FILE_PATTERNS = [...gitHookPaths];
|
|
16
11
|
const findHuskyDependencies = async (configFilePath, { cwd, manifest }) => {
|
|
17
12
|
const script = readFileSync(configFilePath);
|
|
18
13
|
return _getDependenciesFromScripts(String(script), {
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
1
2
|
import { _getDependenciesFromScripts } from '../../binaries/index.js';
|
|
3
|
+
import { fromBinary } from '../../binaries/util.js';
|
|
4
|
+
import { getGitHookPaths } from '../../util/git.js';
|
|
2
5
|
import { getValuesByKeyDeep } from '../../util/object.js';
|
|
3
6
|
import { timerify } from '../../util/Performance.js';
|
|
4
7
|
import { hasDependency, load } from '../../util/plugin.js';
|
|
5
8
|
export const NAME = 'Lefthook';
|
|
6
9
|
export const ENABLERS = ['lefthook', '@arkweid/lefthook'];
|
|
7
10
|
export const isEnabled = ({ dependencies }) => hasDependency(dependencies, ENABLERS);
|
|
8
|
-
|
|
11
|
+
const gitHookPaths = getGitHookPaths();
|
|
12
|
+
export const CONFIG_FILE_PATTERNS = ['lefthook.yml', ...gitHookPaths];
|
|
9
13
|
const findLefthookDependencies = async (configFilePath, { cwd, manifest }) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
cwd,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
14
|
+
if (configFilePath.endsWith('.yml')) {
|
|
15
|
+
const config = await load(configFilePath);
|
|
16
|
+
if (!config)
|
|
17
|
+
return [];
|
|
18
|
+
const scripts = getValuesByKeyDeep(config, 'run').filter((value) => typeof value === 'string');
|
|
19
|
+
return _getDependenciesFromScripts(scripts, { cwd, manifest, knownGlobalsOnly: true });
|
|
20
|
+
}
|
|
21
|
+
const script = readFileSync(configFilePath, 'utf8');
|
|
22
|
+
const scriptDependencies = _getDependenciesFromScripts([script], { cwd, manifest, knownGlobalsOnly: false });
|
|
23
|
+
const dependencies = manifest.devDependencies ? Object.keys(manifest.devDependencies) : [];
|
|
24
|
+
const matches = scriptDependencies.find(dep => dependencies.includes(fromBinary(dep)));
|
|
25
|
+
return matches ? [matches] : [];
|
|
19
26
|
};
|
|
20
27
|
export const findDependencies = timerify(findLefthookDependencies);
|
package/dist/reporters/json.js
CHANGED
|
@@ -22,6 +22,7 @@ export default async ({ report, issues, options }) => {
|
|
|
22
22
|
...(report.files && { files: false }),
|
|
23
23
|
...(report.dependencies && { dependencies: [] }),
|
|
24
24
|
...(report.devDependencies && { devDependencies: [] }),
|
|
25
|
+
...(report.optionalPeerDependencies && { optionalPeerDependencies: [] }),
|
|
25
26
|
...(report.unlisted && { unlisted: [] }),
|
|
26
27
|
...(report.unresolved && { unresolved: [] }),
|
|
27
28
|
...((report.exports || report.nsExports) && { exports: [] }),
|
package/dist/types/exports.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export type ExportItem = {
|
|
|
7
7
|
pos: number;
|
|
8
8
|
type: SymbolType;
|
|
9
9
|
members?: ExportItemMember[];
|
|
10
|
+
jsDocTags?: string[];
|
|
10
11
|
};
|
|
11
12
|
export type ExportItemMember = {
|
|
12
13
|
node: ts.Node;
|
|
@@ -14,6 +15,6 @@ export type ExportItemMember = {
|
|
|
14
15
|
pos: number;
|
|
15
16
|
type: SymbolType;
|
|
16
17
|
};
|
|
17
|
-
export type ExportItems = Map<string, ExportItem
|
|
18
|
+
export type ExportItems = Map<string, Required<ExportItem>>;
|
|
18
19
|
export type Exports = Map<FilePath, ExportItems>;
|
|
19
20
|
export {};
|
package/dist/types/issues.d.ts
CHANGED
|
@@ -23,4 +23,5 @@ export declare function findAncestor<T>(node: ts.Node | undefined, callback: (el
|
|
|
23
23
|
export declare function findDescendants<T>(node: ts.Node | undefined, callback: (element: ts.Node) => boolean | 'STOP'): T[];
|
|
24
24
|
export declare const isDeclarationFileExtension: (extension: string) => boolean;
|
|
25
25
|
export declare const isInModuleBlock: (node: ts.Node) => boolean;
|
|
26
|
+
export declare const getJSDocTags: (node: ts.Node) => string[];
|
|
26
27
|
export {};
|
|
@@ -3,7 +3,7 @@ import ts from 'typescript';
|
|
|
3
3
|
import { getOrSet } from '../util/map.js';
|
|
4
4
|
import { isMaybePackageName } from '../util/modules.js';
|
|
5
5
|
import { isInNodeModules } from '../util/path.js';
|
|
6
|
-
import { isDeclarationFileExtension, isAccessExpression, getAccessExpressionName } from './ast-helpers.js';
|
|
6
|
+
import { isDeclarationFileExtension, isAccessExpression, getAccessExpressionName, getJSDocTags, } from './ast-helpers.js';
|
|
7
7
|
import getExportVisitors from './visitors/exports/index.js';
|
|
8
8
|
import { getJSXImplicitImportBase } from './visitors/helpers.js';
|
|
9
9
|
import getImportVisitors from './visitors/imports/index.js';
|
|
@@ -86,20 +86,25 @@ export const getImportsAndExports = (sourceFile, options) => {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
|
-
const addExport = ({ node, identifier, type, pos, members }) => {
|
|
89
|
+
const addExport = ({ node, identifier, type, pos, members = [] }) => {
|
|
90
90
|
if (options.skipExports)
|
|
91
91
|
return;
|
|
92
|
+
const jsDocTags = getJSDocTags(node);
|
|
92
93
|
if (exports.has(identifier)) {
|
|
93
94
|
const item = exports.get(identifier);
|
|
94
|
-
|
|
95
|
+
const crew = [...item.members, ...members];
|
|
96
|
+
const tags = [...item.jsDocTags, ...jsDocTags];
|
|
97
|
+
exports.set(identifier, { ...item, node, type, pos, members: crew, jsDocTags: tags });
|
|
95
98
|
}
|
|
96
99
|
else {
|
|
97
|
-
exports.set(identifier, { node, type, pos, members });
|
|
100
|
+
exports.set(identifier, { node, type, pos, members, jsDocTags });
|
|
101
|
+
}
|
|
102
|
+
if (!jsDocTags.includes('@alias')) {
|
|
103
|
+
if (ts.isExportAssignment(node))
|
|
104
|
+
maybeAddAliasedExport(node.expression, 'default');
|
|
105
|
+
if (ts.isVariableDeclaration(node))
|
|
106
|
+
maybeAddAliasedExport(node.initializer, identifier);
|
|
98
107
|
}
|
|
99
|
-
if (ts.isExportAssignment(node))
|
|
100
|
-
maybeAddAliasedExport(node.expression, 'default');
|
|
101
|
-
if (ts.isVariableDeclaration(node))
|
|
102
|
-
maybeAddAliasedExport(node.initializer, identifier);
|
|
103
108
|
};
|
|
104
109
|
const maybeAddAliasedExport = (node, alias) => {
|
|
105
110
|
const identifier = node?.getText();
|
|
@@ -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 --ignore-internal Ignore exports with tag @internal (JSDoc/TSDoc)\n --workspace [dir]
|
|
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 --ignore-internal Ignore exports with tag @internal (JSDoc/TSDoc)\n -W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)\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,unresolved\n --exports Shortcut for --include exports,nsExports,classMembers,types,nsTypes,enumMembers,duplicates\n --include-entry-exports Include entry files when reporting unused exports\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 --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 --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 --debug-file-filter Filter for files in debug output (regex as string)\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\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 --debug --debug-file-filter '(specific|particular)-module'\n\nMore documentation and bug reports: https://github.com/webpro/knip";
|
|
2
2
|
declare const _default: {
|
|
3
3
|
config: string | undefined;
|
|
4
4
|
debug: boolean | undefined;
|
|
@@ -9,7 +9,7 @@ Options:
|
|
|
9
9
|
--production Analyze only production source files (e.g. no tests, devDependencies, exported types)
|
|
10
10
|
--strict Consider only direct dependencies of workspace (not devDependencies, not other workspaces)
|
|
11
11
|
--ignore-internal Ignore exports with tag @internal (JSDoc/TSDoc)
|
|
12
|
-
--workspace [dir]
|
|
12
|
+
-W, --workspace [dir] Analyze a single workspace (default: analyze all configured workspaces)
|
|
13
13
|
--no-gitignore Don't use .gitignore
|
|
14
14
|
--include Report only provided issue type(s), can be comma-separated or repeated (1)
|
|
15
15
|
--exclude Exclude provided issue type(s) from report, can be comma-separated or repeated (1)
|
|
@@ -68,7 +68,7 @@ try {
|
|
|
68
68
|
strict: { type: 'boolean' },
|
|
69
69
|
tsConfig: { type: 'string', short: 't' },
|
|
70
70
|
version: { type: 'boolean', short: 'V' },
|
|
71
|
-
workspace: { type: 'string' },
|
|
71
|
+
workspace: { type: 'string', short: 'W' },
|
|
72
72
|
},
|
|
73
73
|
});
|
|
74
74
|
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { ISSUE_TYPES } from '../constants.js';
|
|
2
2
|
export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isProduction = false } = {}) => {
|
|
3
3
|
if (cliArgs.dependencies) {
|
|
4
|
-
cliArgs.include = [
|
|
4
|
+
cliArgs.include = [
|
|
5
|
+
...cliArgs.include,
|
|
6
|
+
'dependencies',
|
|
7
|
+
'optionalPeerDependencies',
|
|
8
|
+
'unlisted',
|
|
9
|
+
'binaries',
|
|
10
|
+
'unresolved',
|
|
11
|
+
];
|
|
5
12
|
}
|
|
6
13
|
if (cliArgs.exports) {
|
|
7
14
|
const exports = ['exports', 'nsExports', 'classMembers', 'types', 'nsTypes', 'enumMembers', 'duplicates'];
|
|
@@ -21,9 +28,9 @@ export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isP
|
|
|
21
28
|
}
|
|
22
29
|
else {
|
|
23
30
|
if (_include.includes('dependencies'))
|
|
24
|
-
_include.push('devDependencies');
|
|
31
|
+
_include.push('devDependencies', 'optionalPeerDependencies');
|
|
25
32
|
if (_exclude.includes('dependencies'))
|
|
26
|
-
_exclude.push('devDependencies');
|
|
33
|
+
_exclude.push('devDependencies', 'optionalPeerDependencies');
|
|
27
34
|
}
|
|
28
35
|
const included = (_include.length > 0 ? _include : ISSUE_TYPES).filter(group => !_exclude.includes(group));
|
|
29
36
|
return ISSUE_TYPES.reduce((types, group) => ((types[group] = included.includes(group)), types), {});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getGitHookPaths: (defaultPath?: string) => string[];
|
package/dist/util/git.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { join } from './path.js';
|
|
3
|
+
const hookFileNames = [
|
|
4
|
+
`prepare-commit-msg`,
|
|
5
|
+
`commit-msg`,
|
|
6
|
+
`pre-{applypatch,commit,merge-commit,push,rebase,receive}`,
|
|
7
|
+
`post-{checkout,commit,merge,rewrite}`,
|
|
8
|
+
];
|
|
9
|
+
const getGitHooksPath = (defaultPath = '.git/hooks') => {
|
|
10
|
+
try {
|
|
11
|
+
return execSync('git config --get core.hooksPath', { encoding: 'utf8' }).trim();
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
return defaultPath;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export const getGitHookPaths = (defaultPath = '.git/hooks') => {
|
|
18
|
+
const gitHooksPath = getGitHooksPath(defaultPath);
|
|
19
|
+
return hookFileNames.map(fileName => join(gitHooksPath, fileName));
|
|
20
|
+
};
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.
|
|
1
|
+
export declare const version = "2.22.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.
|
|
1
|
+
export const version = '2.22.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knip",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.22.0",
|
|
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",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"pretest": "node rmdir.js tmp && swc src -d tmp/src && swc tests -d tmp/tests",
|
|
26
26
|
"test": "node --no-warnings --test tmp",
|
|
27
27
|
"coverage": "c8 --reporter html node --no-warnings --loader tsx --test tests/*.test.ts tests/*/*.test.ts",
|
|
28
|
-
"watch": "tsc --watch",
|
|
28
|
+
"watch": "rm $(which knip); npm link && tsc --watch",
|
|
29
29
|
"prebuild": "node rmdir.js dist",
|
|
30
30
|
"build": "tsc",
|
|
31
31
|
"docs": "npm run docs:cli && npm run docs:plugins && npm run docs:format",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const getGitHooksPath: () => string;
|