diff --git a/packages/react-doctor/src/scan.ts b/packages/react-doctor/src/scan.ts index 9d04aeb..19616c5 100644 --- a/packages/react-doctor/src/scan.ts +++ b/packages/react-doctor/src/scan.ts @@ -361,6 +361,7 @@ export const scan = async (directory: string, inputOptions: ScanOptions = {}): P includePaths: inputOptions.includePaths, }; + const ignoreFilePatterns = userConfig?.ignore?.files ?? []; const includePaths = options.includePaths ?? []; const isDiffMode = includePaths.length > 0; @@ -412,6 +413,7 @@ export const scan = async (directory: string, inputOptions: ScanOptions = {}): P projectInfo.framework, projectInfo.hasReactCompiler, jsxIncludePaths, + ignoreFilePatterns, ); lintSpinner?.succeed("Running lint checks."); return lintDiagnostics; @@ -437,7 +439,7 @@ export const scan = async (directory: string, inputOptions: ScanOptions = {}): P ? null : spinner("Detecting dead code...").start(); try { - const knipDiagnostics = await runKnip(directory); + const knipDiagnostics = await runKnip(directory, ignoreFilePatterns); deadCodeSpinner?.succeed("Detecting dead code."); return knipDiagnostics; } catch (error) { diff --git a/packages/react-doctor/src/utils/run-knip.ts b/packages/react-doctor/src/utils/run-knip.ts index 15b9041..25d7286 100644 --- a/packages/react-doctor/src/utils/run-knip.ts +++ b/packages/react-doctor/src/utils/run-knip.ts @@ -3,6 +3,7 @@ import path from "node:path"; import { main } from "knip"; import { createOptions } from "knip/session"; import type { Diagnostic, KnipIssueRecords, KnipResults } from "../types.js"; +import { compileGlobPattern } from "./match-glob-pattern.js"; const KNIP_CATEGORY_MAP: Record = { files: "Dead Code", @@ -135,7 +136,7 @@ const hasNodeModules = (directory: string): boolean => { return fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory(); }; -export const runKnip = async (rootDirectory: string): Promise => { +export const runKnip = async (rootDirectory: string, ignorePatterns?: string[]): Promise => { const monorepoRoot = findMonorepoRoot(rootDirectory); const hasInstalledDependencies = hasNodeModules(rootDirectory) || (monorepoRoot !== null && hasNodeModules(monorepoRoot)); @@ -186,5 +187,13 @@ export const runKnip = async (rootDirectory: string): Promise => { diagnostics.push(...collectIssueRecords(issues[issueType], issueType, rootDirectory)); } + if (ignorePatterns && ignorePatterns.length > 0) { + const compiled = ignorePatterns.map(compileGlobPattern); + return diagnostics.filter((diagnostic) => { + const normalized = diagnostic.filePath.replace(/\\/g, "/"); + return !compiled.some((pattern) => pattern.test(normalized)); + }); + } + return diagnostics; }; diff --git a/packages/react-doctor/src/utils/run-oxlint.ts b/packages/react-doctor/src/utils/run-oxlint.ts index 9c2dcef..f88f6a2 100644 --- a/packages/react-doctor/src/utils/run-oxlint.ts +++ b/packages/react-doctor/src/utils/run-oxlint.ts @@ -258,6 +258,7 @@ export const runOxlint = async ( framework: Framework, hasReactCompiler: boolean, includePaths?: string[], + ignorePatterns?: string[], ): Promise => { if (includePaths !== undefined && includePaths.length === 0) { return []; @@ -278,6 +279,12 @@ export const runOxlint = async ( args.push("--tsconfig", "./tsconfig.json"); } + if (ignorePatterns) { + for (const pattern of ignorePatterns) { + args.push("--ignore-pattern", pattern); + } + } + if (includePaths !== undefined) { args.push(...includePaths); } else {