knip 5.44.0 → 5.44.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ConfigurationChief.js +3 -3
- package/dist/DependencyDeputy.d.ts +1 -1
- package/dist/DependencyDeputy.js +4 -4
- package/dist/IssueCollector.js +1 -1
- package/dist/ProjectPrincipal.d.ts +2 -2
- package/dist/WorkspaceWorker.js +5 -1
- package/dist/graph/analyze.d.ts +30 -0
- package/dist/graph/analyze.js +232 -0
- package/dist/graph/build.d.ts +40 -0
- package/dist/graph/build.js +268 -0
- package/dist/index.js +46 -484
- package/dist/plugins/react-router/index.js +1 -1
- package/dist/plugins/stylelint/index.js +1 -1
- package/dist/plugins/stylelint/types.d.ts +1 -1
- package/dist/{ConfigurationValidator.d.ts → schema/configuration.d.ts} +1 -1
- package/dist/{ConfigurationValidator.js → schema/configuration.js} +2 -2
- package/dist/types/config.d.ts +2 -2
- package/dist/types/{dependency-graph.d.ts → module-graph.d.ts} +1 -1
- package/dist/typescript/find-internal-references.d.ts +1 -1
- package/dist/typescript/get-imports-and-exports.d.ts +1 -1
- package/dist/typescript/get-imports-and-exports.js +1 -1
- package/dist/util/has-strictly-ns-references.d.ts +2 -2
- package/dist/util/is-identifier-referenced.d.ts +2 -2
- package/dist/util/{dependency-graph.d.ts → module-graph.d.ts} +3 -3
- package/dist/util/trace.d.ts +2 -2
- package/dist/util/watch.d.ts +4 -4
- package/dist/util/watch.js +3 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- /package/dist/types/{dependency-graph.js → module-graph.js} +0 -0
- /package/dist/{issues/initializers.d.ts → util/issue-initializers.d.ts} +0 -0
- /package/dist/{issues/initializers.js → util/issue-initializers.js} +0 -0
- /package/dist/util/{dependency-graph.js → module-graph.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -5,25 +5,10 @@ import { DependencyDeputy } from './DependencyDeputy.js';
|
|
|
5
5
|
import { IssueCollector } from './IssueCollector.js';
|
|
6
6
|
import { IssueFixer } from './IssueFixer.js';
|
|
7
7
|
import { PrincipalFactory } from './PrincipalFactory.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { debugLog, debugLogArray, debugLogObject } from './util/debug.js';
|
|
12
|
-
import { getOrCreateFileNode, updateImportMap } from './util/dependency-graph.js';
|
|
13
|
-
import { getReferencedInputsHandler } from './util/get-referenced-inputs.js';
|
|
8
|
+
import { analyze } from './graph/analyze.js';
|
|
9
|
+
import { build } from './graph/build.js';
|
|
10
|
+
import { debugLogObject } from './util/debug.js';
|
|
14
11
|
import { getGitIgnoredHandler } from './util/glob-core.js';
|
|
15
|
-
import { _glob, negate } from './util/glob.js';
|
|
16
|
-
import { getType, hasStrictlyEnumReferences, hasStrictlyNsReferences } from './util/has-strictly-ns-references.js';
|
|
17
|
-
import { isConfigPattern, isEntry, isProductionEntry, toProductionEntry } from './util/input.js';
|
|
18
|
-
import { getIsIdentifierReferencedHandler } from './util/is-identifier-referenced.js';
|
|
19
|
-
import { getPackageNameFromModuleSpecifier } from './util/modules.js';
|
|
20
|
-
import { getEntryPathsFromManifest } from './util/package-json.js';
|
|
21
|
-
import { dirname, isAbsolute, join, relative } from './util/path.js';
|
|
22
|
-
import { findMatch } from './util/regex.js';
|
|
23
|
-
import { getShouldIgnoreHandler, getShouldIgnoreTagHandler } from './util/tag.js';
|
|
24
|
-
import { augmentWorkspace, getToSourcePathHandler } from './util/to-source-path.js';
|
|
25
|
-
import { createAndPrintTrace, printTrace } from './util/trace.js';
|
|
26
|
-
import { loadTSConfig } from './util/tsconfig-loader.js';
|
|
27
12
|
import { getWatchHandler } from './util/watch.js';
|
|
28
13
|
export const main = async (unresolvedConfiguration) => {
|
|
29
14
|
const { cacheLocation, cwd, excludedIssueTypes, fixTypes, gitignore, includedIssueTypes, isCache, isDebug, isDependenciesShorthand, isExportsShorthand, isFilesShorthand, isFix, isHideConfigHints, isIncludeEntryExports, isIncludeLibs, isIsolateWorkspaces, isProduction, isRemoveFiles, isShowProgress, isStrict, isWatch, tags, tsConfigFile, workspace, } = unresolvedConfiguration;
|
|
@@ -46,478 +31,55 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
46
31
|
const filters = chief.getFilters();
|
|
47
32
|
const fixer = new IssueFixer({ isEnabled: isFix, cwd, fixTypes, isRemoveFiles });
|
|
48
33
|
debugLogObject('*', 'Included issue types', report);
|
|
49
|
-
const isReportDependencies = report.dependencies || report.unlisted || report.unresolved;
|
|
50
|
-
const isReportValues = report.exports || report.nsExports || report.classMembers;
|
|
51
|
-
const isReportTypes = report.types || report.nsTypes || report.enumMembers;
|
|
52
34
|
const isReportClassMembers = report.classMembers;
|
|
53
35
|
const isSkipLibs = !(isIncludeLibs || isReportClassMembers);
|
|
54
|
-
const isShowConfigHints = !workspace && !isProduction && !isHideConfigHints;
|
|
55
36
|
const collector = new IssueCollector({ cwd, rules, filters });
|
|
56
|
-
const allConfigFilePaths = new Set();
|
|
57
|
-
const enabledPluginsStore = new Map();
|
|
58
37
|
const o = () => workspaces.map(w => ({ pkgName: w.pkgName, name: w.name, config: w.config, ancestors: w.ancestors }));
|
|
59
38
|
debugLogObject('*', 'Included workspaces', () => workspaces.map(w => w.pkgName));
|
|
60
39
|
debugLogObject('*', 'Included workspace configs', o);
|
|
61
40
|
const isGitIgnored = await getGitIgnoredHandler({ cwd, gitignore });
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
allConfigFilePaths,
|
|
105
|
-
});
|
|
106
|
-
await worker.init();
|
|
107
|
-
const deps = new Set();
|
|
108
|
-
if (definitionPaths.length > 0) {
|
|
109
|
-
debugLogArray(name, 'Definition paths', definitionPaths);
|
|
110
|
-
for (const id of definitionPaths)
|
|
111
|
-
deps.add(toProductionEntry(id, { containingFilePath: tsConfigFilePath }));
|
|
112
|
-
}
|
|
113
|
-
const ignore = worker.getIgnorePatterns();
|
|
114
|
-
const sharedGlobOptions = { cwd, dir, gitignore };
|
|
115
|
-
collector.addIgnorePatterns(ignore.map(pattern => join(cwd, pattern)));
|
|
116
|
-
const entryPathsFromManifest = await getEntryPathsFromManifest(manifest, { ...sharedGlobOptions, ignore });
|
|
117
|
-
for (const id of entryPathsFromManifest.map(id => toProductionEntry(id)))
|
|
118
|
-
deps.add(id);
|
|
119
|
-
const dependenciesFromPlugins = await worker.findDependenciesByPlugins();
|
|
120
|
-
for (const id of dependenciesFromPlugins)
|
|
121
|
-
deps.add(id);
|
|
122
|
-
enabledPluginsStore.set(name, worker.enabledPlugins);
|
|
123
|
-
const principal = factory.createPrincipal({
|
|
124
|
-
cwd: dir,
|
|
125
|
-
paths: config.paths,
|
|
126
|
-
isFile,
|
|
127
|
-
compilerOptions,
|
|
128
|
-
compilers,
|
|
129
|
-
pkgName,
|
|
130
|
-
isIsolateWorkspaces,
|
|
131
|
-
isSkipLibs,
|
|
132
|
-
isWatch,
|
|
133
|
-
toSourceFilePath,
|
|
134
|
-
isCache,
|
|
135
|
-
cacheLocation,
|
|
136
|
-
});
|
|
137
|
-
const entryFilePatterns = new Set();
|
|
138
|
-
const productionEntryFilePatterns = new Set();
|
|
139
|
-
for (const dependency of deps) {
|
|
140
|
-
const s = dependency.specifier;
|
|
141
|
-
if (isEntry(dependency)) {
|
|
142
|
-
entryFilePatterns.add(isAbsolute(s) ? relative(dir, s) : s);
|
|
143
|
-
}
|
|
144
|
-
else if (isProductionEntry(dependency)) {
|
|
145
|
-
productionEntryFilePatterns.add(isAbsolute(s) ? relative(dir, s) : s);
|
|
146
|
-
}
|
|
147
|
-
else if (!isConfigPattern(dependency)) {
|
|
148
|
-
const ws = (dependency.containingFilePath && chief.findWorkspaceByFilePath(dependency.containingFilePath)) || workspace;
|
|
149
|
-
const specifierFilePath = getReferencedInternalFilePath(dependency, ws);
|
|
150
|
-
if (specifierFilePath)
|
|
151
|
-
principal.addEntryPath(specifierFilePath, { skipExportsAnalysis: true });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (isProduction) {
|
|
155
|
-
const negatedEntryPatterns = Array.from(entryFilePatterns).map(negate);
|
|
156
|
-
{
|
|
157
|
-
const label = 'entry';
|
|
158
|
-
const patterns = worker.getProductionEntryFilePatterns(negatedEntryPatterns);
|
|
159
|
-
const workspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns, gitignore: false, label });
|
|
160
|
-
principal.addEntryPaths(workspaceEntryPaths);
|
|
161
|
-
}
|
|
162
|
-
{
|
|
163
|
-
const label = 'production plugin entry';
|
|
164
|
-
const patterns = Array.from(productionEntryFilePatterns);
|
|
165
|
-
const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns, label });
|
|
166
|
-
principal.addEntryPaths(pluginWorkspaceEntryPaths, { skipExportsAnalysis: true });
|
|
167
|
-
}
|
|
168
|
-
{
|
|
169
|
-
const label = 'project';
|
|
170
|
-
const patterns = worker.getProductionProjectFilePatterns(negatedEntryPatterns);
|
|
171
|
-
const workspaceProjectPaths = await _glob({ ...sharedGlobOptions, patterns, label });
|
|
172
|
-
for (const projectPath of workspaceProjectPaths)
|
|
173
|
-
principal.addProjectPath(projectPath);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
{
|
|
178
|
-
const label = 'entry';
|
|
179
|
-
const patterns = worker.getEntryFilePatterns();
|
|
180
|
-
const workspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns, gitignore: false, label });
|
|
181
|
-
principal.addEntryPaths(workspaceEntryPaths);
|
|
182
|
-
}
|
|
183
|
-
{
|
|
184
|
-
const label = 'project';
|
|
185
|
-
const patterns = worker.getProjectFilePatterns([...productionEntryFilePatterns]);
|
|
186
|
-
const workspaceProjectPaths = await _glob({ ...sharedGlobOptions, patterns, label });
|
|
187
|
-
for (const projectPath of workspaceProjectPaths)
|
|
188
|
-
principal.addProjectPath(projectPath);
|
|
189
|
-
}
|
|
190
|
-
{
|
|
191
|
-
const label = 'plugin entry';
|
|
192
|
-
const patterns = worker.getPluginEntryFilePatterns([...entryFilePatterns, ...productionEntryFilePatterns]);
|
|
193
|
-
const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns, label });
|
|
194
|
-
principal.addEntryPaths(pluginWorkspaceEntryPaths, { skipExportsAnalysis: true });
|
|
195
|
-
}
|
|
196
|
-
{
|
|
197
|
-
const label = 'plugin project';
|
|
198
|
-
const patterns = worker.getPluginProjectFilePatterns();
|
|
199
|
-
const pluginWorkspaceProjectPaths = await _glob({ ...sharedGlobOptions, patterns, label });
|
|
200
|
-
for (const projectPath of pluginWorkspaceProjectPaths)
|
|
201
|
-
principal.addProjectPath(projectPath);
|
|
202
|
-
}
|
|
203
|
-
{
|
|
204
|
-
const label = 'plugin configuration';
|
|
205
|
-
const patterns = worker.getPluginConfigPatterns();
|
|
206
|
-
const configurationEntryPaths = await _glob({ ...sharedGlobOptions, patterns, label });
|
|
207
|
-
principal.addEntryPaths(configurationEntryPaths, { skipExportsAnalysis: true });
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
if (chief.resolvedConfigFilePath) {
|
|
211
|
-
principal.addEntryPath(chief.resolvedConfigFilePath, { skipExportsAnalysis: true });
|
|
212
|
-
}
|
|
213
|
-
worker.onDispose();
|
|
214
|
-
}
|
|
215
|
-
const principals = factory.getPrincipals();
|
|
216
|
-
debugLog('*', `Created ${principals.length} programs for ${workspaces.length} workspaces`);
|
|
217
|
-
const graph = new Map();
|
|
218
|
-
const analyzedFiles = new Set();
|
|
219
|
-
const unreferencedFiles = new Set();
|
|
220
|
-
const entryPaths = new Set();
|
|
221
|
-
const isIdentifierReferenced = getIsIdentifierReferencedHandler(graph, entryPaths);
|
|
222
|
-
const isPackageNameInternalWorkspace = (packageName) => chief.availableWorkspacePkgNames.has(packageName);
|
|
223
|
-
const getPrincipalByFilePath = (filePath) => {
|
|
224
|
-
const workspace = chief.findWorkspaceByFilePath(filePath);
|
|
225
|
-
if (workspace)
|
|
226
|
-
return factory.getPrincipalByPackageName(workspace.pkgName);
|
|
227
|
-
};
|
|
228
|
-
const analyzeSourceFile = (filePath, principal) => {
|
|
229
|
-
if (!isWatch && analyzedFiles.has(filePath))
|
|
230
|
-
return;
|
|
231
|
-
analyzedFiles.add(filePath);
|
|
232
|
-
const workspace = chief.findWorkspaceByFilePath(filePath);
|
|
233
|
-
if (workspace) {
|
|
234
|
-
const { imports, exports, duplicates, scripts, traceRefs } = principal.analyzeSourceFile(filePath, {
|
|
235
|
-
skipTypeOnly: isStrict,
|
|
236
|
-
isFixExports: fixer.isEnabled && fixer.isFixUnusedExports,
|
|
237
|
-
isFixTypes: fixer.isEnabled && fixer.isFixUnusedTypes,
|
|
238
|
-
ignoreExportsUsedInFile: chief.config.ignoreExportsUsedInFile,
|
|
239
|
-
isReportClassMembers,
|
|
240
|
-
tags,
|
|
241
|
-
}, isGitIgnored, isPackageNameInternalWorkspace, getPrincipalByFilePath);
|
|
242
|
-
const file = getOrCreateFileNode(graph, filePath);
|
|
243
|
-
file.imports = imports;
|
|
244
|
-
file.exports = exports;
|
|
245
|
-
file.duplicates = duplicates;
|
|
246
|
-
file.scripts = scripts;
|
|
247
|
-
file.traceRefs = traceRefs;
|
|
248
|
-
updateImportMap(file, imports.internal, graph);
|
|
249
|
-
file.internalImportCache = imports.internal;
|
|
250
|
-
graph.set(filePath, file);
|
|
251
|
-
if (scripts && scripts.size > 0) {
|
|
252
|
-
const dependencies = deputy.getDependencies(workspace.name);
|
|
253
|
-
const manifestScriptNames = new Set(Object.keys(chief.getManifestForWorkspace(workspace.name)?.scripts ?? {}));
|
|
254
|
-
const dir = dirname(filePath);
|
|
255
|
-
const options = {
|
|
256
|
-
cwd: dir,
|
|
257
|
-
rootCwd: cwd,
|
|
258
|
-
containingFilePath: filePath,
|
|
259
|
-
dependencies,
|
|
260
|
-
manifestScriptNames,
|
|
261
|
-
};
|
|
262
|
-
const inputs = _getInputsFromScripts(scripts, options);
|
|
263
|
-
for (const input of inputs) {
|
|
264
|
-
input.containingFilePath ??= filePath;
|
|
265
|
-
input.dir ??= dir;
|
|
266
|
-
const specifierFilePath = getReferencedInternalFilePath(input, workspace);
|
|
267
|
-
if (specifierFilePath)
|
|
268
|
-
analyzeSourceFile(specifierFilePath, principal);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
for (let i = 0; i < principals.length; ++i) {
|
|
274
|
-
const principal = principals[i];
|
|
275
|
-
if (!principal)
|
|
276
|
-
continue;
|
|
277
|
-
principal.init();
|
|
278
|
-
streamer.cast('Running async compilers...');
|
|
279
|
-
await principal.runAsyncCompilers();
|
|
280
|
-
streamer.cast('Analyzing source files...');
|
|
281
|
-
let size = principal.entryPaths.size;
|
|
282
|
-
let round = 0;
|
|
283
|
-
do {
|
|
284
|
-
size = principal.entryPaths.size;
|
|
285
|
-
const resolvedFiles = principal.getUsedResolvedFiles();
|
|
286
|
-
const files = resolvedFiles.filter(filePath => !analyzedFiles.has(filePath));
|
|
287
|
-
debugLogArray('*', `Analyzing used resolved files [P${i + 1}/${++round}]`, files);
|
|
288
|
-
for (const filePath of files)
|
|
289
|
-
analyzeSourceFile(filePath, principal);
|
|
290
|
-
} while (size !== principal.entryPaths.size);
|
|
291
|
-
for (const filePath of principal.getUnreferencedFiles())
|
|
292
|
-
unreferencedFiles.add(filePath);
|
|
293
|
-
for (const filePath of principal.entryPaths)
|
|
294
|
-
entryPaths.add(filePath);
|
|
295
|
-
principal.reconcileCache(graph);
|
|
296
|
-
if (!isIsolateWorkspaces && isSkipLibs && !isWatch) {
|
|
297
|
-
factory.deletePrincipal(principal);
|
|
298
|
-
principals[i] = undefined;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
if (isIsolateWorkspaces) {
|
|
302
|
-
for (const principal of principals) {
|
|
303
|
-
if (principal)
|
|
304
|
-
factory.deletePrincipal(principal);
|
|
305
|
-
}
|
|
306
|
-
principals.length = 0;
|
|
307
|
-
}
|
|
308
|
-
const ignoreExportsUsedInFile = chief.config.ignoreExportsUsedInFile;
|
|
309
|
-
const isExportedItemReferenced = (exportedItem) => exportedItem.refs[1] ||
|
|
310
|
-
(exportedItem.refs[0] > 0 &&
|
|
311
|
-
(typeof ignoreExportsUsedInFile === 'object'
|
|
312
|
-
? exportedItem.type !== 'unknown' && !!ignoreExportsUsedInFile[exportedItem.type]
|
|
313
|
-
: ignoreExportsUsedInFile));
|
|
314
|
-
const collectUnusedExports = async () => {
|
|
315
|
-
if (isReportValues || isReportTypes) {
|
|
316
|
-
streamer.cast('Connecting the dots...');
|
|
317
|
-
for (const [filePath, file] of graph.entries()) {
|
|
318
|
-
const exportItems = file.exports;
|
|
319
|
-
if (!exportItems || exportItems.size === 0)
|
|
320
|
-
continue;
|
|
321
|
-
const workspace = chief.findWorkspaceByFilePath(filePath);
|
|
322
|
-
if (workspace) {
|
|
323
|
-
const { isIncludeEntryExports } = workspace.config;
|
|
324
|
-
const principal = factory.getPrincipalByPackageName(workspace.pkgName);
|
|
325
|
-
const isEntry = entryPaths.has(filePath);
|
|
326
|
-
if (!isIncludeEntryExports && isEntry) {
|
|
327
|
-
createAndPrintTrace(filePath, { isEntry });
|
|
328
|
-
continue;
|
|
329
|
-
}
|
|
330
|
-
const importsForExport = file.imported;
|
|
331
|
-
for (const [identifier, exportedItem] of exportItems.entries()) {
|
|
332
|
-
if (!isFix && exportedItem.isReExport)
|
|
333
|
-
continue;
|
|
334
|
-
if (shouldIgnore(exportedItem.jsDocTags))
|
|
335
|
-
continue;
|
|
336
|
-
const isIgnored = shouldIgnoreTags(exportedItem.jsDocTags);
|
|
337
|
-
if (importsForExport) {
|
|
338
|
-
const { isReferenced, reExportingEntryFile, traceNode } = isIdentifierReferenced(filePath, identifier, isIncludeEntryExports);
|
|
339
|
-
if ((isReferenced || exportedItem.refs[1]) && isIgnored) {
|
|
340
|
-
for (const tagName of exportedItem.jsDocTags) {
|
|
341
|
-
if (tags[1].includes(tagName.replace(/^\@/, ''))) {
|
|
342
|
-
collector.addTagHint({ type: 'tag', filePath, identifier, tagName });
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
if (isIgnored)
|
|
347
|
-
continue;
|
|
348
|
-
if (reExportingEntryFile) {
|
|
349
|
-
if (!isIncludeEntryExports) {
|
|
350
|
-
createAndPrintTrace(filePath, { identifier, isEntry, hasRef: isReferenced });
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
const reExportedItem = graph.get(reExportingEntryFile)?.exports.get(identifier);
|
|
354
|
-
if (reExportedItem && shouldIgnore(reExportedItem.jsDocTags))
|
|
355
|
-
continue;
|
|
356
|
-
}
|
|
357
|
-
if (traceNode)
|
|
358
|
-
printTrace(traceNode, filePath, identifier);
|
|
359
|
-
if (isReferenced) {
|
|
360
|
-
if (report.enumMembers && exportedItem.type === 'enum') {
|
|
361
|
-
if (!report.nsTypes && importsForExport.refs.has(identifier))
|
|
362
|
-
continue;
|
|
363
|
-
if (hasStrictlyEnumReferences(importsForExport, identifier))
|
|
364
|
-
continue;
|
|
365
|
-
for (const member of exportedItem.members) {
|
|
366
|
-
if (findMatch(workspace.ignoreMembers, member.identifier))
|
|
367
|
-
continue;
|
|
368
|
-
if (shouldIgnore(member.jsDocTags))
|
|
369
|
-
continue;
|
|
370
|
-
if (member.refs[0] === 0) {
|
|
371
|
-
const id = `${identifier}.${member.identifier}`;
|
|
372
|
-
const { isReferenced } = isIdentifierReferenced(filePath, id, true);
|
|
373
|
-
const isIgnored = shouldIgnoreTags(member.jsDocTags);
|
|
374
|
-
if (!isReferenced) {
|
|
375
|
-
if (isIgnored)
|
|
376
|
-
continue;
|
|
377
|
-
const isIssueAdded = collector.addIssue({
|
|
378
|
-
type: 'enumMembers',
|
|
379
|
-
filePath,
|
|
380
|
-
workspace: workspace.name,
|
|
381
|
-
symbol: member.identifier,
|
|
382
|
-
parentSymbol: identifier,
|
|
383
|
-
pos: member.pos,
|
|
384
|
-
line: member.line,
|
|
385
|
-
col: member.col,
|
|
386
|
-
});
|
|
387
|
-
if (isFix && isIssueAdded && member.fix)
|
|
388
|
-
fixer.addUnusedTypeNode(filePath, [member.fix]);
|
|
389
|
-
}
|
|
390
|
-
else if (isIgnored) {
|
|
391
|
-
for (const tagName of exportedItem.jsDocTags) {
|
|
392
|
-
if (tags[1].includes(tagName.replace(/^\@/, ''))) {
|
|
393
|
-
collector.addTagHint({ type: 'tag', filePath, identifier: id, tagName });
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
if (principal && isReportClassMembers && exportedItem.type === 'class') {
|
|
401
|
-
const members = exportedItem.members.filter(member => !(findMatch(workspace.ignoreMembers, member.identifier) || shouldIgnore(member.jsDocTags)));
|
|
402
|
-
for (const member of principal.findUnusedMembers(filePath, members)) {
|
|
403
|
-
if (shouldIgnoreTags(member.jsDocTags)) {
|
|
404
|
-
const identifier = `${exportedItem.identifier}.${member.identifier}`;
|
|
405
|
-
for (const tagName of exportedItem.jsDocTags) {
|
|
406
|
-
if (tags[1].includes(tagName.replace(/^\@/, ''))) {
|
|
407
|
-
collector.addTagHint({ type: 'tag', filePath, identifier, tagName });
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
const isIssueAdded = collector.addIssue({
|
|
413
|
-
type: 'classMembers',
|
|
414
|
-
filePath,
|
|
415
|
-
workspace: workspace.name,
|
|
416
|
-
symbol: member.identifier,
|
|
417
|
-
parentSymbol: exportedItem.identifier,
|
|
418
|
-
pos: member.pos,
|
|
419
|
-
line: member.line,
|
|
420
|
-
col: member.col,
|
|
421
|
-
});
|
|
422
|
-
if (isFix && isIssueAdded && member.fix)
|
|
423
|
-
fixer.addUnusedTypeNode(filePath, [member.fix]);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
const [hasStrictlyNsRefs, namespace] = hasStrictlyNsReferences(graph, importsForExport, identifier);
|
|
430
|
-
const isType = ['enum', 'type', 'interface'].includes(exportedItem.type);
|
|
431
|
-
if (hasStrictlyNsRefs && ((!report.nsTypes && isType) || !(report.nsExports || isType)))
|
|
432
|
-
continue;
|
|
433
|
-
if (!isExportedItemReferenced(exportedItem)) {
|
|
434
|
-
if (isIgnored)
|
|
435
|
-
continue;
|
|
436
|
-
if (!isSkipLibs && principal?.hasExternalReferences(filePath, exportedItem))
|
|
437
|
-
continue;
|
|
438
|
-
const type = getType(hasStrictlyNsRefs, isType);
|
|
439
|
-
const isIssueAdded = collector.addIssue({
|
|
440
|
-
type,
|
|
441
|
-
filePath,
|
|
442
|
-
workspace: workspace.name,
|
|
443
|
-
symbol: identifier,
|
|
444
|
-
symbolType: exportedItem.type,
|
|
445
|
-
parentSymbol: namespace,
|
|
446
|
-
pos: exportedItem.pos,
|
|
447
|
-
line: exportedItem.line,
|
|
448
|
-
col: exportedItem.col,
|
|
449
|
-
});
|
|
450
|
-
if (isFix && isIssueAdded) {
|
|
451
|
-
if (isType)
|
|
452
|
-
fixer.addUnusedTypeNode(filePath, exportedItem.fixes);
|
|
453
|
-
else
|
|
454
|
-
fixer.addUnusedExportNode(filePath, exportedItem.fixes);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
for (const [filePath, file] of graph.entries()) {
|
|
462
|
-
const ws = chief.findWorkspaceByFilePath(filePath);
|
|
463
|
-
if (ws) {
|
|
464
|
-
if (file.duplicates) {
|
|
465
|
-
for (const symbols of file.duplicates) {
|
|
466
|
-
if (symbols.length > 1) {
|
|
467
|
-
const symbol = symbols.map(s => s.symbol).join('|');
|
|
468
|
-
collector.addIssue({ type: 'duplicates', filePath, workspace: ws.name, symbol, symbols });
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
if (file.imports?.external) {
|
|
473
|
-
for (const specifier of file.imports.external) {
|
|
474
|
-
const packageName = getPackageNameFromModuleSpecifier(specifier);
|
|
475
|
-
const isHandled = packageName && deputy.maybeAddReferencedExternalDependency(ws, packageName);
|
|
476
|
-
if (!isHandled)
|
|
477
|
-
collector.addIssue({
|
|
478
|
-
type: 'unlisted',
|
|
479
|
-
filePath,
|
|
480
|
-
workspace: ws.name,
|
|
481
|
-
symbol: packageName ?? specifier,
|
|
482
|
-
specifier,
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
if (file.imports?.unresolved) {
|
|
487
|
-
for (const unresolvedImport of file.imports.unresolved) {
|
|
488
|
-
const { specifier, pos, line, col } = unresolvedImport;
|
|
489
|
-
collector.addIssue({ type: 'unresolved', filePath, workspace: ws.name, symbol: specifier, pos, line, col });
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
const unusedFiles = [...unreferencedFiles].filter(filePath => !analyzedFiles.has(filePath));
|
|
495
|
-
collector.addFilesIssues(unusedFiles);
|
|
496
|
-
collector.addFileCounts({ processed: analyzedFiles.size, unused: unusedFiles.length });
|
|
497
|
-
if (isReportDependencies) {
|
|
498
|
-
const { dependencyIssues, devDependencyIssues, optionalPeerDependencyIssues } = deputy.settleDependencyIssues();
|
|
499
|
-
for (const issue of dependencyIssues)
|
|
500
|
-
collector.addIssue(issue);
|
|
501
|
-
if (!isProduction)
|
|
502
|
-
for (const issue of devDependencyIssues)
|
|
503
|
-
collector.addIssue(issue);
|
|
504
|
-
for (const issue of optionalPeerDependencyIssues)
|
|
505
|
-
collector.addIssue(issue);
|
|
506
|
-
deputy.removeIgnoredIssues(collector.getIssues());
|
|
507
|
-
if (isShowConfigHints) {
|
|
508
|
-
const configurationHints = deputy.getConfigurationHints();
|
|
509
|
-
for (const hint of configurationHints)
|
|
510
|
-
collector.addConfigurationHint(hint);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (isShowConfigHints) {
|
|
514
|
-
const unusedIgnoredWorkspaces = chief.getUnusedIgnoredWorkspaces();
|
|
515
|
-
for (const identifier of unusedIgnoredWorkspaces) {
|
|
516
|
-
collector.addConfigurationHint({ type: 'ignoreWorkspaces', identifier });
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
};
|
|
520
|
-
await collectUnusedExports();
|
|
41
|
+
const { graph, entryPaths, analyzedFiles, unreferencedFiles, analyzeSourceFile } = await build({
|
|
42
|
+
cacheLocation,
|
|
43
|
+
chief,
|
|
44
|
+
collector,
|
|
45
|
+
cwd,
|
|
46
|
+
deputy,
|
|
47
|
+
factory,
|
|
48
|
+
gitignore,
|
|
49
|
+
isCache,
|
|
50
|
+
isFixExports: fixer.isEnabled && fixer.isFixUnusedExports,
|
|
51
|
+
isFixTypes: fixer.isEnabled && fixer.isFixUnusedTypes,
|
|
52
|
+
isGitIgnored,
|
|
53
|
+
isIsolateWorkspaces,
|
|
54
|
+
isProduction,
|
|
55
|
+
isSkipLibs,
|
|
56
|
+
isStrict,
|
|
57
|
+
isWatch,
|
|
58
|
+
report,
|
|
59
|
+
streamer,
|
|
60
|
+
tags,
|
|
61
|
+
tsConfigFile,
|
|
62
|
+
workspaces,
|
|
63
|
+
});
|
|
64
|
+
const reAnalyze = await analyze({
|
|
65
|
+
analyzedFiles,
|
|
66
|
+
chief,
|
|
67
|
+
collector,
|
|
68
|
+
deputy,
|
|
69
|
+
entryPaths,
|
|
70
|
+
factory,
|
|
71
|
+
fixer,
|
|
72
|
+
graph,
|
|
73
|
+
isFix,
|
|
74
|
+
isHideConfigHints,
|
|
75
|
+
isIncludeLibs,
|
|
76
|
+
isProduction,
|
|
77
|
+
report,
|
|
78
|
+
streamer,
|
|
79
|
+
tags,
|
|
80
|
+
unreferencedFiles,
|
|
81
|
+
workspace,
|
|
82
|
+
});
|
|
521
83
|
const { issues, counters, tagHints, configurationHints } = collector.getIssues();
|
|
522
84
|
if (isWatch) {
|
|
523
85
|
const isIgnored = (filePath) => filePath.startsWith(cacheLocation) || filePath.includes('/.git/') || isGitIgnored(filePath);
|
|
@@ -526,7 +88,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
526
88
|
analyzeSourceFile,
|
|
527
89
|
chief,
|
|
528
90
|
collector,
|
|
529
|
-
|
|
91
|
+
analyze: reAnalyze,
|
|
530
92
|
cwd,
|
|
531
93
|
factory,
|
|
532
94
|
graph,
|
|
@@ -3,7 +3,7 @@ import { toEntry } from '../../util/input.js';
|
|
|
3
3
|
import { join } from '../../util/path.js';
|
|
4
4
|
import { hasDependency, load } from '../../util/plugin.js';
|
|
5
5
|
import vite from '../vite/index.js';
|
|
6
|
-
const title = '
|
|
6
|
+
const title = 'React Router';
|
|
7
7
|
const enablers = ['@react-router/dev'];
|
|
8
8
|
const isEnabled = ({ dependencies }) => hasDependency(dependencies, enablers);
|
|
9
9
|
const config = ['react-router.config.{js,ts}', ...vite.config];
|
|
@@ -8,7 +8,7 @@ const config = ['package.json', ...toCosmiconfig('stylelint')];
|
|
|
8
8
|
const resolve = (config) => {
|
|
9
9
|
const extend = config.extends ?? [];
|
|
10
10
|
const plugins = config.plugins ?? [];
|
|
11
|
-
const customSyntax = config.customSyntax ? [config.customSyntax] : [];
|
|
11
|
+
const customSyntax = typeof config.customSyntax === 'string' ? [config.customSyntax] : [];
|
|
12
12
|
const overrideConfigs = 'overrides' in config ? config.overrides.flatMap(resolve) : [];
|
|
13
13
|
return [...[extend, plugins, customSyntax].flat().map(toDeferResolve), ...overrideConfigs];
|
|
14
14
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const knipConfigurationSchema: z.ZodObject<z.objectUtil.extendShape<z.objectUtil.extendShape<z.objectUtil.extendShape<{
|
|
3
3
|
rules: z.ZodOptional<z.ZodRecord<z.ZodUnion<[z.ZodLiteral<"files">, z.ZodLiteral<"dependencies">, z.ZodLiteral<"devDependencies">, z.ZodLiteral<"optionalPeerDependencies">, z.ZodLiteral<"unlisted">, z.ZodLiteral<"binaries">, z.ZodLiteral<"unresolved">, z.ZodLiteral<"exports">, z.ZodLiteral<"types">, z.ZodLiteral<"nsExports">, z.ZodLiteral<"nsTypes">, z.ZodLiteral<"duplicates">, z.ZodLiteral<"enumMembers">, z.ZodLiteral<"classMembers">]>, z.ZodEnum<["error", "warn", "off"]>>>;
|
|
4
4
|
entry: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
|
|
5
5
|
project: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { globSchema, pluginsSchema } from './
|
|
2
|
+
import { globSchema, pluginsSchema } from './plugins.js';
|
|
3
3
|
const pathsSchema = z.record(z.string(), z.array(z.string()));
|
|
4
4
|
const syncCompilerSchema = z.function().args(z.string(), z.string()).returns(z.string());
|
|
5
5
|
const asyncCompilerSchema = z.function().args(z.string(), z.string()).returns(z.promise(z.string()));
|
|
@@ -70,7 +70,7 @@ const workspaceConfigurationSchema = baseWorkspaceConfigurationSchema.merge(plug
|
|
|
70
70
|
const workspacesConfigurationSchema = z.object({
|
|
71
71
|
workspaces: z.record(z.string(), workspaceConfigurationSchema).optional(),
|
|
72
72
|
});
|
|
73
|
-
export const
|
|
73
|
+
export const knipConfigurationSchema = rootConfigurationSchema
|
|
74
74
|
.merge(reportConfigSchema)
|
|
75
75
|
.merge(workspacesConfigurationSchema)
|
|
76
76
|
.merge(pluginsSchema.partial());
|
package/dist/types/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { z } from 'zod';
|
|
2
|
-
import type { ConfigurationValidator } from '../ConfigurationValidator.js';
|
|
3
2
|
import type { AsyncCompilers, SyncCompilers } from '../compilers/types.js';
|
|
3
|
+
import type { knipConfigurationSchema } from '../schema/configuration.js';
|
|
4
4
|
import type { pluginSchema } from '../schema/plugins.js';
|
|
5
5
|
import type { Input } from '../util/input.js';
|
|
6
6
|
import type { PluginName } from './PluginNames.js';
|
|
@@ -19,7 +19,7 @@ export interface BinaryResolverOptions extends GetInputsFromScriptsOptions {
|
|
|
19
19
|
fromArgs: FromArgs;
|
|
20
20
|
}
|
|
21
21
|
export type BinaryResolver = (binary: string, args: string[], options: BinaryResolverOptions) => Input[];
|
|
22
|
-
export type RawConfiguration = z.infer<typeof
|
|
22
|
+
export type RawConfiguration = z.infer<typeof knipConfigurationSchema>;
|
|
23
23
|
export type RawPluginConfiguration = z.infer<typeof pluginSchema>;
|
|
24
24
|
export type IgnorePatterns = (string | RegExp)[];
|
|
25
25
|
type IgnorableExport = 'class' | 'enum' | 'function' | 'interface' | 'member' | 'type';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
-
import type { Export, ExportMember } from '../types/
|
|
2
|
+
import type { Export, ExportMember } from '../types/module-graph.js';
|
|
3
3
|
export declare const isType: (item: Export | ExportMember) => boolean;
|
|
4
4
|
export declare const findInternalReferences: (item: Export | ExportMember, sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker, referencedSymbolsInExport: Set<ts.Symbol>, isBindingElement?: boolean) => [number, boolean];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import type { GetImportsAndExportsOptions } from '../types/config.js';
|
|
3
|
-
import type { ExportMap, ImportMap, UnresolvedImport } from '../types/dependency-graph.js';
|
|
4
3
|
import type { IssueSymbol } from '../types/issues.js';
|
|
4
|
+
import type { ExportMap, ImportMap, UnresolvedImport } from '../types/module-graph.js';
|
|
5
5
|
import type { BoundSourceFile } from './SourceFile.js';
|
|
6
6
|
export declare const _getImportsAndExports: (sourceFile: BoundSourceFile, resolveModule: (specifier: string) => ts.ResolvedModuleFull | undefined, typeChecker: ts.TypeChecker, options: GetImportsAndExportsOptions) => {
|
|
7
7
|
imports: {
|