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 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
- loadLocalConfig(): Promise<void>;
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 getWorkspaces;
44
- getActiveWorkspaces(): {
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
- resolveIncludedIssueTypes(): import("./types/issues.js").Report;
58
- findWorkspace(filePath: string): Workspace | undefined;
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 loadLocalConfig() {
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.getActiveWorkspaces();
154
- this.workspaceDirs = this.getWorkspaces()
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
- getWorkspaces() {
178
+ getAllWorkspaces() {
179
179
  return compact([ROOT_WORKSPACE_NAME, ...this.manifestWorkspaces.keys(), ...this.additionalWorkspaces]);
180
180
  }
181
- getActiveWorkspaces() {
182
- const allWorkspaces = this.getWorkspaces();
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.getWorkspaces()
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
- resolveIncludedIssueTypes() {
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 resolveIncludedIssueTypes(cliArgs, config);
248
+ return getIncludedIssueTypes(cliArgs, config);
249
249
  }
250
- findWorkspace(filePath) {
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 { findFile, loadJSON, findFileWithExtensions } from './util/fs.js';
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 { loadTSConfig } from './util/tsconfig-loader.js';
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 collector = new IssueCollector({ cwd });
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 workspaces = chief.getActiveWorkspaces();
24
- debugLogObject('Included workspaces', workspaces);
25
- const report = chief.resolveIncludedIssueTypes();
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
- const suffix = isRoot ? '' : ` (${name})`;
35
+ console.cast(`Analyzing workspace (${name})...`);
35
36
  const manifestPath = isRoot ? chief.manifestPath : findFile(dir, 'package.json');
36
- const manifest = isRoot ? chief.manifest : manifestPath && (await loadJSON(manifestPath));
37
+ const manifest = isRoot ? chief.manifest : manifestPath && _require(manifestPath);
37
38
  if (!manifestPath || !manifest)
38
- continue;
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 tsConfigFilePath = join(dir, tsConfigFile ?? 'tsconfig.json');
42
- const tsConfig = await loadTSConfig(tsConfigFilePath);
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
- const enabledPluginsInAncestors = ancestors.flatMap(ancestor => enabledPluginsStore.get(ancestor) ?? []);
67
- await worker.setEnabledPlugins(enabledPluginsInAncestors);
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 workspaceEntryPaths = await _glob({
73
- cwd,
74
- workingDir: dir,
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 pluginWorkspaceEntryPaths = await _glob({
85
- cwd,
86
- workingDir: dir,
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 workspaceProjectPaths = await _glob({
97
- cwd,
98
- workingDir: dir,
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 workspaceEntryPaths = await _glob({
110
- cwd,
111
- workingDir: dir,
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 workspaceProjectPaths = await _glob({
122
- cwd,
123
- workingDir: dir,
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 pluginWorkspaceEntryPaths = await _glob({
133
- cwd,
134
- workingDir: dir,
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 pluginWorkspaceProjectPaths = await _glob({
145
- cwd,
146
- workingDir: dir,
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 configurationEntryPaths = await _glob({
157
- cwd,
158
- workingDir: dir,
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
- if (report.dependencies || report.unlisted || report.files) {
171
- await worker.findDependenciesByPlugins();
172
- const { referencedDependencies, peerDependencies, installedBinaries, entryFiles, enabledPlugins } = worker.getFinalDependencies();
173
- deputy.addPeerDependencies(name, peerDependencies);
174
- deputy.setInstalledBinaries(name, installedBinaries);
175
- principal.addEntryPaths(entryFiles);
176
- enabledPluginsStore.set(name, enabledPlugins);
177
- referencedDependencies.forEach(([filePath, specifier]) => {
178
- const [isAdded, packageName] = deputy.maybeAddReferencedExternalDependency(workspace, specifier);
179
- if (!isAdded) {
180
- if (!ignoreDependencies.includes(specifier)) {
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
- else if (packageName && packageName !== specifier) {
185
- const workspace = workspaces.find(workspace => workspace.pkgName === packageName);
186
- if (workspace) {
187
- const relativeSpecifier = specifier.replace(new RegExp(`^${packageName}`), '.');
188
- const filePath = findFileWithExtensions(workspace.dir, relativeSpecifier, DEFAULT_EXTENSIONS);
189
- if (filePath) {
190
- principal.addEntryPath(filePath);
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
- if (report.files || report.dependencies || report.unlisted || report.unresolved) {
204
- const workspace = chief.findWorkspace(filePath);
205
- if (workspace) {
206
- const { internalImports, unresolvedImports, externalImports, exports, duplicateExports } = principal.analyzeSourceFile(filePath);
207
- if (exports.size > 0) {
208
- exportedSymbols.set(filePath, exports);
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
- for (const [specifierFilePath, importItems] of internalImports.entries()) {
211
- const importedWorkspace = chief.findWorkspace(specifierFilePath);
212
- if (importedWorkspace && importedWorkspace !== workspace) {
213
- externalImports.add(importItems.specifier);
161
+ else {
162
+ const importedModule = importedSymbols.get(specifierFilePath);
163
+ for (const identifier of importItems.symbols) {
164
+ importedModule.symbols.add(identifier);
214
165
  }
215
- if (!importedSymbols.has(specifierFilePath)) {
216
- importedSymbols.set(specifierFilePath, importItems);
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
- progress.updateMessage('Running async compilers...');
195
+ console.cast('Running async compilers...');
254
196
  await principal.runAsyncCompilers();
255
- progress.updateMessage('Connecting the dots...');
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
- progress.updateMessage('Analyzing source files...');
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
- progress.removeProgress();
263
+ console.clear();
322
264
  return { report, issues, counters };
323
265
  };
@@ -1,24 +1,17 @@
1
- import { LineRewriter } from './util/log.js';
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
- report: Report;
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: string;
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
  };
@@ -1,22 +1,12 @@
1
- import { initReport, initIssues, initCounters } from './issues/initializers.js';
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
- constructor({ cwd, report }) {
13
- this.lineRewriter = new LineRewriter();
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,4 +1,3 @@
1
- import { Issues, Counters, Report } from '../types/issues.js';
1
+ import { Issues, Counters } from '../types/issues.js';
2
2
  export declare const initIssues: () => Issues;
3
3
  export declare const initCounters: () => Counters;
4
- export declare const initReport: () => Report;
@@ -8,4 +8,3 @@ export const initCounters = () => ({
8
8
  processed: 0,
9
9
  total: 0,
10
10
  });
11
- export const initReport = () => Object.fromEntries(ISSUE_TYPES.map(issueType => [issueType, true]));
@@ -1 +1,7 @@
1
- export declare const getPackageManifest: (workingDir: string, packageName: string, isRoot: boolean, cwd: string) => Promise<any>;
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 {};
@@ -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 (workingDir, packageName, isRoot, cwd) => {
3
+ export const getPackageManifest = async ({ dir, packageName, cwd }) => {
4
4
  try {
5
- return _require(join(workingDir, 'node_modules', packageName, 'package.json'));
5
+ return _require(join(dir, 'node_modules', packageName, 'package.json'));
6
6
  }
7
7
  catch (error) {
8
- if (!isRoot) {
8
+ if (dir !== cwd) {
9
9
  try {
10
10
  return _require(join(cwd, 'node_modules', packageName, 'package.json'));
11
11
  }
@@ -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, isRoot, isProduction, dir, cwd }: Options) => Promise<{
11
+ export declare const findDependencies: ({ config, manifest, isProduction, dir, cwd }: Options) => Promise<{
13
12
  dependencies: string[];
14
13
  peerDependencies: PeerDependencies;
15
14
  installedBinaries: InstalledBinaries;
@@ -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, isRoot, isProduction, dir, cwd }) => {
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, isRoot, cwd);
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
- import { LineRewriter } from './util/log.js';
2
- type ProgressUpdaterOptions = {
3
- isShowProgress?: boolean;
4
- };
5
- export declare class ProgressUpdater {
6
- lineRewriter: LineRewriter;
7
- isShowProgress: boolean;
8
- constructor({ isShowProgress }: ProgressUpdaterOptions);
9
- setIsShowProgress(isShowProgress: boolean): void;
10
- updateMessage(message: string): void;
11
- removeProgress(): void;
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 {};
@@ -1,22 +1,34 @@
1
- import { LineRewriter } from './util/log.js';
2
- export class ProgressUpdater {
3
- lineRewriter;
4
- isShowProgress = false;
5
- constructor({ isShowProgress = false }) {
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
- setIsShowProgress(isShowProgress) {
10
- this.isShowProgress = isShowProgress;
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
- updateMessage(message) {
13
- if (!this.isShowProgress)
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.lineRewriter.update([message]);
27
+ this.update([message]);
16
28
  }
17
- removeProgress() {
18
- if (!this.isShowProgress)
29
+ clear() {
30
+ if (!this.isEnabled)
19
31
  return;
20
- this.lineRewriter.resetLines();
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
- internalImports: import("./types/ast.js").Imports;
42
- unresolvedImports: Set<string>;
43
- externalImports: Set<string>;
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 options = { skipTypeOnly: !this.isReportTypes, skipExports: this.skipExportsAnalysis.has(filePath) };
111
- const { internalImports, unresolvedImports, externalImports, exports, duplicateExports } = getImportsAndExports(sourceFile, options);
112
- const finalUnresolvedImports = new Set();
113
- unresolvedImports.forEach(specifier => {
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
- externalImports.add(specifier);
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
- externalImports.add(specifier);
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
- finalUnresolvedImports.add(specifier);
135
+ unresolvedImports.add(specifier);
134
136
  }
135
137
  else {
136
138
  }
137
139
  }
138
140
  }
139
141
  });
140
- return { internalImports, unresolvedImports: finalUnresolvedImports, externalImports, exports, duplicateExports };
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
- internalImports: Imports;
9
- externalImports: Set<string>;
10
- unresolvedImports: Set<string>;
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 { internalImports, externalImports, unresolvedImports, exports, duplicateExports };
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 { Report } from '../types/issues.js';
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 resolveIncludedIssueTypes: (cliArgs: CLIArguments, { include, exclude, isProduction }?: Options) => Report;
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 resolveIncludedIssueTypes = (cliArgs, { include = [], exclude = [], isProduction = false } = {}) => {
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.3";
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.3';
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
- rootWorkspaceConfig: WorkspaceConfiguration;
10
- rootConfig: Configuration;
10
+ rootIgnore: Configuration['ignore'];
11
11
  negatedWorkspacePatterns: string[];
12
- rootWorkspaceDir: string;
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
- rootWorkspaceDir: string;
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: string[];
29
- enabled: Record<PluginName, boolean>;
30
- enabledPlugins: PluginName[];
31
- isRoot: boolean;
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
- getWorkspaceIgnorePatterns(): string[];
47
- findDependenciesByPlugins(): Promise<void>;
48
- getFinalDependencies(): {
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 {};
@@ -1,4 +1,4 @@
1
- import { ROOT_WORKSPACE_NAME, TEST_FILE_PATTERNS } from './constants.js';
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
- rootWorkspaceDir;
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.isRoot = name === ROOT_WORKSPACE_NAME;
29
+ this.manifest = manifest;
30
30
  this.isProduction = isProduction;
31
- this.rootConfig = rootConfig;
32
- this.rootWorkspaceConfig = rootWorkspaceConfig;
33
- this.rootWorkspaceDir = rootWorkspaceDir;
31
+ this.rootIgnore = rootIgnore;
34
32
  this.negatedWorkspacePatterns = negatedWorkspacePatterns;
35
- this.manifest = manifest;
33
+ this.enabledPluginsInAncestors = enabledPluginsInAncestors;
36
34
  this.enabled = Object.keys(plugins).reduce((enabled, pluginName) => ({ ...enabled, [pluginName]: false }), {});
37
35
  }
38
- getConfigForPlugin(pluginName) {
39
- return this.config[pluginName] ?? { config: null, entry: null, project: null };
36
+ async init() {
37
+ await this.setEnabledPlugins();
38
+ await this.initReferencedDependencies();
40
39
  }
41
- async setEnabledPlugins(enabledPluginsInAncestors) {
42
- const { manifest } = this;
43
- const dependencies = new Set([Object.keys(manifest?.dependencies ?? {}), Object.keys(manifest?.devDependencies ?? {})].flat());
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
- const isEnabled = this.config[pluginName] !== false;
47
- const isEnabledInAncestor = enabledPluginsInAncestors.includes(pluginName);
48
- this.enabled[pluginName] =
49
- isEnabled && (isEnabledInAncestor || (await plugin.isEnabled({ cwd: this.dir, manifest, dependencies })));
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.rootWorkspaceDir,
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
- getWorkspaceIgnorePatterns() {
191
- return [...this.rootConfig.ignore, ...this.config.ignore.map(pattern => prependDirToPattern(this.name, pattern))];
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
- getFinalDependencies() {
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",
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",