knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
130 lines (129 loc) • 5.17 kB
JavaScript
import { watch } from 'node:fs';
import { formatly } from 'formatly';
import { ConfigurationChief } from './ConfigurationChief.js';
import { ConsoleStreamer } from './ConsoleStreamer.js';
import { DependencyDeputy } from './DependencyDeputy.js';
import { IssueCollector } from './IssueCollector.js';
import { IssueFixer } from './IssueFixer.js';
import { PrincipalFactory } from './PrincipalFactory.js';
import { analyze } from './graph/analyze.js';
import { build } from './graph/build.js';
import { debugLogArray, debugLogObject } from './util/debug.js';
import { getGitIgnoredHandler } from './util/glob-core.js';
import { getWatchHandler } from './util/watch.js';
export const main = async (unresolvedConfiguration) => {
const { cacheLocation, cwd, excludedIssueTypes, fixTypes, gitignore, includedIssueTypes, isCache, isDebug, isDependenciesShorthand, isExportsShorthand, isFilesShorthand, isFix, isFormat, isIncludeEntryExports, isIncludeLibs, isIsolateWorkspaces, isProduction, isRemoveFiles, isShowProgress, isStrict, isWatch, tags, tsConfigFile, workspace, } = unresolvedConfiguration;
debugLogObject('*', 'Unresolved configuration (from CLI arguments)', unresolvedConfiguration);
const chief = new ConfigurationChief({ cwd, isProduction, isStrict, isIncludeEntryExports, workspace });
const deputy = new DependencyDeputy({ isProduction, isStrict });
const factory = new PrincipalFactory();
const streamer = new ConsoleStreamer({ isEnabled: isShowProgress });
streamer.cast('Reading workspace configuration');
await chief.init();
const workspaces = chief.getWorkspaces();
const report = chief.getIncludedIssueTypes({
includedIssueTypes,
excludedIssueTypes,
isDependenciesShorthand,
isExportsShorthand,
isFilesShorthand,
});
const rules = chief.getRules();
const filters = chief.getFilters();
const finalTags = tags[0].length > 0 || tags[1].length > 0 ? tags : chief.getTags();
const fixer = new IssueFixer({ isEnabled: isFix, cwd, fixTypes, isRemoveFiles });
debugLogObject('*', 'Included issue types', report);
const isReportClassMembers = report.classMembers;
const isSkipLibs = !(isIncludeLibs || isReportClassMembers);
const collector = new IssueCollector({ cwd, rules, filters });
const o = () => workspaces.map(w => ({ pkgName: w.pkgName, name: w.name, config: w.config, ancestors: w.ancestors }));
debugLogObject('*', 'Included workspaces', () => workspaces.map(w => w.pkgName));
debugLogObject('*', 'Included workspace configs', o);
const isGitIgnored = await getGitIgnoredHandler({ cwd, gitignore });
const { graph, entryPaths, analyzedFiles, unreferencedFiles, analyzeSourceFile } = await build({
cacheLocation,
chief,
collector,
cwd,
deputy,
factory,
gitignore,
isCache,
isFixExports: fixer.isEnabled && fixer.isFixUnusedExports,
isFixTypes: fixer.isEnabled && fixer.isFixUnusedTypes,
isGitIgnored,
isIsolateWorkspaces,
isProduction,
isSkipLibs,
isStrict,
isWatch,
report,
streamer,
tags: finalTags,
tsConfigFile,
workspaces,
});
const reAnalyze = await analyze({
analyzedFiles,
chief,
collector,
deputy,
entryPaths,
factory,
fixer,
graph,
isFix,
isIncludeLibs,
isProduction,
report,
streamer,
tags: finalTags,
unreferencedFiles,
});
const { issues, counters, tagHints, configurationHints } = collector.getIssues();
for (const hint of chief.getConfigurationHints())
collector.addConfigurationHint(hint);
if (isWatch) {
const isIgnored = (filePath) => filePath.startsWith(cacheLocation) || filePath.includes('/.git/') || isGitIgnored(filePath);
const watchHandler = await getWatchHandler({
analyzedFiles,
analyzeSourceFile,
chief,
collector,
analyze: reAnalyze,
cwd,
factory,
graph,
isDebug,
isIgnored,
report,
streamer,
unreferencedFiles,
});
watch('.', { recursive: true }, watchHandler);
}
if (isFix) {
const touchedFiles = await fixer.fixIssues(issues);
if (isFormat) {
const report = await formatly(Array.from(touchedFiles), { cwd });
if (report.ran && report.result.code === 0) {
debugLogArray('*', `Formatted files using ${report.formatter.name} (${report.formatter.runner})`, touchedFiles);
}
else {
debugLogObject('*', 'Formatting files failed', report);
}
}
}
if (!isWatch)
streamer.clear();
return {
report,
issues,
counters,
rules,
tagHints,
configurationHints,
isTreatConfigHintsAsErrors: chief.config.isTreatConfigHintsAsErrors,
includedWorkspaces: chief.includedWorkspaces,
};
};