knip 2.0.0-alpha.3 → 2.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +0 -0
- package/dist/configuration-chief.d.ts +6 -5
- package/dist/configuration-chief.js +15 -12
- package/dist/console-streamer.d.ts +12 -0
- package/dist/console-streamer.js +34 -0
- package/dist/index.js +108 -166
- package/dist/issue-collector.d.ts +3 -10
- package/dist/issue-collector.js +5 -19
- package/dist/issues/initializers.d.ts +1 -2
- package/dist/issues/initializers.js +0 -1
- package/dist/manifest/helpers.d.ts +7 -1
- package/dist/manifest/helpers.js +3 -3
- package/dist/manifest/index.d.ts +1 -2
- package/dist/manifest/index.js +2 -2
- package/dist/progress-updater.d.ts +11 -12
- package/dist/progress-updater.js +27 -15
- package/dist/project-principal.d.ts +5 -3
- package/dist/project-principal.js +18 -8
- package/dist/typescript/ast-walker.d.ts +5 -3
- package/dist/typescript/ast-walker.js +9 -1
- package/dist/util/get-included-issue-types.d.ts +16 -0
- package/dist/util/get-included-issue-types.js +30 -0
- package/dist/util/resolve-included-issue-types.d.ts +2 -2
- package/dist/util/resolve-included-issue-types.js +1 -1
- package/dist/util/tsconfig-loader.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace-worker.d.ts +18 -18
- package/dist/workspace-worker.js +39 -32
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -26,7 +26,7 @@ export declare class ConfigurationChief {
|
|
|
26
26
|
workspaces: Workspace[];
|
|
27
27
|
resolvedConfigFilePath?: string;
|
|
28
28
|
constructor({ cwd, isProduction }: ConfigurationManagerOptions);
|
|
29
|
-
|
|
29
|
+
init(): Promise<void>;
|
|
30
30
|
getCompilers(): [SyncCompilers, AsyncCompilers];
|
|
31
31
|
normalize(rawLocalConfig: RawConfiguration): {
|
|
32
32
|
include: string[];
|
|
@@ -40,8 +40,8 @@ export declare class ConfigurationChief {
|
|
|
40
40
|
setWorkspaces(): Promise<void>;
|
|
41
41
|
private getManifestWorkspaces;
|
|
42
42
|
private getAdditionalWorkspaces;
|
|
43
|
-
private
|
|
44
|
-
|
|
43
|
+
private getAllWorkspaces;
|
|
44
|
+
getEnabledWorkspaces(): {
|
|
45
45
|
name: string;
|
|
46
46
|
pkgName: string | undefined;
|
|
47
47
|
dir: string;
|
|
@@ -54,7 +54,8 @@ export declare class ConfigurationChief {
|
|
|
54
54
|
getNegatedWorkspacePatterns(name: string): string[];
|
|
55
55
|
private getConfigKeyForWorkspace;
|
|
56
56
|
getConfigForWorkspace(workspaceName: string): WorkspaceConfiguration;
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
getIssueTypesToReport(): import("./types/issues.js").Report;
|
|
58
|
+
findWorkspaceByFilePath(filePath: string): Workspace | undefined;
|
|
59
|
+
findWorkspaceByPackageName(packageName: string): Workspace | undefined;
|
|
59
60
|
}
|
|
60
61
|
export {};
|
|
@@ -8,11 +8,11 @@ import parsedArgs from './util/cli-arguments.js';
|
|
|
8
8
|
import { partitionCompilers } from './util/compilers.js';
|
|
9
9
|
import { ConfigurationError } from './util/errors.js';
|
|
10
10
|
import { findFile, loadJSON } from './util/fs.js';
|
|
11
|
+
import { getIncludedIssueTypes } from './util/get-included-issue-types.js';
|
|
11
12
|
import { _dirGlob } from './util/glob.js';
|
|
12
13
|
import { _load } from './util/loader.js';
|
|
13
14
|
import { join, relative } from './util/path.js';
|
|
14
15
|
import { toCamelCase } from './util/plugin.js';
|
|
15
|
-
import { resolveIncludedIssueTypes } from './util/resolve-included-issue-types.js';
|
|
16
16
|
import { byPathDepth } from './util/workspace.js';
|
|
17
17
|
const { config: rawConfigArg, workspace: rawWorkspaceArg, include = [], exclude = [], dependencies = false, exports = false, } = parsedArgs.values;
|
|
18
18
|
const getDefaultWorkspaceConfig = (extensions) => {
|
|
@@ -55,7 +55,7 @@ export class ConfigurationChief {
|
|
|
55
55
|
this.isProduction = isProduction;
|
|
56
56
|
this.config = defaultConfig;
|
|
57
57
|
}
|
|
58
|
-
async
|
|
58
|
+
async init() {
|
|
59
59
|
const manifestPath = findFile(this.cwd, 'package.json');
|
|
60
60
|
const manifest = manifestPath && (await loadJSON(manifestPath));
|
|
61
61
|
if (!manifestPath || !manifest) {
|
|
@@ -150,8 +150,8 @@ export class ConfigurationChief {
|
|
|
150
150
|
this.ignoreWorkspaces = this.getIgnoredWorkspaces();
|
|
151
151
|
this.manifestWorkspaces = await this.getManifestWorkspaces();
|
|
152
152
|
this.additionalWorkspaces = await this.getAdditionalWorkspaces();
|
|
153
|
-
this.workspaces = this.
|
|
154
|
-
this.workspaceDirs = this.
|
|
153
|
+
this.workspaces = this.getEnabledWorkspaces();
|
|
154
|
+
this.workspaceDirs = this.getAllWorkspaces()
|
|
155
155
|
.sort(byPathDepth)
|
|
156
156
|
.reverse()
|
|
157
157
|
.map(dir => join(this.cwd, dir));
|
|
@@ -175,11 +175,11 @@ export class ConfigurationChief {
|
|
|
175
175
|
const globbedDirs = await _dirGlob({ patterns, cwd: this.cwd });
|
|
176
176
|
return new Set([...dirs, ...globbedDirs].filter(name => name !== ROOT_WORKSPACE_NAME && !this.manifestWorkspaces.has(name) && !this.ignoreWorkspaces.includes(name)));
|
|
177
177
|
}
|
|
178
|
-
|
|
178
|
+
getAllWorkspaces() {
|
|
179
179
|
return compact([ROOT_WORKSPACE_NAME, ...this.manifestWorkspaces.keys(), ...this.additionalWorkspaces]);
|
|
180
180
|
}
|
|
181
|
-
|
|
182
|
-
const allWorkspaces = this.
|
|
181
|
+
getEnabledWorkspaces() {
|
|
182
|
+
const allWorkspaces = this.getAllWorkspaces();
|
|
183
183
|
const workspace = (rawWorkspaceArg ?? '').replace(/\/$/, '');
|
|
184
184
|
const getAncestors = (name) => (ancestors, ancestorName) => {
|
|
185
185
|
if (name === ancestorName)
|
|
@@ -193,14 +193,14 @@ export class ConfigurationChief {
|
|
|
193
193
|
: allWorkspaces;
|
|
194
194
|
return workspaces.sort(byPathDepth).map(name => ({
|
|
195
195
|
name,
|
|
196
|
-
pkgName: this.manifestWorkspaces.get(name),
|
|
196
|
+
pkgName: this.manifestWorkspaces.get(name) ?? this.manifest?.name,
|
|
197
197
|
dir: join(this.cwd, name),
|
|
198
198
|
config: this.getConfigForWorkspace(name),
|
|
199
199
|
ancestors: allWorkspaces.reduce(getAncestors(name), []),
|
|
200
200
|
}));
|
|
201
201
|
}
|
|
202
202
|
getDescendentWorkspaces(name) {
|
|
203
|
-
return this.
|
|
203
|
+
return this.getAllWorkspaces()
|
|
204
204
|
.filter(workspaceName => workspaceName !== name)
|
|
205
205
|
.filter(workspaceName => name === ROOT_WORKSPACE_NAME || workspaceName.startsWith(name));
|
|
206
206
|
}
|
|
@@ -238,17 +238,20 @@ export class ConfigurationChief {
|
|
|
238
238
|
return this.config.workspaces[key];
|
|
239
239
|
return getDefaultWorkspaceConfig();
|
|
240
240
|
}
|
|
241
|
-
|
|
241
|
+
getIssueTypesToReport() {
|
|
242
242
|
const cliArgs = { include, exclude, dependencies, exports };
|
|
243
243
|
const config = {
|
|
244
244
|
include: this.config.include ?? [],
|
|
245
245
|
exclude: this.config.exclude ?? [],
|
|
246
246
|
isProduction: this.isProduction,
|
|
247
247
|
};
|
|
248
|
-
return
|
|
248
|
+
return getIncludedIssueTypes(cliArgs, config);
|
|
249
249
|
}
|
|
250
|
-
|
|
250
|
+
findWorkspaceByFilePath(filePath) {
|
|
251
251
|
const workspaceDir = this.workspaceDirs.find(workspaceDir => filePath.startsWith(workspaceDir + '/'));
|
|
252
252
|
return this.workspaces.find(workspace => workspace.dir === workspaceDir);
|
|
253
253
|
}
|
|
254
|
+
findWorkspaceByPackageName(packageName) {
|
|
255
|
+
return this.workspaces.find(workspace => workspace.pkgName === packageName);
|
|
256
|
+
}
|
|
254
257
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class ConsoleStreamer {
|
|
2
|
+
isEnabled: boolean;
|
|
3
|
+
private lines;
|
|
4
|
+
constructor({ isEnabled }: {
|
|
5
|
+
isEnabled?: boolean | undefined;
|
|
6
|
+
});
|
|
7
|
+
private clearLines;
|
|
8
|
+
private resetLines;
|
|
9
|
+
private update;
|
|
10
|
+
cast(message: string): void;
|
|
11
|
+
clear(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class ConsoleStreamer {
|
|
2
|
+
isEnabled = false;
|
|
3
|
+
lines = 0;
|
|
4
|
+
constructor({ isEnabled = false }) {
|
|
5
|
+
this.isEnabled = isEnabled;
|
|
6
|
+
}
|
|
7
|
+
clearLines(count) {
|
|
8
|
+
if (count > 0) {
|
|
9
|
+
for (let i = 0; i < count; i++) {
|
|
10
|
+
process.stdout.moveCursor(0, -1);
|
|
11
|
+
process.stdout.clearLine(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
process.stdout.cursorTo(0);
|
|
15
|
+
}
|
|
16
|
+
resetLines() {
|
|
17
|
+
this.clearLines(this.lines);
|
|
18
|
+
}
|
|
19
|
+
update(messages) {
|
|
20
|
+
this.resetLines();
|
|
21
|
+
process.stdout.write(messages.join('\n') + '\n');
|
|
22
|
+
this.lines = messages.length;
|
|
23
|
+
}
|
|
24
|
+
cast(message) {
|
|
25
|
+
if (!this.isEnabled)
|
|
26
|
+
return;
|
|
27
|
+
this.update([message]);
|
|
28
|
+
}
|
|
29
|
+
clear() {
|
|
30
|
+
if (!this.isEnabled)
|
|
31
|
+
return;
|
|
32
|
+
this.resetLines();
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,198 +1,142 @@
|
|
|
1
1
|
import { ConfigurationChief } from './configuration-chief.js';
|
|
2
|
+
import { ConsoleStreamer } from './console-streamer.js';
|
|
2
3
|
import { ROOT_WORKSPACE_NAME, DEFAULT_EXTENSIONS } from './constants.js';
|
|
3
4
|
import { DependencyDeputy } from './dependency-deputy.js';
|
|
4
5
|
import { IssueCollector } from './issue-collector.js';
|
|
5
6
|
import { PrincipalFactory } from './principal-factory.js';
|
|
6
|
-
import { ProgressUpdater } from './progress-updater.js';
|
|
7
7
|
import { compact } from './util/array.js';
|
|
8
8
|
import { debugLogObject, debugLogArray } from './util/debug.js';
|
|
9
|
-
import {
|
|
9
|
+
import { ConfigurationError } from './util/errors.js';
|
|
10
|
+
import { findFile, findFileWithExtensions } from './util/fs.js';
|
|
10
11
|
import { _glob } from './util/glob.js';
|
|
11
12
|
import { join } from './util/path.js';
|
|
12
|
-
import {
|
|
13
|
+
import { _require } from './util/require.js';
|
|
14
|
+
import { loadTSConfig as loadCompilerOptions } from './util/tsconfig-loader.js';
|
|
13
15
|
import { WorkspaceWorker } from './workspace-worker.js';
|
|
14
16
|
export const main = async (unresolvedConfiguration) => {
|
|
15
17
|
const { cwd, tsConfigFile, gitignore, isStrict, isProduction, isShowProgress } = unresolvedConfiguration;
|
|
16
|
-
const chief = new ConfigurationChief({ cwd, isProduction });
|
|
17
18
|
debugLogObject('Unresolved configuration (from CLI arguments)', unresolvedConfiguration);
|
|
18
|
-
const
|
|
19
|
-
const progress = new ProgressUpdater({ isShowProgress });
|
|
20
|
-
progress.updateMessage('Reading configuration and manifest files...');
|
|
21
|
-
await chief.loadLocalConfig();
|
|
19
|
+
const chief = new ConfigurationChief({ cwd, isProduction });
|
|
22
20
|
const deputy = new DependencyDeputy({ isStrict });
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const
|
|
21
|
+
const factory = new PrincipalFactory();
|
|
22
|
+
const collector = new IssueCollector({ cwd });
|
|
23
|
+
const console = new ConsoleStreamer({ isEnabled: isShowProgress });
|
|
24
|
+
console.cast('Reading workspace configuration(s)...');
|
|
25
|
+
await chief.init();
|
|
26
26
|
const compilers = chief.getCompilers();
|
|
27
|
+
const workspaces = chief.getEnabledWorkspaces();
|
|
28
|
+
const report = chief.getIssueTypesToReport();
|
|
29
|
+
debugLogObject('Included workspaces', workspaces);
|
|
27
30
|
const enabledPluginsStore = new Map();
|
|
28
|
-
collector.setReport(report);
|
|
29
|
-
progress.updateMessage('Scanning workspaces...');
|
|
30
|
-
const factory = new PrincipalFactory();
|
|
31
31
|
for (const workspace of workspaces) {
|
|
32
32
|
const { name, dir, config, ancestors } = workspace;
|
|
33
|
+
const { paths, ignoreDependencies } = config;
|
|
33
34
|
const isRoot = name === ROOT_WORKSPACE_NAME;
|
|
34
|
-
|
|
35
|
+
console.cast(`Analyzing workspace (${name})...`);
|
|
35
36
|
const manifestPath = isRoot ? chief.manifestPath : findFile(dir, 'package.json');
|
|
36
|
-
const manifest = isRoot ? chief.manifest : manifestPath && (
|
|
37
|
+
const manifest = isRoot ? chief.manifest : manifestPath && _require(manifestPath);
|
|
37
38
|
if (!manifestPath || !manifest)
|
|
38
|
-
|
|
39
|
-
const { ignoreDependencies } = chief.getConfigForWorkspace(name);
|
|
39
|
+
throw new ConfigurationError(`Unable to load package.json for ${name}`);
|
|
40
40
|
deputy.addWorkspace({ name, dir, manifestPath, manifest, ignoreDependencies });
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const principal = factory.getPrincipal({
|
|
44
|
-
cwd: dir,
|
|
45
|
-
compilerOptions: tsConfig?.compilerOptions,
|
|
46
|
-
paths: config.paths,
|
|
47
|
-
report,
|
|
48
|
-
compilers,
|
|
49
|
-
});
|
|
50
|
-
progress.updateMessage(`Resolving custom dependencies...${suffix}`);
|
|
51
|
-
const workspaceManifest = deputy.getWorkspaceManifest(name);
|
|
52
|
-
if (!workspaceManifest)
|
|
53
|
-
continue;
|
|
54
|
-
const negatedWorkspacePatterns = await chief.getNegatedWorkspacePatterns(name);
|
|
41
|
+
const compilerOptions = await loadCompilerOptions(join(dir, tsConfigFile ?? 'tsconfig.json'));
|
|
42
|
+
const principal = factory.getPrincipal({ cwd: dir, report: report, paths, compilerOptions, compilers });
|
|
55
43
|
const worker = new WorkspaceWorker({
|
|
56
44
|
name,
|
|
57
45
|
dir,
|
|
46
|
+
cwd,
|
|
58
47
|
config,
|
|
59
|
-
rootWorkspaceConfig: chief.getConfigForWorkspace(ROOT_WORKSPACE_NAME),
|
|
60
48
|
manifest,
|
|
61
|
-
rootConfig: chief.config,
|
|
62
|
-
negatedWorkspacePatterns,
|
|
63
|
-
rootWorkspaceDir: cwd,
|
|
64
49
|
isProduction,
|
|
50
|
+
rootIgnore: chief.config.ignore,
|
|
51
|
+
negatedWorkspacePatterns: chief.getNegatedWorkspacePatterns(name),
|
|
52
|
+
enabledPluginsInAncestors: ancestors.flatMap(ancestor => enabledPluginsStore.get(ancestor) ?? []),
|
|
65
53
|
});
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
await worker.initReferencedDependencies();
|
|
69
|
-
progress.updateMessage(`Finding entry and project files${suffix}...`);
|
|
54
|
+
await worker.init();
|
|
55
|
+
const sharedGlobOptions = { cwd, workingDir: dir, gitignore, ignore: worker.getIgnorePatterns() };
|
|
70
56
|
if (isProduction) {
|
|
71
57
|
{
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
patterns: worker.getProductionEntryFilePatterns(),
|
|
76
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
77
|
-
gitignore,
|
|
78
|
-
});
|
|
79
|
-
debugLogArray(`Found entry paths${suffix}`, workspaceEntryPaths);
|
|
58
|
+
const patterns = worker.getProductionEntryFilePatterns();
|
|
59
|
+
const workspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
60
|
+
debugLogArray(`Found entry paths (${name})`, workspaceEntryPaths);
|
|
80
61
|
principal.addEntryPaths(workspaceEntryPaths);
|
|
81
62
|
principal.skipExportsAnalysisFor(workspaceEntryPaths);
|
|
82
63
|
}
|
|
83
64
|
{
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
patterns: worker.getProductionPluginEntryFilePatterns(),
|
|
88
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
89
|
-
gitignore,
|
|
90
|
-
});
|
|
91
|
-
debugLogArray(`Found production plugin entry paths${suffix}`, pluginWorkspaceEntryPaths);
|
|
65
|
+
const patterns = worker.getProductionPluginEntryFilePatterns();
|
|
66
|
+
const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
67
|
+
debugLogArray(`Found production plugin entry paths (${name})`, pluginWorkspaceEntryPaths);
|
|
92
68
|
principal.addEntryPaths(pluginWorkspaceEntryPaths);
|
|
93
69
|
principal.skipExportsAnalysisFor(pluginWorkspaceEntryPaths);
|
|
94
70
|
}
|
|
95
71
|
{
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
patterns: worker.getProductionProjectFilePatterns(),
|
|
100
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
101
|
-
gitignore,
|
|
102
|
-
});
|
|
103
|
-
debugLogArray(`Found project paths${suffix}`, workspaceProjectPaths);
|
|
72
|
+
const patterns = worker.getProductionProjectFilePatterns();
|
|
73
|
+
const workspaceProjectPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
74
|
+
debugLogArray(`Found project paths (${name})`, workspaceProjectPaths);
|
|
104
75
|
workspaceProjectPaths.forEach(projectPath => principal.addProjectPath(projectPath));
|
|
105
76
|
}
|
|
106
77
|
}
|
|
107
78
|
else {
|
|
108
79
|
{
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
patterns: worker.getEntryFilePatterns(),
|
|
113
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
114
|
-
gitignore,
|
|
115
|
-
});
|
|
116
|
-
debugLogArray(`Found entry paths${suffix}`, workspaceEntryPaths);
|
|
80
|
+
const patterns = worker.getEntryFilePatterns();
|
|
81
|
+
const workspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
82
|
+
debugLogArray(`Found entry paths (${name})`, workspaceEntryPaths);
|
|
117
83
|
principal.addEntryPaths(workspaceEntryPaths);
|
|
118
84
|
principal.skipExportsAnalysisFor(workspaceEntryPaths);
|
|
119
85
|
}
|
|
120
86
|
{
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
patterns: worker.getProjectFilePatterns(),
|
|
125
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
126
|
-
gitignore,
|
|
127
|
-
});
|
|
128
|
-
debugLogArray(`Found project paths${suffix}`, workspaceProjectPaths);
|
|
87
|
+
const patterns = worker.getProjectFilePatterns();
|
|
88
|
+
const workspaceProjectPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
89
|
+
debugLogArray(`Found project paths (${name})`, workspaceProjectPaths);
|
|
129
90
|
workspaceProjectPaths.forEach(projectPath => principal.addProjectPath(projectPath));
|
|
130
91
|
}
|
|
131
92
|
{
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
patterns: worker.getPluginEntryFilePatterns(),
|
|
136
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
137
|
-
gitignore,
|
|
138
|
-
});
|
|
139
|
-
debugLogArray(`Found plugin entry paths${suffix}`, pluginWorkspaceEntryPaths);
|
|
93
|
+
const patterns = worker.getPluginEntryFilePatterns();
|
|
94
|
+
const pluginWorkspaceEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
95
|
+
debugLogArray(`Found plugin entry paths (${name})`, pluginWorkspaceEntryPaths);
|
|
140
96
|
principal.addEntryPaths(pluginWorkspaceEntryPaths);
|
|
141
97
|
principal.skipExportsAnalysisFor(pluginWorkspaceEntryPaths);
|
|
142
98
|
}
|
|
143
99
|
{
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
patterns: worker.getPluginProjectFilePatterns(),
|
|
148
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
149
|
-
gitignore,
|
|
150
|
-
});
|
|
151
|
-
debugLogArray(`Found plugin project paths${suffix}`, pluginWorkspaceProjectPaths);
|
|
100
|
+
const patterns = worker.getPluginProjectFilePatterns();
|
|
101
|
+
const pluginWorkspaceProjectPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
102
|
+
debugLogArray(`Found plugin project paths (${name})`, pluginWorkspaceProjectPaths);
|
|
152
103
|
pluginWorkspaceProjectPaths.forEach(projectPath => principal.addProjectPath(projectPath));
|
|
153
104
|
principal.skipExportsAnalysisFor(pluginWorkspaceProjectPaths);
|
|
154
105
|
}
|
|
155
106
|
{
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
patterns: compact(worker.getPluginConfigPatterns()),
|
|
160
|
-
ignore: worker.getWorkspaceIgnorePatterns(),
|
|
161
|
-
gitignore,
|
|
162
|
-
});
|
|
163
|
-
debugLogArray(`Found plugin configuration paths${suffix}`, configurationEntryPaths);
|
|
107
|
+
const patterns = compact(worker.getPluginConfigPatterns());
|
|
108
|
+
const configurationEntryPaths = await _glob({ ...sharedGlobOptions, patterns });
|
|
109
|
+
debugLogArray(`Found plugin configuration paths (${name})`, configurationEntryPaths);
|
|
164
110
|
principal.addEntryPaths(configurationEntryPaths);
|
|
165
111
|
principal.skipExportsAnalysisFor(configurationEntryPaths);
|
|
166
112
|
}
|
|
167
113
|
}
|
|
168
114
|
if (chief.resolvedConfigFilePath)
|
|
169
115
|
principal.addEntryPath(chief.resolvedConfigFilePath);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (!
|
|
180
|
-
|
|
181
|
-
collector.addIssue({ type: 'unlisted', filePath, symbol: specifier });
|
|
182
|
-
}
|
|
116
|
+
const dependencies = await worker.findAllDependencies();
|
|
117
|
+
const { referencedDependencies, peerDependencies, installedBinaries, entryFiles, enabledPlugins } = dependencies;
|
|
118
|
+
deputy.addPeerDependencies(name, peerDependencies);
|
|
119
|
+
deputy.setInstalledBinaries(name, installedBinaries);
|
|
120
|
+
principal.addEntryPaths(entryFiles);
|
|
121
|
+
enabledPluginsStore.set(name, enabledPlugins);
|
|
122
|
+
referencedDependencies.forEach(([filePath, specifier]) => {
|
|
123
|
+
const [isAdded, packageName] = deputy.maybeAddReferencedExternalDependency(workspace, specifier);
|
|
124
|
+
if (!isAdded) {
|
|
125
|
+
if (!ignoreDependencies.includes(specifier)) {
|
|
126
|
+
collector.addIssue({ type: 'unlisted', filePath, symbol: specifier });
|
|
183
127
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
128
|
+
}
|
|
129
|
+
else if (packageName && packageName !== specifier) {
|
|
130
|
+
const workspace = chief.findWorkspaceByPackageName(packageName);
|
|
131
|
+
if (workspace) {
|
|
132
|
+
const relativeSpecifier = specifier.replace(new RegExp(`^${packageName}`), '.');
|
|
133
|
+
const filePath = findFileWithExtensions(workspace.dir, relativeSpecifier, DEFAULT_EXTENSIONS);
|
|
134
|
+
if (filePath) {
|
|
135
|
+
principal.addEntryPath(filePath);
|
|
192
136
|
}
|
|
193
137
|
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
196
140
|
}
|
|
197
141
|
const principals = factory.getPrincipals();
|
|
198
142
|
for (const principal of principals) {
|
|
@@ -200,46 +144,44 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
200
144
|
const importedSymbols = new Map();
|
|
201
145
|
const analyzeSourceFile = (filePath) => {
|
|
202
146
|
collector.counters.processed++;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
147
|
+
const workspace = chief.findWorkspaceByFilePath(filePath);
|
|
148
|
+
if (workspace) {
|
|
149
|
+
const { imports, exports, duplicateExports } = principal.analyzeSourceFile(filePath);
|
|
150
|
+
const { internal, external, unresolved } = imports;
|
|
151
|
+
if (exports.size > 0)
|
|
152
|
+
exportedSymbols.set(filePath, exports);
|
|
153
|
+
for (const [specifierFilePath, importItems] of internal.entries()) {
|
|
154
|
+
const importedWorkspace = chief.findWorkspaceByFilePath(specifierFilePath);
|
|
155
|
+
if (importedWorkspace && importedWorkspace !== workspace) {
|
|
156
|
+
external.add(importItems.specifier);
|
|
157
|
+
}
|
|
158
|
+
if (!importedSymbols.has(specifierFilePath)) {
|
|
159
|
+
importedSymbols.set(specifierFilePath, importItems);
|
|
209
160
|
}
|
|
210
|
-
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
161
|
+
else {
|
|
162
|
+
const importedModule = importedSymbols.get(specifierFilePath);
|
|
163
|
+
for (const identifier of importItems.symbols) {
|
|
164
|
+
importedModule.symbols.add(identifier);
|
|
214
165
|
}
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
else {
|
|
219
|
-
const importedModule = importedSymbols.get(specifierFilePath);
|
|
220
|
-
for (const identifier of importItems.symbols) {
|
|
221
|
-
importedModule.symbols.add(identifier);
|
|
222
|
-
}
|
|
223
|
-
if (importItems.isReExported) {
|
|
224
|
-
importedModule.isReExported = importItems.isReExported;
|
|
225
|
-
importedModule.isReExportedBy.add(filePath);
|
|
226
|
-
}
|
|
166
|
+
if (importItems.isReExported) {
|
|
167
|
+
importedModule.isReExported = importItems.isReExported;
|
|
168
|
+
importedModule.isReExportedBy.add(filePath);
|
|
227
169
|
}
|
|
228
170
|
}
|
|
229
|
-
duplicateExports.forEach(symbols => {
|
|
230
|
-
const symbol = symbols.join('|');
|
|
231
|
-
collector.addIssue({ type: 'duplicates', filePath, symbol, symbols });
|
|
232
|
-
});
|
|
233
|
-
externalImports.forEach(specifier => {
|
|
234
|
-
const [isAdded, packageName] = deputy.maybeAddReferencedExternalDependency(workspace, specifier);
|
|
235
|
-
if (!isAdded && packageName) {
|
|
236
|
-
collector.addIssue({ type: 'unlisted', filePath, symbol: specifier });
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
unresolvedImports.forEach(moduleSpecifier => {
|
|
240
|
-
collector.addIssue({ type: 'unresolved', filePath, symbol: moduleSpecifier });
|
|
241
|
-
});
|
|
242
171
|
}
|
|
172
|
+
duplicateExports.forEach(symbols => {
|
|
173
|
+
const symbol = symbols.join('|');
|
|
174
|
+
collector.addIssue({ type: 'duplicates', filePath, symbol, symbols });
|
|
175
|
+
});
|
|
176
|
+
external.forEach(specifier => {
|
|
177
|
+
const [isAdded, packageName] = deputy.maybeAddReferencedExternalDependency(workspace, specifier);
|
|
178
|
+
if (!isAdded && packageName) {
|
|
179
|
+
collector.addIssue({ type: 'unlisted', filePath, symbol: specifier });
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
unresolved.forEach(moduleSpecifier => {
|
|
183
|
+
collector.addIssue({ type: 'unresolved', filePath, symbol: moduleSpecifier });
|
|
184
|
+
});
|
|
243
185
|
}
|
|
244
186
|
};
|
|
245
187
|
const isExportedInEntryFile = (importedModule) => {
|
|
@@ -250,9 +192,9 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
250
192
|
const hasFile = (file) => entryPaths.has(file) || isExportedInEntryFile(importedSymbols.get(file));
|
|
251
193
|
return isReExported ? Array.from(isReExportedBy).some(hasFile) : false;
|
|
252
194
|
};
|
|
253
|
-
|
|
195
|
+
console.cast('Running async compilers...');
|
|
254
196
|
await principal.runAsyncCompilers();
|
|
255
|
-
|
|
197
|
+
console.cast('Connecting the dots...');
|
|
256
198
|
const analyzedFiles = new Set();
|
|
257
199
|
let size = principal.entryPaths.size;
|
|
258
200
|
let round = 0;
|
|
@@ -269,7 +211,7 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
269
211
|
const unusedFiles = principal.getUnreferencedFiles();
|
|
270
212
|
collector.addFilesIssues(unusedFiles);
|
|
271
213
|
collector.setTotalFileCount(analyzedFiles.size + unusedFiles.length);
|
|
272
|
-
|
|
214
|
+
console.cast('Analyzing source files...');
|
|
273
215
|
for (const [filePath, exportItems] of exportedSymbols.entries()) {
|
|
274
216
|
const importedModule = importedSymbols.get(filePath);
|
|
275
217
|
if (importedModule) {
|
|
@@ -318,6 +260,6 @@ export const main = async (unresolvedConfiguration) => {
|
|
|
318
260
|
devDependencyIssues.forEach(issue => collector.addIssue(issue));
|
|
319
261
|
}
|
|
320
262
|
const { issues, counters } = collector.getIssues();
|
|
321
|
-
|
|
263
|
+
console.clear();
|
|
322
264
|
return { report, issues, counters };
|
|
323
265
|
};
|
|
@@ -1,24 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Issue, Report } from './types/issues.js';
|
|
1
|
+
import type { Issue } from './types/issues.js';
|
|
3
2
|
type IssueCollectorOptions = {
|
|
4
3
|
cwd: string;
|
|
5
|
-
report?: Report;
|
|
6
4
|
};
|
|
7
5
|
export declare class IssueCollector {
|
|
8
|
-
|
|
6
|
+
cwd: string;
|
|
9
7
|
issues: import("./types/issues.js").Issues;
|
|
10
8
|
counters: import("./types/issues.js").Counters;
|
|
11
|
-
lineRewriter: LineRewriter;
|
|
12
|
-
pluginEntryFile: Set<string>;
|
|
13
9
|
referencedFiles: Set<string>;
|
|
14
|
-
cwd:
|
|
15
|
-
constructor({ cwd, report }: IssueCollectorOptions);
|
|
10
|
+
constructor({ cwd }: IssueCollectorOptions);
|
|
16
11
|
setTotalFileCount(count: number): void;
|
|
17
12
|
addFilesIssues(filePaths: string[]): void;
|
|
18
13
|
addIssue(issue: Issue): void;
|
|
19
|
-
setReport(report: Report): void;
|
|
20
14
|
getIssues(): {
|
|
21
|
-
report: Report;
|
|
22
15
|
issues: import("./types/issues.js").Issues;
|
|
23
16
|
counters: import("./types/issues.js").Counters;
|
|
24
17
|
};
|
package/dist/issue-collector.js
CHANGED
|
@@ -1,22 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LineRewriter } from './util/log.js';
|
|
1
|
+
import { initIssues, initCounters } from './issues/initializers.js';
|
|
3
2
|
import { relative } from './util/path.js';
|
|
4
3
|
export class IssueCollector {
|
|
5
|
-
report;
|
|
6
|
-
issues;
|
|
7
|
-
counters;
|
|
8
|
-
lineRewriter;
|
|
9
|
-
pluginEntryFile;
|
|
10
|
-
referencedFiles;
|
|
11
4
|
cwd;
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
issues = initIssues();
|
|
6
|
+
counters = initCounters();
|
|
7
|
+
referencedFiles = new Set();
|
|
8
|
+
constructor({ cwd }) {
|
|
14
9
|
this.cwd = cwd;
|
|
15
|
-
this.report = report ?? initReport();
|
|
16
|
-
this.issues = initIssues();
|
|
17
|
-
this.counters = initCounters();
|
|
18
|
-
this.pluginEntryFile = new Set();
|
|
19
|
-
this.referencedFiles = new Set();
|
|
20
10
|
}
|
|
21
11
|
setTotalFileCount(count) {
|
|
22
12
|
this.counters.total = count;
|
|
@@ -38,12 +28,8 @@ export class IssueCollector {
|
|
|
38
28
|
this.counters[issue.type]++;
|
|
39
29
|
}
|
|
40
30
|
}
|
|
41
|
-
setReport(report) {
|
|
42
|
-
this.report = report;
|
|
43
|
-
}
|
|
44
31
|
getIssues() {
|
|
45
32
|
return {
|
|
46
|
-
report: this.report,
|
|
47
33
|
issues: this.issues,
|
|
48
34
|
counters: this.counters,
|
|
49
35
|
};
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type Options = {
|
|
2
|
+
dir: string;
|
|
3
|
+
packageName: string;
|
|
4
|
+
cwd: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const getPackageManifest: ({ dir, packageName, cwd }: Options) => Promise<any>;
|
|
7
|
+
export {};
|
package/dist/manifest/helpers.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { join } from '../util/path.js';
|
|
2
2
|
import { _require } from '../util/require.js';
|
|
3
|
-
export const getPackageManifest = async (
|
|
3
|
+
export const getPackageManifest = async ({ dir, packageName, cwd }) => {
|
|
4
4
|
try {
|
|
5
|
-
return _require(join(
|
|
5
|
+
return _require(join(dir, 'node_modules', packageName, 'package.json'));
|
|
6
6
|
}
|
|
7
7
|
catch (error) {
|
|
8
|
-
if (
|
|
8
|
+
if (dir !== cwd) {
|
|
9
9
|
try {
|
|
10
10
|
return _require(join(cwd, 'node_modules', packageName, 'package.json'));
|
|
11
11
|
}
|
package/dist/manifest/index.d.ts
CHANGED
|
@@ -4,12 +4,11 @@ import type { PackageJson } from 'type-fest';
|
|
|
4
4
|
type Options = {
|
|
5
5
|
config: WorkspaceConfiguration;
|
|
6
6
|
manifest: PackageJson;
|
|
7
|
-
isRoot: boolean;
|
|
8
7
|
isProduction: boolean;
|
|
9
8
|
dir: string;
|
|
10
9
|
cwd: string;
|
|
11
10
|
};
|
|
12
|
-
export declare const findDependencies: ({ config, manifest,
|
|
11
|
+
export declare const findDependencies: ({ config, manifest, isProduction, dir, cwd }: Options) => Promise<{
|
|
13
12
|
dependencies: string[];
|
|
14
13
|
peerDependencies: PeerDependencies;
|
|
15
14
|
installedBinaries: InstalledBinaries;
|
package/dist/manifest/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { _getReferencesFromScripts } from '../util/binaries/index.js';
|
|
2
2
|
import { timerify } from '../util/performance.js';
|
|
3
3
|
import { getPackageManifest } from './helpers.js';
|
|
4
|
-
const findManifestDependencies = async ({ config, manifest,
|
|
4
|
+
const findManifestDependencies = async ({ config, manifest, isProduction, dir, cwd }) => {
|
|
5
5
|
const { ignoreBinaries } = config;
|
|
6
6
|
const scriptFilter = isProduction ? ['start', 'postinstall'] : [];
|
|
7
7
|
const referencedDependencies = new Set();
|
|
@@ -20,7 +20,7 @@ const findManifestDependencies = async ({ config, manifest, isRoot, isProduction
|
|
|
20
20
|
const installedBinaries = new Map();
|
|
21
21
|
const packageNames = [...Object.keys(manifest.dependencies ?? {}), ...Object.keys(manifest.devDependencies ?? {})];
|
|
22
22
|
for (const packageName of packageNames) {
|
|
23
|
-
const manifest = await getPackageManifest(dir, packageName,
|
|
23
|
+
const manifest = await getPackageManifest({ dir, packageName, cwd });
|
|
24
24
|
if (manifest) {
|
|
25
25
|
const binaries = typeof manifest.bin === 'string' ? [packageName] : Object.keys(manifest.bin ?? {});
|
|
26
26
|
binaries.forEach(binaryName => {
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
export declare class ConsoleStreamer {
|
|
2
|
+
isEnabled: boolean;
|
|
3
|
+
private lines;
|
|
4
|
+
constructor({ isEnabled }: {
|
|
5
|
+
isEnabled?: boolean | undefined;
|
|
6
|
+
});
|
|
7
|
+
private clearLines;
|
|
8
|
+
private resetLines;
|
|
9
|
+
private update;
|
|
10
|
+
cast(message: string): void;
|
|
11
|
+
clear(): void;
|
|
12
12
|
}
|
|
13
|
-
export {};
|
package/dist/progress-updater.js
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this.lineRewriter = new LineRewriter();
|
|
7
|
-
this.setIsShowProgress(isShowProgress);
|
|
1
|
+
export class ConsoleStreamer {
|
|
2
|
+
isEnabled = false;
|
|
3
|
+
lines = 0;
|
|
4
|
+
constructor({ isEnabled = false }) {
|
|
5
|
+
this.isEnabled = isEnabled;
|
|
8
6
|
}
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
clearLines(count) {
|
|
8
|
+
if (count > 0) {
|
|
9
|
+
for (let i = 0; i < count; i++) {
|
|
10
|
+
process.stdout.moveCursor(0, -1);
|
|
11
|
+
process.stdout.clearLine(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
process.stdout.cursorTo(0);
|
|
11
15
|
}
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
resetLines() {
|
|
17
|
+
this.clearLines(this.lines);
|
|
18
|
+
}
|
|
19
|
+
update(messages) {
|
|
20
|
+
this.resetLines();
|
|
21
|
+
process.stdout.write(messages.join('\n') + '\n');
|
|
22
|
+
this.lines = messages.length;
|
|
23
|
+
}
|
|
24
|
+
cast(message) {
|
|
25
|
+
if (!this.isEnabled)
|
|
14
26
|
return;
|
|
15
|
-
this.
|
|
27
|
+
this.update([message]);
|
|
16
28
|
}
|
|
17
|
-
|
|
18
|
-
if (!this.
|
|
29
|
+
clear() {
|
|
30
|
+
if (!this.isEnabled)
|
|
19
31
|
return;
|
|
20
|
-
this.
|
|
32
|
+
this.resetLines();
|
|
21
33
|
}
|
|
22
34
|
}
|
|
@@ -38,9 +38,11 @@ export declare class ProjectPrincipal {
|
|
|
38
38
|
private getProgramSourceFiles;
|
|
39
39
|
getUnreferencedFiles(): string[];
|
|
40
40
|
analyzeSourceFile(filePath: string): {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
imports: {
|
|
42
|
+
internal: import("./types/ast.js").Imports;
|
|
43
|
+
unresolved: Set<string>;
|
|
44
|
+
external: Set<string>;
|
|
45
|
+
};
|
|
44
46
|
exports: import("./types/ast.js").ExportItems;
|
|
45
47
|
duplicateExports: string[][];
|
|
46
48
|
};
|
|
@@ -107,17 +107,19 @@ export class ProjectPrincipal {
|
|
|
107
107
|
const sourceFile = this.backend.program?.getSourceFile(filePath);
|
|
108
108
|
if (!sourceFile)
|
|
109
109
|
throw new Error(`Unable to find ${filePath}`);
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
|
|
110
|
+
const skipTypeOnly = !this.isReportTypes;
|
|
111
|
+
const skipExports = this.skipExportsAnalysis.has(filePath);
|
|
112
|
+
const { imports, exports, duplicateExports } = getImportsAndExports(sourceFile, { skipTypeOnly, skipExports });
|
|
113
|
+
const { internal, unresolved, external } = imports;
|
|
114
|
+
const unresolvedImports = new Set();
|
|
115
|
+
unresolved.forEach(specifier => {
|
|
114
116
|
if (specifier.startsWith('http')) {
|
|
115
117
|
return;
|
|
116
118
|
}
|
|
117
119
|
const resolvedModule = this.resolveModule(specifier, filePath);
|
|
118
120
|
if (resolvedModule) {
|
|
119
121
|
if (resolvedModule.isExternalLibraryImport) {
|
|
120
|
-
|
|
122
|
+
external.add(specifier);
|
|
121
123
|
}
|
|
122
124
|
else {
|
|
123
125
|
this.addEntryPath(resolvedModule.resolvedFileName);
|
|
@@ -125,19 +127,27 @@ export class ProjectPrincipal {
|
|
|
125
127
|
}
|
|
126
128
|
else {
|
|
127
129
|
if (/^(@|[a-z])/.test(specifier)) {
|
|
128
|
-
|
|
130
|
+
external.add(specifier);
|
|
129
131
|
}
|
|
130
132
|
else {
|
|
131
133
|
const ext = extname(specifier);
|
|
132
134
|
if (!ext || (ext !== '.json' && !IGNORED_FILE_EXTENSIONS.includes(ext))) {
|
|
133
|
-
|
|
135
|
+
unresolvedImports.add(specifier);
|
|
134
136
|
}
|
|
135
137
|
else {
|
|
136
138
|
}
|
|
137
139
|
}
|
|
138
140
|
}
|
|
139
141
|
});
|
|
140
|
-
return {
|
|
142
|
+
return {
|
|
143
|
+
imports: {
|
|
144
|
+
internal,
|
|
145
|
+
unresolved: unresolvedImports,
|
|
146
|
+
external,
|
|
147
|
+
},
|
|
148
|
+
exports,
|
|
149
|
+
duplicateExports,
|
|
150
|
+
};
|
|
141
151
|
}
|
|
142
152
|
resolveModule(specifier, filePath = specifier) {
|
|
143
153
|
const module = ts.resolveModuleName(specifier, filePath, this.compilerOptions, this.backend.languageServiceHost);
|
|
@@ -5,9 +5,11 @@ type Options = {
|
|
|
5
5
|
skipExports: boolean;
|
|
6
6
|
};
|
|
7
7
|
export declare const getImportsAndExports: (sourceFile: BoundSourceFile, options: Options) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
imports: {
|
|
9
|
+
internal: Imports;
|
|
10
|
+
external: Set<string>;
|
|
11
|
+
unresolved: Set<string>;
|
|
12
|
+
};
|
|
11
13
|
exports: ExportItems;
|
|
12
14
|
duplicateExports: string[][];
|
|
13
15
|
};
|
|
@@ -339,5 +339,13 @@ export const getImportsAndExports = (sourceFile, options) => {
|
|
|
339
339
|
};
|
|
340
340
|
visit(sourceFile);
|
|
341
341
|
const duplicateExports = Object.values(aliasedExports);
|
|
342
|
-
return {
|
|
342
|
+
return {
|
|
343
|
+
imports: {
|
|
344
|
+
internal: internalImports,
|
|
345
|
+
external: externalImports,
|
|
346
|
+
unresolved: unresolvedImports,
|
|
347
|
+
},
|
|
348
|
+
exports,
|
|
349
|
+
duplicateExports,
|
|
350
|
+
};
|
|
343
351
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Report } from '../types/issues.js';
|
|
2
|
+
type CLIArguments = {
|
|
3
|
+
include: string[];
|
|
4
|
+
exclude: string[];
|
|
5
|
+
dependencies: boolean;
|
|
6
|
+
exports: boolean;
|
|
7
|
+
};
|
|
8
|
+
type Options = {
|
|
9
|
+
isProduction?: boolean;
|
|
10
|
+
include?: string[];
|
|
11
|
+
exclude?: string[];
|
|
12
|
+
dependencies?: boolean;
|
|
13
|
+
exports?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export declare const getIncludedIssueTypes: (cliArgs: CLIArguments, { include, exclude, isProduction }?: Options) => Report;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ISSUE_TYPES } from '../constants.js';
|
|
2
|
+
export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isProduction = false } = {}) => {
|
|
3
|
+
if (cliArgs.dependencies) {
|
|
4
|
+
cliArgs.include = [...cliArgs.include, 'dependencies', 'unlisted', 'unresolved'];
|
|
5
|
+
}
|
|
6
|
+
if (cliArgs.exports) {
|
|
7
|
+
const exports = ['exports', 'nsExports', 'classMembers', 'types', 'nsTypes', 'enumMembers', 'duplicates'];
|
|
8
|
+
cliArgs.include = [...cliArgs.include, ...exports];
|
|
9
|
+
}
|
|
10
|
+
const normalizedIncludesArg = cliArgs.include.map(value => value.split(',')).flat();
|
|
11
|
+
const normalizedExcludesArg = cliArgs.exclude.map(value => value.split(',')).flat();
|
|
12
|
+
const excludes = exclude.filter(exclude => !normalizedIncludesArg.includes(exclude));
|
|
13
|
+
const includes = include.filter(include => !normalizedExcludesArg.includes(include));
|
|
14
|
+
const _include = [normalizedIncludesArg, includes].flat();
|
|
15
|
+
const _exclude = [normalizedExcludesArg, excludes].flat();
|
|
16
|
+
if (isProduction) {
|
|
17
|
+
_exclude.push('types');
|
|
18
|
+
_exclude.push('nsTypes');
|
|
19
|
+
_exclude.push('enumMembers');
|
|
20
|
+
_exclude.push('devDependencies');
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
if (_include.includes('dependencies'))
|
|
24
|
+
_include.push('devDependencies');
|
|
25
|
+
if (_exclude.includes('dependencies'))
|
|
26
|
+
_exclude.push('devDependencies');
|
|
27
|
+
}
|
|
28
|
+
const included = (_include.length > 0 ? _include : ISSUE_TYPES).filter(group => !_exclude.includes(group));
|
|
29
|
+
return ISSUE_TYPES.reduce((types, group) => ((types[group] = included.includes(group)), types), {});
|
|
30
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IncludedIssueTypes } from '../types/issues.js';
|
|
2
2
|
type CLIArguments = {
|
|
3
3
|
include: string[];
|
|
4
4
|
exclude: string[];
|
|
@@ -12,5 +12,5 @@ type Options = {
|
|
|
12
12
|
dependencies?: boolean;
|
|
13
13
|
exports?: boolean;
|
|
14
14
|
};
|
|
15
|
-
export declare const
|
|
15
|
+
export declare const getIncludedIssueTypes: (cliArgs: CLIArguments, { include, exclude, isProduction }?: Options) => IncludedIssueTypes;
|
|
16
16
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ISSUE_TYPES } from '../constants.js';
|
|
2
|
-
export const
|
|
2
|
+
export const getIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isProduction = false } = {}) => {
|
|
3
3
|
if (cliArgs.dependencies) {
|
|
4
4
|
cliArgs.include = [...cliArgs.include, 'dependencies', 'unlisted', 'unresolved'];
|
|
5
5
|
}
|
|
@@ -3,6 +3,6 @@ import { isFile } from './fs.js';
|
|
|
3
3
|
export const loadTSConfig = async (tsConfigFilePath) => {
|
|
4
4
|
if (isFile(tsConfigFilePath)) {
|
|
5
5
|
const config = ts.readConfigFile(tsConfigFilePath, ts.sys.readFile);
|
|
6
|
-
return config.config;
|
|
6
|
+
return config.config.compilerOptions;
|
|
7
7
|
}
|
|
8
8
|
};
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.0.0-alpha.
|
|
1
|
+
export declare const version = "2.0.0-alpha.4";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.0.0-alpha.
|
|
1
|
+
export const version = '2.0.0-alpha.4';
|
|
@@ -4,36 +4,36 @@ import type { PackageJson } from 'type-fest';
|
|
|
4
4
|
type WorkspaceManagerOptions = {
|
|
5
5
|
name: string;
|
|
6
6
|
dir: string;
|
|
7
|
+
cwd: string;
|
|
7
8
|
config: WorkspaceConfiguration;
|
|
8
9
|
manifest: PackageJson;
|
|
9
|
-
|
|
10
|
-
rootConfig: Configuration;
|
|
10
|
+
rootIgnore: Configuration['ignore'];
|
|
11
11
|
negatedWorkspacePatterns: string[];
|
|
12
|
-
|
|
12
|
+
enabledPluginsInAncestors: string[];
|
|
13
13
|
isProduction: boolean;
|
|
14
14
|
};
|
|
15
15
|
type ReferencedDependencies = Set<[string, string]>;
|
|
16
16
|
export declare class WorkspaceWorker {
|
|
17
17
|
name: string;
|
|
18
18
|
dir: string;
|
|
19
|
+
cwd: string;
|
|
19
20
|
config: WorkspaceConfiguration;
|
|
20
|
-
rootWorkspaceConfig: WorkspaceConfiguration;
|
|
21
|
-
rootConfig: Configuration;
|
|
22
21
|
manifest: PackageJson;
|
|
23
|
-
|
|
22
|
+
isProduction: boolean;
|
|
23
|
+
rootIgnore: Configuration['ignore'];
|
|
24
|
+
negatedWorkspacePatterns: string[];
|
|
25
|
+
enabledPluginsInAncestors: string[];
|
|
26
|
+
enabled: Record<PluginName, boolean>;
|
|
27
|
+
enabledPlugins: PluginName[];
|
|
24
28
|
referencedDependencies: ReferencedDependencies;
|
|
25
29
|
peerDependencies: PeerDependencies;
|
|
26
30
|
installedBinaries: InstalledBinaries;
|
|
27
31
|
entryFiles: Set<string>;
|
|
28
|
-
negatedWorkspacePatterns:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
isProduction: boolean;
|
|
33
|
-
constructor({ name, dir, config, rootWorkspaceConfig, rootConfig, negatedWorkspacePatterns, manifest, rootWorkspaceDir, isProduction, }: WorkspaceManagerOptions);
|
|
32
|
+
constructor({ name, dir, cwd, config, manifest, isProduction, rootIgnore, negatedWorkspacePatterns, enabledPluginsInAncestors, }: WorkspaceManagerOptions);
|
|
33
|
+
init(): Promise<void>;
|
|
34
|
+
private setEnabledPlugins;
|
|
35
|
+
private initReferencedDependencies;
|
|
34
36
|
private getConfigForPlugin;
|
|
35
|
-
setEnabledPlugins(enabledPluginsInAncestors: string[]): Promise<void>;
|
|
36
|
-
initReferencedDependencies(): Promise<void>;
|
|
37
37
|
getEntryFilePatterns(): string[];
|
|
38
38
|
getProjectFilePatterns(): string[];
|
|
39
39
|
getPluginEntryFilePatterns(isIncludeProductionEntryFiles?: boolean): string[];
|
|
@@ -43,14 +43,14 @@ export declare class WorkspaceWorker {
|
|
|
43
43
|
getProductionProjectFilePatterns(): string[];
|
|
44
44
|
getProductionPluginEntryFilePatterns(): string[];
|
|
45
45
|
private getConfigurationEntryFilePattern;
|
|
46
|
-
|
|
47
|
-
findDependenciesByPlugins
|
|
48
|
-
|
|
46
|
+
getIgnorePatterns(): string[];
|
|
47
|
+
private findDependenciesByPlugins;
|
|
48
|
+
findAllDependencies(): Promise<{
|
|
49
49
|
peerDependencies: PeerDependencies;
|
|
50
50
|
installedBinaries: InstalledBinaries;
|
|
51
51
|
referencedDependencies: ReferencedDependencies;
|
|
52
52
|
entryFiles: Set<string>;
|
|
53
53
|
enabledPlugins: ("typescript" | "babel" | "capacitor" | "changesets" | "commitlint" | "cypress" | "eslint" | "gatsby" | "husky" | "jest" | "markdownlint" | "mocha" | "next" | "nx" | "nyc" | "playwright" | "postcss" | "prettier" | "remark" | "remix" | "rollup" | "sentry" | "storybook" | "stryker" | "vitest" | "webpack" | "githubActions" | "lefthook" | "lintStaged" | "npmPackageJsonLint" | "releaseIt" | "typedoc")[];
|
|
54
|
-
}
|
|
54
|
+
}>;
|
|
55
55
|
}
|
|
56
56
|
export {};
|
package/dist/workspace-worker.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TEST_FILE_PATTERNS } from './constants.js';
|
|
2
2
|
import * as npm from './manifest/index.js';
|
|
3
3
|
import * as plugins from './plugins/index.js';
|
|
4
4
|
import { debugLogArray, debugLogObject } from './util/debug.js';
|
|
@@ -8,45 +8,48 @@ const negatedTestFilePatterns = TEST_FILE_PATTERNS.map(negate);
|
|
|
8
8
|
export class WorkspaceWorker {
|
|
9
9
|
name;
|
|
10
10
|
dir;
|
|
11
|
+
cwd;
|
|
11
12
|
config;
|
|
12
|
-
rootWorkspaceConfig;
|
|
13
|
-
rootConfig;
|
|
14
13
|
manifest;
|
|
15
|
-
|
|
14
|
+
isProduction;
|
|
15
|
+
rootIgnore;
|
|
16
|
+
negatedWorkspacePatterns = [];
|
|
17
|
+
enabledPluginsInAncestors;
|
|
18
|
+
enabled;
|
|
19
|
+
enabledPlugins = [];
|
|
16
20
|
referencedDependencies = new Set();
|
|
17
21
|
peerDependencies = new Map();
|
|
18
22
|
installedBinaries = new Map();
|
|
19
23
|
entryFiles = new Set();
|
|
20
|
-
negatedWorkspacePatterns
|
|
21
|
-
enabled;
|
|
22
|
-
enabledPlugins = [];
|
|
23
|
-
isRoot;
|
|
24
|
-
isProduction;
|
|
25
|
-
constructor({ name, dir, config, rootWorkspaceConfig, rootConfig, negatedWorkspacePatterns, manifest, rootWorkspaceDir, isProduction, }) {
|
|
24
|
+
constructor({ name, dir, cwd, config, manifest, isProduction, rootIgnore, negatedWorkspacePatterns, enabledPluginsInAncestors, }) {
|
|
26
25
|
this.name = name;
|
|
27
26
|
this.dir = dir;
|
|
27
|
+
this.cwd = cwd;
|
|
28
28
|
this.config = config;
|
|
29
|
-
this.
|
|
29
|
+
this.manifest = manifest;
|
|
30
30
|
this.isProduction = isProduction;
|
|
31
|
-
this.
|
|
32
|
-
this.rootWorkspaceConfig = rootWorkspaceConfig;
|
|
33
|
-
this.rootWorkspaceDir = rootWorkspaceDir;
|
|
31
|
+
this.rootIgnore = rootIgnore;
|
|
34
32
|
this.negatedWorkspacePatterns = negatedWorkspacePatterns;
|
|
35
|
-
this.
|
|
33
|
+
this.enabledPluginsInAncestors = enabledPluginsInAncestors;
|
|
36
34
|
this.enabled = Object.keys(plugins).reduce((enabled, pluginName) => ({ ...enabled, [pluginName]: false }), {});
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
async init() {
|
|
37
|
+
await this.setEnabledPlugins();
|
|
38
|
+
await this.initReferencedDependencies();
|
|
40
39
|
}
|
|
41
|
-
async setEnabledPlugins(
|
|
42
|
-
const
|
|
43
|
-
const
|
|
40
|
+
async setEnabledPlugins() {
|
|
41
|
+
const manifest = this.manifest;
|
|
42
|
+
const deps = Object.keys(manifest.dependencies ?? {});
|
|
43
|
+
const devDeps = Object.keys(manifest.devDependencies ?? {});
|
|
44
|
+
const dependencies = new Set([...deps, ...devDeps]);
|
|
44
45
|
const pluginEntries = Object.entries(plugins);
|
|
45
46
|
for (const [pluginName, plugin] of pluginEntries) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.
|
|
49
|
-
|
|
47
|
+
if (this.config[pluginName] === false)
|
|
48
|
+
continue;
|
|
49
|
+
const isEnabledInAncestor = this.enabledPluginsInAncestors.includes(pluginName);
|
|
50
|
+
if (isEnabledInAncestor || (await plugin.isEnabled({ cwd: this.dir, manifest, dependencies }))) {
|
|
51
|
+
this.enabled[pluginName] = true;
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
54
|
this.enabledPlugins = pluginEntries.filter(([name]) => this.enabled[name]).map(([name]) => name);
|
|
52
55
|
const enabledPluginNames = this.enabledPlugins.map(name => plugins[name].NAME);
|
|
@@ -56,10 +59,9 @@ export class WorkspaceWorker {
|
|
|
56
59
|
const { dependencies, peerDependencies, installedBinaries, entryFiles } = await npm.findDependencies({
|
|
57
60
|
config: this.config,
|
|
58
61
|
manifest: this.manifest,
|
|
59
|
-
isRoot: this.isRoot,
|
|
60
62
|
isProduction: this.isProduction,
|
|
61
63
|
dir: this.dir,
|
|
62
|
-
cwd: this.
|
|
64
|
+
cwd: this.cwd,
|
|
63
65
|
});
|
|
64
66
|
const filePath = join(this.dir, 'package.json');
|
|
65
67
|
dependencies.forEach(dependency => this.referencedDependencies.add([filePath, dependency]));
|
|
@@ -67,6 +69,9 @@ export class WorkspaceWorker {
|
|
|
67
69
|
this.peerDependencies = peerDependencies;
|
|
68
70
|
this.installedBinaries = installedBinaries;
|
|
69
71
|
}
|
|
72
|
+
getConfigForPlugin(pluginName) {
|
|
73
|
+
return this.config[pluginName] ?? { config: null, entry: null, project: null };
|
|
74
|
+
}
|
|
70
75
|
getEntryFilePatterns() {
|
|
71
76
|
const { entry } = this.config;
|
|
72
77
|
if (entry.length === 0)
|
|
@@ -187,10 +192,12 @@ export class WorkspaceWorker {
|
|
|
187
192
|
}
|
|
188
193
|
return [];
|
|
189
194
|
}
|
|
190
|
-
|
|
191
|
-
return [...this.
|
|
195
|
+
getIgnorePatterns() {
|
|
196
|
+
return [...this.rootIgnore, ...this.config.ignore.map(pattern => prependDirToPattern(this.name, pattern))];
|
|
192
197
|
}
|
|
193
198
|
async findDependenciesByPlugins() {
|
|
199
|
+
const cwd = this.dir;
|
|
200
|
+
const ignore = this.getIgnorePatterns();
|
|
194
201
|
for (const [pluginName, plugin] of Object.entries(plugins)) {
|
|
195
202
|
const isIncludePlugin = this.isProduction ? `PRODUCTION_ENTRY_FILE_PATTERNS` in plugin : true;
|
|
196
203
|
if (this.enabled[pluginName] && isIncludePlugin) {
|
|
@@ -200,8 +207,6 @@ export class WorkspaceWorker {
|
|
|
200
207
|
if (!pluginConfig)
|
|
201
208
|
continue;
|
|
202
209
|
const patterns = this.getConfigurationEntryFilePattern(pluginName);
|
|
203
|
-
const cwd = this.dir;
|
|
204
|
-
const ignore = this.getWorkspaceIgnorePatterns();
|
|
205
210
|
const configFilePaths = await _pureGlob({ patterns, cwd, ignore });
|
|
206
211
|
debugLogArray(`Found ${plugin.NAME} config file paths`, configFilePaths);
|
|
207
212
|
if (configFilePaths.length === 0)
|
|
@@ -224,13 +229,15 @@ export class WorkspaceWorker {
|
|
|
224
229
|
entryFiles.forEach(entryFile => pluginEntryFiles.add(entryFile));
|
|
225
230
|
}
|
|
226
231
|
debugLogArray(`Dependencies referenced in ${plugin.NAME}`, pluginDependencies);
|
|
227
|
-
if (pluginEntryFiles.size > 0)
|
|
232
|
+
if (pluginEntryFiles.size > 0) {
|
|
228
233
|
debugLogArray(`Entry files referenced in ${plugin.NAME}`, pluginEntryFiles);
|
|
234
|
+
}
|
|
229
235
|
}
|
|
230
236
|
}
|
|
231
237
|
}
|
|
232
238
|
}
|
|
233
|
-
|
|
239
|
+
async findAllDependencies() {
|
|
240
|
+
await this.findDependenciesByPlugins();
|
|
234
241
|
return {
|
|
235
242
|
peerDependencies: this.peerDependencies,
|
|
236
243
|
installedBinaries: this.installedBinaries,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knip",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.4",
|
|
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",
|