knip
Version:
Find and fix unused dependencies, exports and files in your TypeScript and JavaScript projects
86 lines (85 loc) • 4.48 kB
JavaScript
import watchReporter from '../reporters/watch.js';
import { debugLog } from './debug.js';
import { isFile } from './fs.js';
import { updateImportMap } from './module-graph.js';
import { join, toPosix } from './path.js';
export const getWatchHandler = async ({ analyzedFiles, analyzeSourceFile, chief, collector, analyze, cwd, factory, graph, isDebug, isIgnored, report, streamer, unreferencedFiles, }) => {
const reportIssues = async (startTime) => {
const { issues } = collector.getIssues();
watchReporter({ report, issues, streamer, startTime, size: analyzedFiles.size, isDebug });
};
const listener = async (eventType, filename) => {
debugLog('*', `(raw) ${eventType} ${filename}`);
if (typeof filename === 'string') {
const startTime = performance.now();
const filePath = join(cwd, toPosix(filename));
if (isIgnored(filePath)) {
debugLog('*', `ignoring ${eventType} ${filename}`);
return;
}
const workspace = chief.findWorkspaceByFilePath(filePath);
if (workspace) {
const principal = factory.getPrincipalByPackageName(workspace.pkgName);
if (principal) {
const event = eventType === 'rename' ? (isFile(filePath) ? 'added' : 'deleted') : 'modified';
principal.invalidateFile(filePath);
unreferencedFiles.clear();
const cachedUnusedFiles = collector.purge();
switch (event) {
case 'added':
principal.addProjectPath(filePath);
principal.deletedFiles.delete(filePath);
cachedUnusedFiles.add(filePath);
debugLog(workspace.name, `Watcher: + ${filename}`);
break;
case 'deleted':
analyzedFiles.delete(filePath);
principal.removeProjectPath(filePath);
cachedUnusedFiles.delete(filePath);
debugLog(workspace.name, `Watcher: - ${filename}`);
break;
case 'modified':
debugLog(workspace.name, `Watcher: ± ${filename}`);
break;
}
const filePaths = factory.getPrincipals().flatMap(p => p.getUsedResolvedFiles());
if (event === 'added' || event === 'deleted') {
graph.clear();
for (const filePath of filePaths)
analyzeSourceFile(filePath, principal);
}
else {
for (const [filePath, file] of graph) {
if (filePaths.includes(filePath)) {
file.imported = undefined;
}
else {
graph.delete(filePath);
analyzedFiles.delete(filePath);
if (principal.projectPaths.has(filePath))
cachedUnusedFiles.add(filePath);
}
}
for (const filePath of filePaths)
if (!graph.has(filePath))
analyzeSourceFile(filePath, principal);
if (!cachedUnusedFiles.has(filePath))
analyzeSourceFile(filePath, principal);
for (const filePath of filePaths) {
const file = graph.get(filePath);
if (file?.internalImportCache)
updateImportMap(file, file.internalImportCache, graph);
}
}
await analyze();
const unusedFiles = [...cachedUnusedFiles].filter(filePath => !analyzedFiles.has(filePath));
collector.addFilesIssues(unusedFiles);
collector.addFileCounts({ processed: analyzedFiles.size, unused: unusedFiles.length });
await reportIssues(startTime);
}
}
}
};
await reportIssues();
return listener;
};