knip 0.10.0 → 0.11.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 +15 -1
- package/dist/help.js +1 -1
- package/dist/index.js +11 -6
- package/dist/reporters/json.js +2 -0
- package/dist/runner.js +7 -13
- package/dist/types.d.ts +4 -4
- package/dist/util/debug.js +4 -9
- package/dist/util/glob.d.ts +7 -0
- package/dist/util/glob.js +29 -0
- package/dist/util/path.d.ts +0 -7
- package/dist/util/path.js +1 -21
- package/dist/util/project.d.ts +1 -0
- package/dist/util/project.js +12 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,9 +83,10 @@ Knip works by creating two sets of files:
|
|
|
83
83
|
--ignore Ignore files matching this glob pattern (can be set multiple times)
|
|
84
84
|
--no-gitignore Don't use .gitignore
|
|
85
85
|
--dev Include `devDependencies` in report(s)
|
|
86
|
+
--include-entry-files Report unused exports and types for entry files
|
|
86
87
|
--no-progress Don't show dynamic progress updates
|
|
87
88
|
--max-issues Maximum number of issues before non-zero exit code (default: 0)
|
|
88
|
-
--reporter Select reporter: symbols, compact, codeowners (default: symbols)
|
|
89
|
+
--reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
|
|
89
90
|
--reporter-options Pass extra options to the reporter (as JSON string, see example)
|
|
90
91
|
--jsdoc Enable JSDoc parsing, with options: public
|
|
91
92
|
--debug Show debug output
|
|
@@ -309,10 +310,23 @@ per file like this:
|
|
|
309
310
|
|
|
310
311
|
```json
|
|
311
312
|
[
|
|
313
|
+
{
|
|
314
|
+
"file": "package.json",
|
|
315
|
+
"owners": ["@org/admin"],
|
|
316
|
+
"files": false,
|
|
317
|
+
"dependencies": ["jquery", "moment"],
|
|
318
|
+
"devDependencies": [],
|
|
319
|
+
"unlisted": [],
|
|
320
|
+
"exports": [],
|
|
321
|
+
"types": [],
|
|
322
|
+
"duplicates": []
|
|
323
|
+
},
|
|
312
324
|
{
|
|
313
325
|
"file": "src/Registration.tsx",
|
|
314
326
|
"owners": ["@org/owner"],
|
|
315
327
|
"files": true,
|
|
328
|
+
"dependencies": [],
|
|
329
|
+
"devDependencies": [],
|
|
316
330
|
"unlisted": ["react"],
|
|
317
331
|
"exports": ["lowercaseFirstLetter", "RegistrationBox"],
|
|
318
332
|
"types": ["RegistrationServices", "RegistrationAction"],
|
package/dist/help.js
CHANGED
|
@@ -16,7 +16,7 @@ Options:
|
|
|
16
16
|
--include-entry-files Report unused exports and types for entry files
|
|
17
17
|
--no-progress Don't show dynamic progress updates
|
|
18
18
|
--max-issues Maximum number of issues before non-zero exit code (default: 0)
|
|
19
|
-
--reporter Select reporter: symbols, compact, codeowners (default: symbols)
|
|
19
|
+
--reporter Select reporter: symbols, compact, codeowners, json (default: symbols)
|
|
20
20
|
--reporter-options Pass extra options to the reporter (as JSON string, see example)
|
|
21
21
|
--jsdoc Enable JSDoc parsing, with options: public
|
|
22
22
|
--debug Show debug output
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const typescript_1 = __importDefault(require("typescript"));
|
|
|
8
8
|
const config_1 = require("./util/config");
|
|
9
9
|
const fs_1 = require("./util/fs");
|
|
10
10
|
const path_1 = require("./util/path");
|
|
11
|
+
const glob_1 = require("./util/glob");
|
|
11
12
|
const project_1 = require("./util/project");
|
|
12
13
|
const runner_1 = require("./runner");
|
|
13
14
|
const errors_1 = require("./util/errors");
|
|
@@ -20,6 +21,9 @@ const main = async (unresolvedConfiguration) => {
|
|
|
20
21
|
updateMessage('Reading configuration and manifest files...');
|
|
21
22
|
const manifestPath = await (0, fs_1.findFile)(cwd, workingDir, 'package.json');
|
|
22
23
|
const manifest = manifestPath && require(manifestPath);
|
|
24
|
+
if (!manifestPath || !manifest) {
|
|
25
|
+
throw new errors_1.ConfigurationError('Unable to find package.json');
|
|
26
|
+
}
|
|
23
27
|
const configFilePath = configFilePathArg ?? 'knip.json';
|
|
24
28
|
const resolvedConfigFilePath = await (0, fs_1.findFile)(cwd, workingDir, configFilePath);
|
|
25
29
|
const localConfig = resolvedConfigFilePath && require(resolvedConfigFilePath);
|
|
@@ -54,7 +58,7 @@ const main = async (unresolvedConfiguration) => {
|
|
|
54
58
|
? { tsConfigFilePath: resolvedTsConfigFilePath }
|
|
55
59
|
: { compilerOptions: { allowJs: true } };
|
|
56
60
|
updateMessage('Resolving entry files...');
|
|
57
|
-
const entryPaths = await (0,
|
|
61
|
+
const entryPaths = await (0, glob_1.glob)({
|
|
58
62
|
cwd,
|
|
59
63
|
workingDir,
|
|
60
64
|
patterns: resolvedConfig.entryFiles,
|
|
@@ -64,12 +68,12 @@ const main = async (unresolvedConfiguration) => {
|
|
|
64
68
|
(0, debug_1.debugLogFiles)(debug, 1, 'Globbed entry paths', entryPaths);
|
|
65
69
|
const production = (0, project_1.createProject)({ ...projectOptions, ...skipAddFiles }, entryPaths);
|
|
66
70
|
const entryFiles = production.getSourceFiles();
|
|
67
|
-
(0, debug_1.debugLogSourceFiles)(debug, 1, '
|
|
71
|
+
(0, debug_1.debugLogSourceFiles)(debug, 1, 'Resolved entry source files', entryFiles);
|
|
68
72
|
production.resolveSourceFileDependencies();
|
|
69
|
-
const productionFiles =
|
|
70
|
-
(0, debug_1.debugLogSourceFiles)(debug, 1, '
|
|
73
|
+
const productionFiles = (0, project_1.removeExternalSourceFiles)(production);
|
|
74
|
+
(0, debug_1.debugLogSourceFiles)(debug, 1, 'Resolved production source files', productionFiles);
|
|
71
75
|
updateMessage('Resolving project files...');
|
|
72
|
-
const projectPaths = await (0,
|
|
76
|
+
const projectPaths = await (0, glob_1.glob)({
|
|
73
77
|
cwd,
|
|
74
78
|
workingDir,
|
|
75
79
|
patterns: resolvedConfig.projectFiles,
|
|
@@ -79,7 +83,7 @@ const main = async (unresolvedConfiguration) => {
|
|
|
79
83
|
(0, debug_1.debugLogFiles)(debug, 1, 'Globbed project paths', projectPaths);
|
|
80
84
|
const project = (0, project_1.createProject)({ ...projectOptions, ...skipAddFiles }, projectPaths);
|
|
81
85
|
const projectFiles = project.getSourceFiles();
|
|
82
|
-
(0, debug_1.debugLogSourceFiles)(debug, 1, '
|
|
86
|
+
(0, debug_1.debugLogSourceFiles)(debug, 1, 'Resolved project source files', projectFiles);
|
|
83
87
|
return { entryFiles, productionFiles, projectFiles };
|
|
84
88
|
}
|
|
85
89
|
else {
|
|
@@ -97,6 +101,7 @@ const main = async (unresolvedConfiguration) => {
|
|
|
97
101
|
productionFiles,
|
|
98
102
|
projectFiles,
|
|
99
103
|
isIncludeEntryFiles: !resolvedConfig || isIncludeEntryFiles,
|
|
104
|
+
manifestPath,
|
|
100
105
|
dependencies: Object.keys(manifest.dependencies ?? {}),
|
|
101
106
|
peerDependencies: Object.keys(manifest.peerDependencies ?? {}),
|
|
102
107
|
optionalDependencies: Object.keys(manifest.optionalDependencies ?? {}),
|
package/dist/reporters/json.js
CHANGED
|
@@ -26,6 +26,8 @@ exports.default = async ({ report, issues, options }) => {
|
|
|
26
26
|
file,
|
|
27
27
|
...(codeownersEngine && { owners: codeownersEngine.calcFileOwnership(file) }),
|
|
28
28
|
...(report.files && { files: false }),
|
|
29
|
+
...(report.dependencies && { dependencies: [] }),
|
|
30
|
+
...(report.devDependencies && { devDependencies: [] }),
|
|
29
31
|
...(report.unlisted && { unlisted: [] }),
|
|
30
32
|
...((report.exports || report.nsExports) && { exports: [] }),
|
|
31
33
|
...((report.types || report.nsTypes) && { types: [] }),
|
package/dist/runner.js
CHANGED
|
@@ -15,6 +15,7 @@ const progress_1 = require("./progress");
|
|
|
15
15
|
async function findIssues(configuration) {
|
|
16
16
|
const { workingDir, report, isDev, jsDocOptions, debug } = configuration;
|
|
17
17
|
const { entryFiles, productionFiles, projectFiles, isIncludeEntryFiles } = configuration;
|
|
18
|
+
const { manifestPath } = configuration;
|
|
18
19
|
const updateMessage = (0, progress_1.getMessageUpdater)(configuration);
|
|
19
20
|
const { getUnresolvedDependencies, getUnusedDependencies, getUnusedDevDependencies } = (0, dependencies_1.getDependencyAnalyzer)(configuration);
|
|
20
21
|
const [usedProductionFiles, unreferencedProductionFiles] = (0, project_1.partitionSourceFiles)(projectFiles, productionFiles);
|
|
@@ -25,8 +26,8 @@ async function findIssues(configuration) {
|
|
|
25
26
|
(0, debug_1.debugLogSourceFiles)(debug, 1, 'Used non-entry files', usedNonEntryFiles);
|
|
26
27
|
const issues = {
|
|
27
28
|
files: new Set(unreferencedProductionFiles.map(file => file.getFilePath())),
|
|
28
|
-
dependencies:
|
|
29
|
-
devDependencies:
|
|
29
|
+
dependencies: {},
|
|
30
|
+
devDependencies: {},
|
|
30
31
|
unlisted: {},
|
|
31
32
|
exports: {},
|
|
32
33
|
types: {},
|
|
@@ -36,8 +37,8 @@ async function findIssues(configuration) {
|
|
|
36
37
|
};
|
|
37
38
|
const counters = {
|
|
38
39
|
files: issues.files.size,
|
|
39
|
-
dependencies:
|
|
40
|
-
devDependencies:
|
|
40
|
+
dependencies: 0,
|
|
41
|
+
devDependencies: 0,
|
|
41
42
|
unlisted: 0,
|
|
42
43
|
exports: 0,
|
|
43
44
|
types: 0,
|
|
@@ -56,13 +57,6 @@ async function findIssues(configuration) {
|
|
|
56
57
|
counters[issueType]++;
|
|
57
58
|
updateCounters(issue);
|
|
58
59
|
};
|
|
59
|
-
const addProjectIssue = (issueType, issue) => {
|
|
60
|
-
if (!issues[issueType].has(issue.symbol)) {
|
|
61
|
-
issues[issueType].add(issue.symbol);
|
|
62
|
-
counters[issueType]++;
|
|
63
|
-
}
|
|
64
|
-
updateCounters(issue);
|
|
65
|
-
};
|
|
66
60
|
updateMessage('Connecting the dots...');
|
|
67
61
|
if (report.dependencies ||
|
|
68
62
|
report.unlisted ||
|
|
@@ -174,10 +168,10 @@ async function findIssues(configuration) {
|
|
|
174
168
|
}
|
|
175
169
|
if (report.dependencies) {
|
|
176
170
|
const unusedDependencies = getUnusedDependencies();
|
|
177
|
-
unusedDependencies.forEach(symbol =>
|
|
171
|
+
unusedDependencies.forEach(symbol => addSymbolIssue('dependencies', { filePath: manifestPath, symbol }));
|
|
178
172
|
if (isDev) {
|
|
179
173
|
const unusedDevDependencies = getUnusedDevDependencies();
|
|
180
|
-
unusedDevDependencies.forEach(symbol =>
|
|
174
|
+
unusedDevDependencies.forEach(symbol => addSymbolIssue('devDependencies', { filePath: manifestPath, symbol }));
|
|
181
175
|
}
|
|
182
176
|
}
|
|
183
177
|
updateCounters();
|
package/dist/types.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ export declare type IssueSet = Set<string>;
|
|
|
10
10
|
export declare type IssueRecords = Record<string, Record<string, Issue>>;
|
|
11
11
|
export declare type Issues = {
|
|
12
12
|
files: IssueSet;
|
|
13
|
-
dependencies:
|
|
14
|
-
devDependencies:
|
|
13
|
+
dependencies: IssueRecords;
|
|
14
|
+
devDependencies: IssueRecords;
|
|
15
15
|
unlisted: IssueRecords;
|
|
16
16
|
exports: IssueRecords;
|
|
17
17
|
types: IssueRecords;
|
|
@@ -20,8 +20,7 @@ export declare type Issues = {
|
|
|
20
20
|
duplicates: IssueRecords;
|
|
21
21
|
};
|
|
22
22
|
export declare type IssueType = keyof Issues;
|
|
23
|
-
export declare type
|
|
24
|
-
export declare type SymbolIssueType = Exclude<IssueType, ProjectIssueType>;
|
|
23
|
+
export declare type SymbolIssueType = Exclude<IssueType, 'files'>;
|
|
25
24
|
export declare type Report = {
|
|
26
25
|
[key in keyof Issues]: boolean;
|
|
27
26
|
};
|
|
@@ -60,6 +59,7 @@ export declare type Configuration = {
|
|
|
60
59
|
productionFiles: SourceFile[];
|
|
61
60
|
entryFiles: SourceFile[];
|
|
62
61
|
isIncludeEntryFiles: boolean;
|
|
62
|
+
manifestPath: string;
|
|
63
63
|
dependencies: string[];
|
|
64
64
|
peerDependencies: string[];
|
|
65
65
|
optionalDependencies: string[];
|
package/dist/util/debug.js
CHANGED
|
@@ -16,24 +16,19 @@ exports.debugLogObject = debugLogObject;
|
|
|
16
16
|
const debugLogFiles = (debug, minimumLevel, name, filePaths) => {
|
|
17
17
|
if (minimumLevel > debug.level)
|
|
18
18
|
return;
|
|
19
|
+
console.debug(`[knip] ${name} (${filePaths.length}):`);
|
|
19
20
|
if (debug.level > 1) {
|
|
20
|
-
console.debug(`[knip] ${name} (${filePaths.length}):`);
|
|
21
21
|
logArray(filePaths);
|
|
22
22
|
}
|
|
23
|
-
else {
|
|
24
|
-
console.debug(`[knip] ${name} (${filePaths.length})`);
|
|
25
|
-
}
|
|
26
23
|
};
|
|
27
24
|
exports.debugLogFiles = debugLogFiles;
|
|
28
25
|
const debugLogSourceFiles = (debug, minimumLevel, name, sourceFiles) => {
|
|
29
26
|
if (minimumLevel > debug.level)
|
|
30
27
|
return;
|
|
28
|
+
console.debug(`[knip] ${name} (${sourceFiles.length})`);
|
|
31
29
|
if (debug.level > 1) {
|
|
32
|
-
|
|
33
|
-
logArray(
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
console.debug(`[knip] ${name} (${sourceFiles.length})`);
|
|
30
|
+
const files = sourceFiles.map(sourceFile => sourceFile.getFilePath());
|
|
31
|
+
logArray(files);
|
|
37
32
|
}
|
|
38
33
|
};
|
|
39
34
|
exports.debugLogSourceFiles = debugLogSourceFiles;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.glob = void 0;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
let _globby;
|
|
9
|
+
const globProxy = async function (patterns, options) {
|
|
10
|
+
if (!_globby) {
|
|
11
|
+
const { globby } = await eval('import("globby")');
|
|
12
|
+
_globby = globby;
|
|
13
|
+
}
|
|
14
|
+
return _globby(patterns, options);
|
|
15
|
+
};
|
|
16
|
+
const prependDirToPattern = (workingDir, pattern) => {
|
|
17
|
+
if (pattern.startsWith('!'))
|
|
18
|
+
return '!' + node_path_1.default.posix.join(workingDir, pattern.slice(1));
|
|
19
|
+
return node_path_1.default.posix.join(workingDir, pattern);
|
|
20
|
+
};
|
|
21
|
+
const glob = async ({ cwd, workingDir, patterns, ignore, gitignore, }) => {
|
|
22
|
+
return globProxy(patterns.map(pattern => prependDirToPattern(node_path_1.default.posix.relative(cwd, workingDir), pattern)), {
|
|
23
|
+
cwd,
|
|
24
|
+
ignore: [...ignore, '**/node_modules/**'],
|
|
25
|
+
gitignore,
|
|
26
|
+
absolute: true,
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
exports.glob = glob;
|
package/dist/util/path.d.ts
CHANGED
|
@@ -1,8 +1 @@
|
|
|
1
1
|
export declare const relative: (to: string) => string;
|
|
2
|
-
export declare const resolvePaths: ({ cwd, workingDir, patterns, ignore, gitignore, }: {
|
|
3
|
-
cwd: string;
|
|
4
|
-
workingDir: string;
|
|
5
|
-
patterns: string[];
|
|
6
|
-
ignore: string[];
|
|
7
|
-
gitignore: boolean;
|
|
8
|
-
}) => Promise<string[]>;
|
package/dist/util/path.js
CHANGED
|
@@ -3,28 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.relative = void 0;
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
8
|
const cwd = process.cwd();
|
|
9
9
|
const relative = (to) => node_path_1.default.relative(cwd, to);
|
|
10
10
|
exports.relative = relative;
|
|
11
|
-
let _globby;
|
|
12
|
-
const glob = async function (patterns, options) {
|
|
13
|
-
if (!_globby) {
|
|
14
|
-
const { globby } = await eval('import("globby")');
|
|
15
|
-
_globby = globby;
|
|
16
|
-
}
|
|
17
|
-
return _globby(patterns, options);
|
|
18
|
-
};
|
|
19
|
-
const prependDirToPattern = (workingDir, pattern) => {
|
|
20
|
-
if (pattern.startsWith('!'))
|
|
21
|
-
return '!' + node_path_1.default.posix.join(workingDir, pattern.slice(1));
|
|
22
|
-
return node_path_1.default.posix.join(workingDir, pattern);
|
|
23
|
-
};
|
|
24
|
-
const resolvePaths = async ({ cwd, workingDir, patterns, ignore, gitignore, }) => glob(patterns.map(pattern => prependDirToPattern(node_path_1.default.posix.relative(cwd, workingDir), pattern)), {
|
|
25
|
-
cwd,
|
|
26
|
-
ignore: [...ignore, '**/node_modules'],
|
|
27
|
-
gitignore,
|
|
28
|
-
absolute: true,
|
|
29
|
-
});
|
|
30
|
-
exports.resolvePaths = resolvePaths;
|
package/dist/util/project.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Project } from 'ts-morph';
|
|
2
2
|
import type { ProjectOptions, SourceFile } from 'ts-morph';
|
|
3
3
|
export declare const createProject: (projectOptions: ProjectOptions, paths?: string[]) => Project;
|
|
4
|
+
export declare const removeExternalSourceFiles: (project: Project) => SourceFile[];
|
|
4
5
|
export declare const partitionSourceFiles: (projectFiles: SourceFile[], productionFiles: SourceFile[]) => SourceFile[][];
|
package/dist/util/project.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.partitionSourceFiles = exports.createProject = void 0;
|
|
3
|
+
exports.partitionSourceFiles = exports.removeExternalSourceFiles = exports.createProject = void 0;
|
|
4
4
|
const ts_morph_1 = require("ts-morph");
|
|
5
5
|
const createProject = (projectOptions, paths) => {
|
|
6
|
-
const
|
|
6
|
+
const project = new ts_morph_1.Project(projectOptions);
|
|
7
7
|
if (paths)
|
|
8
|
-
|
|
9
|
-
return
|
|
8
|
+
project.addSourceFilesAtPaths(paths);
|
|
9
|
+
return project;
|
|
10
10
|
};
|
|
11
11
|
exports.createProject = createProject;
|
|
12
|
+
const removeExternalSourceFiles = (project) => project.getSourceFiles().filter(sourceFile => {
|
|
13
|
+
if (/\/node_modules\//.test(sourceFile.getFilePath())) {
|
|
14
|
+
project.removeSourceFile(sourceFile);
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
});
|
|
19
|
+
exports.removeExternalSourceFiles = removeExternalSourceFiles;
|
|
12
20
|
const partitionSourceFiles = (projectFiles, productionFiles) => {
|
|
13
21
|
const productionFilePaths = productionFiles.map(file => file.getFilePath());
|
|
14
22
|
const usedFiles = [];
|