knip 0.11.2 → 0.12.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 -0
- package/dist/cli.js +15 -38
- package/dist/help.js +2 -5
- package/dist/index.d.ts +4 -4
- package/dist/index.js +42 -49
- package/dist/log.js +2 -7
- package/dist/progress.d.ts +1 -1
- package/dist/progress.js +14 -19
- package/dist/reporters/codeowners.d.ts +1 -1
- package/dist/reporters/codeowners.js +11 -16
- package/dist/reporters/compact.d.ts +1 -1
- package/dist/reporters/compact.js +6 -8
- package/dist/reporters/constants.js +1 -4
- package/dist/reporters/index.d.ts +4 -4
- package/dist/reporters/index.js +9 -14
- package/dist/reporters/json.d.ts +1 -1
- package/dist/reporters/json.js +8 -13
- package/dist/reporters/symbols.d.ts +1 -1
- package/dist/reporters/symbols.js +6 -8
- package/dist/runner.d.ts +1 -1
- package/dist/runner.js +46 -54
- package/dist/types.js +1 -2
- package/dist/util/config.d.ts +1 -1
- package/dist/util/config.js +19 -16
- package/dist/util/debug.js +6 -15
- package/dist/util/dependencies.d.ts +2 -2
- package/dist/util/dependencies.js +15 -17
- package/dist/util/errors.js +1 -5
- package/dist/util/fs.d.ts +1 -0
- package/dist/util/fs.js +12 -17
- package/dist/util/glob.d.ts +1 -1
- package/dist/util/glob.js +8 -20
- package/dist/util/parseArgs.d.ts +24 -0
- package/dist/util/parseArgs.js +23 -0
- package/dist/util/path.js +2 -9
- package/dist/util/performance.d.ts +22 -0
- package/dist/util/performance.js +81 -0
- package/dist/util/project.d.ts +9 -3
- package/dist/util/project.js +16 -9
- package/dist/util/type.js +5 -9
- package/package.json +6 -4
package/dist/runner.js
CHANGED
|
@@ -1,29 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const project_1 = require("./util/project");
|
|
11
|
-
const type_1 = require("./util/type");
|
|
12
|
-
const dependencies_1 = require("./util/dependencies");
|
|
13
|
-
const debug_1 = require("./util/debug");
|
|
14
|
-
const progress_1 = require("./progress");
|
|
15
|
-
async function findIssues(configuration) {
|
|
16
|
-
const { workingDir, report, isDev, jsDocOptions, debug } = configuration;
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { ts } from 'ts-morph';
|
|
3
|
+
import { partitionSourceFiles, _findDuplicateExportedNames, _hasReferencingDefaultImport, _findReferencingNamespaceNodes, _getExportedDeclarations, _findReferences, } from './util/project.js';
|
|
4
|
+
import { getType } from './util/type.js';
|
|
5
|
+
import { getDependencyAnalyzer } from './util/dependencies.js';
|
|
6
|
+
import { debugLogSourceFiles } from './util/debug.js';
|
|
7
|
+
import { getCountersUpdater, getMessageUpdater } from './progress.js';
|
|
8
|
+
export async function findIssues(configuration) {
|
|
9
|
+
const { workingDir, report, jsDocOptions, debug } = configuration;
|
|
17
10
|
const { entryFiles, productionFiles, projectFiles, isIncludeEntryFiles } = configuration;
|
|
18
11
|
const { manifestPath } = configuration;
|
|
19
|
-
const updateMessage =
|
|
20
|
-
const {
|
|
21
|
-
const [usedProductionFiles, unreferencedProductionFiles] =
|
|
22
|
-
const [usedEntryFiles, usedNonEntryFiles] =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
const updateMessage = getMessageUpdater(configuration);
|
|
13
|
+
const { _findUnresolvedDependencies, getUnusedDependencies, getUnusedDevDependencies } = getDependencyAnalyzer(configuration);
|
|
14
|
+
const [usedProductionFiles, unreferencedProductionFiles] = partitionSourceFiles(projectFiles, productionFiles);
|
|
15
|
+
const [usedEntryFiles, usedNonEntryFiles] = partitionSourceFiles(usedProductionFiles, entryFiles);
|
|
16
|
+
debugLogSourceFiles(debug, 1, 'Used production files', usedProductionFiles);
|
|
17
|
+
debugLogSourceFiles(debug, 1, 'Unreferenced production files', unreferencedProductionFiles);
|
|
18
|
+
debugLogSourceFiles(debug, 1, 'Used entry files', usedEntryFiles);
|
|
19
|
+
debugLogSourceFiles(debug, 1, 'Used non-entry files', usedNonEntryFiles);
|
|
27
20
|
const issues = {
|
|
28
21
|
files: new Set(unreferencedProductionFiles.map(file => file.getFilePath())),
|
|
29
22
|
dependencies: {},
|
|
@@ -48,10 +41,10 @@ async function findIssues(configuration) {
|
|
|
48
41
|
processed: issues.files.size,
|
|
49
42
|
total: projectFiles.length,
|
|
50
43
|
};
|
|
51
|
-
const updateCounters =
|
|
44
|
+
const updateCounters = getCountersUpdater(configuration, counters);
|
|
52
45
|
const addSymbolIssue = (issueType, issue) => {
|
|
53
46
|
const { filePath, symbol } = issue;
|
|
54
|
-
const key =
|
|
47
|
+
const key = path.relative(workingDir, filePath).replace(/\\/g, '/');
|
|
55
48
|
issues[issueType][key] = issues[issueType][key] ?? {};
|
|
56
49
|
issues[issueType][key][symbol] = issue;
|
|
57
50
|
counters[issueType]++;
|
|
@@ -69,12 +62,11 @@ async function findIssues(configuration) {
|
|
|
69
62
|
counters.processed++;
|
|
70
63
|
const filePath = sourceFile.getFilePath();
|
|
71
64
|
if (report.dependencies || report.unlisted) {
|
|
72
|
-
const unresolvedDependencies =
|
|
65
|
+
const unresolvedDependencies = _findUnresolvedDependencies(sourceFile);
|
|
73
66
|
unresolvedDependencies.forEach(issue => addSymbolIssue('unlisted', issue));
|
|
74
67
|
}
|
|
75
|
-
const exportDeclarations = sourceFile.getExportedDeclarations();
|
|
76
68
|
if (report.duplicates) {
|
|
77
|
-
const duplicateExports = (
|
|
69
|
+
const duplicateExports = _findDuplicateExportedNames(sourceFile);
|
|
78
70
|
duplicateExports.forEach(symbols => {
|
|
79
71
|
const symbol = symbols.join('|');
|
|
80
72
|
addSymbolIssue('duplicates', { filePath, symbol, symbols });
|
|
@@ -83,6 +75,7 @@ async function findIssues(configuration) {
|
|
|
83
75
|
if (!isIncludeEntryFiles && usedEntryFiles.includes(sourceFile))
|
|
84
76
|
return;
|
|
85
77
|
if (report.exports || report.types || report.nsExports || report.nsTypes) {
|
|
78
|
+
const exportDeclarations = _getExportedDeclarations(sourceFile);
|
|
86
79
|
if (!isIncludeEntryFiles) {
|
|
87
80
|
const uniqueExportedSymbols = new Set([...exportDeclarations.values()].flat());
|
|
88
81
|
if (uniqueExportedSymbols.size === 1)
|
|
@@ -90,41 +83,41 @@ async function findIssues(configuration) {
|
|
|
90
83
|
}
|
|
91
84
|
exportDeclarations.forEach(declarations => {
|
|
92
85
|
declarations.forEach(declaration => {
|
|
93
|
-
const type =
|
|
86
|
+
const type = getType(declaration);
|
|
94
87
|
if (!report.nsExports && !report.nsTypes) {
|
|
95
88
|
if (!report.types && type)
|
|
96
89
|
return;
|
|
97
90
|
if (!report.exports && !type)
|
|
98
91
|
return;
|
|
99
92
|
}
|
|
100
|
-
if (jsDocOptions.isReadPublicTag &&
|
|
93
|
+
if (jsDocOptions.isReadPublicTag && ts.getJSDocPublicTag(declaration.compilerNode))
|
|
101
94
|
return;
|
|
102
95
|
let identifier;
|
|
103
96
|
let fakeIdentifier;
|
|
104
|
-
if (declaration.isKind(
|
|
97
|
+
if (declaration.isKind(ts.SyntaxKind.Identifier)) {
|
|
105
98
|
identifier = declaration;
|
|
106
99
|
}
|
|
107
|
-
else if (declaration.isKind(
|
|
108
|
-
declaration.isKind(
|
|
109
|
-
declaration.isKind(
|
|
110
|
-
declaration.isKind(
|
|
111
|
-
declaration.isKind(
|
|
112
|
-
if (!(
|
|
100
|
+
else if (declaration.isKind(ts.SyntaxKind.ArrowFunction) ||
|
|
101
|
+
declaration.isKind(ts.SyntaxKind.ObjectLiteralExpression) ||
|
|
102
|
+
declaration.isKind(ts.SyntaxKind.ArrayLiteralExpression) ||
|
|
103
|
+
declaration.isKind(ts.SyntaxKind.StringLiteral) ||
|
|
104
|
+
declaration.isKind(ts.SyntaxKind.NumericLiteral)) {
|
|
105
|
+
if (!_hasReferencingDefaultImport(sourceFile)) {
|
|
113
106
|
fakeIdentifier = 'default';
|
|
114
107
|
}
|
|
115
108
|
}
|
|
116
|
-
else if (declaration.isKind(
|
|
117
|
-
declaration.isKind(
|
|
118
|
-
declaration.isKind(
|
|
119
|
-
declaration.isKind(
|
|
120
|
-
declaration.isKind(
|
|
121
|
-
identifier = declaration.getFirstChildByKindOrThrow(
|
|
109
|
+
else if (declaration.isKind(ts.SyntaxKind.FunctionDeclaration) ||
|
|
110
|
+
declaration.isKind(ts.SyntaxKind.ClassDeclaration) ||
|
|
111
|
+
declaration.isKind(ts.SyntaxKind.TypeAliasDeclaration) ||
|
|
112
|
+
declaration.isKind(ts.SyntaxKind.InterfaceDeclaration) ||
|
|
113
|
+
declaration.isKind(ts.SyntaxKind.EnumDeclaration)) {
|
|
114
|
+
identifier = declaration.getFirstChildByKindOrThrow(ts.SyntaxKind.Identifier);
|
|
122
115
|
}
|
|
123
|
-
else if (declaration.isKind(
|
|
124
|
-
identifier = declaration.getLastChildByKindOrThrow(
|
|
116
|
+
else if (declaration.isKind(ts.SyntaxKind.PropertyAccessExpression)) {
|
|
117
|
+
identifier = declaration.getLastChildByKindOrThrow(ts.SyntaxKind.Identifier);
|
|
125
118
|
}
|
|
126
119
|
else {
|
|
127
|
-
identifier = declaration.getFirstDescendantByKind(
|
|
120
|
+
identifier = declaration.getFirstDescendantByKind(ts.SyntaxKind.Identifier);
|
|
128
121
|
}
|
|
129
122
|
if (identifier || fakeIdentifier) {
|
|
130
123
|
const identifierText = fakeIdentifier ?? identifier?.getText() ?? '*';
|
|
@@ -136,7 +129,7 @@ async function findIssues(configuration) {
|
|
|
136
129
|
return;
|
|
137
130
|
if (report.nsTypes && issues.nsTypes[filePath]?.[identifierText])
|
|
138
131
|
return;
|
|
139
|
-
const refs = identifier
|
|
132
|
+
const refs = _findReferences(identifier);
|
|
140
133
|
if (refs.length === 0) {
|
|
141
134
|
addSymbolIssue('exports', { filePath, symbol: identifierText });
|
|
142
135
|
}
|
|
@@ -145,7 +138,7 @@ async function findIssues(configuration) {
|
|
|
145
138
|
const isReferencedOnlyBySelf = refFiles.size === 1 && [...refFiles][0] === filePath;
|
|
146
139
|
if (!isReferencedOnlyBySelf)
|
|
147
140
|
return;
|
|
148
|
-
if ((
|
|
141
|
+
if (_findReferencingNamespaceNodes(sourceFile).length > 0) {
|
|
149
142
|
if (type) {
|
|
150
143
|
addSymbolIssue('nsTypes', { filePath, symbol: identifierText, symbolType: type });
|
|
151
144
|
}
|
|
@@ -169,12 +162,11 @@ async function findIssues(configuration) {
|
|
|
169
162
|
if (report.dependencies) {
|
|
170
163
|
const unusedDependencies = getUnusedDependencies();
|
|
171
164
|
unusedDependencies.forEach(symbol => addSymbolIssue('dependencies', { filePath: manifestPath, symbol }));
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
165
|
+
}
|
|
166
|
+
if (report.devDependencies) {
|
|
167
|
+
const unusedDevDependencies = getUnusedDevDependencies();
|
|
168
|
+
unusedDevDependencies.forEach(symbol => addSymbolIssue('devDependencies', { filePath: manifestPath, symbol }));
|
|
176
169
|
}
|
|
177
170
|
updateCounters();
|
|
178
171
|
return { issues, counters };
|
|
179
172
|
}
|
|
180
|
-
exports.findIssues = findIssues;
|
package/dist/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
package/dist/util/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImportedConfiguration, LocalConfiguration, Report } from '../types';
|
|
1
|
+
import type { ImportedConfiguration, LocalConfiguration, Report } from '../types.js';
|
|
2
2
|
export declare const resolveConfig: (importedConfiguration: ImportedConfiguration, options?: {
|
|
3
3
|
workingDir?: string;
|
|
4
4
|
isDev?: boolean;
|
package/dist/util/config.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.resolveIncludedIssueTypes = exports.resolveConfig = void 0;
|
|
7
|
-
const micromatch_1 = __importDefault(require("micromatch"));
|
|
8
|
-
const resolveConfig = (importedConfiguration, options) => {
|
|
1
|
+
import micromatch from 'micromatch';
|
|
2
|
+
export const resolveConfig = (importedConfiguration, options) => {
|
|
9
3
|
if (!importedConfiguration)
|
|
10
4
|
return;
|
|
11
5
|
let resolvedConfig = importedConfiguration;
|
|
12
6
|
const { workingDir, isDev } = options ?? {};
|
|
13
7
|
const configKeys = Object.keys(importedConfiguration);
|
|
14
8
|
if (workingDir && !('projectFiles' in importedConfiguration)) {
|
|
15
|
-
const importedConfigKey = configKeys.find(pattern =>
|
|
9
|
+
const importedConfigKey = configKeys.find(pattern => micromatch.isMatch(workingDir.replace(/\/$/, ''), pattern));
|
|
16
10
|
if (importedConfigKey) {
|
|
17
11
|
resolvedConfig = importedConfiguration[importedConfigKey];
|
|
18
12
|
}
|
|
@@ -27,17 +21,26 @@ const resolveConfig = (importedConfiguration, options) => {
|
|
|
27
21
|
resolvedConfig.dev = Boolean(typeof resolvedConfig.dev === 'boolean' ? resolvedConfig.dev : isDev);
|
|
28
22
|
return resolvedConfig;
|
|
29
23
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
const ISSUE_TYPES = [
|
|
25
|
+
'files',
|
|
26
|
+
'dependencies',
|
|
27
|
+
'devDependencies',
|
|
28
|
+
'unlisted',
|
|
29
|
+
'exports',
|
|
30
|
+
'types',
|
|
31
|
+
'nsExports',
|
|
32
|
+
'nsTypes',
|
|
33
|
+
'duplicates',
|
|
34
|
+
];
|
|
35
|
+
export const resolveIncludedIssueTypes = (includeArg, excludeArg, resolvedConfig) => {
|
|
34
36
|
const normalizedIncludesArg = includeArg.map(value => value.split(',')).flat();
|
|
35
37
|
const normalizedExcludesArg = excludeArg.map(value => value.split(',')).flat();
|
|
36
38
|
const excludes = (resolvedConfig?.exclude ?? []).filter(exclude => !normalizedIncludesArg.includes(exclude));
|
|
37
39
|
const includes = (resolvedConfig?.include ?? []).filter(include => !normalizedExcludesArg.includes(include));
|
|
38
40
|
const include = [normalizedIncludesArg, includes].flat();
|
|
39
41
|
const exclude = [normalizedExcludesArg, excludes].flat();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
include.includes('dependencies') && include.push('devDependencies');
|
|
43
|
+
!resolvedConfig?.dev && exclude.push('devDependencies');
|
|
44
|
+
const included = (include.length > 0 ? include : ISSUE_TYPES).filter(group => !exclude.includes(group));
|
|
45
|
+
return ISSUE_TYPES.reduce((types, group) => ((types[group] = included.includes(group)), types), {});
|
|
42
46
|
};
|
|
43
|
-
exports.resolveIncludedIssueTypes = resolveIncludedIssueTypes;
|
package/dist/util/debug.js
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.debugLogSourceFiles = exports.debugLogFiles = exports.debugLogObject = void 0;
|
|
7
|
-
const node_util_1 = __importDefault(require("node:util"));
|
|
8
|
-
const logArray = (collection) => console.log(node_util_1.default.inspect(collection, { maxArrayLength: null }));
|
|
9
|
-
const debugLogObject = (debug, minimumLevel, name, obj) => {
|
|
1
|
+
import util from 'node:util';
|
|
2
|
+
const logArray = (collection) => console.log(util.inspect(collection, { maxArrayLength: null }));
|
|
3
|
+
export const debugLogObject = (debug, minimumLevel, name, obj) => {
|
|
10
4
|
if (minimumLevel > debug.level)
|
|
11
5
|
return;
|
|
12
6
|
console.log(`[knip] ${name}:`);
|
|
13
|
-
console.log(
|
|
7
|
+
console.log(util.inspect(obj, { depth: null, colors: true }));
|
|
14
8
|
};
|
|
15
|
-
|
|
16
|
-
const debugLogFiles = (debug, minimumLevel, name, filePaths) => {
|
|
9
|
+
export const debugLogFiles = (debug, minimumLevel, name, filePaths) => {
|
|
17
10
|
if (minimumLevel > debug.level)
|
|
18
11
|
return;
|
|
19
12
|
console.debug(`[knip] ${name} (${filePaths.length}):`);
|
|
@@ -21,8 +14,7 @@ const debugLogFiles = (debug, minimumLevel, name, filePaths) => {
|
|
|
21
14
|
logArray(filePaths);
|
|
22
15
|
}
|
|
23
16
|
};
|
|
24
|
-
|
|
25
|
-
const debugLogSourceFiles = (debug, minimumLevel, name, sourceFiles) => {
|
|
17
|
+
export const debugLogSourceFiles = (debug, minimumLevel, name, sourceFiles) => {
|
|
26
18
|
if (minimumLevel > debug.level)
|
|
27
19
|
return;
|
|
28
20
|
console.debug(`[knip] ${name} (${sourceFiles.length})`);
|
|
@@ -31,7 +23,6 @@ const debugLogSourceFiles = (debug, minimumLevel, name, sourceFiles) => {
|
|
|
31
23
|
logArray(files);
|
|
32
24
|
}
|
|
33
25
|
};
|
|
34
|
-
exports.debugLogSourceFiles = debugLogSourceFiles;
|
|
35
26
|
const debugLogDiff = (debug, minimumLevel, name, arrA, arrB) => {
|
|
36
27
|
if (minimumLevel > debug.level)
|
|
37
28
|
return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SourceFile } from 'ts-morph';
|
|
2
|
-
import type { Configuration, Issue } from '../types';
|
|
2
|
+
import type { Configuration, Issue } from '../types.js';
|
|
3
3
|
export declare const getDependencyAnalyzer: (configuration: Configuration) => {
|
|
4
|
-
|
|
4
|
+
_findUnresolvedDependencies: (sourceFile: SourceFile) => Set<Issue>;
|
|
5
5
|
getUnusedDependencies: () => string[];
|
|
6
6
|
getUnusedDevDependencies: () => string[];
|
|
7
7
|
};
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
exports.getDependencyAnalyzer = void 0;
|
|
7
|
-
const ts_morph_1 = require("ts-morph");
|
|
8
|
-
const is_builtin_module_1 = __importDefault(require("is-builtin-module"));
|
|
9
|
-
const micromatch_1 = __importDefault(require("micromatch"));
|
|
10
|
-
const ts_morph_helpers_1 = require("ts-morph-helpers");
|
|
1
|
+
import { isBuiltin } from 'node:module';
|
|
2
|
+
import { ts } from 'ts-morph';
|
|
3
|
+
import micromatch from 'micromatch';
|
|
4
|
+
import { findCallExpressionsByName } from 'ts-morph-helpers';
|
|
5
|
+
import { timerify } from './performance.js';
|
|
11
6
|
const compact = (collection) => Array.from(new Set(collection)).filter((value) => Boolean(value));
|
|
12
|
-
const findRequireModuleSpecifiers = (sourceFile) =>
|
|
7
|
+
const findRequireModuleSpecifiers = (sourceFile) => findCallExpressionsByName(sourceFile, 'require').map(expression => expression.getFirstDescendantByKind(ts.SyntaxKind.StringLiteral));
|
|
13
8
|
const isExternalDependency = (moduleSpecifier, tsConfigPathGlobs) => {
|
|
14
9
|
if (moduleSpecifier.startsWith('.'))
|
|
15
10
|
return false;
|
|
16
|
-
if ((
|
|
11
|
+
if (isBuiltin(moduleSpecifier))
|
|
17
12
|
return false;
|
|
18
|
-
if (tsConfigPathGlobs.length > 0 &&
|
|
13
|
+
if (tsConfigPathGlobs.length > 0 && micromatch.isMatch(moduleSpecifier, tsConfigPathGlobs))
|
|
19
14
|
return false;
|
|
20
15
|
return true;
|
|
21
16
|
};
|
|
@@ -23,11 +18,11 @@ const resolvePackageName = (moduleSpecifier) => {
|
|
|
23
18
|
const parts = moduleSpecifier.split('/').slice(0, 2);
|
|
24
19
|
return moduleSpecifier.startsWith('@') ? parts.join('/') : parts[0];
|
|
25
20
|
};
|
|
26
|
-
const getDependencyAnalyzer = (configuration) => {
|
|
21
|
+
export const getDependencyAnalyzer = (configuration) => {
|
|
27
22
|
const { dependencies, devDependencies, peerDependencies, optionalDependencies, tsConfigPathGlobs } = configuration;
|
|
28
23
|
const productionDependencies = [...dependencies, ...peerDependencies, ...optionalDependencies];
|
|
29
24
|
const referencedDependencies = new Set();
|
|
30
|
-
const
|
|
25
|
+
const findUnresolvedDependencies = (sourceFile) => {
|
|
31
26
|
const unresolvedDependencies = new Set();
|
|
32
27
|
const importLiterals = sourceFile.getImportStringLiterals();
|
|
33
28
|
const requireCallExpressions = findRequireModuleSpecifiers(sourceFile);
|
|
@@ -47,6 +42,9 @@ const getDependencyAnalyzer = (configuration) => {
|
|
|
47
42
|
};
|
|
48
43
|
const getUnusedDependencies = () => productionDependencies.filter(dependency => !referencedDependencies.has(dependency));
|
|
49
44
|
const getUnusedDevDependencies = () => devDependencies.filter(dependency => !referencedDependencies.has(dependency));
|
|
50
|
-
return {
|
|
45
|
+
return {
|
|
46
|
+
_findUnresolvedDependencies: timerify(findUnresolvedDependencies),
|
|
47
|
+
getUnusedDependencies,
|
|
48
|
+
getUnusedDevDependencies,
|
|
49
|
+
};
|
|
51
50
|
};
|
|
52
|
-
exports.getDependencyAnalyzer = getDependencyAnalyzer;
|
package/dist/util/errors.js
CHANGED
package/dist/util/fs.d.ts
CHANGED
package/dist/util/fs.js
CHANGED
|
@@ -1,31 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports.findFile = exports.isFile = void 0;
|
|
7
|
-
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const isFile = async (filePath) => {
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
const require = createRequire(process.cwd());
|
|
5
|
+
export const isFile = async (filePath) => {
|
|
10
6
|
try {
|
|
11
|
-
const stats = await
|
|
7
|
+
const stats = await fs.stat(filePath);
|
|
12
8
|
return stats.isFile();
|
|
13
9
|
}
|
|
14
10
|
catch {
|
|
15
11
|
return false;
|
|
16
12
|
}
|
|
17
13
|
};
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
if (await (0, exports.isFile)(filePath)) {
|
|
14
|
+
export const findFile = async (cwd, workingDir, fileName) => {
|
|
15
|
+
const filePath = path.join(workingDir, fileName);
|
|
16
|
+
if (await isFile(filePath)) {
|
|
22
17
|
return filePath;
|
|
23
18
|
}
|
|
24
19
|
else {
|
|
25
20
|
if (cwd === workingDir)
|
|
26
21
|
return;
|
|
27
|
-
const parentDir =
|
|
28
|
-
return
|
|
22
|
+
const parentDir = path.resolve(workingDir, '..');
|
|
23
|
+
return findFile(cwd, parentDir, fileName);
|
|
29
24
|
}
|
|
30
25
|
};
|
|
31
|
-
|
|
26
|
+
export const loadJSON = (filePath) => require(filePath);
|
package/dist/util/glob.d.ts
CHANGED
package/dist/util/glob.js
CHANGED
|
@@ -1,32 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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 ensurePosixPath = (value) => value.split(node_path_1.default.sep).join(node_path_1.default.posix.sep);
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { globby } from 'globby';
|
|
3
|
+
import { timerify } from './performance.js';
|
|
4
|
+
const ensurePosixPath = (value) => value.split(path.sep).join(path.posix.sep);
|
|
17
5
|
const prependDirToPattern = (workingDir, pattern) => {
|
|
18
6
|
if (pattern.startsWith('!'))
|
|
19
|
-
return '!' +
|
|
20
|
-
return
|
|
7
|
+
return '!' + path.posix.join(workingDir, pattern.slice(1));
|
|
8
|
+
return path.posix.join(workingDir, pattern);
|
|
21
9
|
};
|
|
22
10
|
const glob = async ({ cwd, workingDir, patterns, ignore, gitignore, }) => {
|
|
23
11
|
const cwdPosix = ensurePosixPath(cwd);
|
|
24
12
|
const workingDirPosix = ensurePosixPath(workingDir);
|
|
25
|
-
return
|
|
13
|
+
return globby(patterns.map(pattern => prependDirToPattern(path.posix.relative(cwdPosix, workingDirPosix), pattern)), {
|
|
26
14
|
cwd,
|
|
27
15
|
ignore: [...ignore, '**/node_modules/**'],
|
|
28
16
|
gitignore,
|
|
29
17
|
absolute: true,
|
|
30
18
|
});
|
|
31
19
|
};
|
|
32
|
-
|
|
20
|
+
export const _glob = timerify(glob);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
values: {
|
|
3
|
+
help: boolean | undefined;
|
|
4
|
+
config: string | undefined;
|
|
5
|
+
tsConfig: string | undefined;
|
|
6
|
+
dir: string | undefined;
|
|
7
|
+
include: string[] | undefined;
|
|
8
|
+
exclude: string[] | undefined;
|
|
9
|
+
ignore: string[] | undefined;
|
|
10
|
+
'no-gitignore': boolean | undefined;
|
|
11
|
+
dev: boolean | undefined;
|
|
12
|
+
'include-entry-files': boolean | undefined;
|
|
13
|
+
'no-progress': boolean | undefined;
|
|
14
|
+
'max-issues': string | undefined;
|
|
15
|
+
reporter: string | undefined;
|
|
16
|
+
'reporter-options': string | undefined;
|
|
17
|
+
jsdoc: string[] | undefined;
|
|
18
|
+
debug: boolean | undefined;
|
|
19
|
+
'debug-level': string | undefined;
|
|
20
|
+
performance: boolean | undefined;
|
|
21
|
+
};
|
|
22
|
+
positionals: [];
|
|
23
|
+
};
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
export default parseArgs({
|
|
3
|
+
options: {
|
|
4
|
+
help: { type: 'boolean' },
|
|
5
|
+
config: { type: 'string', short: 'c' },
|
|
6
|
+
tsConfig: { type: 'string', short: 't' },
|
|
7
|
+
dir: { type: 'string' },
|
|
8
|
+
include: { type: 'string', multiple: true },
|
|
9
|
+
exclude: { type: 'string', multiple: true },
|
|
10
|
+
ignore: { type: 'string', multiple: true },
|
|
11
|
+
'no-gitignore': { type: 'boolean' },
|
|
12
|
+
dev: { type: 'boolean' },
|
|
13
|
+
'include-entry-files': { type: 'boolean' },
|
|
14
|
+
'no-progress': { type: 'boolean' },
|
|
15
|
+
'max-issues': { type: 'string' },
|
|
16
|
+
reporter: { type: 'string' },
|
|
17
|
+
'reporter-options': { type: 'string' },
|
|
18
|
+
jsdoc: { type: 'string', multiple: true },
|
|
19
|
+
debug: { type: 'boolean' },
|
|
20
|
+
'debug-level': { type: 'string' },
|
|
21
|
+
performance: { type: 'boolean' },
|
|
22
|
+
},
|
|
23
|
+
});
|
package/dist/util/path.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
|
|
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.relative = void 0;
|
|
7
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
1
|
+
import path from 'node:path';
|
|
8
2
|
const cwd = process.cwd();
|
|
9
|
-
const relative = (to) =>
|
|
10
|
-
exports.relative = relative;
|
|
3
|
+
export const relative = (to) => path.relative(cwd, to);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import { PerformanceObserver, PerformanceEntry } from 'node:perf_hooks';
|
|
3
|
+
import EasyTable from 'easy-table';
|
|
4
|
+
import type { TimerifyOptions } from 'node:perf_hooks';
|
|
5
|
+
declare type Timerify = <T extends (...params: any[]) => any>(fn: T, options?: TimerifyOptions) => T;
|
|
6
|
+
export declare const timerify: Timerify;
|
|
7
|
+
declare class Performance {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
entries: PerformanceEntry[];
|
|
10
|
+
instanceId?: number;
|
|
11
|
+
observer?: PerformanceObserver;
|
|
12
|
+
constructor(enabled: boolean);
|
|
13
|
+
start(name: string): void;
|
|
14
|
+
end(name: string): void;
|
|
15
|
+
getEntriesByName(): Record<string, number[]>;
|
|
16
|
+
getTable(sort?: string[]): EasyTable;
|
|
17
|
+
flush(): Promise<void>;
|
|
18
|
+
print(): Promise<void>;
|
|
19
|
+
reset(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare const measure: Performance;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { performance, PerformanceObserver } from 'node:perf_hooks';
|
|
2
|
+
import Summary from 'summary';
|
|
3
|
+
import EasyTable from 'easy-table';
|
|
4
|
+
import parsedArgs from './parseArgs.js';
|
|
5
|
+
const { values } = parsedArgs;
|
|
6
|
+
const { performance: isEnabled = false } = values;
|
|
7
|
+
export const timerify = fn => (isEnabled ? performance.timerify(fn) : fn);
|
|
8
|
+
class Performance {
|
|
9
|
+
enabled;
|
|
10
|
+
entries = [];
|
|
11
|
+
instanceId;
|
|
12
|
+
observer;
|
|
13
|
+
constructor(enabled) {
|
|
14
|
+
if (enabled) {
|
|
15
|
+
this.instanceId = Math.floor(performance.now() * 100);
|
|
16
|
+
this.observer = new PerformanceObserver(items => {
|
|
17
|
+
items.getEntries().forEach(entry => {
|
|
18
|
+
this.entries.push(entry);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
this.observer.observe({ entryTypes: ['measure', 'function'] });
|
|
22
|
+
}
|
|
23
|
+
this.enabled = enabled;
|
|
24
|
+
}
|
|
25
|
+
start(name) {
|
|
26
|
+
if (!this.enabled)
|
|
27
|
+
return;
|
|
28
|
+
const id = `${this.instanceId}:${name}`;
|
|
29
|
+
performance.mark(`${id}:start`);
|
|
30
|
+
}
|
|
31
|
+
end(name) {
|
|
32
|
+
if (!this.enabled)
|
|
33
|
+
return;
|
|
34
|
+
const id = `${this.instanceId}:${name}`;
|
|
35
|
+
performance.mark(`${id}:end`);
|
|
36
|
+
performance.measure(id, `${id}:start`, `${id}:end`);
|
|
37
|
+
performance.clearMarks(`${id}:start`);
|
|
38
|
+
performance.clearMarks(`${id}:end`);
|
|
39
|
+
}
|
|
40
|
+
getEntriesByName() {
|
|
41
|
+
return this.entries.reduce((entries, entry) => {
|
|
42
|
+
const name = entry.name.replace(`${this.instanceId}:`, '');
|
|
43
|
+
entries[name] = entries[name] ?? [];
|
|
44
|
+
entries[name].push(entry.duration);
|
|
45
|
+
return entries;
|
|
46
|
+
}, {});
|
|
47
|
+
}
|
|
48
|
+
getTable(sort = ['sum|des']) {
|
|
49
|
+
const entriesByName = this.getEntriesByName();
|
|
50
|
+
const table = new EasyTable();
|
|
51
|
+
Object.entries(entriesByName).map(([name, values]) => {
|
|
52
|
+
const stats = new Summary(values);
|
|
53
|
+
table.cell('Name', name);
|
|
54
|
+
table.cell('size', stats.size(), EasyTable.number(0));
|
|
55
|
+
table.cell('min', stats.min(), EasyTable.number(2));
|
|
56
|
+
table.cell('max', stats.max(), EasyTable.number(2));
|
|
57
|
+
table.cell('median', stats.median(), EasyTable.number(2));
|
|
58
|
+
table.cell('sum', stats.sum(), EasyTable.number(2));
|
|
59
|
+
table.newRow();
|
|
60
|
+
});
|
|
61
|
+
table.total('sum', { printer: EasyTable.number(2) });
|
|
62
|
+
table.sort(sort);
|
|
63
|
+
return table;
|
|
64
|
+
}
|
|
65
|
+
async flush() {
|
|
66
|
+
this.start('_flush');
|
|
67
|
+
await new Promise(resolve => setTimeout(resolve, 1));
|
|
68
|
+
this.end('_flush');
|
|
69
|
+
}
|
|
70
|
+
async print() {
|
|
71
|
+
if (!this.enabled)
|
|
72
|
+
return;
|
|
73
|
+
await this.flush();
|
|
74
|
+
console.log('\n' + this.getTable().toString().trim());
|
|
75
|
+
}
|
|
76
|
+
reset() {
|
|
77
|
+
this.entries = [];
|
|
78
|
+
this.observer?.disconnect();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export const measure = new Performance(isEnabled);
|