react-doctor 0.0.41 → 0.0.42

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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["esmRequire"],"sources":["../src/core/build-diagnose-result.ts","../src/utils/match-glob-pattern.ts","../src/utils/is-ignored-file.ts","../src/utils/filter-diagnostics.ts","../src/utils/merge-and-filter-diagnostics.ts","../src/core/build-result.ts","../src/constants.ts","../src/utils/jsx-include-paths.ts","../src/core/diagnose-core.ts","../src/plugin/constants.ts","../src/utils/is-file.ts","../src/utils/read-package-json.ts","../src/utils/check-reduced-motion.ts","../src/utils/find-monorepo-root.ts","../src/utils/is-plain-object.ts","../src/utils/discover-project.ts","../src/utils/load-config.ts","../src/utils/read-file-lines-node.ts","../src/utils/resolve-lint-include-paths.ts","../src/core/calculate-score-locally.ts","../src/core/try-score-from-api.ts","../src/utils/proxy-fetch.ts","../src/utils/calculate-score-node.ts","../src/utils/collect-unused-file-paths.ts","../src/utils/run-knip.ts","../src/oxlint-config.ts","../src/utils/neutralize-disable-directives.ts","../src/utils/run-oxlint.ts","../src/utils/get-diff-files.ts","../src/index.ts"],"sourcesContent":["import type { Diagnostic, ProjectInfo, ScoreResult } from \"../types.js\";\n\ninterface BuildDiagnoseResultParams {\n diagnostics: Diagnostic[];\n project: ProjectInfo;\n elapsedMilliseconds: number;\n score: ScoreResult | null;\n}\n\ninterface DiagnoseResultShape {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n project: ProjectInfo;\n elapsedMilliseconds: number;\n}\n\nexport const buildDiagnoseResult = (params: BuildDiagnoseResultParams): DiagnoseResultShape => ({\n diagnostics: params.diagnostics,\n score: params.score,\n project: params.project,\n elapsedMilliseconds: params.elapsedMilliseconds,\n});\n","const REGEX_SPECIAL_CHARACTERS = /[.+^${}()|[\\]\\\\]/g;\n\nexport const compileGlobPattern = (pattern: string): RegExp => {\n const normalizedPattern = pattern.replace(/\\\\/g, \"/\").replace(/^\\//, \"\");\n\n let regexSource = \"^\";\n let characterIndex = 0;\n\n while (characterIndex < normalizedPattern.length) {\n if (\n normalizedPattern[characterIndex] === \"*\" &&\n normalizedPattern[characterIndex + 1] === \"*\"\n ) {\n if (normalizedPattern[characterIndex + 2] === \"/\") {\n regexSource += \"(?:.+/)?\";\n characterIndex += 3;\n } else {\n regexSource += \".*\";\n characterIndex += 2;\n }\n } else if (normalizedPattern[characterIndex] === \"*\") {\n regexSource += \"[^/]*\";\n characterIndex++;\n } else if (normalizedPattern[characterIndex] === \"?\") {\n regexSource += \"[^/]\";\n characterIndex++;\n } else {\n regexSource += normalizedPattern[characterIndex].replace(REGEX_SPECIAL_CHARACTERS, \"\\\\$&\");\n characterIndex++;\n }\n }\n\n regexSource += \"$\";\n return new RegExp(regexSource);\n};\n\nexport const matchGlobPattern = (filePath: string, pattern: string): boolean => {\n const normalizedPath = filePath.replace(/\\\\/g, \"/\");\n return compileGlobPattern(pattern).test(normalizedPath);\n};\n","import type { ReactDoctorConfig } from \"../types.js\";\nimport { compileGlobPattern } from \"./match-glob-pattern.js\";\n\nconst toRelativePath = (filePath: string, rootDirectory: string): string => {\n const normalizedFilePath = filePath.replace(/\\\\/g, \"/\");\n const normalizedRoot = rootDirectory.replace(/\\\\/g, \"/\").replace(/\\/$/, \"\") + \"/\";\n\n if (normalizedFilePath.startsWith(normalizedRoot)) {\n return normalizedFilePath.slice(normalizedRoot.length);\n }\n\n return normalizedFilePath.replace(/^\\.\\//, \"\");\n};\n\nexport const compileIgnoredFilePatterns = (userConfig: ReactDoctorConfig | null): RegExp[] =>\n Array.isArray(userConfig?.ignore?.files) ? userConfig.ignore.files.map(compileGlobPattern) : [];\n\nexport const isFileIgnoredByPatterns = (\n filePath: string,\n rootDirectory: string,\n patterns: RegExp[],\n): boolean => {\n if (patterns.length === 0) {\n return false;\n }\n\n const relativePath = toRelativePath(filePath, rootDirectory);\n return patterns.some((pattern) => pattern.test(relativePath));\n};\n","import type { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { compileIgnoredFilePatterns, isFileIgnoredByPatterns } from \"./is-ignored-file.js\";\n\nconst resolveCandidateReadPath = (rootDirectory: string, filePath: string): string => {\n const normalizedFile = filePath.replace(/\\\\/g, \"/\");\n if (\n normalizedFile.startsWith(\"/\") ||\n /^[a-zA-Z]:\\//.test(normalizedFile) ||\n /^[a-zA-Z]:\\\\/.test(filePath)\n ) {\n return filePath;\n }\n const root = rootDirectory.replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n return `${root}/${normalizedFile.replace(/^\\.\\//, \"\")}`;\n};\n\nconst OPENING_TAG_PATTERN = /<([A-Z][\\w.]*)/;\nconst DISABLE_NEXT_LINE_PATTERN = /\\/\\/\\s*react-doctor-disable-next-line\\b(?:\\s+(.+))?/;\nconst DISABLE_LINE_PATTERN = /\\/\\/\\s*react-doctor-disable-line\\b(?:\\s+(.+))?/;\n\nconst createFileLinesCache = (\n rootDirectory: string,\n readFileLinesSync: (filePath: string) => string[] | null,\n) => {\n const cache = new Map<string, string[] | null>();\n\n return (filePath: string): string[] | null => {\n const cached = cache.get(filePath);\n if (cached !== undefined) return cached;\n const absolutePath = resolveCandidateReadPath(rootDirectory, filePath);\n const lines = readFileLinesSync(absolutePath);\n cache.set(filePath, lines);\n return lines;\n };\n};\n\nconst isInsideTextComponent = (\n lines: string[],\n diagnosticLine: number,\n textComponentNames: Set<string>,\n): boolean => {\n for (let lineIndex = diagnosticLine - 1; lineIndex >= 0; lineIndex--) {\n const match = lines[lineIndex].match(OPENING_TAG_PATTERN);\n if (!match) continue;\n const fullTagName = match[1];\n const leafTagName = fullTagName.includes(\".\")\n ? (fullTagName.split(\".\").at(-1) ?? fullTagName)\n : fullTagName;\n return textComponentNames.has(fullTagName) || textComponentNames.has(leafTagName);\n }\n return false;\n};\n\nconst isRuleSuppressed = (commentRules: string | undefined, ruleId: string): boolean => {\n if (!commentRules?.trim()) return true;\n return commentRules.split(/[,\\s]+/).some((rule) => rule.trim() === ruleId);\n};\n\nexport const filterIgnoredDiagnostics = (\n diagnostics: Diagnostic[],\n config: ReactDoctorConfig,\n rootDirectory: string,\n readFileLinesSync: (filePath: string) => string[] | null,\n): Diagnostic[] => {\n const ignoredRules = new Set(Array.isArray(config.ignore?.rules) ? config.ignore.rules : []);\n const ignoredFilePatterns = compileIgnoredFilePatterns(config);\n const textComponentNames = new Set(\n Array.isArray(config.textComponents) ? config.textComponents : [],\n );\n const hasTextComponents = textComponentNames.size > 0;\n const getFileLines = createFileLinesCache(rootDirectory, readFileLinesSync);\n\n return diagnostics.filter((diagnostic) => {\n const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;\n if (ignoredRules.has(ruleIdentifier)) {\n return false;\n }\n\n if (isFileIgnoredByPatterns(diagnostic.filePath, rootDirectory, ignoredFilePatterns)) {\n return false;\n }\n\n if (hasTextComponents && diagnostic.rule === \"rn-no-raw-text\" && diagnostic.line > 0) {\n const lines = getFileLines(diagnostic.filePath);\n if (lines && isInsideTextComponent(lines, diagnostic.line, textComponentNames)) {\n return false;\n }\n }\n\n return true;\n });\n};\n\nexport const filterInlineSuppressions = (\n diagnostics: Diagnostic[],\n rootDirectory: string,\n readFileLinesSync: (filePath: string) => string[] | null,\n): Diagnostic[] => {\n const getFileLines = createFileLinesCache(rootDirectory, readFileLinesSync);\n\n return diagnostics.filter((diagnostic) => {\n if (diagnostic.line <= 0) return true;\n\n const lines = getFileLines(diagnostic.filePath);\n if (!lines) return true;\n\n const ruleId = `${diagnostic.plugin}/${diagnostic.rule}`;\n\n const currentLine = lines[diagnostic.line - 1];\n if (currentLine) {\n const lineMatch = currentLine.match(DISABLE_LINE_PATTERN);\n if (lineMatch && isRuleSuppressed(lineMatch[1], ruleId)) return false;\n }\n\n if (diagnostic.line >= 2) {\n const previousLine = lines[diagnostic.line - 2];\n if (previousLine) {\n const nextLineMatch = previousLine.match(DISABLE_NEXT_LINE_PATTERN);\n if (nextLineMatch && isRuleSuppressed(nextLineMatch[1], ruleId)) return false;\n }\n }\n\n return true;\n });\n};\n","import type { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { filterIgnoredDiagnostics, filterInlineSuppressions } from \"./filter-diagnostics.js\";\n\nexport const mergeAndFilterDiagnostics = (\n mergedDiagnostics: Diagnostic[],\n directory: string,\n userConfig: ReactDoctorConfig | null,\n readFileLinesSync: (filePath: string) => string[] | null,\n): Diagnostic[] => {\n const filtered = userConfig\n ? filterIgnoredDiagnostics(mergedDiagnostics, userConfig, directory, readFileLinesSync)\n : mergedDiagnostics;\n return filterInlineSuppressions(filtered, directory, readFileLinesSync);\n};\n","import type { Diagnostic, ReactDoctorConfig, ScoreResult } from \"../types.js\";\nimport { mergeAndFilterDiagnostics } from \"../utils/merge-and-filter-diagnostics.js\";\n\nexport interface BuildDiagnoseResultInput {\n mergedDiagnostics: Diagnostic[];\n rootDirectory: string;\n userConfig: ReactDoctorConfig | null;\n readFileLinesSync: (filePath: string) => string[] | null;\n startTime: number;\n score?: ScoreResult | null;\n calculateDiagnosticsScore: (diagnostics: Diagnostic[]) => Promise<ScoreResult | null>;\n}\n\nexport interface BuildDiagnoseTimedResult {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n elapsedMilliseconds: number;\n}\n\nexport const buildDiagnoseTimedResult = async (\n input: BuildDiagnoseResultInput,\n): Promise<BuildDiagnoseTimedResult> => {\n const diagnostics = mergeAndFilterDiagnostics(\n input.mergedDiagnostics,\n input.rootDirectory,\n input.userConfig,\n input.readFileLinesSync,\n );\n const elapsedMilliseconds = globalThis.performance.now() - input.startTime;\n const score =\n input.score !== undefined ? input.score : await input.calculateDiagnosticsScore(diagnostics);\n return { diagnostics, score, elapsedMilliseconds };\n};\n","export const SOURCE_FILE_PATTERN = /\\.(tsx?|jsx?)$/;\n\nexport const JSX_FILE_PATTERN = /\\.(tsx|jsx)$/;\n\nexport const MILLISECONDS_PER_SECOND = 1000;\n\nexport const ERROR_PREVIEW_LENGTH_CHARS = 200;\n\nexport const PERFECT_SCORE = 100;\n\nexport const SCORE_GOOD_THRESHOLD = 75;\n\nexport const SCORE_OK_THRESHOLD = 50;\n\nexport const SCORE_BAR_WIDTH_CHARS = 50;\n\nexport const SUMMARY_BOX_HORIZONTAL_PADDING_CHARS = 1;\n\nexport const SUMMARY_BOX_OUTER_INDENT_CHARS = 2;\n\nexport const SCORE_API_URL = \"https://www.react.doctor/api/score\";\n\nexport const SHARE_BASE_URL = \"https://www.react.doctor/share\";\n\nexport const FETCH_TIMEOUT_MS = 10_000;\n\nexport const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\n// HACK: Windows CreateProcessW limits total command-line length to 32,767 chars.\n// Use a conservative threshold to leave room for the executable path and quoting overhead.\nexport const SPAWN_ARGS_MAX_LENGTH_CHARS = 24_000;\n\n// HACK: oxlint can SIGABRT on very large file sets due to memory pressure.\n// Cap each batch to avoid OOM crashes on projects with 100+ source files.\nexport const OXLINT_MAX_FILES_PER_BATCH = 500;\n\nexport const OFFLINE_MESSAGE = \"Score calculated locally (offline mode).\";\n\nexport const DEFAULT_BRANCH_CANDIDATES = [\"main\", \"master\"];\n\nexport const ERROR_RULE_PENALTY = 1.5;\n\nexport const WARNING_RULE_PENALTY = 0.75;\n\nexport const MAX_KNIP_RETRIES = 5;\n\nexport const OXLINT_NODE_REQUIREMENT = \"^20.19.0 || >=22.12.0\";\n\nexport const OXLINT_RECOMMENDED_NODE_MAJOR = 24;\n\nexport const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;\n\nexport const IGNORED_DIRECTORIES = new Set([\"node_modules\", \"dist\", \"build\", \"coverage\"]);\n","import { JSX_FILE_PATTERN } from \"../constants.js\";\n\nexport const computeJsxIncludePaths = (includePaths: string[]): string[] | undefined =>\n includePaths.length > 0\n ? includePaths.filter((filePath) => JSX_FILE_PATTERN.test(filePath))\n : undefined;\n","import type { Diagnostic, ProjectInfo, ReactDoctorConfig, ScoreResult } from \"../types.js\";\nimport { buildDiagnoseResult } from \"./build-diagnose-result.js\";\nimport { buildDiagnoseTimedResult } from \"./build-result.js\";\nimport { computeJsxIncludePaths } from \"../utils/jsx-include-paths.js\";\n\nexport interface DiagnoseCoreOptions {\n lint?: boolean;\n deadCode?: boolean;\n includePaths?: string[];\n lintIncludePaths?: string[] | undefined;\n}\n\nexport interface DiagnoseCoreResult {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n project: ProjectInfo;\n elapsedMilliseconds: number;\n}\n\nexport interface DiagnoseRunnerContext {\n resolvedDirectory: string;\n projectInfo: ProjectInfo;\n userConfig: ReactDoctorConfig | null;\n lintIncludePaths: string[] | undefined;\n isDiffMode: boolean;\n}\n\nexport interface DiagnoseCoreDeps {\n rootDirectory: string;\n readFileLinesSync: (filePath: string) => string[] | null;\n loadUserConfig: () => ReactDoctorConfig | null;\n discoverProjectInfo: () => ProjectInfo;\n calculateDiagnosticsScore: (diagnostics: Diagnostic[]) => Promise<ScoreResult | null>;\n getExtraDiagnostics?: () => Diagnostic[];\n createRunners: (context: DiagnoseRunnerContext) => {\n runLint: () => Promise<Diagnostic[]>;\n runDeadCode: () => Promise<Diagnostic[]>;\n };\n}\n\nexport const diagnoseCore = async (\n deps: DiagnoseCoreDeps,\n options: DiagnoseCoreOptions = {},\n): Promise<DiagnoseCoreResult> => {\n const { includePaths = [] } = options;\n const isDiffMode = includePaths.length > 0;\n\n const startTime = globalThis.performance.now();\n const resolvedDirectory = deps.rootDirectory;\n const projectInfo = deps.discoverProjectInfo();\n const userConfig = deps.loadUserConfig();\n\n const effectiveLint = options.lint ?? userConfig?.lint ?? true;\n const effectiveDeadCode = options.deadCode ?? userConfig?.deadCode ?? true;\n\n if (!projectInfo.reactVersion) {\n throw new Error(\"No React dependency found in package.json\");\n }\n\n const lintIncludePaths =\n options.lintIncludePaths !== undefined\n ? options.lintIncludePaths\n : computeJsxIncludePaths(includePaths);\n\n const { runLint, runDeadCode } = deps.createRunners({\n resolvedDirectory,\n projectInfo,\n userConfig,\n lintIncludePaths,\n isDiffMode,\n });\n\n const emptyDiagnostics: Diagnostic[] = [];\n\n const lintPromise = effectiveLint\n ? runLint().catch((error: unknown) => {\n console.error(\"Lint failed:\", error);\n return emptyDiagnostics;\n })\n : Promise.resolve(emptyDiagnostics);\n\n const deadCodePromise =\n effectiveDeadCode && !isDiffMode\n ? runDeadCode().catch((error: unknown) => {\n console.error(\"Dead code analysis failed:\", error);\n return emptyDiagnostics;\n })\n : Promise.resolve(emptyDiagnostics);\n\n const [lintDiagnostics, deadCodeDiagnostics] = await Promise.all([lintPromise, deadCodePromise]);\n const environmentDiagnostics = deps.getExtraDiagnostics?.() ?? [];\n const mergedDiagnostics = [...lintDiagnostics, ...deadCodeDiagnostics, ...environmentDiagnostics];\n const timed = await buildDiagnoseTimedResult({\n mergedDiagnostics,\n rootDirectory: resolvedDirectory,\n userConfig,\n readFileLinesSync: deps.readFileLinesSync,\n startTime,\n calculateDiagnosticsScore: deps.calculateDiagnosticsScore,\n });\n\n return buildDiagnoseResult({\n diagnostics: timed.diagnostics,\n score: timed.score,\n project: projectInfo,\n elapsedMilliseconds: timed.elapsedMilliseconds,\n });\n};\n","export const GIANT_COMPONENT_LINE_THRESHOLD = 300;\nexport const CASCADING_SET_STATE_THRESHOLD = 3;\nexport const RELATED_USE_STATE_THRESHOLD = 5;\nexport const DEEP_NESTING_THRESHOLD = 3;\nexport const DUPLICATE_STORAGE_READ_THRESHOLD = 2;\nexport const SEQUENTIAL_AWAIT_THRESHOLD = 3;\nexport const SECRET_MIN_LENGTH_CHARS = 8;\nexport const AUTH_CHECK_LOOKAHEAD_STATEMENTS = 3;\n\nexport const LAYOUT_PROPERTIES = new Set([\n \"width\",\n \"height\",\n \"top\",\n \"left\",\n \"right\",\n \"bottom\",\n \"padding\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"margin\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"borderWidth\",\n \"fontSize\",\n \"lineHeight\",\n \"gap\",\n]);\n\nexport const MOTION_ANIMATE_PROPS = new Set([\n \"animate\",\n \"initial\",\n \"exit\",\n \"whileHover\",\n \"whileTap\",\n \"whileFocus\",\n \"whileDrag\",\n \"whileInView\",\n]);\n\nexport const HEAVY_LIBRARIES = new Set([\n \"@monaco-editor/react\",\n \"monaco-editor\",\n \"recharts\",\n \"@react-pdf/renderer\",\n \"react-quill\",\n \"@codemirror/view\",\n \"@codemirror/state\",\n \"chart.js\",\n \"react-chartjs-2\",\n \"@toast-ui/editor\",\n \"draft-js\",\n]);\n\nexport const FETCH_CALLEE_NAMES = new Set([\"fetch\"]);\nexport const FETCH_MEMBER_OBJECTS = new Set([\"axios\", \"ky\", \"got\"]);\nexport const INDEX_PARAMETER_NAMES = new Set([\"index\", \"idx\", \"i\"]);\nexport const BARREL_INDEX_SUFFIXES = [\n \"/index\",\n \"/index.js\",\n \"/index.ts\",\n \"/index.tsx\",\n \"/index.mjs\",\n];\nexport const PASSIVE_EVENT_NAMES = new Set([\n \"scroll\",\n \"wheel\",\n \"touchstart\",\n \"touchmove\",\n \"touchend\",\n]);\n\nexport const LOOP_TYPES = [\n \"ForStatement\",\n \"ForInStatement\",\n \"ForOfStatement\",\n \"WhileStatement\",\n \"DoWhileStatement\",\n];\n\nexport const AUTH_FUNCTION_NAMES = new Set([\n \"auth\",\n \"getSession\",\n \"getServerSession\",\n \"getUser\",\n \"requireAuth\",\n \"checkAuth\",\n \"verifyAuth\",\n \"authenticate\",\n \"currentUser\",\n \"getAuth\",\n \"validateSession\",\n]);\n\nexport const SECRET_PATTERNS = [\n /^sk_live_/,\n /^sk_test_/,\n /^AKIA[0-9A-Z]{16}$/,\n /^ghp_[a-zA-Z0-9]{36}$/,\n /^gho_[a-zA-Z0-9]{36}$/,\n /^github_pat_/,\n /^glpat-/,\n /^xox[bporas]-/,\n /^sk-[a-zA-Z0-9]{32,}$/,\n];\n\nexport const SECRET_VARIABLE_PATTERN = /(?:api_?key|secret|token|password|credential|auth)/i;\n\nexport const SECRET_FALSE_POSITIVE_SUFFIXES = new Set([\n \"modal\",\n \"label\",\n \"text\",\n \"title\",\n \"name\",\n \"id\",\n \"key\",\n \"url\",\n \"path\",\n \"route\",\n \"page\",\n \"param\",\n \"field\",\n \"column\",\n \"header\",\n \"placeholder\",\n \"description\",\n \"type\",\n \"icon\",\n \"class\",\n \"style\",\n \"variant\",\n \"event\",\n \"action\",\n \"status\",\n \"state\",\n \"mode\",\n \"flag\",\n \"option\",\n \"config\",\n \"message\",\n \"error\",\n \"display\",\n \"view\",\n \"component\",\n \"element\",\n \"container\",\n \"wrapper\",\n \"button\",\n \"link\",\n \"input\",\n \"select\",\n \"dialog\",\n \"menu\",\n \"form\",\n \"step\",\n \"index\",\n \"count\",\n \"length\",\n \"role\",\n \"scope\",\n \"context\",\n \"provider\",\n \"ref\",\n \"handler\",\n \"query\",\n \"schema\",\n \"constant\",\n]);\n\nexport const LOADING_STATE_PATTERN = /^(?:isLoading|isPending)$/;\n\nexport const TANSTACK_ROUTE_FILE_PATTERN = /\\/routes\\//;\nexport const TANSTACK_ROOT_ROUTE_FILE_PATTERN = /__root\\.(tsx?|jsx?)$/;\n\nexport const TANSTACK_ROUTE_PROPERTY_ORDER = [\n \"params\",\n \"validateSearch\",\n \"loaderDeps\",\n \"search.middlewares\",\n \"ssr\",\n \"context\",\n \"beforeLoad\",\n \"loader\",\n \"onEnter\",\n \"onStay\",\n \"onLeave\",\n \"head\",\n \"scripts\",\n \"headers\",\n \"remountDeps\",\n];\n\nexport const TANSTACK_ROUTE_CREATION_FUNCTIONS = new Set([\n \"createFileRoute\",\n \"createRoute\",\n \"createRootRoute\",\n \"createRootRouteWithContext\",\n]);\n\nexport const TANSTACK_SERVER_FN_NAMES = new Set([\"createServerFn\"]);\n\nexport const TANSTACK_MIDDLEWARE_METHOD_ORDER = [\n \"middleware\",\n \"inputValidator\",\n \"client\",\n \"server\",\n \"handler\",\n];\n\nexport const TANSTACK_REDIRECT_FUNCTIONS = new Set([\"redirect\", \"notFound\"]);\n\nexport const TANSTACK_SERVER_FN_FILE_PATTERN = /\\.functions(\\.[jt]sx?)?$/;\n\nexport const SEQUENTIAL_AWAIT_THRESHOLD_FOR_LOADER = 2;\n\nexport const TANSTACK_QUERY_HOOKS = new Set([\n \"useQuery\",\n \"useInfiniteQuery\",\n \"useSuspenseQuery\",\n \"useSuspenseInfiniteQuery\",\n]);\n\nexport const TANSTACK_MUTATION_HOOKS = new Set([\"useMutation\"]);\n\nexport const TANSTACK_QUERY_CLIENT_CLASS = \"QueryClient\";\n\nexport const STABLE_HOOK_WRAPPERS = new Set([\"useState\", \"useMemo\", \"useRef\"]);\n\nexport const SCRIPT_LOADING_ATTRIBUTES = new Set([\"defer\", \"async\"]);\n\nexport const GENERIC_EVENT_SUFFIXES = new Set([\"Click\", \"Change\", \"Input\", \"Blur\", \"Focus\"]);\n\nexport const TRIVIAL_INITIALIZER_NAMES = new Set([\n \"Boolean\",\n \"String\",\n \"Number\",\n \"Array\",\n \"Object\",\n \"parseInt\",\n \"parseFloat\",\n]);\n\nexport const SETTER_PATTERN = /^set[A-Z]/;\nexport const RENDER_FUNCTION_PATTERN = /^render[A-Z]/;\nexport const UPPERCASE_PATTERN = /^[A-Z]/;\nexport const PAGE_FILE_PATTERN = /\\/page\\.(tsx?|jsx?)$/;\nexport const PAGE_OR_LAYOUT_FILE_PATTERN = /\\/(page|layout)\\.(tsx?|jsx?)$/;\n\nexport const INTERNAL_PAGE_PATH_PATTERN =\n /\\/(?:(?:\\((?:dashboard|admin|settings|account|internal|manage|console|portal|auth|onboarding|app|ee|protected)\\))|(?:dashboard|admin|settings|account|internal|manage|console|portal))\\//i;\n\nexport const TEST_FILE_PATTERN = /\\.(?:test|spec|stories)\\.[tj]sx?$/;\nexport const OG_ROUTE_PATTERN = /\\/og\\b/i;\n\nexport const PAGES_DIRECTORY_PATTERN = /\\/pages\\//;\nexport const SERVER_ACTION_FILE_PATTERN = /actions?\\.(tsx?|jsx?)$/;\nexport const SERVER_ACTION_DIRECTORY_PATTERN = /\\/actions\\//;\n\nexport const NEXTJS_NAVIGATION_FUNCTIONS = new Set([\n \"redirect\",\n \"permanentRedirect\",\n \"notFound\",\n \"forbidden\",\n \"unauthorized\",\n]);\n\nexport const GOOGLE_FONTS_PATTERN = /fonts\\.googleapis\\.com/;\n\nexport const POLYFILL_SCRIPT_PATTERN = /polyfill\\.io|polyfill\\.min\\.js|cdn\\.polyfill/;\n\nexport const EXECUTABLE_SCRIPT_TYPES = new Set([\n \"text/javascript\",\n \"application/javascript\",\n \"module\",\n]);\n\nexport const APP_DIRECTORY_PATTERN = /\\/app\\//;\n\nexport const ROUTE_HANDLER_FILE_PATTERN = /\\/route\\.(tsx?|jsx?)$/;\n\nexport const MUTATION_METHOD_NAMES = new Set([\n \"create\",\n \"insert\",\n \"insertInto\",\n \"update\",\n \"upsert\",\n \"delete\",\n \"remove\",\n \"destroy\",\n \"set\",\n \"append\",\n]);\n\nexport const MUTATING_HTTP_METHODS = new Set([\"POST\", \"PUT\", \"DELETE\", \"PATCH\"]);\n\nexport const MUTATING_ROUTE_SEGMENTS = new Set([\n \"logout\",\n \"log-out\",\n \"signout\",\n \"sign-out\",\n \"unsubscribe\",\n \"delete\",\n \"remove\",\n \"revoke\",\n \"cancel\",\n \"deactivate\",\n]);\n\nexport const EFFECT_HOOK_NAMES = new Set([\"useEffect\", \"useLayoutEffect\"]);\nexport const HOOKS_WITH_DEPS = new Set([\"useEffect\", \"useLayoutEffect\", \"useMemo\", \"useCallback\"]);\nexport const CHAINABLE_ITERATION_METHODS = new Set([\"map\", \"filter\", \"forEach\", \"flatMap\"]);\nexport const STORAGE_OBJECTS = new Set([\"localStorage\", \"sessionStorage\"]);\n\nexport const LARGE_BLUR_THRESHOLD_PX = 10;\nexport const BLUR_VALUE_PATTERN = /blur\\((\\d+(?:\\.\\d+)?)px\\)/;\nexport const ANIMATION_CALLBACK_NAMES = new Set([\"requestAnimationFrame\", \"setInterval\"]);\nexport const MOTION_LIBRARY_PACKAGES = new Set([\"framer-motion\", \"motion\"]);\n\nexport const RAW_TEXT_PREVIEW_MAX_CHARS = 30;\n\nexport const REACT_NATIVE_TEXT_COMPONENTS = new Set([\n \"Text\",\n \"TextInput\",\n \"Typography\",\n \"Paragraph\",\n \"Span\",\n \"H1\",\n \"H2\",\n \"H3\",\n \"H4\",\n \"H5\",\n \"H6\",\n]);\n\nexport const REACT_NATIVE_TEXT_COMPONENT_KEYWORDS = new Set([\n \"Text\",\n \"Title\",\n \"Label\",\n \"Heading\",\n \"Caption\",\n \"Subtitle\",\n \"Typography\",\n \"Paragraph\",\n \"Description\",\n \"Body\",\n]);\n\nexport const DEPRECATED_RN_MODULE_REPLACEMENTS: Record<string, string> = {\n AsyncStorage: \"@react-native-async-storage/async-storage\",\n Picker: \"@react-native-picker/picker\",\n PickerIOS: \"@react-native-picker/picker\",\n DatePickerIOS: \"@react-native-community/datetimepicker\",\n DatePickerAndroid: \"@react-native-community/datetimepicker\",\n ProgressBarAndroid: \"a community alternative\",\n ProgressViewIOS: \"a community alternative\",\n SafeAreaView: \"react-native-safe-area-context\",\n Slider: \"@react-native-community/slider\",\n ViewPagerAndroid: \"react-native-pager-view\",\n WebView: \"react-native-webview\",\n NetInfo: \"@react-native-community/netinfo\",\n CameraRoll: \"@react-native-camera-roll/camera-roll\",\n Clipboard: \"@react-native-clipboard/clipboard\",\n ImageEditor: \"@react-native-community/image-editor\",\n MaskedViewIOS: \"@react-native-masked-view/masked-view\",\n};\n\nexport const LEGACY_EXPO_PACKAGE_REPLACEMENTS: Record<string, string> = {\n \"expo-av\": \"expo-audio for audio and expo-video for video\",\n \"expo-permissions\": \"the permissions API in each module (e.g. Camera.requestPermissionsAsync())\",\n \"@expo/vector-icons\":\n \"expo-symbols or expo-image (see https://docs.expo.dev/versions/latest/sdk/symbols/)\",\n};\n\nexport const REACT_NATIVE_LIST_COMPONENTS = new Set([\n \"FlatList\",\n \"SectionList\",\n \"VirtualizedList\",\n \"FlashList\",\n]);\n\nexport const LEGACY_SHADOW_STYLE_PROPERTIES = new Set([\n \"shadowColor\",\n \"shadowOffset\",\n \"shadowOpacity\",\n \"shadowRadius\",\n \"elevation\",\n]);\n\nexport const BOUNCE_ANIMATION_NAMES = new Set([\"bounce\", \"elastic\", \"wobble\", \"jiggle\", \"spring\"]);\n\nexport const Z_INDEX_ABSURD_THRESHOLD = 100;\n\nexport const INLINE_STYLE_PROPERTY_THRESHOLD = 8;\n\nexport const SIDE_TAB_BORDER_WIDTH_WITHOUT_RADIUS_PX = 3;\n\nexport const SIDE_TAB_BORDER_WIDTH_WITH_RADIUS_PX = 1;\n\nexport const SIDE_TAB_TAILWIND_WIDTH_WITHOUT_RADIUS = 4;\n\nexport const DARK_GLOW_BLUR_THRESHOLD_PX = 4;\n\nexport const DARK_BACKGROUND_CHANNEL_MAX = 35;\n\nexport const COLOR_CHROMA_THRESHOLD = 30;\n\nexport const TINY_TEXT_THRESHOLD_PX = 12;\n\nexport const WIDE_TRACKING_THRESHOLD_EM = 0.05;\n\nexport const LONG_TRANSITION_DURATION_THRESHOLD_MS = 1000;\n","import fs from \"node:fs\";\n\nexport const isFile = (filePath: string): boolean => {\n try {\n return fs.statSync(filePath).isFile();\n } catch {\n return false;\n }\n};\n","import fs from \"node:fs\";\nimport type { PackageJson } from \"../types.js\";\n\nexport const readPackageJson = (packageJsonPath: string): PackageJson => {\n try {\n return JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n } catch (error) {\n if (error instanceof SyntaxError) {\n return {};\n }\n if (error instanceof Error && \"code\" in error) {\n const { code } = error as { code: string };\n if (code === \"EISDIR\" || code === \"EACCES\") {\n return {};\n }\n }\n throw error;\n }\n};\n","import { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { MOTION_LIBRARY_PACKAGES } from \"../plugin/constants.js\";\nimport type { Diagnostic } from \"../types.js\";\nimport { isFile } from \"./is-file.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REDUCED_MOTION_GREP_PATTERN =\n \"prefers-reduced-motion|useReducedMotion|MotionConfig|reducedMotion\";\nconst REDUCED_MOTION_FILE_GLOBS = '\"*.ts\" \"*.tsx\" \"*.js\" \"*.jsx\" \"*.css\" \"*.scss\"';\n\nconst MISSING_REDUCED_MOTION_DIAGNOSTIC: Diagnostic = {\n filePath: \"package.json\",\n plugin: \"react-doctor\",\n rule: \"require-reduced-motion\",\n severity: \"error\",\n message:\n \"Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)\",\n help: \"Add `useReducedMotion()` from your animation library, or a `@media (prefers-reduced-motion: reduce)` CSS query\",\n line: 0,\n column: 0,\n category: \"Accessibility\",\n weight: 2,\n};\n\nexport const checkReducedMotion = (rootDirectory: string): Diagnostic[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!isFile(packageJsonPath)) return [];\n\n let hasMotionLibrary = false;\n try {\n const packageJson = readPackageJson(packageJsonPath);\n const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };\n hasMotionLibrary = Object.keys(allDependencies).some((packageName) =>\n MOTION_LIBRARY_PACKAGES.has(packageName),\n );\n } catch {\n return [];\n }\n if (!hasMotionLibrary) return [];\n\n try {\n execSync(`git grep -ql -E \"${REDUCED_MOTION_GREP_PATTERN}\" -- ${REDUCED_MOTION_FILE_GLOBS}`, {\n cwd: rootDirectory,\n stdio: \"pipe\",\n });\n return [];\n } catch {\n return [MISSING_REDUCED_MOTION_DIAGNOSTIC];\n }\n};\n","import path from \"node:path\";\nimport { isFile } from \"./is-file.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nexport const isMonorepoRoot = (directory: string): boolean => {\n if (isFile(path.join(directory, \"pnpm-workspace.yaml\"))) return true;\n if (isFile(path.join(directory, \"nx.json\"))) return true;\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!isFile(packageJsonPath)) return false;\n const packageJson = readPackageJson(packageJsonPath);\n return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);\n};\n\nexport const findMonorepoRoot = (startDirectory: string): string | null => {\n let currentDirectory = path.dirname(startDirectory);\n\n while (currentDirectory !== path.dirname(currentDirectory)) {\n if (isMonorepoRoot(currentDirectory)) return currentDirectory;\n currentDirectory = path.dirname(currentDirectory);\n }\n\n return null;\n};\n","export const isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport {\n GIT_LS_FILES_MAX_BUFFER_BYTES,\n IGNORED_DIRECTORIES,\n SOURCE_FILE_PATTERN,\n} from \"../constants.js\";\nimport type {\n DependencyInfo,\n Framework,\n PackageJson,\n ProjectInfo,\n WorkspacePackage,\n} from \"../types.js\";\nimport { findMonorepoRoot, isMonorepoRoot } from \"./find-monorepo-root.js\";\nimport { isFile } from \"./is-file.js\";\nimport { isPlainObject } from \"./is-plain-object.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REACT_COMPILER_PACKAGES = new Set([\n \"babel-plugin-react-compiler\",\n \"react-compiler-runtime\",\n \"eslint-plugin-react-compiler\",\n]);\n\nconst NEXT_CONFIG_FILENAMES = [\n \"next.config.js\",\n \"next.config.mjs\",\n \"next.config.ts\",\n \"next.config.cjs\",\n];\n\nconst BABEL_CONFIG_FILENAMES = [\n \".babelrc\",\n \".babelrc.json\",\n \"babel.config.js\",\n \"babel.config.json\",\n \"babel.config.cjs\",\n \"babel.config.mjs\",\n];\n\nconst VITE_CONFIG_FILENAMES = [\n \"vite.config.js\",\n \"vite.config.ts\",\n \"vite.config.mjs\",\n \"vite.config.cjs\",\n];\n\nconst EXPO_APP_CONFIG_FILENAMES = [\"app.json\", \"app.config.js\", \"app.config.ts\"];\n\nconst REACT_COMPILER_PACKAGE_REFERENCE_PATTERN =\n /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|[\"']react-compiler[\"']/;\nconst REACT_COMPILER_ENABLED_FLAG_PATTERN = /[\"']?reactCompiler[\"']?\\s*:\\s*true\\b/;\n\nconst FRAMEWORK_PACKAGES: Record<string, Framework> = {\n next: \"nextjs\",\n \"@tanstack/react-start\": \"tanstack-start\",\n vite: \"vite\",\n \"react-scripts\": \"cra\",\n \"@remix-run/react\": \"remix\",\n gatsby: \"gatsby\",\n expo: \"expo\",\n \"react-native\": \"react-native\",\n};\n\nconst FRAMEWORK_DISPLAY_NAMES: Record<Framework, string> = {\n nextjs: \"Next.js\",\n \"tanstack-start\": \"TanStack Start\",\n vite: \"Vite\",\n cra: \"Create React App\",\n remix: \"Remix\",\n gatsby: \"Gatsby\",\n expo: \"Expo\",\n \"react-native\": \"React Native\",\n unknown: \"React\",\n};\n\nexport const formatFrameworkName = (framework: Framework): string =>\n FRAMEWORK_DISPLAY_NAMES[framework];\n\nconst countSourceFilesViaFilesystem = (rootDirectory: string): number => {\n let count = 0;\n const stack = [rootDirectory];\n\n while (stack.length > 0) {\n const currentDirectory = stack.pop()!;\n const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (!entry.name.startsWith(\".\") && !IGNORED_DIRECTORIES.has(entry.name)) {\n stack.push(path.join(currentDirectory, entry.name));\n }\n continue;\n }\n if (entry.isFile() && SOURCE_FILE_PATTERN.test(entry.name)) {\n count++;\n }\n }\n }\n\n return count;\n};\n\nconst countSourceFilesViaGit = (rootDirectory: string): number | null => {\n const result = spawnSync(\"git\", [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"], {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,\n });\n\n if (result.error || result.status !== 0) {\n return null;\n }\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath)).length;\n};\n\nconst countSourceFiles = (rootDirectory: string): number =>\n countSourceFilesViaGit(rootDirectory) ?? countSourceFilesViaFilesystem(rootDirectory);\n\nconst collectAllDependencies = (packageJson: PackageJson): Record<string, string> => ({\n ...packageJson.peerDependencies,\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n});\n\nconst detectFramework = (dependencies: Record<string, string>): Framework => {\n for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) {\n if (dependencies[packageName]) {\n return frameworkName;\n }\n }\n return \"unknown\";\n};\n\nconst isCatalogReference = (version: string): boolean => version.startsWith(\"catalog:\");\n\nconst extractCatalogName = (version: string): string | null => {\n if (!isCatalogReference(version)) return null;\n const name = version.slice(\"catalog:\".length).trim();\n return name.length > 0 ? name : null;\n};\n\nconst resolveVersionFromCatalog = (\n catalog: Record<string, unknown>,\n packageName: string,\n): string | null => {\n const version = catalog[packageName];\n if (typeof version === \"string\" && !isCatalogReference(version)) return version;\n return null;\n};\n\ninterface CatalogCollection {\n defaultCatalog: Record<string, string>;\n namedCatalogs: Record<string, Record<string, string>>;\n}\n\nconst parsePnpmWorkspaceCatalogs = (rootDirectory: string): CatalogCollection => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!isFile(workspacePath)) return { defaultCatalog: {}, namedCatalogs: {} };\n\n const content = fs.readFileSync(workspacePath, \"utf-8\");\n const defaultCatalog: Record<string, string> = {};\n const namedCatalogs: Record<string, Record<string, string>> = {};\n\n let currentSection: \"none\" | \"catalog\" | \"catalogs\" | \"named-catalog\" = \"none\";\n let currentCatalogName = \"\";\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.length === 0 || trimmed.startsWith(\"#\")) continue;\n\n const indentLevel = line.search(/\\S/);\n\n if (indentLevel === 0 && trimmed === \"catalog:\") {\n currentSection = \"catalog\";\n continue;\n }\n if (indentLevel === 0 && trimmed === \"catalogs:\") {\n currentSection = \"catalogs\";\n continue;\n }\n if (indentLevel === 0) {\n currentSection = \"none\";\n continue;\n }\n\n if (currentSection === \"catalog\" && indentLevel > 0) {\n const colonIndex = trimmed.indexOf(\":\");\n if (colonIndex > 0) {\n const key = trimmed.slice(0, colonIndex).trim().replace(/[\"']/g, \"\");\n const value = trimmed\n .slice(colonIndex + 1)\n .trim()\n .replace(/[\"']/g, \"\");\n if (key && value) defaultCatalog[key] = value;\n }\n continue;\n }\n\n if (currentSection === \"catalogs\" && indentLevel > 0) {\n if (trimmed.endsWith(\":\") && !trimmed.includes(\" \")) {\n currentCatalogName = trimmed.slice(0, -1).replace(/[\"']/g, \"\");\n currentSection = \"named-catalog\";\n namedCatalogs[currentCatalogName] = {};\n continue;\n }\n }\n\n if (currentSection === \"named-catalog\" && indentLevel > 0) {\n if (indentLevel <= 2 && trimmed.endsWith(\":\") && !trimmed.includes(\" \")) {\n currentCatalogName = trimmed.slice(0, -1).replace(/[\"']/g, \"\");\n namedCatalogs[currentCatalogName] = {};\n continue;\n }\n const colonIndex = trimmed.indexOf(\":\");\n if (colonIndex > 0 && currentCatalogName) {\n const key = trimmed.slice(0, colonIndex).trim().replace(/[\"']/g, \"\");\n const value = trimmed\n .slice(colonIndex + 1)\n .trim()\n .replace(/[\"']/g, \"\");\n if (key && value) namedCatalogs[currentCatalogName][key] = value;\n }\n }\n }\n\n return { defaultCatalog, namedCatalogs };\n};\n\nconst resolveCatalogVersionFromCollection = (\n catalogs: CatalogCollection,\n packageName: string,\n catalogReference?: string | null,\n): string | null => {\n if (catalogReference) {\n const namedCatalog = catalogs.namedCatalogs[catalogReference];\n if (namedCatalog?.[packageName]) return namedCatalog[packageName];\n }\n\n if (catalogs.defaultCatalog[packageName]) return catalogs.defaultCatalog[packageName];\n\n for (const namedCatalog of Object.values(catalogs.namedCatalogs)) {\n if (namedCatalog[packageName]) return namedCatalog[packageName];\n }\n\n return null;\n};\n\nconst resolveCatalogVersion = (\n packageJson: PackageJson,\n packageName: string,\n rootDirectory?: string,\n): string | null => {\n const allDependencies = collectAllDependencies(packageJson);\n const rawVersion = allDependencies[packageName];\n const catalogName = rawVersion ? extractCatalogName(rawVersion) : null;\n\n const raw = packageJson as Record<string, unknown>;\n\n if (isPlainObject(raw.catalog)) {\n const version = resolveVersionFromCatalog(raw.catalog, packageName);\n if (version) return version;\n }\n\n if (isPlainObject(raw.catalogs)) {\n if (catalogName && isPlainObject((raw.catalogs as Record<string, unknown>)[catalogName])) {\n const version = resolveVersionFromCatalog(\n (raw.catalogs as Record<string, unknown>)[catalogName] as Record<string, unknown>,\n packageName,\n );\n if (version) return version;\n }\n for (const catalogEntries of Object.values(raw.catalogs)) {\n if (isPlainObject(catalogEntries)) {\n const version = resolveVersionFromCatalog(catalogEntries, packageName);\n if (version) return version;\n }\n }\n }\n\n const workspaces = packageJson.workspaces;\n if (workspaces && !Array.isArray(workspaces) && isPlainObject(workspaces.catalog)) {\n const version = resolveVersionFromCatalog(\n workspaces.catalog as Record<string, unknown>,\n packageName,\n );\n if (version) return version;\n }\n\n if (rootDirectory) {\n const pnpmCatalogs = parsePnpmWorkspaceCatalogs(rootDirectory);\n const pnpmVersion = resolveCatalogVersionFromCollection(pnpmCatalogs, packageName, catalogName);\n if (pnpmVersion) return pnpmVersion;\n }\n\n return null;\n};\n\nconst extractDependencyInfo = (packageJson: PackageJson): DependencyInfo => {\n const allDependencies = collectAllDependencies(packageJson);\n const rawVersion = allDependencies.react ?? null;\n const reactVersion = rawVersion && !isCatalogReference(rawVersion) ? rawVersion : null;\n return {\n reactVersion,\n framework: detectFramework(allDependencies),\n };\n};\n\nconst parsePnpmWorkspacePatterns = (rootDirectory: string): string[] => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!isFile(workspacePath)) return [];\n\n const content = fs.readFileSync(workspacePath, \"utf-8\");\n const patterns: string[] = [];\n let isInsidePackagesBlock = false;\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed === \"packages:\") {\n isInsidePackagesBlock = true;\n continue;\n }\n if (isInsidePackagesBlock && trimmed.startsWith(\"-\")) {\n patterns.push(trimmed.replace(/^-\\s*/, \"\").replace(/[\"']/g, \"\"));\n } else if (isInsidePackagesBlock && trimmed.length > 0 && !trimmed.startsWith(\"#\")) {\n isInsidePackagesBlock = false;\n }\n }\n\n return patterns;\n};\n\nconst getWorkspacePatterns = (rootDirectory: string, packageJson: PackageJson): string[] => {\n const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);\n if (pnpmPatterns.length > 0) return pnpmPatterns;\n\n if (Array.isArray(packageJson.workspaces)) {\n return packageJson.workspaces;\n }\n\n if (packageJson.workspaces?.packages) {\n return packageJson.workspaces.packages;\n }\n\n return [];\n};\n\nconst resolveWorkspaceDirectories = (rootDirectory: string, pattern: string): string[] => {\n const cleanPattern = pattern.replace(/[\"']/g, \"\").replace(/\\/\\*\\*$/, \"/*\");\n\n if (!cleanPattern.includes(\"*\")) {\n const directoryPath = path.join(rootDirectory, cleanPattern);\n if (fs.existsSync(directoryPath) && isFile(path.join(directoryPath, \"package.json\"))) {\n return [directoryPath];\n }\n return [];\n }\n\n const wildcardIndex = cleanPattern.indexOf(\"*\");\n const baseDirectory = path.join(rootDirectory, cleanPattern.slice(0, wildcardIndex));\n const suffixAfterWildcard = cleanPattern.slice(wildcardIndex + 1);\n\n if (!fs.existsSync(baseDirectory) || !fs.statSync(baseDirectory).isDirectory()) {\n return [];\n }\n\n return fs\n .readdirSync(baseDirectory)\n .map((entry) => path.join(baseDirectory, entry, suffixAfterWildcard))\n .filter(\n (entryPath) =>\n fs.existsSync(entryPath) &&\n fs.statSync(entryPath).isDirectory() &&\n isFile(path.join(entryPath, \"package.json\")),\n );\n};\n\nconst findDependencyInfoFromMonorepoRoot = (directory: string): DependencyInfo => {\n const monorepoRoot = findMonorepoRoot(directory);\n if (!monorepoRoot) return { reactVersion: null, framework: \"unknown\" };\n\n const monorepoPackageJsonPath = path.join(monorepoRoot, \"package.json\");\n if (!isFile(monorepoPackageJsonPath)) return { reactVersion: null, framework: \"unknown\" };\n\n const rootPackageJson = readPackageJson(monorepoPackageJsonPath);\n const rootInfo = extractDependencyInfo(rootPackageJson);\n const catalogVersion = resolveCatalogVersion(rootPackageJson, \"react\", monorepoRoot);\n const workspaceInfo = findReactInWorkspaces(monorepoRoot, rootPackageJson);\n\n return {\n reactVersion: rootInfo.reactVersion ?? catalogVersion ?? workspaceInfo.reactVersion,\n framework: rootInfo.framework !== \"unknown\" ? rootInfo.framework : workspaceInfo.framework,\n };\n};\n\nconst findReactInWorkspaces = (rootDirectory: string, packageJson: PackageJson): DependencyInfo => {\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n const result: DependencyInfo = { reactVersion: null, framework: \"unknown\" };\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n const info = extractDependencyInfo(workspacePackageJson);\n\n if (info.reactVersion && !result.reactVersion) {\n result.reactVersion = info.reactVersion;\n }\n if (info.framework !== \"unknown\" && result.framework === \"unknown\") {\n result.framework = info.framework;\n }\n\n if (result.reactVersion && result.framework !== \"unknown\") {\n return result;\n }\n }\n }\n\n return result;\n};\n\nconst REACT_DEPENDENCY_NAMES = new Set([\"react\", \"react-native\", \"next\"]);\n\nconst hasReactDependency = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some((packageName) =>\n REACT_DEPENDENCY_NAMES.has(packageName),\n );\n};\n\nexport const discoverReactSubprojects = (rootDirectory: string): WorkspacePackage[] => {\n if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];\n\n const packages: WorkspacePackage[] = [];\n\n const rootPackageJsonPath = path.join(rootDirectory, \"package.json\");\n if (isFile(rootPackageJsonPath)) {\n const rootPackageJson = readPackageJson(rootPackageJsonPath);\n if (hasReactDependency(rootPackageJson)) {\n const name = rootPackageJson.name ?? path.basename(rootDirectory);\n packages.push({ name, directory: rootDirectory });\n }\n }\n\n const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n continue;\n }\n\n const subdirectory = path.join(rootDirectory, entry.name);\n const packageJsonPath = path.join(subdirectory, \"package.json\");\n if (!isFile(packageJsonPath)) continue;\n\n const packageJson = readPackageJson(packageJsonPath);\n if (!hasReactDependency(packageJson)) continue;\n\n const name = packageJson.name ?? entry.name;\n packages.push({ name, directory: subdirectory });\n }\n\n return packages;\n};\n\nexport const listWorkspacePackages = (rootDirectory: string): WorkspacePackage[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!isFile(packageJsonPath)) return [];\n\n const packageJson = readPackageJson(packageJsonPath);\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n if (patterns.length === 0) return [];\n\n const packages: WorkspacePackage[] = [];\n\n if (hasReactDependency(packageJson)) {\n const rootName = packageJson.name ?? path.basename(rootDirectory);\n packages.push({ name: rootName, directory: rootDirectory });\n }\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n\n if (!hasReactDependency(workspacePackageJson)) continue;\n\n const name = workspacePackageJson.name ?? path.basename(workspaceDirectory);\n packages.push({ name, directory: workspaceDirectory });\n }\n }\n\n return packages;\n};\n\nconst hasCompilerPackage = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some((packageName) =>\n REACT_COMPILER_PACKAGES.has(packageName),\n );\n};\n\nconst fileContainsPattern = (filePath: string, pattern: RegExp): boolean => {\n if (!isFile(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return pattern.test(content);\n};\n\nconst hasCompilerInConfigFile = (filePath: string): boolean => {\n if (!isFile(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return (\n REACT_COMPILER_ENABLED_FLAG_PATTERN.test(content) ||\n REACT_COMPILER_PACKAGE_REFERENCE_PATTERN.test(content)\n );\n};\n\nconst hasCompilerInConfigFiles = (directory: string, filenames: string[]): boolean =>\n filenames.some((filename) => hasCompilerInConfigFile(path.join(directory, filename)));\n\nconst detectReactCompiler = (directory: string, packageJson: PackageJson): boolean => {\n if (hasCompilerPackage(packageJson)) return true;\n\n if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;\n\n let ancestorDirectory = path.dirname(directory);\n while (ancestorDirectory !== path.dirname(ancestorDirectory)) {\n const ancestorPackagePath = path.join(ancestorDirectory, \"package.json\");\n if (isFile(ancestorPackagePath)) {\n const ancestorPackageJson = readPackageJson(ancestorPackagePath);\n if (hasCompilerPackage(ancestorPackageJson)) return true;\n }\n ancestorDirectory = path.dirname(ancestorDirectory);\n }\n\n return false;\n};\n\nexport const discoverProject = (directory: string): ProjectInfo => {\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!isFile(packageJsonPath)) {\n throw new Error(`No package.json found in ${directory}`);\n }\n\n const packageJson = readPackageJson(packageJsonPath);\n let { reactVersion, framework } = extractDependencyInfo(packageJson);\n\n if (!reactVersion) {\n reactVersion = resolveCatalogVersion(packageJson, \"react\", directory);\n }\n\n if (!reactVersion) {\n const monorepoRoot = findMonorepoRoot(directory);\n if (monorepoRoot) {\n const monorepoPackageJsonPath = path.join(monorepoRoot, \"package.json\");\n if (isFile(monorepoPackageJsonPath)) {\n const rootPackageJson = readPackageJson(monorepoPackageJsonPath);\n reactVersion = resolveCatalogVersion(rootPackageJson, \"react\", monorepoRoot);\n }\n }\n }\n\n if (!reactVersion || framework === \"unknown\") {\n const workspaceInfo = findReactInWorkspaces(directory, packageJson);\n if (!reactVersion && workspaceInfo.reactVersion) {\n reactVersion = workspaceInfo.reactVersion;\n }\n if (framework === \"unknown\" && workspaceInfo.framework !== \"unknown\") {\n framework = workspaceInfo.framework;\n }\n }\n\n if ((!reactVersion || framework === \"unknown\") && !isMonorepoRoot(directory)) {\n const monorepoInfo = findDependencyInfoFromMonorepoRoot(directory);\n if (!reactVersion) {\n reactVersion = monorepoInfo.reactVersion;\n }\n if (framework === \"unknown\") {\n framework = monorepoInfo.framework;\n }\n }\n\n const projectName = packageJson.name ?? path.basename(directory);\n const hasTypeScript = fs.existsSync(path.join(directory, \"tsconfig.json\"));\n const sourceFileCount = countSourceFiles(directory);\n\n const hasReactCompiler = detectReactCompiler(directory, packageJson);\n\n return {\n rootDirectory: directory,\n projectName,\n reactVersion,\n framework,\n hasTypeScript,\n hasReactCompiler,\n sourceFileCount,\n };\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { ReactDoctorConfig } from \"../types.js\";\nimport { isFile } from \"./is-file.js\";\nimport { isPlainObject } from \"./is-plain-object.js\";\n\nconst CONFIG_FILENAME = \"react-doctor.config.json\";\nconst PACKAGE_JSON_CONFIG_KEY = \"reactDoctor\";\n\nconst loadConfigFromDirectory = (directory: string): ReactDoctorConfig | null => {\n const configFilePath = path.join(directory, CONFIG_FILENAME);\n\n if (isFile(configFilePath)) {\n try {\n const fileContent = fs.readFileSync(configFilePath, \"utf-8\");\n const parsed: unknown = JSON.parse(fileContent);\n if (isPlainObject(parsed)) {\n return parsed as ReactDoctorConfig;\n }\n console.warn(`Warning: ${CONFIG_FILENAME} must be a JSON object, ignoring.`);\n } catch (error) {\n console.warn(\n `Warning: Failed to parse ${CONFIG_FILENAME}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n const packageJsonPath = path.join(directory, \"package.json\");\n if (isFile(packageJsonPath)) {\n try {\n const fileContent = fs.readFileSync(packageJsonPath, \"utf-8\");\n const packageJson = JSON.parse(fileContent);\n const embeddedConfig = packageJson[PACKAGE_JSON_CONFIG_KEY];\n if (isPlainObject(embeddedConfig)) {\n return embeddedConfig as ReactDoctorConfig;\n }\n } catch {\n return null;\n }\n }\n\n return null;\n};\n\nexport const loadConfig = (rootDirectory: string): ReactDoctorConfig | null => {\n const localConfig = loadConfigFromDirectory(rootDirectory);\n if (localConfig) return localConfig;\n\n let ancestorDirectory = path.dirname(rootDirectory);\n while (ancestorDirectory !== path.dirname(ancestorDirectory)) {\n const ancestorConfig = loadConfigFromDirectory(ancestorDirectory);\n if (ancestorConfig) return ancestorConfig;\n ancestorDirectory = path.dirname(ancestorDirectory);\n }\n\n return null;\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport const createNodeReadFileLinesSync = (\n rootDirectory: string,\n): ((filePath: string) => string[] | null) => {\n return (filePath: string): string[] | null => {\n const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(rootDirectory, filePath);\n try {\n return fs.readFileSync(absolutePath, \"utf-8\").split(\"\\n\");\n } catch {\n return null;\n }\n };\n};\n","import { spawnSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n GIT_LS_FILES_MAX_BUFFER_BYTES,\n IGNORED_DIRECTORIES,\n JSX_FILE_PATTERN,\n SOURCE_FILE_PATTERN,\n} from \"../constants.js\";\nimport type { ReactDoctorConfig } from \"../types.js\";\nimport { compileIgnoredFilePatterns, isFileIgnoredByPatterns } from \"./is-ignored-file.js\";\n\nconst listSourceFilesViaGit = (rootDirectory: string): string[] | null => {\n const result = spawnSync(\"git\", [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"], {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,\n });\n\n if (result.error || result.status !== 0) {\n return null;\n }\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath));\n};\n\nconst listSourceFilesViaFilesystem = (rootDirectory: string): string[] => {\n const filePaths: string[] = [];\n const stack = [rootDirectory];\n\n while (stack.length > 0) {\n const currentDirectory = stack.pop()!;\n const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });\n\n for (const entry of entries) {\n const absolutePath = path.join(currentDirectory, entry.name);\n\n if (entry.isDirectory()) {\n if (!entry.name.startsWith(\".\") && !IGNORED_DIRECTORIES.has(entry.name)) {\n stack.push(absolutePath);\n }\n continue;\n }\n\n if (entry.isFile() && SOURCE_FILE_PATTERN.test(entry.name)) {\n filePaths.push(path.relative(rootDirectory, absolutePath).replace(/\\\\/g, \"/\"));\n }\n }\n }\n\n return filePaths;\n};\n\nconst listSourceFiles = (rootDirectory: string): string[] =>\n listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory);\n\nexport const resolveLintIncludePaths = (\n rootDirectory: string,\n userConfig: ReactDoctorConfig | null,\n): string[] | undefined => {\n if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) {\n return undefined;\n }\n\n const ignoredPatterns = compileIgnoredFilePatterns(userConfig);\n\n const includedPaths = listSourceFiles(rootDirectory).filter((filePath) => {\n if (!JSX_FILE_PATTERN.test(filePath)) {\n return false;\n }\n\n return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);\n });\n\n return includedPaths;\n};\n","import {\n ERROR_RULE_PENALTY,\n PERFECT_SCORE,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n WARNING_RULE_PENALTY,\n} from \"../constants.js\";\nimport type { Diagnostic, ScoreResult } from \"../types.js\";\n\nconst getScoreLabel = (score: number): string => {\n if (score >= SCORE_GOOD_THRESHOLD) return \"Great\";\n if (score >= SCORE_OK_THRESHOLD) return \"Needs work\";\n return \"Critical\";\n};\n\nconst countUniqueRules = (\n diagnostics: Diagnostic[],\n): { errorRuleCount: number; warningRuleCount: number } => {\n const errorRules = new Set<string>();\n const warningRules = new Set<string>();\n\n for (const diagnostic of diagnostics) {\n const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;\n if (diagnostic.severity === \"error\") {\n errorRules.add(ruleKey);\n } else {\n warningRules.add(ruleKey);\n }\n }\n\n return { errorRuleCount: errorRules.size, warningRuleCount: warningRules.size };\n};\n\nconst scoreFromRuleCounts = (errorRuleCount: number, warningRuleCount: number): number => {\n const penalty = errorRuleCount * ERROR_RULE_PENALTY + warningRuleCount * WARNING_RULE_PENALTY;\n return Math.max(0, Math.round(PERFECT_SCORE - penalty));\n};\n\nexport const calculateScoreLocally = (diagnostics: Diagnostic[]): ScoreResult => {\n const { errorRuleCount, warningRuleCount } = countUniqueRules(diagnostics);\n const score = scoreFromRuleCounts(errorRuleCount, warningRuleCount);\n return { score, label: getScoreLabel(score) };\n};\n","import { FETCH_TIMEOUT_MS, SCORE_API_URL } from \"../constants.js\";\nimport type { Diagnostic, ScoreResult } from \"../types.js\";\n\ninterface ScoreRequestFetch {\n (input: string | URL, init?: RequestInit): Promise<Response>;\n}\n\nconst parseScoreResult = (value: unknown): ScoreResult | null => {\n if (typeof value !== \"object\" || value === null) return null;\n if (!(\"score\" in value) || !(\"label\" in value)) return null;\n const scoreValue = Reflect.get(value, \"score\");\n const labelValue = Reflect.get(value, \"label\");\n if (typeof scoreValue !== \"number\" || typeof labelValue !== \"string\") return null;\n return { score: scoreValue, label: labelValue };\n};\n\nexport const tryScoreFromApi = async (\n diagnostics: Diagnostic[],\n fetchImplementation: ScoreRequestFetch,\n): Promise<ScoreResult | null> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n try {\n const response = await fetchImplementation(SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics }),\n signal: controller.signal,\n });\n\n if (!response.ok) return null;\n\n return parseScoreResult(await response.json());\n } catch {\n return null;\n } finally {\n clearTimeout(timeoutId);\n }\n};\n","import { FETCH_TIMEOUT_MS } from \"../constants.js\";\n\ninterface GlobalProcessLike {\n env?: Record<string, string | undefined>;\n versions?: { node?: string };\n}\n\nconst getGlobalProcess = (): GlobalProcessLike | undefined => {\n const candidate = (globalThis as { process?: GlobalProcessLike }).process;\n return candidate?.versions?.node ? candidate : undefined;\n};\n\nconst readEnvProxy = (): string | undefined => {\n const proc = getGlobalProcess();\n if (!proc?.env) return undefined;\n return proc.env.HTTPS_PROXY ?? proc.env.https_proxy ?? proc.env.HTTP_PROXY ?? proc.env.http_proxy;\n};\n\nlet isProxyUrlResolved = false;\nlet resolvedProxyUrl: string | undefined;\n\nconst getProxyUrl = (): string | undefined => {\n if (isProxyUrlResolved) return resolvedProxyUrl;\n isProxyUrlResolved = true;\n resolvedProxyUrl = readEnvProxy();\n return resolvedProxyUrl;\n};\n\nconst createProxyDispatcher = async (proxyUrl: string): Promise<object | null> => {\n try {\n // @ts-expect-error undici is bundled with Node.js 18+ but lacks standalone type declarations\n const { ProxyAgent } = await import(\"undici\");\n return new ProxyAgent(proxyUrl);\n } catch {\n return null;\n }\n};\n\n// HACK: Node.js's global fetch (undici) accepts `dispatcher` for proxy routing,\n// which isn't part of the standard RequestInit type.\nexport const proxyFetch = async (url: string | URL, init?: RequestInit): Promise<Response> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n try {\n const proxyUrl = getProxyUrl();\n const dispatcher = proxyUrl ? await createProxyDispatcher(proxyUrl) : null;\n\n return await fetch(url, {\n ...init,\n signal: controller.signal,\n ...(dispatcher ? { dispatcher } : {}),\n } as RequestInit);\n } finally {\n clearTimeout(timeoutId);\n }\n};\n","import type { Diagnostic, ScoreResult } from \"../types.js\";\nimport { calculateScoreLocally } from \"../core/calculate-score-locally.js\";\nimport { tryScoreFromApi } from \"../core/try-score-from-api.js\";\nimport { proxyFetch } from \"./proxy-fetch.js\";\n\nexport { calculateScoreLocally } from \"../core/calculate-score-locally.js\";\n\nexport const calculateScore = async (diagnostics: Diagnostic[]): Promise<ScoreResult | null> => {\n const apiScore = await tryScoreFromApi(diagnostics, proxyFetch);\n if (apiScore) return apiScore;\n return calculateScoreLocally(diagnostics);\n};\n","import type { KnipIssueRecords } from \"../types.js\";\nimport { isPlainObject } from \"./is-plain-object.js\";\n\nexport const collectUnusedFilePaths = (\n filesIssues: KnipIssueRecords | Set<string> | string[] | unknown,\n): string[] => {\n if (filesIssues instanceof Set) {\n return [...filesIssues];\n }\n\n if (Array.isArray(filesIssues)) {\n return filesIssues.filter((entry): entry is string => typeof entry === \"string\");\n }\n\n if (!isPlainObject(filesIssues)) {\n return [];\n }\n\n const unusedFilePaths: string[] = [];\n\n for (const innerValue of Object.values(filesIssues)) {\n if (!isPlainObject(innerValue)) continue;\n\n for (const issue of Object.values(innerValue)) {\n if (isPlainObject(issue) && typeof issue.filePath === \"string\") {\n unusedFilePaths.push(issue.filePath);\n }\n }\n }\n\n return unusedFilePaths;\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { main } from \"knip\";\nimport { createOptions } from \"knip/session\";\nimport { MAX_KNIP_RETRIES } from \"../constants.js\";\nimport type { Diagnostic, KnipIssueRecords, KnipResults } from \"../types.js\";\nimport { collectUnusedFilePaths } from \"./collect-unused-file-paths.js\";\nimport { findMonorepoRoot } from \"./find-monorepo-root.js\";\nimport { isFile } from \"./is-file.js\";\n\nconst KNIP_CATEGORY_MAP: Record<string, string> = {\n files: \"Dead Code\",\n exports: \"Dead Code\",\n types: \"Dead Code\",\n duplicates: \"Dead Code\",\n};\n\nconst KNIP_MESSAGE_MAP: Record<string, string> = {\n files: \"Unused file\",\n exports: \"Unused export\",\n types: \"Unused type\",\n duplicates: \"Duplicate export\",\n};\n\nconst KNIP_SEVERITY_MAP: Record<string, \"error\" | \"warning\"> = {\n files: \"warning\",\n exports: \"warning\",\n types: \"warning\",\n duplicates: \"warning\",\n};\n\nconst collectIssueRecords = (\n records: KnipIssueRecords,\n issueType: string,\n rootDirectory: string,\n): Diagnostic[] => {\n const diagnostics: Diagnostic[] = [];\n\n for (const issues of Object.values(records)) {\n for (const issue of Object.values(issues)) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, issue.filePath),\n plugin: \"knip\",\n rule: issueType,\n severity: KNIP_SEVERITY_MAP[issueType] ?? \"warning\",\n message: `${KNIP_MESSAGE_MAP[issueType]}: ${issue.symbol}`,\n help: \"\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[issueType] ?? \"Dead Code\",\n weight: 1,\n });\n }\n }\n\n return diagnostics;\n};\n\n// HACK: knip triggers dotenv which logs to stdout/stderr via console methods\nconst silenced = async <T>(fn: () => Promise<T>): Promise<T> => {\n const originalLog = console.log;\n const originalInfo = console.info;\n const originalWarn = console.warn;\n const originalError = console.error;\n console.log = () => {};\n console.info = () => {};\n console.warn = () => {};\n console.error = () => {};\n try {\n return await fn();\n } finally {\n console.log = originalLog;\n console.info = originalInfo;\n console.warn = originalWarn;\n console.error = originalError;\n }\n};\n\nconst CONFIG_LOADING_ERROR_PATTERN = /Error loading .*\\/([a-z-]+)\\.config\\./;\n\nconst extractFailedPluginName = (error: unknown): string | null => {\n const match = String(error).match(CONFIG_LOADING_ERROR_PATTERN);\n return match?.[1] ?? null;\n};\n\nconst TSCONFIG_FILENAMES = [\"tsconfig.base.json\", \"tsconfig.json\"];\n\nconst resolveTsConfigFile = (directory: string): string | undefined =>\n TSCONFIG_FILENAMES.find((filename) => fs.existsSync(path.join(directory, filename)));\n\nconst runKnipWithOptions = async (\n knipCwd: string,\n workspaceName?: string,\n): Promise<KnipResults> => {\n const tsConfigFile = resolveTsConfigFile(knipCwd);\n const options = await silenced(() =>\n createOptions({\n cwd: knipCwd,\n isShowProgress: false,\n ...(workspaceName ? { workspace: workspaceName } : {}),\n ...(tsConfigFile ? { tsConfigFile } : {}),\n }),\n );\n\n const parsedConfig = options.parsedConfig as Record<string, unknown>;\n\n for (let attempt = 0; attempt <= MAX_KNIP_RETRIES; attempt++) {\n try {\n return (await silenced(() => main(options))) as KnipResults;\n } catch (error) {\n const failedPlugin = extractFailedPluginName(error);\n if (!failedPlugin || attempt === MAX_KNIP_RETRIES) {\n throw error;\n }\n parsedConfig[failedPlugin] = false;\n }\n }\n\n throw new Error(\"Unreachable\");\n};\n\nconst hasNodeModules = (directory: string): boolean => {\n const nodeModulesPath = path.join(directory, \"node_modules\");\n return fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory();\n};\n\nexport const runKnip = async (rootDirectory: string): Promise<Diagnostic[]> => {\n const monorepoRoot = findMonorepoRoot(rootDirectory);\n const hasInstalledDependencies =\n hasNodeModules(rootDirectory) || (monorepoRoot !== null && hasNodeModules(monorepoRoot));\n\n if (!hasInstalledDependencies) {\n return [];\n }\n\n let knipResult: KnipResults;\n\n if (monorepoRoot) {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n const packageJson = isFile(packageJsonPath)\n ? JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"))\n : {};\n const workspaceName = packageJson.name ?? path.basename(rootDirectory);\n\n try {\n knipResult = await runKnipWithOptions(monorepoRoot, workspaceName);\n } catch {\n knipResult = await runKnipWithOptions(rootDirectory);\n }\n } else {\n knipResult = await runKnipWithOptions(rootDirectory);\n }\n\n const { issues } = knipResult;\n const diagnostics: Diagnostic[] = [];\n\n for (const unusedFilePath of collectUnusedFilePaths(issues.files)) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, unusedFilePath),\n plugin: \"knip\",\n rule: \"files\",\n severity: KNIP_SEVERITY_MAP[\"files\"],\n message: KNIP_MESSAGE_MAP[\"files\"],\n help: \"This file is not imported by any other file in the project.\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[\"files\"],\n weight: 1,\n });\n }\n\n const recordTypes = [\"exports\", \"types\", \"duplicates\"] as const;\n\n for (const issueType of recordTypes) {\n diagnostics.push(...collectIssueRecords(issues[issueType], issueType, rootDirectory));\n }\n\n return diagnostics;\n};\n","import { createRequire } from \"node:module\";\nimport type { Framework } from \"./types.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst NEXTJS_RULES: Record<string, string> = {\n \"react-doctor/nextjs-no-img-element\": \"warn\",\n \"react-doctor/nextjs-async-client-component\": \"error\",\n \"react-doctor/nextjs-no-a-element\": \"warn\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"warn\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"warn\",\n \"react-doctor/nextjs-missing-metadata\": \"warn\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"warn\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"warn\",\n \"react-doctor/nextjs-image-missing-sizes\": \"warn\",\n \"react-doctor/nextjs-no-native-script\": \"warn\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"warn\",\n \"react-doctor/nextjs-no-font-link\": \"warn\",\n \"react-doctor/nextjs-no-css-link\": \"warn\",\n \"react-doctor/nextjs-no-polyfill-script\": \"warn\",\n \"react-doctor/nextjs-no-head-import\": \"error\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"error\",\n};\n\nconst REACT_NATIVE_RULES: Record<string, string> = {\n \"react-doctor/rn-no-raw-text\": \"error\",\n \"react-doctor/rn-no-deprecated-modules\": \"error\",\n \"react-doctor/rn-no-legacy-expo-packages\": \"warn\",\n \"react-doctor/rn-no-dimensions-get\": \"warn\",\n \"react-doctor/rn-no-inline-flatlist-renderitem\": \"warn\",\n \"react-doctor/rn-no-legacy-shadow-styles\": \"warn\",\n \"react-doctor/rn-prefer-reanimated\": \"warn\",\n \"react-doctor/rn-no-single-element-style-array\": \"warn\",\n};\n\nconst TANSTACK_START_RULES: Record<string, string> = {\n \"react-doctor/tanstack-start-route-property-order\": \"error\",\n \"react-doctor/tanstack-start-no-direct-fetch-in-loader\": \"warn\",\n \"react-doctor/tanstack-start-server-fn-validate-input\": \"warn\",\n \"react-doctor/tanstack-start-no-useeffect-fetch\": \"warn\",\n \"react-doctor/tanstack-start-missing-head-content\": \"warn\",\n \"react-doctor/tanstack-start-no-anchor-element\": \"warn\",\n \"react-doctor/tanstack-start-server-fn-method-order\": \"error\",\n \"react-doctor/tanstack-start-no-navigate-in-render\": \"warn\",\n \"react-doctor/tanstack-start-no-dynamic-server-fn-import\": \"error\",\n \"react-doctor/tanstack-start-no-use-server-in-handler\": \"error\",\n \"react-doctor/tanstack-start-no-secrets-in-loader\": \"error\",\n \"react-doctor/tanstack-start-get-mutation\": \"warn\",\n \"react-doctor/tanstack-start-redirect-in-try-catch\": \"warn\",\n \"react-doctor/tanstack-start-loader-parallel-fetch\": \"warn\",\n};\n\nconst REACT_COMPILER_RULES: Record<string, string> = {\n \"react-hooks-js/set-state-in-render\": \"error\",\n \"react-hooks-js/immutability\": \"error\",\n \"react-hooks-js/refs\": \"error\",\n \"react-hooks-js/purity\": \"error\",\n \"react-hooks-js/hooks\": \"error\",\n \"react-hooks-js/set-state-in-effect\": \"error\",\n \"react-hooks-js/globals\": \"error\",\n \"react-hooks-js/error-boundaries\": \"error\",\n \"react-hooks-js/preserve-manual-memoization\": \"error\",\n \"react-hooks-js/unsupported-syntax\": \"error\",\n \"react-hooks-js/component-hook-factories\": \"error\",\n \"react-hooks-js/static-components\": \"error\",\n \"react-hooks-js/use-memo\": \"error\",\n \"react-hooks-js/void-use-memo\": \"error\",\n \"react-hooks-js/incompatible-library\": \"error\",\n \"react-hooks-js/todo\": \"error\",\n};\n\ninterface OxlintConfigOptions {\n pluginPath: string;\n framework: Framework;\n hasReactCompiler: boolean;\n customRulesOnly?: boolean;\n}\n\nconst BUILTIN_REACT_RULES: Record<string, string> = {\n \"react/rules-of-hooks\": \"error\",\n \"react/no-direct-mutation-state\": \"error\",\n \"react/jsx-no-duplicate-props\": \"error\",\n \"react/jsx-key\": \"error\",\n \"react/no-children-prop\": \"warn\",\n \"react/no-danger\": \"warn\",\n \"react/jsx-no-script-url\": \"error\",\n \"react/no-render-return-value\": \"warn\",\n \"react/no-string-refs\": \"warn\",\n \"react/no-is-mounted\": \"warn\",\n \"react/require-render-return\": \"error\",\n \"react/no-unknown-property\": \"warn\",\n};\n\nconst BUILTIN_A11Y_RULES: Record<string, string> = {\n \"jsx-a11y/alt-text\": \"error\",\n \"jsx-a11y/anchor-is-valid\": \"warn\",\n \"jsx-a11y/click-events-have-key-events\": \"warn\",\n \"jsx-a11y/no-static-element-interactions\": \"warn\",\n \"jsx-a11y/role-has-required-aria-props\": \"error\",\n \"jsx-a11y/no-autofocus\": \"warn\",\n \"jsx-a11y/heading-has-content\": \"warn\",\n \"jsx-a11y/html-has-lang\": \"warn\",\n \"jsx-a11y/no-redundant-roles\": \"warn\",\n \"jsx-a11y/scope\": \"warn\",\n \"jsx-a11y/tabindex-no-positive\": \"warn\",\n \"jsx-a11y/label-has-associated-control\": \"warn\",\n \"jsx-a11y/no-distracting-elements\": \"error\",\n \"jsx-a11y/iframe-has-title\": \"warn\",\n};\n\nexport const createOxlintConfig = ({\n pluginPath,\n framework,\n hasReactCompiler,\n customRulesOnly = false,\n}: OxlintConfigOptions) => ({\n categories: {\n correctness: \"off\",\n suspicious: \"off\",\n pedantic: \"off\",\n perf: \"off\",\n restriction: \"off\",\n style: \"off\",\n nursery: \"off\",\n },\n plugins: [\"react\", \"jsx-a11y\", ...(hasReactCompiler ? [] : [\"react-perf\"])],\n jsPlugins: [\n ...(hasReactCompiler && !customRulesOnly\n ? [{ name: \"react-hooks-js\", specifier: esmRequire.resolve(\"eslint-plugin-react-hooks\") }]\n : []),\n pluginPath,\n ],\n rules: {\n ...(customRulesOnly ? {} : BUILTIN_REACT_RULES),\n ...(customRulesOnly ? {} : BUILTIN_A11Y_RULES),\n ...(hasReactCompiler && !customRulesOnly ? REACT_COMPILER_RULES : {}),\n\n \"react-doctor/no-derived-state-effect\": \"error\",\n \"react-doctor/no-fetch-in-effect\": \"error\",\n \"react-doctor/no-cascading-set-state\": \"warn\",\n \"react-doctor/no-effect-event-handler\": \"warn\",\n \"react-doctor/no-derived-useState\": \"warn\",\n \"react-doctor/prefer-useReducer\": \"warn\",\n \"react-doctor/rerender-lazy-state-init\": \"warn\",\n \"react-doctor/rerender-functional-setstate\": \"warn\",\n \"react-doctor/rerender-dependencies\": \"error\",\n\n \"react-doctor/no-giant-component\": \"warn\",\n \"react-doctor/no-render-in-render\": \"warn\",\n \"react-doctor/no-nested-component-definition\": \"error\",\n\n \"react-doctor/no-usememo-simple-expression\": \"warn\",\n \"react-doctor/no-layout-property-animation\": \"error\",\n \"react-doctor/rerender-memo-with-default-value\": \"warn\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"warn\",\n \"react-doctor/no-inline-prop-on-memo-component\": \"warn\",\n \"react-doctor/rendering-hydration-no-flicker\": \"warn\",\n \"react-doctor/rendering-script-defer-async\": \"warn\",\n\n \"react-doctor/no-transition-all\": \"warn\",\n \"react-doctor/no-global-css-variable-animation\": \"error\",\n \"react-doctor/no-large-animated-blur\": \"warn\",\n \"react-doctor/no-scale-from-zero\": \"warn\",\n \"react-doctor/no-permanent-will-change\": \"warn\",\n\n \"react-doctor/no-secrets-in-client-code\": \"error\",\n\n \"react-doctor/js-flatmap-filter\": \"warn\",\n\n \"react-doctor/no-barrel-import\": \"warn\",\n \"react-doctor/no-full-lodash-import\": \"warn\",\n \"react-doctor/no-moment\": \"warn\",\n \"react-doctor/prefer-dynamic-import\": \"warn\",\n \"react-doctor/use-lazy-motion\": \"warn\",\n \"react-doctor/no-undeferred-third-party\": \"warn\",\n\n \"react-doctor/no-array-index-as-key\": \"warn\",\n \"react-doctor/rendering-conditional-render\": \"warn\",\n \"react-doctor/no-prevent-default\": \"warn\",\n\n \"react-doctor/server-auth-actions\": \"error\",\n \"react-doctor/server-after-nonblocking\": \"warn\",\n\n \"react-doctor/client-passive-event-listeners\": \"warn\",\n\n \"react-doctor/query-stable-query-client\": \"error\",\n \"react-doctor/query-no-rest-destructuring\": \"warn\",\n \"react-doctor/query-no-void-query-fn\": \"warn\",\n \"react-doctor/query-no-query-in-effect\": \"warn\",\n \"react-doctor/query-mutation-missing-invalidation\": \"warn\",\n \"react-doctor/query-no-usequery-for-mutation\": \"warn\",\n\n \"react-doctor/no-inline-bounce-easing\": \"warn\",\n \"react-doctor/no-z-index-9999\": \"warn\",\n \"react-doctor/no-inline-exhaustive-style\": \"warn\",\n \"react-doctor/no-side-tab-border\": \"warn\",\n \"react-doctor/no-pure-black-background\": \"warn\",\n \"react-doctor/no-gradient-text\": \"warn\",\n \"react-doctor/no-dark-mode-glow\": \"warn\",\n \"react-doctor/no-justified-text\": \"warn\",\n \"react-doctor/no-tiny-text\": \"warn\",\n \"react-doctor/no-wide-letter-spacing\": \"warn\",\n \"react-doctor/no-gray-on-colored-background\": \"warn\",\n \"react-doctor/no-layout-transition-inline\": \"warn\",\n \"react-doctor/no-disabled-zoom\": \"error\",\n \"react-doctor/no-outline-none\": \"warn\",\n \"react-doctor/no-long-transition-duration\": \"warn\",\n\n \"react-doctor/async-parallel\": \"warn\",\n ...(framework === \"nextjs\" ? NEXTJS_RULES : {}),\n ...(framework === \"expo\" || framework === \"react-native\" ? REACT_NATIVE_RULES : {}),\n ...(framework === \"tanstack-start\" ? TANSTACK_START_RULES : {}),\n },\n});\n","import { spawnSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { GIT_LS_FILES_MAX_BUFFER_BYTES, SOURCE_FILE_PATTERN } from \"../constants.js\";\n\nconst findFilesWithDisableDirectives = (\n rootDirectory: string,\n includePaths?: string[],\n): string[] => {\n const grepArgs = [\"grep\", \"-l\", \"--untracked\", \"-E\", \"(eslint|oxlint)-disable\"];\n if (includePaths && includePaths.length > 0) {\n grepArgs.push(\"--\", ...includePaths);\n }\n\n const result = spawnSync(\"git\", grepArgs, {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,\n });\n\n if (result.error || result.status === null) return [];\n if (result.status !== 0 && result.stdout.trim().length === 0) return [];\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath));\n};\n\nconst neutralizeContent = (content: string): string =>\n content\n .replaceAll(\"eslint-disable\", \"eslint_disable\")\n .replaceAll(\"oxlint-disable\", \"oxlint_disable\");\n\nexport const neutralizeDisableDirectives = (\n rootDirectory: string,\n includePaths?: string[],\n): (() => void) => {\n const filePaths = findFilesWithDisableDirectives(rootDirectory, includePaths);\n const originalContents = new Map<string, string>();\n\n for (const relativePath of filePaths) {\n const absolutePath = path.join(rootDirectory, relativePath);\n\n let originalContent: string;\n try {\n originalContent = fs.readFileSync(absolutePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const neutralizedContent = neutralizeContent(originalContent);\n if (neutralizedContent !== originalContent) {\n originalContents.set(absolutePath, originalContent);\n fs.writeFileSync(absolutePath, neutralizedContent);\n }\n }\n\n return () => {\n for (const [absolutePath, originalContent] of originalContents) {\n fs.writeFileSync(absolutePath, originalContent);\n }\n };\n};\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n ERROR_PREVIEW_LENGTH_CHARS,\n JSX_FILE_PATTERN,\n OXLINT_MAX_FILES_PER_BATCH,\n SPAWN_ARGS_MAX_LENGTH_CHARS,\n} from \"../constants.js\";\nimport { createOxlintConfig } from \"../oxlint-config.js\";\nimport type { CleanedDiagnostic, Diagnostic, Framework, OxlintOutput } from \"../types.js\";\nimport { neutralizeDisableDirectives } from \"./neutralize-disable-directives.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst PLUGIN_CATEGORY_MAP: Record<string, string> = {\n react: \"Correctness\",\n \"react-hooks\": \"Correctness\",\n \"react-hooks-js\": \"React Compiler\",\n \"react-perf\": \"Performance\",\n \"jsx-a11y\": \"Accessibility\",\n};\n\nconst RULE_CATEGORY_MAP: Record<string, string> = {\n \"react-doctor/no-derived-state-effect\": \"State & Effects\",\n \"react-doctor/no-fetch-in-effect\": \"State & Effects\",\n \"react-doctor/no-cascading-set-state\": \"State & Effects\",\n \"react-doctor/no-effect-event-handler\": \"State & Effects\",\n \"react-doctor/no-derived-useState\": \"State & Effects\",\n \"react-doctor/prefer-useReducer\": \"State & Effects\",\n \"react-doctor/rerender-lazy-state-init\": \"Performance\",\n \"react-doctor/rerender-functional-setstate\": \"Performance\",\n \"react-doctor/rerender-dependencies\": \"State & Effects\",\n\n \"react-doctor/no-generic-handler-names\": \"Architecture\",\n \"react-doctor/no-giant-component\": \"Architecture\",\n \"react-doctor/no-render-in-render\": \"Architecture\",\n \"react-doctor/no-nested-component-definition\": \"Correctness\",\n\n \"react-doctor/no-usememo-simple-expression\": \"Performance\",\n \"react-doctor/no-layout-property-animation\": \"Performance\",\n \"react-doctor/rerender-memo-with-default-value\": \"Performance\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"Performance\",\n \"react-doctor/rendering-usetransition-loading\": \"Performance\",\n \"react-doctor/rendering-hydration-no-flicker\": \"Performance\",\n \"react-doctor/rendering-script-defer-async\": \"Performance\",\n\n \"react-doctor/no-transition-all\": \"Performance\",\n \"react-doctor/no-global-css-variable-animation\": \"Performance\",\n \"react-doctor/no-large-animated-blur\": \"Performance\",\n \"react-doctor/no-scale-from-zero\": \"Performance\",\n \"react-doctor/no-permanent-will-change\": \"Performance\",\n\n \"react-doctor/no-secrets-in-client-code\": \"Security\",\n\n \"react-doctor/no-barrel-import\": \"Bundle Size\",\n \"react-doctor/no-full-lodash-import\": \"Bundle Size\",\n \"react-doctor/no-moment\": \"Bundle Size\",\n \"react-doctor/prefer-dynamic-import\": \"Bundle Size\",\n \"react-doctor/use-lazy-motion\": \"Bundle Size\",\n \"react-doctor/no-undeferred-third-party\": \"Bundle Size\",\n\n \"react-doctor/no-array-index-as-key\": \"Correctness\",\n \"react-doctor/rendering-conditional-render\": \"Correctness\",\n \"react-doctor/no-prevent-default\": \"Correctness\",\n \"react-doctor/nextjs-no-img-element\": \"Next.js\",\n \"react-doctor/nextjs-async-client-component\": \"Next.js\",\n \"react-doctor/nextjs-no-a-element\": \"Next.js\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"Next.js\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"Next.js\",\n \"react-doctor/nextjs-missing-metadata\": \"Next.js\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"Next.js\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"Next.js\",\n \"react-doctor/nextjs-image-missing-sizes\": \"Next.js\",\n \"react-doctor/nextjs-no-native-script\": \"Next.js\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"Next.js\",\n \"react-doctor/nextjs-no-font-link\": \"Next.js\",\n \"react-doctor/nextjs-no-css-link\": \"Next.js\",\n \"react-doctor/nextjs-no-polyfill-script\": \"Next.js\",\n \"react-doctor/nextjs-no-head-import\": \"Next.js\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"Security\",\n\n \"react-doctor/server-auth-actions\": \"Server\",\n \"react-doctor/server-after-nonblocking\": \"Server\",\n\n \"react-doctor/client-passive-event-listeners\": \"Performance\",\n\n \"react-doctor/query-stable-query-client\": \"TanStack Query\",\n \"react-doctor/query-no-rest-destructuring\": \"TanStack Query\",\n \"react-doctor/query-no-void-query-fn\": \"TanStack Query\",\n \"react-doctor/query-no-query-in-effect\": \"TanStack Query\",\n \"react-doctor/query-mutation-missing-invalidation\": \"TanStack Query\",\n \"react-doctor/query-no-usequery-for-mutation\": \"TanStack Query\",\n\n \"react-doctor/no-inline-bounce-easing\": \"Performance\",\n \"react-doctor/no-z-index-9999\": \"Architecture\",\n \"react-doctor/no-inline-exhaustive-style\": \"Architecture\",\n \"react-doctor/no-side-tab-border\": \"Architecture\",\n \"react-doctor/no-pure-black-background\": \"Architecture\",\n \"react-doctor/no-gradient-text\": \"Architecture\",\n \"react-doctor/no-dark-mode-glow\": \"Architecture\",\n \"react-doctor/no-justified-text\": \"Accessibility\",\n \"react-doctor/no-tiny-text\": \"Accessibility\",\n \"react-doctor/no-wide-letter-spacing\": \"Architecture\",\n \"react-doctor/no-gray-on-colored-background\": \"Accessibility\",\n \"react-doctor/no-layout-transition-inline\": \"Performance\",\n \"react-doctor/no-disabled-zoom\": \"Accessibility\",\n \"react-doctor/no-outline-none\": \"Accessibility\",\n \"react-doctor/no-long-transition-duration\": \"Performance\",\n\n \"react-doctor/js-flatmap-filter\": \"Performance\",\n\n \"react-doctor/async-parallel\": \"Performance\",\n\n \"react-doctor/rn-no-raw-text\": \"React Native\",\n \"react-doctor/rn-no-deprecated-modules\": \"React Native\",\n \"react-doctor/rn-no-legacy-expo-packages\": \"React Native\",\n \"react-doctor/rn-no-dimensions-get\": \"React Native\",\n \"react-doctor/rn-no-inline-flatlist-renderitem\": \"React Native\",\n \"react-doctor/rn-no-legacy-shadow-styles\": \"React Native\",\n \"react-doctor/rn-prefer-reanimated\": \"React Native\",\n \"react-doctor/rn-no-single-element-style-array\": \"React Native\",\n\n \"react-doctor/tanstack-start-route-property-order\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-direct-fetch-in-loader\": \"TanStack Start\",\n \"react-doctor/tanstack-start-server-fn-validate-input\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-useeffect-fetch\": \"TanStack Start\",\n \"react-doctor/tanstack-start-missing-head-content\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-anchor-element\": \"TanStack Start\",\n \"react-doctor/tanstack-start-server-fn-method-order\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-navigate-in-render\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-dynamic-server-fn-import\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-use-server-in-handler\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-secrets-in-loader\": \"Security\",\n \"react-doctor/tanstack-start-get-mutation\": \"Security\",\n \"react-doctor/tanstack-start-redirect-in-try-catch\": \"TanStack Start\",\n \"react-doctor/tanstack-start-loader-parallel-fetch\": \"Performance\",\n};\n\nconst RULE_HELP_MAP: Record<string, string> = {\n \"no-derived-state-effect\":\n \"For derived state, compute inline: `const x = fn(dep)`. For state resets on prop change, use a key prop: `<Component key={prop} />`. See https://react.dev/learn/you-might-not-need-an-effect\",\n \"no-fetch-in-effect\":\n \"Use `useQuery()` from @tanstack/react-query, `useSWR()`, or fetch in a Server Component instead\",\n \"no-cascading-set-state\":\n \"Combine into useReducer: `const [state, dispatch] = useReducer(reducer, initialState)`\",\n \"no-effect-event-handler\":\n \"Move the conditional logic into onClick, onChange, or onSubmit handlers directly\",\n \"no-derived-useState\":\n \"Remove useState and compute the value inline: `const value = transform(propName)`\",\n \"prefer-useReducer\":\n \"Group related state: `const [state, dispatch] = useReducer(reducer, { field1, field2, ... })`\",\n \"rerender-lazy-state-init\":\n \"Wrap in an arrow function so it only runs once: `useState(() => expensiveComputation())`\",\n \"rerender-functional-setstate\":\n \"Use the callback form: `setState(prev => prev + 1)` to always read the latest value\",\n \"rerender-dependencies\":\n \"Extract to a useMemo, useRef, or module-level constant so the reference is stable\",\n\n \"no-generic-handler-names\":\n \"Rename to describe the action: e.g. `handleSubmit` → `saveUserProfile`, `handleClick` → `toggleSidebar`\",\n \"no-giant-component\":\n \"Extract logical sections into focused components: `<UserHeader />`, `<UserActions />`, etc.\",\n \"no-render-in-render\":\n \"Extract to a named component: `const ListItem = ({ item }) => <div>{item.name}</div>`\",\n \"no-nested-component-definition\":\n \"Move to a separate file or to module scope above the parent component\",\n\n \"no-usememo-simple-expression\":\n \"Remove useMemo — property access, math, and ternaries are already cheap without memoization\",\n \"no-layout-property-animation\":\n \"Use `transform: translateX()` or `scale()` instead — they run on the compositor and skip layout/paint\",\n \"rerender-memo-with-default-value\":\n \"Move to module scope: `const EMPTY_ITEMS: Item[] = []` then use as the default value\",\n \"rendering-animate-svg-wrapper\":\n \"Wrap the SVG: `<motion.div animate={...}><svg>...</svg></motion.div>`\",\n \"rendering-usetransition-loading\":\n \"Replace with `const [isPending, startTransition] = useTransition()` — avoids a re-render for the loading state\",\n \"rendering-hydration-no-flicker\":\n \"Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` or add `suppressHydrationWarning` to the element\",\n \"rendering-script-defer-async\":\n 'Add `defer` for DOM-dependent scripts or `async` for independent ones (analytics). In Next.js, use `<Script strategy=\"afterInteractive\" />` instead',\n\n \"no-transition-all\":\n 'List specific properties: `transition: \"opacity 200ms, transform 200ms\"` — or in Tailwind use `transition-colors`, `transition-opacity`, or `transition-transform`',\n \"no-global-css-variable-animation\":\n \"Set the variable on the nearest element instead of a parent, or use `@property` with `inherits: false` to prevent cascade. Better yet, use targeted `element.style.transform` updates\",\n \"no-large-animated-blur\":\n \"Keep blur radius under 10px, or apply blur to a smaller element. Large blurs multiply GPU memory usage with layer size\",\n \"no-scale-from-zero\":\n \"Use `initial={{ scale: 0.95, opacity: 0 }}` — elements should deflate like a balloon, not vanish into a point\",\n \"no-permanent-will-change\":\n \"Add will-change on animation start (`onMouseEnter`) and remove on end (`onAnimationEnd`). Permanent promotion wastes GPU memory and can degrade performance\",\n\n \"no-secrets-in-client-code\":\n \"Move to server-side `process.env.SECRET_NAME`. Only `NEXT_PUBLIC_*` vars are safe for the client (and should not contain secrets)\",\n\n \"no-barrel-import\":\n \"Import from the direct path: `import { Button } from './components/Button'` instead of `./components`\",\n \"no-full-lodash-import\":\n \"Import the specific function: `import debounce from 'lodash/debounce'` — saves ~70kb\",\n \"no-moment\":\n \"Replace with `import { format } from 'date-fns'` (tree-shakeable) or `import dayjs from 'dayjs'` (2kb)\",\n \"prefer-dynamic-import\":\n \"Use `const Component = dynamic(() => import('library'), { ssr: false })` from next/dynamic or React.lazy()\",\n \"use-lazy-motion\":\n 'Use `import { LazyMotion, m } from \"framer-motion\"` with `domAnimation` features — saves ~30kb',\n \"no-undeferred-third-party\":\n 'Use `next/script` with `strategy=\"lazyOnload\"` or add the `defer` attribute',\n\n \"no-inline-bounce-easing\":\n \"Use `cubic-bezier(0.16, 1, 0.3, 1)` (ease-out-expo) for natural deceleration — objects in the real world don't bounce\",\n \"no-z-index-9999\":\n \"Define a z-index scale in your design tokens (e.g. dropdown: 10, modal: 20, toast: 30). Create a new stacking context with `isolation: isolate` instead of escalating values\",\n \"no-inline-exhaustive-style\":\n \"Move styles to a CSS class, CSS module, Tailwind utilities, or a styled component — inline objects with many properties hurt readability and create new references every render\",\n \"no-side-tab-border\":\n \"Use a subtler accent (box-shadow inset, background gradient, or border-bottom) instead of a thick one-sided border\",\n \"no-pure-black-background\":\n \"Tint the background slightly toward your brand hue — e.g. `#0a0a0f` or Tailwind's `bg-gray-950`. Pure black looks harsh on modern displays\",\n \"no-gradient-text\":\n \"Use solid text colors for readability. If you need emphasis, use font weight, size, or a distinct color instead of gradients\",\n \"no-dark-mode-glow\":\n \"Use a subtle `box-shadow` with neutral colors for depth, or `border` with low opacity. Colored glows on dark backgrounds are the default AI-generated aesthetic\",\n \"no-justified-text\":\n \"Use `text-align: left` for body text, or add `hyphens: auto` and `overflow-wrap: break-word` if you must justify\",\n \"no-tiny-text\":\n \"Use at least 12px for body content, 16px is ideal. Small text is hard to read, especially on high-DPI mobile screens\",\n \"no-wide-letter-spacing\":\n \"Reserve wide tracking (letter-spacing > 0.05em) for short uppercase labels, navigation items, and buttons — not body text\",\n \"no-gray-on-colored-background\":\n \"Use a darker shade of the background color for text, or white/near-white for contrast. Gray text on colored backgrounds looks washed out\",\n \"no-layout-transition-inline\":\n \"Use `transform` and `opacity` for transitions — they run on the compositor thread. For height animations, use `grid-template-rows: 0fr → 1fr`\",\n \"no-disabled-zoom\":\n \"Remove `user-scalable=no` and `maximum-scale` from the viewport meta tag. If your layout breaks at 200% zoom, fix the layout — don't punish users with disabilities\",\n \"no-outline-none\":\n \"Use `:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px }` to show focus only for keyboard users while hiding it for mouse clicks\",\n \"no-long-transition-duration\":\n \"Keep UI transitions under 1s — 100-150ms for instant feedback, 200-300ms for state changes, 300-500ms for layout changes. Use longer durations only for page-load hero animations\",\n\n \"no-array-index-as-key\":\n \"Use a stable unique identifier: `key={item.id}` or `key={item.slug}` — index keys break on reorder/filter\",\n \"rendering-conditional-render\":\n \"Change to `{items.length > 0 && <List />}` or use a ternary: `{items.length ? <List /> : null}`\",\n \"no-prevent-default\":\n \"Use `<form action={serverAction}>` (works without JS) or `<button>` instead of `<a>` with preventDefault\",\n\n \"nextjs-no-img-element\":\n \"`import Image from 'next/image'` — provides automatic WebP/AVIF, lazy loading, and responsive srcset\",\n \"nextjs-async-client-component\":\n \"Fetch data in a parent Server Component and pass it as props, or use useQuery/useSWR in the client component\",\n \"nextjs-no-a-element\":\n \"`import Link from 'next/link'` — enables client-side navigation, prefetching, and preserves scroll position\",\n \"nextjs-no-use-search-params-without-suspense\":\n \"Wrap the component using useSearchParams: `<Suspense fallback={<Skeleton />}><SearchComponent /></Suspense>`\",\n \"nextjs-no-client-fetch-for-server-data\":\n \"Remove 'use client' and fetch directly in the Server Component — no API round-trip, secrets stay on server\",\n \"nextjs-missing-metadata\":\n \"Add `export const metadata = { title: '...', description: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-client-side-redirect\":\n \"Avoid redirects inside useEffect. Use an event handler, middleware, or server-side redirect (App Router: redirect() from next/navigation; Pages Router: getServerSideProps redirect)\",\n \"nextjs-no-redirect-in-try-catch\":\n \"Move the redirect/notFound call outside the try block, or add `unstable_rethrow(error)` in the catch\",\n \"nextjs-image-missing-sizes\":\n 'Add sizes for responsive behavior: `sizes=\"(max-width: 768px) 100vw, 50vw\"` matching your layout breakpoints',\n \"nextjs-no-native-script\":\n '`import Script from \"next/script\"` — use `strategy=\"afterInteractive\"` for analytics or `\"lazyOnload\"` for widgets',\n \"nextjs-inline-script-missing-id\":\n 'Add `id=\"descriptive-name\"` so Next.js can track, deduplicate, and re-execute the script correctly',\n \"nextjs-no-font-link\":\n '`import { Inter } from \"next/font/google\"` — self-hosted, zero layout shift, no render-blocking requests',\n \"nextjs-no-css-link\":\n \"Import CSS directly: `import './styles.css'` or use CSS Modules: `import styles from './Button.module.css'`\",\n \"nextjs-no-polyfill-script\":\n \"Next.js includes polyfills for fetch, Promise, Object.assign, Array.from, and 50+ others automatically\",\n \"nextjs-no-head-import\":\n \"Use the Metadata API instead: `export const metadata = { title: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-side-effect-in-get-handler\":\n \"Move the side effect to a POST handler and use a <form> or fetch with method POST — GET requests can be triggered by prefetching and are vulnerable to CSRF\",\n\n \"server-auth-actions\":\n \"Add `const session = await auth()` at the top and throw/redirect if unauthorized before any data access\",\n \"server-after-nonblocking\":\n \"`import { after } from 'next/server'` then wrap: `after(() => analytics.track(...))` — response isn't blocked\",\n\n \"client-passive-event-listeners\":\n \"Add `{ passive: true }` as the third argument: `addEventListener('scroll', handler, { passive: true })`\",\n\n \"query-stable-query-client\":\n \"Move `new QueryClient()` to module scope or wrap in `useState(() => new QueryClient())` — recreating it on every render resets the entire cache\",\n \"query-no-rest-destructuring\":\n \"Destructure only the fields you need: `const { data, isLoading } = useQuery(...)` — rest destructuring subscribes to all fields and causes extra re-renders\",\n \"query-no-void-query-fn\":\n \"queryFn must return a value for the cache. Use the `enabled` option to conditionally disable the query instead of returning undefined\",\n \"query-no-query-in-effect\":\n \"React Query manages refetching automatically via queryKey dependencies and the `enabled` option — manual refetch() in useEffect is usually unnecessary\",\n \"query-mutation-missing-invalidation\":\n \"Add `onSuccess: () => queryClient.invalidateQueries({ queryKey: ['...'] })` so cached data stays in sync after the mutation\",\n \"query-no-usequery-for-mutation\":\n \"Use `useMutation()` for POST/PUT/DELETE — it provides onSuccess/onError callbacks, doesn't auto-refetch, and correctly models write operations\",\n\n \"js-flatmap-filter\":\n \"Use `.flatMap(item => condition ? [value] : [])` — transforms and filters in a single pass instead of creating an intermediate array\",\n\n \"async-parallel\":\n \"Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to run independent operations concurrently\",\n\n \"rn-no-raw-text\":\n \"Wrap text in a `<Text>` component: `<Text>{value}</Text>` — raw strings outside `<Text>` crash on React Native\",\n \"rn-no-deprecated-modules\":\n \"Import from the community package instead — deprecated modules were removed from the react-native core\",\n \"rn-no-legacy-expo-packages\":\n \"Migrate to the recommended replacement package — legacy Expo packages are no longer maintained\",\n \"rn-no-dimensions-get\":\n \"Use `const { width, height } = useWindowDimensions()` — it updates reactively on rotation and resize\",\n \"rn-no-inline-flatlist-renderitem\":\n \"Extract renderItem to a named function or wrap in useCallback to avoid re-creating on every render\",\n \"rn-no-legacy-shadow-styles\":\n \"Use `boxShadow` for cross-platform shadows on the new architecture instead of platform-specific shadow properties\",\n \"rn-prefer-reanimated\":\n \"Use `import Animated from 'react-native-reanimated'` — animations run on the UI thread instead of the JS thread\",\n \"rn-no-single-element-style-array\":\n \"Use `style={value}` instead of `style={[value]}` — single-element arrays add unnecessary allocation\",\n\n \"tanstack-start-route-property-order\":\n \"Follow the order: params/validateSearch → loaderDeps → context → beforeLoad → loader → head. See https://tanstack.com/router/latest/docs/eslint/create-route-property-order\",\n \"tanstack-start-no-direct-fetch-in-loader\":\n \"Use `createServerFn()` from @tanstack/react-start — provides type-safe RPC, input validation, and proper server/client code splitting\",\n \"tanstack-start-server-fn-validate-input\":\n \"Add `.inputValidator(schema)` before `.handler()` — data crosses a network boundary and must be validated at runtime\",\n \"tanstack-start-no-useeffect-fetch\":\n \"Fetch data in the route `loader` instead — the router coordinates loading before rendering to avoid waterfalls\",\n \"tanstack-start-missing-head-content\":\n \"Add `<HeadContent />` inside `<head>` in your __root route — without it, route `head()` meta tags are silently dropped\",\n \"tanstack-start-no-anchor-element\":\n \"`import { Link } from '@tanstack/react-router'` — enables type-safe routes, preloading via `preload=\\\"intent\\\"`, and client-side navigation\",\n \"tanstack-start-server-fn-method-order\":\n \"Chain methods in order: .middleware() → .inputValidator() → .client() → .server() → .handler() — types depend on this sequence\",\n \"tanstack-start-no-navigate-in-render\":\n \"Use `throw redirect({ to: '/path' })` in `beforeLoad` or `loader` instead — navigate() during render causes hydration issues\",\n \"tanstack-start-no-dynamic-server-fn-import\":\n \"Use `import { myFn } from '~/utils/my.functions'` — the bundler replaces server code with RPC stubs only for static imports\",\n \"tanstack-start-no-use-server-in-handler\":\n 'TanStack Start handles server boundaries automatically via the Vite plugin — \"use server\" inside createServerFn causes compilation errors',\n \"tanstack-start-no-secrets-in-loader\":\n \"Loaders are isomorphic (run on both server and client). Wrap secret access in `createServerFn()` so it stays server-only\",\n \"tanstack-start-get-mutation\":\n \"Use `createServerFn({ method: 'POST' })` for data modifications — GET requests can be triggered by prefetching and are vulnerable to CSRF\",\n \"tanstack-start-redirect-in-try-catch\":\n \"TanStack Router's `redirect()` and `notFound()` throw special errors caught by the router. Move them outside the try block or re-throw in the catch\",\n \"tanstack-start-loader-parallel-fetch\":\n \"Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to avoid request waterfalls in route loaders\",\n};\n\nconst FILEPATH_WITH_LOCATION_PATTERN = /\\S+\\.\\w+:\\d+:\\d+[\\s\\S]*$/;\n\nconst REACT_COMPILER_MESSAGE = \"React Compiler can't optimize this code\";\n\nconst cleanDiagnosticMessage = (\n message: string,\n help: string,\n plugin: string,\n rule: string,\n): CleanedDiagnostic => {\n if (plugin === \"react-hooks-js\") {\n const rawMessage = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: REACT_COMPILER_MESSAGE, help: rawMessage || help };\n }\n const cleaned = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: cleaned || message, help: help || RULE_HELP_MAP[rule] || \"\" };\n};\n\nconst parseRuleCode = (code: string): { plugin: string; rule: string } => {\n const match = code.match(/^(.+)\\((.+)\\)$/);\n if (!match) return { plugin: \"unknown\", rule: code };\n return { plugin: match[1].replace(/^eslint-plugin-/, \"\"), rule: match[2] };\n};\n\nconst resolveOxlintBinary = (): string => {\n const oxlintMainPath = esmRequire.resolve(\"oxlint\");\n const oxlintPackageDirectory = path.resolve(path.dirname(oxlintMainPath), \"..\");\n return path.join(oxlintPackageDirectory, \"bin\", \"oxlint\");\n};\n\nconst resolvePluginPath = (): string => {\n const currentDirectory = path.dirname(fileURLToPath(import.meta.url));\n const pluginPath = path.join(currentDirectory, \"react-doctor-plugin.js\");\n if (fs.existsSync(pluginPath)) return pluginPath;\n\n const distPluginPath = path.resolve(currentDirectory, \"../../dist/react-doctor-plugin.js\");\n if (fs.existsSync(distPluginPath)) return distPluginPath;\n\n return pluginPath;\n};\n\nconst resolveDiagnosticCategory = (plugin: string, rule: string): string => {\n const ruleKey = `${plugin}/${rule}`;\n return RULE_CATEGORY_MAP[ruleKey] ?? PLUGIN_CATEGORY_MAP[plugin] ?? \"Other\";\n};\n\nconst estimateArgsLength = (args: string[]): number =>\n args.reduce((total, argument) => total + argument.length + 1, 0);\n\nconst batchIncludePaths = (baseArgs: string[], includePaths: string[]): string[][] => {\n const baseArgsLength = estimateArgsLength(baseArgs);\n const batches: string[][] = [];\n let currentBatch: string[] = [];\n let currentBatchLength = baseArgsLength;\n\n for (const filePath of includePaths) {\n const entryLength = filePath.length + 1;\n const exceedsArgLength =\n currentBatch.length > 0 && currentBatchLength + entryLength > SPAWN_ARGS_MAX_LENGTH_CHARS;\n const exceedsFileCount = currentBatch.length >= OXLINT_MAX_FILES_PER_BATCH;\n\n if (exceedsArgLength || exceedsFileCount) {\n batches.push(currentBatch);\n currentBatch = [];\n currentBatchLength = baseArgsLength;\n }\n currentBatch.push(filePath);\n currentBatchLength += entryLength;\n }\n\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n};\n\nconst spawnOxlint = (\n args: string[],\n rootDirectory: string,\n nodeBinaryPath: string,\n): Promise<string> =>\n new Promise<string>((resolve, reject) => {\n const child = spawn(nodeBinaryPath, args, {\n cwd: rootDirectory,\n });\n\n const stdoutBuffers: Buffer[] = [];\n const stderrBuffers: Buffer[] = [];\n\n child.stdout.on(\"data\", (buffer: Buffer) => stdoutBuffers.push(buffer));\n child.stderr.on(\"data\", (buffer: Buffer) => stderrBuffers.push(buffer));\n\n child.on(\"error\", (error) => reject(new Error(`Failed to run oxlint: ${error.message}`)));\n child.on(\"close\", (code, signal) => {\n if (signal) {\n const stderrOutput = Buffer.concat(stderrBuffers).toString(\"utf-8\").trim();\n const hint =\n signal === \"SIGABRT\" ? \" (out of memory — try scanning fewer files with --diff)\" : \"\";\n const detail = stderrOutput ? `: ${stderrOutput}` : \"\";\n reject(new Error(`oxlint was killed by ${signal}${hint}${detail}`));\n return;\n }\n const output = Buffer.concat(stdoutBuffers).toString(\"utf-8\").trim();\n if (!output) {\n const stderrOutput = Buffer.concat(stderrBuffers).toString(\"utf-8\").trim();\n if (stderrOutput) {\n reject(new Error(`Failed to run oxlint: ${stderrOutput}`));\n return;\n }\n }\n resolve(output);\n });\n });\n\nconst parseOxlintOutput = (stdout: string): Diagnostic[] => {\n if (!stdout) return [];\n\n let output: OxlintOutput;\n try {\n output = JSON.parse(stdout) as OxlintOutput;\n } catch {\n throw new Error(\n `Failed to parse oxlint output: ${stdout.slice(0, ERROR_PREVIEW_LENGTH_CHARS)}`,\n );\n }\n\n return output.diagnostics\n .filter((diagnostic) => diagnostic.code && JSX_FILE_PATTERN.test(diagnostic.filename))\n .map((diagnostic) => {\n const { plugin, rule } = parseRuleCode(diagnostic.code);\n const primaryLabel = diagnostic.labels[0];\n\n const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule);\n\n return {\n filePath: diagnostic.filename,\n plugin,\n rule,\n severity: diagnostic.severity,\n message: cleaned.message,\n help: cleaned.help,\n line: primaryLabel?.span.line ?? 0,\n column: primaryLabel?.span.column ?? 0,\n category: resolveDiagnosticCategory(plugin, rule),\n };\n });\n};\n\nexport const runOxlint = async (\n rootDirectory: string,\n hasTypeScript: boolean,\n framework: Framework,\n hasReactCompiler: boolean,\n includePaths?: string[],\n nodeBinaryPath: string = process.execPath,\n customRulesOnly = false,\n): Promise<Diagnostic[]> => {\n if (includePaths !== undefined && includePaths.length === 0) {\n return [];\n }\n\n const configPath = path.join(os.tmpdir(), `react-doctor-oxlintrc-${process.pid}.json`);\n const pluginPath = resolvePluginPath();\n const config = createOxlintConfig({ pluginPath, framework, hasReactCompiler, customRulesOnly });\n const restoreDisableDirectives = neutralizeDisableDirectives(rootDirectory, includePaths);\n\n try {\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2));\n\n const oxlintBinary = resolveOxlintBinary();\n const baseArgs = [oxlintBinary, \"-c\", configPath, \"--format\", \"json\"];\n\n if (hasTypeScript) {\n baseArgs.push(\"--tsconfig\", \"./tsconfig.json\");\n }\n\n const fileBatches =\n includePaths !== undefined ? batchIncludePaths(baseArgs, includePaths) : [[\".\"]];\n\n const allDiagnostics: Diagnostic[] = [];\n for (const batch of fileBatches) {\n const batchArgs = [...baseArgs, ...batch];\n const stdout = await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath);\n allDiagnostics.push(...parseOxlintOutput(stdout));\n }\n\n return allDiagnostics;\n } finally {\n restoreDisableDirectives();\n if (fs.existsSync(configPath)) {\n fs.unlinkSync(configPath);\n }\n }\n};\n","import { execSync } from \"node:child_process\";\nimport { DEFAULT_BRANCH_CANDIDATES, SOURCE_FILE_PATTERN } from \"../constants.js\";\nimport type { DiffInfo } from \"../types.js\";\n\nconst getCurrentBranch = (directory: string): string | null => {\n try {\n const branch = execSync(\"git rev-parse --abbrev-ref HEAD\", {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n return branch === \"HEAD\" ? null : branch;\n } catch {\n return null;\n }\n};\n\nconst detectDefaultBranch = (directory: string): string | null => {\n try {\n const reference = execSync(\"git symbolic-ref refs/remotes/origin/HEAD\", {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n return reference.replace(\"refs/remotes/origin/\", \"\");\n } catch {\n for (const candidate of DEFAULT_BRANCH_CANDIDATES) {\n try {\n execSync(`git rev-parse --verify ${candidate}`, {\n cwd: directory,\n stdio: \"pipe\",\n });\n return candidate;\n } catch {}\n }\n return null;\n }\n};\n\nconst getChangedFilesSinceBranch = (directory: string, baseBranch: string): string[] => {\n try {\n const mergeBase = execSync(`git merge-base ${baseBranch} HEAD`, {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n\n const output = execSync(`git diff --name-only --diff-filter=ACMR --relative ${mergeBase}`, {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n\n if (!output) return [];\n return output.split(\"\\n\").filter(Boolean);\n } catch {\n return [];\n }\n};\n\nconst getUncommittedChangedFiles = (directory: string): string[] => {\n try {\n const output = execSync(\"git diff --name-only --diff-filter=ACMR --relative HEAD\", {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n if (!output) return [];\n return output.split(\"\\n\").filter(Boolean);\n } catch {\n return [];\n }\n};\n\nexport const getDiffInfo = (directory: string, explicitBaseBranch?: string): DiffInfo | null => {\n const currentBranch = getCurrentBranch(directory);\n if (!currentBranch) return null;\n\n const baseBranch = explicitBaseBranch ?? detectDefaultBranch(directory);\n if (!baseBranch) return null;\n\n if (currentBranch === baseBranch) {\n const uncommittedFiles = getUncommittedChangedFiles(directory);\n if (uncommittedFiles.length === 0) return null;\n return { currentBranch, baseBranch, changedFiles: uncommittedFiles, isCurrentChanges: true };\n }\n\n const changedFiles = getChangedFilesSinceBranch(directory, baseBranch);\n return { currentBranch, baseBranch, changedFiles };\n};\n\nexport const filterSourceFiles = (filePaths: string[]): string[] =>\n filePaths.filter((filePath) => SOURCE_FILE_PATTERN.test(filePath));\n","import path from \"node:path\";\nimport type { Diagnostic, DiffInfo, ProjectInfo, ReactDoctorConfig, ScoreResult } from \"./types.js\";\nimport { diagnoseCore } from \"./core/diagnose-core.js\";\nimport { computeJsxIncludePaths } from \"./utils/jsx-include-paths.js\";\nimport { checkReducedMotion } from \"./utils/check-reduced-motion.js\";\nimport { discoverProject } from \"./utils/discover-project.js\";\nimport { loadConfig } from \"./utils/load-config.js\";\nimport { createNodeReadFileLinesSync } from \"./utils/read-file-lines-node.js\";\nimport { resolveLintIncludePaths } from \"./utils/resolve-lint-include-paths.js\";\nimport { calculateScore } from \"./utils/calculate-score-node.js\";\nimport { runKnip } from \"./utils/run-knip.js\";\nimport { runOxlint } from \"./utils/run-oxlint.js\";\n\nexport type { Diagnostic, DiffInfo, ProjectInfo, ReactDoctorConfig, ScoreResult };\nexport { getDiffInfo, filterSourceFiles } from \"./utils/get-diff-files.js\";\n\nexport interface DiagnoseOptions {\n lint?: boolean;\n deadCode?: boolean;\n includePaths?: string[];\n}\n\nexport interface DiagnoseResult {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n project: ProjectInfo;\n elapsedMilliseconds: number;\n}\n\nexport const diagnose = async (\n directory: string,\n options: DiagnoseOptions = {},\n): Promise<DiagnoseResult> => {\n const resolvedDirectory = path.resolve(directory);\n const userConfig = loadConfig(resolvedDirectory);\n const includePaths = options.includePaths ?? [];\n const isDiffMode = includePaths.length > 0;\n const lintIncludePaths =\n computeJsxIncludePaths(includePaths) ?? resolveLintIncludePaths(resolvedDirectory, userConfig);\n const readFileLinesSync = createNodeReadFileLinesSync(resolvedDirectory);\n\n return diagnoseCore(\n {\n rootDirectory: resolvedDirectory,\n readFileLinesSync,\n loadUserConfig: () => userConfig,\n discoverProjectInfo: () => discoverProject(resolvedDirectory),\n calculateDiagnosticsScore: calculateScore,\n getExtraDiagnostics: () => (isDiffMode ? [] : checkReducedMotion(resolvedDirectory)),\n createRunners: ({ resolvedDirectory: projectRoot, projectInfo, userConfig: config }) => ({\n runLint: () =>\n runOxlint(\n projectRoot,\n projectInfo.hasTypeScript,\n projectInfo.framework,\n projectInfo.hasReactCompiler,\n lintIncludePaths,\n undefined,\n config?.customRulesOnly ?? false,\n ),\n runDeadCode: () => runKnip(projectRoot),\n }),\n },\n { ...options, lintIncludePaths },\n );\n};\n"],"mappings":";;;;;;;;;;AAgBA,MAAa,uBAAuB,YAA4D;CAC9F,aAAa,OAAO;CACpB,OAAO,OAAO;CACd,SAAS,OAAO;CAChB,qBAAqB,OAAO;CAC7B;;;;ACrBD,MAAM,2BAA2B;AAEjC,MAAa,sBAAsB,YAA4B;CAC7D,MAAM,oBAAoB,QAAQ,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,GAAG;CAExE,IAAI,cAAc;CAClB,IAAI,iBAAiB;AAErB,QAAO,iBAAiB,kBAAkB,OACxC,KACE,kBAAkB,oBAAoB,OACtC,kBAAkB,iBAAiB,OAAO,IAE1C,KAAI,kBAAkB,iBAAiB,OAAO,KAAK;AACjD,iBAAe;AACf,oBAAkB;QACb;AACL,iBAAe;AACf,oBAAkB;;UAEX,kBAAkB,oBAAoB,KAAK;AACpD,iBAAe;AACf;YACS,kBAAkB,oBAAoB,KAAK;AACpD,iBAAe;AACf;QACK;AACL,iBAAe,kBAAkB,gBAAgB,QAAQ,0BAA0B,OAAO;AAC1F;;AAIJ,gBAAe;AACf,QAAO,IAAI,OAAO,YAAY;;;;;AC9BhC,MAAM,kBAAkB,UAAkB,kBAAkC;CAC1E,MAAM,qBAAqB,SAAS,QAAQ,OAAO,IAAI;CACvD,MAAM,iBAAiB,cAAc,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,GAAG,GAAG;AAE9E,KAAI,mBAAmB,WAAW,eAAe,CAC/C,QAAO,mBAAmB,MAAM,eAAe,OAAO;AAGxD,QAAO,mBAAmB,QAAQ,SAAS,GAAG;;AAGhD,MAAa,8BAA8B,eACzC,MAAM,QAAQ,YAAY,QAAQ,MAAM,GAAG,WAAW,OAAO,MAAM,IAAI,mBAAmB,GAAG,EAAE;AAEjG,MAAa,2BACX,UACA,eACA,aACY;AACZ,KAAI,SAAS,WAAW,EACtB,QAAO;CAGT,MAAM,eAAe,eAAe,UAAU,cAAc;AAC5D,QAAO,SAAS,MAAM,YAAY,QAAQ,KAAK,aAAa,CAAC;;;;;ACxB/D,MAAM,4BAA4B,eAAuB,aAA6B;CACpF,MAAM,iBAAiB,SAAS,QAAQ,OAAO,IAAI;AACnD,KACE,eAAe,WAAW,IAAI,IAC9B,eAAe,KAAK,eAAe,IACnC,eAAe,KAAK,SAAS,CAE7B,QAAO;AAGT,QAAO,GADM,cAAc,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,GAAG,CAClD,GAAG,eAAe,QAAQ,SAAS,GAAG;;AAGvD,MAAM,sBAAsB;AAC5B,MAAM,4BAA4B;AAClC,MAAM,uBAAuB;AAE7B,MAAM,wBACJ,eACA,sBACG;CACH,MAAM,wBAAQ,IAAI,KAA8B;AAEhD,SAAQ,aAAsC;EAC5C,MAAM,SAAS,MAAM,IAAI,SAAS;AAClC,MAAI,WAAW,OAAW,QAAO;EAEjC,MAAM,QAAQ,kBADO,yBAAyB,eAAe,SAAS,CACzB;AAC7C,QAAM,IAAI,UAAU,MAAM;AAC1B,SAAO;;;AAIX,MAAM,yBACJ,OACA,gBACA,uBACY;AACZ,MAAK,IAAI,YAAY,iBAAiB,GAAG,aAAa,GAAG,aAAa;EACpE,MAAM,QAAQ,MAAM,WAAW,MAAM,oBAAoB;AACzD,MAAI,CAAC,MAAO;EACZ,MAAM,cAAc,MAAM;EAC1B,MAAM,cAAc,YAAY,SAAS,IAAI,GACxC,YAAY,MAAM,IAAI,CAAC,GAAG,GAAG,IAAI,cAClC;AACJ,SAAO,mBAAmB,IAAI,YAAY,IAAI,mBAAmB,IAAI,YAAY;;AAEnF,QAAO;;AAGT,MAAM,oBAAoB,cAAkC,WAA4B;AACtF,KAAI,CAAC,cAAc,MAAM,CAAE,QAAO;AAClC,QAAO,aAAa,MAAM,SAAS,CAAC,MAAM,SAAS,KAAK,MAAM,KAAK,OAAO;;AAG5E,MAAa,4BACX,aACA,QACA,eACA,sBACiB;CACjB,MAAM,eAAe,IAAI,IAAI,MAAM,QAAQ,OAAO,QAAQ,MAAM,GAAG,OAAO,OAAO,QAAQ,EAAE,CAAC;CAC5F,MAAM,sBAAsB,2BAA2B,OAAO;CAC9D,MAAM,qBAAqB,IAAI,IAC7B,MAAM,QAAQ,OAAO,eAAe,GAAG,OAAO,iBAAiB,EAAE,CAClE;CACD,MAAM,oBAAoB,mBAAmB,OAAO;CACpD,MAAM,eAAe,qBAAqB,eAAe,kBAAkB;AAE3E,QAAO,YAAY,QAAQ,eAAe;EACxC,MAAM,iBAAiB,GAAG,WAAW,OAAO,GAAG,WAAW;AAC1D,MAAI,aAAa,IAAI,eAAe,CAClC,QAAO;AAGT,MAAI,wBAAwB,WAAW,UAAU,eAAe,oBAAoB,CAClF,QAAO;AAGT,MAAI,qBAAqB,WAAW,SAAS,oBAAoB,WAAW,OAAO,GAAG;GACpF,MAAM,QAAQ,aAAa,WAAW,SAAS;AAC/C,OAAI,SAAS,sBAAsB,OAAO,WAAW,MAAM,mBAAmB,CAC5E,QAAO;;AAIX,SAAO;GACP;;AAGJ,MAAa,4BACX,aACA,eACA,sBACiB;CACjB,MAAM,eAAe,qBAAqB,eAAe,kBAAkB;AAE3E,QAAO,YAAY,QAAQ,eAAe;AACxC,MAAI,WAAW,QAAQ,EAAG,QAAO;EAEjC,MAAM,QAAQ,aAAa,WAAW,SAAS;AAC/C,MAAI,CAAC,MAAO,QAAO;EAEnB,MAAM,SAAS,GAAG,WAAW,OAAO,GAAG,WAAW;EAElD,MAAM,cAAc,MAAM,WAAW,OAAO;AAC5C,MAAI,aAAa;GACf,MAAM,YAAY,YAAY,MAAM,qBAAqB;AACzD,OAAI,aAAa,iBAAiB,UAAU,IAAI,OAAO,CAAE,QAAO;;AAGlE,MAAI,WAAW,QAAQ,GAAG;GACxB,MAAM,eAAe,MAAM,WAAW,OAAO;AAC7C,OAAI,cAAc;IAChB,MAAM,gBAAgB,aAAa,MAAM,0BAA0B;AACnE,QAAI,iBAAiB,iBAAiB,cAAc,IAAI,OAAO,CAAE,QAAO;;;AAI5E,SAAO;GACP;;;;;ACxHJ,MAAa,6BACX,mBACA,WACA,YACA,sBACiB;AAIjB,QAAO,yBAHU,aACb,yBAAyB,mBAAmB,YAAY,WAAW,kBAAkB,GACrF,mBACsC,WAAW,kBAAkB;;;;;ACOzE,MAAa,2BAA2B,OACtC,UACsC;CACtC,MAAM,cAAc,0BAClB,MAAM,mBACN,MAAM,eACN,MAAM,YACN,MAAM,kBACP;CACD,MAAM,sBAAsB,WAAW,YAAY,KAAK,GAAG,MAAM;AAGjE,QAAO;EAAE;EAAa,OADpB,MAAM,UAAU,SAAY,MAAM,QAAQ,MAAM,MAAM,0BAA0B,YAAY;EACjE;EAAqB;;;;;AC/BpD,MAAa,sBAAsB;AAEnC,MAAa,mBAAmB;AAIhC,MAAa,6BAA6B;AAE1C,MAAa,gBAAgB;AAE7B,MAAa,uBAAuB;AAEpC,MAAa,qBAAqB;AAQlC,MAAa,gBAAgB;AAI7B,MAAa,mBAAmB;AAEhC,MAAa,gCAAgC,KAAK,OAAO;AAIzD,MAAa,8BAA8B;AAI3C,MAAa,6BAA6B;AAI1C,MAAa,4BAA4B,CAAC,QAAQ,SAAS;AAE3D,MAAa,qBAAqB;AAElC,MAAa,uBAAuB;AAEpC,MAAa,mBAAmB;AAMhC,MAAa,4BAA4B,KAAK,OAAO;AAErD,MAAa,sBAAsB,IAAI,IAAI;CAAC;CAAgB;CAAQ;CAAS;CAAW,CAAC;;;;AClDzF,MAAa,0BAA0B,iBACrC,aAAa,SAAS,IAClB,aAAa,QAAQ,aAAa,iBAAiB,KAAK,SAAS,CAAC,GAClE;;;;ACmCN,MAAa,eAAe,OAC1B,MACA,UAA+B,EAAE,KACD;CAChC,MAAM,EAAE,eAAe,EAAE,KAAK;CAC9B,MAAM,aAAa,aAAa,SAAS;CAEzC,MAAM,YAAY,WAAW,YAAY,KAAK;CAC9C,MAAM,oBAAoB,KAAK;CAC/B,MAAM,cAAc,KAAK,qBAAqB;CAC9C,MAAM,aAAa,KAAK,gBAAgB;CAExC,MAAM,gBAAgB,QAAQ,QAAQ,YAAY,QAAQ;CAC1D,MAAM,oBAAoB,QAAQ,YAAY,YAAY,YAAY;AAEtE,KAAI,CAAC,YAAY,aACf,OAAM,IAAI,MAAM,4CAA4C;CAG9D,MAAM,mBACJ,QAAQ,qBAAqB,SACzB,QAAQ,mBACR,uBAAuB,aAAa;CAE1C,MAAM,EAAE,SAAS,gBAAgB,KAAK,cAAc;EAClD;EACA;EACA;EACA;EACA;EACD,CAAC;CAEF,MAAM,mBAAiC,EAAE;CAEzC,MAAM,cAAc,gBAChB,SAAS,CAAC,OAAO,UAAmB;AAClC,UAAQ,MAAM,gBAAgB,MAAM;AACpC,SAAO;GACP,GACF,QAAQ,QAAQ,iBAAiB;CAErC,MAAM,kBACJ,qBAAqB,CAAC,aAClB,aAAa,CAAC,OAAO,UAAmB;AACtC,UAAQ,MAAM,8BAA8B,MAAM;AAClD,SAAO;GACP,GACF,QAAQ,QAAQ,iBAAiB;CAEvC,MAAM,CAAC,iBAAiB,uBAAuB,MAAM,QAAQ,IAAI,CAAC,aAAa,gBAAgB,CAAC;CAChG,MAAM,yBAAyB,KAAK,uBAAuB,IAAI,EAAE;CAEjE,MAAM,QAAQ,MAAM,yBAAyB;EAC3C,mBAFwB;GAAC,GAAG;GAAiB,GAAG;GAAqB,GAAG;GAAuB;EAG/F,eAAe;EACf;EACA,mBAAmB,KAAK;EACxB;EACA,2BAA2B,KAAK;EACjC,CAAC;AAEF,QAAO,oBAAoB;EACzB,aAAa,MAAM;EACnB,OAAO,MAAM;EACb,SAAS;EACT,qBAAqB,MAAM;EAC5B,CAAC;;;;;ACqNJ,MAAa,0BAA0B,IAAI,IAAI,CAAC,iBAAiB,SAAS,CAAC;;;;AC7T3E,MAAa,UAAU,aAA8B;AACnD,KAAI;AACF,SAAO,GAAG,SAAS,SAAS,CAAC,QAAQ;SAC/B;AACN,SAAO;;;;;;ACHX,MAAa,mBAAmB,oBAAyC;AACvE,KAAI;AACF,SAAO,KAAK,MAAM,GAAG,aAAa,iBAAiB,QAAQ,CAAC;UACrD,OAAO;AACd,MAAI,iBAAiB,YACnB,QAAO,EAAE;AAEX,MAAI,iBAAiB,SAAS,UAAU,OAAO;GAC7C,MAAM,EAAE,SAAS;AACjB,OAAI,SAAS,YAAY,SAAS,SAChC,QAAO,EAAE;;AAGb,QAAM;;;;;;ACTV,MAAM,8BACJ;AACF,MAAM,4BAA4B;AAElC,MAAM,oCAAgD;CACpD,UAAU;CACV,QAAQ;CACR,MAAM;CACN,UAAU;CACV,SACE;CACF,MAAM;CACN,MAAM;CACN,QAAQ;CACR,UAAU;CACV,QAAQ;CACT;AAED,MAAa,sBAAsB,kBAAwC;CACzE,MAAM,kBAAkB,KAAK,KAAK,eAAe,eAAe;AAChE,KAAI,CAAC,OAAO,gBAAgB,CAAE,QAAO,EAAE;CAEvC,IAAI,mBAAmB;AACvB,KAAI;EACF,MAAM,cAAc,gBAAgB,gBAAgB;EACpD,MAAM,kBAAkB;GAAE,GAAG,YAAY;GAAc,GAAG,YAAY;GAAiB;AACvF,qBAAmB,OAAO,KAAK,gBAAgB,CAAC,MAAM,gBACpD,wBAAwB,IAAI,YAAY,CACzC;SACK;AACN,SAAO,EAAE;;AAEX,KAAI,CAAC,iBAAkB,QAAO,EAAE;AAEhC,KAAI;AACF,WAAS,oBAAoB,4BAA4B,OAAO,6BAA6B;GAC3F,KAAK;GACL,OAAO;GACR,CAAC;AACF,SAAO,EAAE;SACH;AACN,SAAO,CAAC,kCAAkC;;;;;;AC5C9C,MAAa,kBAAkB,cAA+B;AAC5D,KAAI,OAAO,KAAK,KAAK,WAAW,sBAAsB,CAAC,CAAE,QAAO;AAChE,KAAI,OAAO,KAAK,KAAK,WAAW,UAAU,CAAC,CAAE,QAAO;CACpD,MAAM,kBAAkB,KAAK,KAAK,WAAW,eAAe;AAC5D,KAAI,CAAC,OAAO,gBAAgB,CAAE,QAAO;CACrC,MAAM,cAAc,gBAAgB,gBAAgB;AACpD,QAAO,MAAM,QAAQ,YAAY,WAAW,IAAI,QAAQ,YAAY,YAAY,SAAS;;AAG3F,MAAa,oBAAoB,mBAA0C;CACzE,IAAI,mBAAmB,KAAK,QAAQ,eAAe;AAEnD,QAAO,qBAAqB,KAAK,QAAQ,iBAAiB,EAAE;AAC1D,MAAI,eAAe,iBAAiB,CAAE,QAAO;AAC7C,qBAAmB,KAAK,QAAQ,iBAAiB;;AAGnD,QAAO;;;;;ACrBT,MAAa,iBAAiB,UAC5B,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;ACmBtE,MAAM,0BAA0B,IAAI,IAAI;CACtC;CACA;CACA;CACD,CAAC;AAEF,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;CACD;AAED,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,wBAAwB;CAC5B;CACA;CACA;CACA;CACD;AAED,MAAM,4BAA4B;CAAC;CAAY;CAAiB;CAAgB;AAEhF,MAAM,2CACJ;AACF,MAAM,sCAAsC;AAE5C,MAAM,qBAAgD;CACpD,MAAM;CACN,yBAAyB;CACzB,MAAM;CACN,iBAAiB;CACjB,oBAAoB;CACpB,QAAQ;CACR,MAAM;CACN,gBAAgB;CACjB;AAiBD,MAAM,iCAAiC,kBAAkC;CACvE,IAAI,QAAQ;CACZ,MAAM,QAAQ,CAAC,cAAc;AAE7B,QAAO,MAAM,SAAS,GAAG;EACvB,MAAM,mBAAmB,MAAM,KAAK;EACpC,MAAM,UAAU,GAAG,YAAY,kBAAkB,EAAE,eAAe,MAAM,CAAC;AAEzE,OAAK,MAAM,SAAS,SAAS;AAC3B,OAAI,MAAM,aAAa,EAAE;AACvB,QAAI,CAAC,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,oBAAoB,IAAI,MAAM,KAAK,CACrE,OAAM,KAAK,KAAK,KAAK,kBAAkB,MAAM,KAAK,CAAC;AAErD;;AAEF,OAAI,MAAM,QAAQ,IAAI,oBAAoB,KAAK,MAAM,KAAK,CACxD;;;AAKN,QAAO;;AAGT,MAAM,0BAA0B,kBAAyC;CACvE,MAAM,SAAS,UAAU,OAAO;EAAC;EAAY;EAAY;EAAY;EAAqB,EAAE;EAC1F,KAAK;EACL,UAAU;EACV,WAAW;EACZ,CAAC;AAEF,KAAI,OAAO,SAAS,OAAO,WAAW,EACpC,QAAO;AAGT,QAAO,OAAO,OACX,MAAM,KAAK,CACX,QAAQ,aAAa,SAAS,SAAS,KAAK,oBAAoB,KAAK,SAAS,CAAC,CAAC;;AAGrF,MAAM,oBAAoB,kBACxB,uBAAuB,cAAc,IAAI,8BAA8B,cAAc;AAEvF,MAAM,0BAA0B,iBAAsD;CACpF,GAAG,YAAY;CACf,GAAG,YAAY;CACf,GAAG,YAAY;CAChB;AAED,MAAM,mBAAmB,iBAAoD;AAC3E,MAAK,MAAM,CAAC,aAAa,kBAAkB,OAAO,QAAQ,mBAAmB,CAC3E,KAAI,aAAa,aACf,QAAO;AAGX,QAAO;;AAGT,MAAM,sBAAsB,YAA6B,QAAQ,WAAW,WAAW;AAEvF,MAAM,sBAAsB,YAAmC;AAC7D,KAAI,CAAC,mBAAmB,QAAQ,CAAE,QAAO;CACzC,MAAM,OAAO,QAAQ,MAAM,EAAkB,CAAC,MAAM;AACpD,QAAO,KAAK,SAAS,IAAI,OAAO;;AAGlC,MAAM,6BACJ,SACA,gBACkB;CAClB,MAAM,UAAU,QAAQ;AACxB,KAAI,OAAO,YAAY,YAAY,CAAC,mBAAmB,QAAQ,CAAE,QAAO;AACxE,QAAO;;AAQT,MAAM,8BAA8B,kBAA6C;CAC/E,MAAM,gBAAgB,KAAK,KAAK,eAAe,sBAAsB;AACrE,KAAI,CAAC,OAAO,cAAc,CAAE,QAAO;EAAE,gBAAgB,EAAE;EAAE,eAAe,EAAE;EAAE;CAE5E,MAAM,UAAU,GAAG,aAAa,eAAe,QAAQ;CACvD,MAAM,iBAAyC,EAAE;CACjD,MAAM,gBAAwD,EAAE;CAEhE,IAAI,iBAAoE;CACxE,IAAI,qBAAqB;AAEzB,MAAK,MAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE;EACtC,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,QAAQ,WAAW,KAAK,QAAQ,WAAW,IAAI,CAAE;EAErD,MAAM,cAAc,KAAK,OAAO,KAAK;AAErC,MAAI,gBAAgB,KAAK,YAAY,YAAY;AAC/C,oBAAiB;AACjB;;AAEF,MAAI,gBAAgB,KAAK,YAAY,aAAa;AAChD,oBAAiB;AACjB;;AAEF,MAAI,gBAAgB,GAAG;AACrB,oBAAiB;AACjB;;AAGF,MAAI,mBAAmB,aAAa,cAAc,GAAG;GACnD,MAAM,aAAa,QAAQ,QAAQ,IAAI;AACvC,OAAI,aAAa,GAAG;IAClB,MAAM,MAAM,QAAQ,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,SAAS,GAAG;IACpE,MAAM,QAAQ,QACX,MAAM,aAAa,EAAE,CACrB,MAAM,CACN,QAAQ,SAAS,GAAG;AACvB,QAAI,OAAO,MAAO,gBAAe,OAAO;;AAE1C;;AAGF,MAAI,mBAAmB,cAAc,cAAc,GACjD;OAAI,QAAQ,SAAS,IAAI,IAAI,CAAC,QAAQ,SAAS,IAAI,EAAE;AACnD,yBAAqB,QAAQ,MAAM,GAAG,GAAG,CAAC,QAAQ,SAAS,GAAG;AAC9D,qBAAiB;AACjB,kBAAc,sBAAsB,EAAE;AACtC;;;AAIJ,MAAI,mBAAmB,mBAAmB,cAAc,GAAG;AACzD,OAAI,eAAe,KAAK,QAAQ,SAAS,IAAI,IAAI,CAAC,QAAQ,SAAS,IAAI,EAAE;AACvE,yBAAqB,QAAQ,MAAM,GAAG,GAAG,CAAC,QAAQ,SAAS,GAAG;AAC9D,kBAAc,sBAAsB,EAAE;AACtC;;GAEF,MAAM,aAAa,QAAQ,QAAQ,IAAI;AACvC,OAAI,aAAa,KAAK,oBAAoB;IACxC,MAAM,MAAM,QAAQ,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,SAAS,GAAG;IACpE,MAAM,QAAQ,QACX,MAAM,aAAa,EAAE,CACrB,MAAM,CACN,QAAQ,SAAS,GAAG;AACvB,QAAI,OAAO,MAAO,eAAc,oBAAoB,OAAO;;;;AAKjE,QAAO;EAAE;EAAgB;EAAe;;AAG1C,MAAM,uCACJ,UACA,aACA,qBACkB;AAClB,KAAI,kBAAkB;EACpB,MAAM,eAAe,SAAS,cAAc;AAC5C,MAAI,eAAe,aAAc,QAAO,aAAa;;AAGvD,KAAI,SAAS,eAAe,aAAc,QAAO,SAAS,eAAe;AAEzE,MAAK,MAAM,gBAAgB,OAAO,OAAO,SAAS,cAAc,CAC9D,KAAI,aAAa,aAAc,QAAO,aAAa;AAGrD,QAAO;;AAGT,MAAM,yBACJ,aACA,aACA,kBACkB;CAElB,MAAM,aADkB,uBAAuB,YAAY,CACxB;CACnC,MAAM,cAAc,aAAa,mBAAmB,WAAW,GAAG;CAElE,MAAM,MAAM;AAEZ,KAAI,cAAc,IAAI,QAAQ,EAAE;EAC9B,MAAM,UAAU,0BAA0B,IAAI,SAAS,YAAY;AACnE,MAAI,QAAS,QAAO;;AAGtB,KAAI,cAAc,IAAI,SAAS,EAAE;AAC/B,MAAI,eAAe,cAAe,IAAI,SAAqC,aAAa,EAAE;GACxF,MAAM,UAAU,0BACb,IAAI,SAAqC,cAC1C,YACD;AACD,OAAI,QAAS,QAAO;;AAEtB,OAAK,MAAM,kBAAkB,OAAO,OAAO,IAAI,SAAS,CACtD,KAAI,cAAc,eAAe,EAAE;GACjC,MAAM,UAAU,0BAA0B,gBAAgB,YAAY;AACtE,OAAI,QAAS,QAAO;;;CAK1B,MAAM,aAAa,YAAY;AAC/B,KAAI,cAAc,CAAC,MAAM,QAAQ,WAAW,IAAI,cAAc,WAAW,QAAQ,EAAE;EACjF,MAAM,UAAU,0BACd,WAAW,SACX,YACD;AACD,MAAI,QAAS,QAAO;;AAGtB,KAAI,eAAe;EAEjB,MAAM,cAAc,oCADC,2BAA2B,cAAc,EACQ,aAAa,YAAY;AAC/F,MAAI,YAAa,QAAO;;AAG1B,QAAO;;AAGT,MAAM,yBAAyB,gBAA6C;CAC1E,MAAM,kBAAkB,uBAAuB,YAAY;CAC3D,MAAM,aAAa,gBAAgB,SAAS;AAE5C,QAAO;EACL,cAFmB,cAAc,CAAC,mBAAmB,WAAW,GAAG,aAAa;EAGhF,WAAW,gBAAgB,gBAAgB;EAC5C;;AAGH,MAAM,8BAA8B,kBAAoC;CACtE,MAAM,gBAAgB,KAAK,KAAK,eAAe,sBAAsB;AACrE,KAAI,CAAC,OAAO,cAAc,CAAE,QAAO,EAAE;CAErC,MAAM,UAAU,GAAG,aAAa,eAAe,QAAQ;CACvD,MAAM,WAAqB,EAAE;CAC7B,IAAI,wBAAwB;AAE5B,MAAK,MAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE;EACtC,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,YAAY,aAAa;AAC3B,2BAAwB;AACxB;;AAEF,MAAI,yBAAyB,QAAQ,WAAW,IAAI,CAClD,UAAS,KAAK,QAAQ,QAAQ,SAAS,GAAG,CAAC,QAAQ,SAAS,GAAG,CAAC;WACvD,yBAAyB,QAAQ,SAAS,KAAK,CAAC,QAAQ,WAAW,IAAI,CAChF,yBAAwB;;AAI5B,QAAO;;AAGT,MAAM,wBAAwB,eAAuB,gBAAuC;CAC1F,MAAM,eAAe,2BAA2B,cAAc;AAC9D,KAAI,aAAa,SAAS,EAAG,QAAO;AAEpC,KAAI,MAAM,QAAQ,YAAY,WAAW,CACvC,QAAO,YAAY;AAGrB,KAAI,YAAY,YAAY,SAC1B,QAAO,YAAY,WAAW;AAGhC,QAAO,EAAE;;AAGX,MAAM,+BAA+B,eAAuB,YAA8B;CACxF,MAAM,eAAe,QAAQ,QAAQ,SAAS,GAAG,CAAC,QAAQ,WAAW,KAAK;AAE1E,KAAI,CAAC,aAAa,SAAS,IAAI,EAAE;EAC/B,MAAM,gBAAgB,KAAK,KAAK,eAAe,aAAa;AAC5D,MAAI,GAAG,WAAW,cAAc,IAAI,OAAO,KAAK,KAAK,eAAe,eAAe,CAAC,CAClF,QAAO,CAAC,cAAc;AAExB,SAAO,EAAE;;CAGX,MAAM,gBAAgB,aAAa,QAAQ,IAAI;CAC/C,MAAM,gBAAgB,KAAK,KAAK,eAAe,aAAa,MAAM,GAAG,cAAc,CAAC;CACpF,MAAM,sBAAsB,aAAa,MAAM,gBAAgB,EAAE;AAEjE,KAAI,CAAC,GAAG,WAAW,cAAc,IAAI,CAAC,GAAG,SAAS,cAAc,CAAC,aAAa,CAC5E,QAAO,EAAE;AAGX,QAAO,GACJ,YAAY,cAAc,CAC1B,KAAK,UAAU,KAAK,KAAK,eAAe,OAAO,oBAAoB,CAAC,CACpE,QACE,cACC,GAAG,WAAW,UAAU,IACxB,GAAG,SAAS,UAAU,CAAC,aAAa,IACpC,OAAO,KAAK,KAAK,WAAW,eAAe,CAAC,CAC/C;;AAGL,MAAM,sCAAsC,cAAsC;CAChF,MAAM,eAAe,iBAAiB,UAAU;AAChD,KAAI,CAAC,aAAc,QAAO;EAAE,cAAc;EAAM,WAAW;EAAW;CAEtE,MAAM,0BAA0B,KAAK,KAAK,cAAc,eAAe;AACvE,KAAI,CAAC,OAAO,wBAAwB,CAAE,QAAO;EAAE,cAAc;EAAM,WAAW;EAAW;CAEzF,MAAM,kBAAkB,gBAAgB,wBAAwB;CAChE,MAAM,WAAW,sBAAsB,gBAAgB;CACvD,MAAM,iBAAiB,sBAAsB,iBAAiB,SAAS,aAAa;CACpF,MAAM,gBAAgB,sBAAsB,cAAc,gBAAgB;AAE1E,QAAO;EACL,cAAc,SAAS,gBAAgB,kBAAkB,cAAc;EACvE,WAAW,SAAS,cAAc,YAAY,SAAS,YAAY,cAAc;EAClF;;AAGH,MAAM,yBAAyB,eAAuB,gBAA6C;CACjG,MAAM,WAAW,qBAAqB,eAAe,YAAY;CACjE,MAAM,SAAyB;EAAE,cAAc;EAAM,WAAW;EAAW;AAE3E,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,cAAc,4BAA4B,eAAe,QAAQ;AAEvE,OAAK,MAAM,sBAAsB,aAAa;GAE5C,MAAM,OAAO,sBADgB,gBAAgB,KAAK,KAAK,oBAAoB,eAAe,CAAC,CACnC;AAExD,OAAI,KAAK,gBAAgB,CAAC,OAAO,aAC/B,QAAO,eAAe,KAAK;AAE7B,OAAI,KAAK,cAAc,aAAa,OAAO,cAAc,UACvD,QAAO,YAAY,KAAK;AAG1B,OAAI,OAAO,gBAAgB,OAAO,cAAc,UAC9C,QAAO;;;AAKb,QAAO;;AA6ET,MAAM,sBAAsB,gBAAsC;CAChE,MAAM,kBAAkB,uBAAuB,YAAY;AAC3D,QAAO,OAAO,KAAK,gBAAgB,CAAC,MAAM,gBACxC,wBAAwB,IAAI,YAAY,CACzC;;AASH,MAAM,2BAA2B,aAA8B;AAC7D,KAAI,CAAC,OAAO,SAAS,CAAE,QAAO;CAC9B,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;AAClD,QACE,oCAAoC,KAAK,QAAQ,IACjD,yCAAyC,KAAK,QAAQ;;AAI1D,MAAM,4BAA4B,WAAmB,cACnD,UAAU,MAAM,aAAa,wBAAwB,KAAK,KAAK,WAAW,SAAS,CAAC,CAAC;AAEvF,MAAM,uBAAuB,WAAmB,gBAAsC;AACpF,KAAI,mBAAmB,YAAY,CAAE,QAAO;AAE5C,KAAI,yBAAyB,WAAW,sBAAsB,CAAE,QAAO;AACvE,KAAI,yBAAyB,WAAW,uBAAuB,CAAE,QAAO;AACxE,KAAI,yBAAyB,WAAW,sBAAsB,CAAE,QAAO;AACvE,KAAI,yBAAyB,WAAW,0BAA0B,CAAE,QAAO;CAE3E,IAAI,oBAAoB,KAAK,QAAQ,UAAU;AAC/C,QAAO,sBAAsB,KAAK,QAAQ,kBAAkB,EAAE;EAC5D,MAAM,sBAAsB,KAAK,KAAK,mBAAmB,eAAe;AACxE,MAAI,OAAO,oBAAoB,EAE7B;OAAI,mBADwB,gBAAgB,oBAAoB,CACrB,CAAE,QAAO;;AAEtD,sBAAoB,KAAK,QAAQ,kBAAkB;;AAGrD,QAAO;;AAGT,MAAa,mBAAmB,cAAmC;CACjE,MAAM,kBAAkB,KAAK,KAAK,WAAW,eAAe;AAC5D,KAAI,CAAC,OAAO,gBAAgB,CAC1B,OAAM,IAAI,MAAM,4BAA4B,YAAY;CAG1D,MAAM,cAAc,gBAAgB,gBAAgB;CACpD,IAAI,EAAE,cAAc,cAAc,sBAAsB,YAAY;AAEpE,KAAI,CAAC,aACH,gBAAe,sBAAsB,aAAa,SAAS,UAAU;AAGvE,KAAI,CAAC,cAAc;EACjB,MAAM,eAAe,iBAAiB,UAAU;AAChD,MAAI,cAAc;GAChB,MAAM,0BAA0B,KAAK,KAAK,cAAc,eAAe;AACvE,OAAI,OAAO,wBAAwB,CAEjC,gBAAe,sBADS,gBAAgB,wBAAwB,EACV,SAAS,aAAa;;;AAKlF,KAAI,CAAC,gBAAgB,cAAc,WAAW;EAC5C,MAAM,gBAAgB,sBAAsB,WAAW,YAAY;AACnE,MAAI,CAAC,gBAAgB,cAAc,aACjC,gBAAe,cAAc;AAE/B,MAAI,cAAc,aAAa,cAAc,cAAc,UACzD,aAAY,cAAc;;AAI9B,MAAK,CAAC,gBAAgB,cAAc,cAAc,CAAC,eAAe,UAAU,EAAE;EAC5E,MAAM,eAAe,mCAAmC,UAAU;AAClE,MAAI,CAAC,aACH,gBAAe,aAAa;AAE9B,MAAI,cAAc,UAChB,aAAY,aAAa;;CAI7B,MAAM,cAAc,YAAY,QAAQ,KAAK,SAAS,UAAU;CAChE,MAAM,gBAAgB,GAAG,WAAW,KAAK,KAAK,WAAW,gBAAgB,CAAC;CAC1E,MAAM,kBAAkB,iBAAiB,UAAU;CAEnD,MAAM,mBAAmB,oBAAoB,WAAW,YAAY;AAEpE,QAAO;EACL,eAAe;EACf;EACA;EACA;EACA;EACA;EACA;EACD;;;;;ACvlBH,MAAM,kBAAkB;AACxB,MAAM,0BAA0B;AAEhC,MAAM,2BAA2B,cAAgD;CAC/E,MAAM,iBAAiB,KAAK,KAAK,WAAW,gBAAgB;AAE5D,KAAI,OAAO,eAAe,CACxB,KAAI;EACF,MAAM,cAAc,GAAG,aAAa,gBAAgB,QAAQ;EAC5D,MAAM,SAAkB,KAAK,MAAM,YAAY;AAC/C,MAAI,cAAc,OAAO,CACvB,QAAO;AAET,UAAQ,KAAK,YAAY,gBAAgB,mCAAmC;UACrE,OAAO;AACd,UAAQ,KACN,4BAA4B,gBAAgB,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACvG;;CAIL,MAAM,kBAAkB,KAAK,KAAK,WAAW,eAAe;AAC5D,KAAI,OAAO,gBAAgB,CACzB,KAAI;EACF,MAAM,cAAc,GAAG,aAAa,iBAAiB,QAAQ;EAE7D,MAAM,iBADc,KAAK,MAAM,YAAY,CACR;AACnC,MAAI,cAAc,eAAe,CAC/B,QAAO;SAEH;AACN,SAAO;;AAIX,QAAO;;AAGT,MAAa,cAAc,kBAAoD;CAC7E,MAAM,cAAc,wBAAwB,cAAc;AAC1D,KAAI,YAAa,QAAO;CAExB,IAAI,oBAAoB,KAAK,QAAQ,cAAc;AACnD,QAAO,sBAAsB,KAAK,QAAQ,kBAAkB,EAAE;EAC5D,MAAM,iBAAiB,wBAAwB,kBAAkB;AACjE,MAAI,eAAgB,QAAO;AAC3B,sBAAoB,KAAK,QAAQ,kBAAkB;;AAGrD,QAAO;;;;;ACpDT,MAAa,+BACX,kBAC4C;AAC5C,SAAQ,aAAsC;EAC5C,MAAM,eAAe,KAAK,WAAW,SAAS,GAAG,WAAW,KAAK,KAAK,eAAe,SAAS;AAC9F,MAAI;AACF,UAAO,GAAG,aAAa,cAAc,QAAQ,CAAC,MAAM,KAAK;UACnD;AACN,UAAO;;;;;;;ACCb,MAAM,yBAAyB,kBAA2C;CACxE,MAAM,SAAS,UAAU,OAAO;EAAC;EAAY;EAAY;EAAY;EAAqB,EAAE;EAC1F,KAAK;EACL,UAAU;EACV,WAAW;EACZ,CAAC;AAEF,KAAI,OAAO,SAAS,OAAO,WAAW,EACpC,QAAO;AAGT,QAAO,OAAO,OACX,MAAM,KAAK,CACX,QAAQ,aAAa,SAAS,SAAS,KAAK,oBAAoB,KAAK,SAAS,CAAC;;AAGpF,MAAM,gCAAgC,kBAAoC;CACxE,MAAM,YAAsB,EAAE;CAC9B,MAAM,QAAQ,CAAC,cAAc;AAE7B,QAAO,MAAM,SAAS,GAAG;EACvB,MAAM,mBAAmB,MAAM,KAAK;EACpC,MAAM,UAAU,GAAG,YAAY,kBAAkB,EAAE,eAAe,MAAM,CAAC;AAEzE,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,eAAe,KAAK,KAAK,kBAAkB,MAAM,KAAK;AAE5D,OAAI,MAAM,aAAa,EAAE;AACvB,QAAI,CAAC,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,oBAAoB,IAAI,MAAM,KAAK,CACrE,OAAM,KAAK,aAAa;AAE1B;;AAGF,OAAI,MAAM,QAAQ,IAAI,oBAAoB,KAAK,MAAM,KAAK,CACxD,WAAU,KAAK,KAAK,SAAS,eAAe,aAAa,CAAC,QAAQ,OAAO,IAAI,CAAC;;;AAKpF,QAAO;;AAGT,MAAM,mBAAmB,kBACvB,sBAAsB,cAAc,IAAI,6BAA6B,cAAc;AAErF,MAAa,2BACX,eACA,eACyB;AACzB,KAAI,CAAC,MAAM,QAAQ,YAAY,QAAQ,MAAM,IAAI,WAAW,OAAO,MAAM,WAAW,EAClF;CAGF,MAAM,kBAAkB,2BAA2B,WAAW;AAU9D,QARsB,gBAAgB,cAAc,CAAC,QAAQ,aAAa;AACxE,MAAI,CAAC,iBAAiB,KAAK,SAAS,CAClC,QAAO;AAGT,SAAO,CAAC,wBAAwB,UAAU,eAAe,gBAAgB;GACzE;;;;;ACjEJ,MAAM,iBAAiB,UAA0B;AAC/C,KAAI,SAAS,qBAAsB,QAAO;AAC1C,KAAI,SAAS,mBAAoB,QAAO;AACxC,QAAO;;AAGT,MAAM,oBACJ,gBACyD;CACzD,MAAM,6BAAa,IAAI,KAAa;CACpC,MAAM,+BAAe,IAAI,KAAa;AAEtC,MAAK,MAAM,cAAc,aAAa;EACpC,MAAM,UAAU,GAAG,WAAW,OAAO,GAAG,WAAW;AACnD,MAAI,WAAW,aAAa,QAC1B,YAAW,IAAI,QAAQ;MAEvB,cAAa,IAAI,QAAQ;;AAI7B,QAAO;EAAE,gBAAgB,WAAW;EAAM,kBAAkB,aAAa;EAAM;;AAGjF,MAAM,uBAAuB,gBAAwB,qBAAqC;CACxF,MAAM,UAAU,iBAAiB,qBAAqB,mBAAmB;AACzE,QAAO,KAAK,IAAI,GAAG,KAAK,MAAM,gBAAgB,QAAQ,CAAC;;AAGzD,MAAa,yBAAyB,gBAA2C;CAC/E,MAAM,EAAE,gBAAgB,qBAAqB,iBAAiB,YAAY;CAC1E,MAAM,QAAQ,oBAAoB,gBAAgB,iBAAiB;AACnE,QAAO;EAAE;EAAO,OAAO,cAAc,MAAM;EAAE;;;;;AClC/C,MAAM,oBAAoB,UAAuC;AAC/D,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,KAAI,EAAE,WAAW,UAAU,EAAE,WAAW,OAAQ,QAAO;CACvD,MAAM,aAAa,QAAQ,IAAI,OAAO,QAAQ;CAC9C,MAAM,aAAa,QAAQ,IAAI,OAAO,QAAQ;AAC9C,KAAI,OAAO,eAAe,YAAY,OAAO,eAAe,SAAU,QAAO;AAC7E,QAAO;EAAE,OAAO;EAAY,OAAO;EAAY;;AAGjD,MAAa,kBAAkB,OAC7B,aACA,wBACgC;CAChC,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,iBAAiB;AAExE,KAAI;EACF,MAAM,WAAW,MAAM,oBAAoB,eAAe;GACxD,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU,EAAE,aAAa,CAAC;GACrC,QAAQ,WAAW;GACpB,CAAC;AAEF,MAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,SAAO,iBAAiB,MAAM,SAAS,MAAM,CAAC;SACxC;AACN,SAAO;WACC;AACR,eAAa,UAAU;;;;;;AC9B3B,MAAM,yBAAwD;CAC5D,MAAM,YAAa,WAA+C;AAClE,QAAO,WAAW,UAAU,OAAO,YAAY;;AAGjD,MAAM,qBAAyC;CAC7C,MAAM,OAAO,kBAAkB;AAC/B,KAAI,CAAC,MAAM,IAAK,QAAO;AACvB,QAAO,KAAK,IAAI,eAAe,KAAK,IAAI,eAAe,KAAK,IAAI,cAAc,KAAK,IAAI;;AAGzF,IAAI,qBAAqB;AACzB,IAAI;AAEJ,MAAM,oBAAwC;AAC5C,KAAI,mBAAoB,QAAO;AAC/B,sBAAqB;AACrB,oBAAmB,cAAc;AACjC,QAAO;;AAGT,MAAM,wBAAwB,OAAO,aAA6C;AAChF,KAAI;EAEF,MAAM,EAAE,eAAe,MAAM,OAAO;AACpC,SAAO,IAAI,WAAW,SAAS;SACzB;AACN,SAAO;;;AAMX,MAAa,aAAa,OAAO,KAAmB,SAA0C;CAC5F,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,YAAY,iBAAiB,WAAW,OAAO,EAAE,iBAAiB;AAExE,KAAI;EACF,MAAM,WAAW,aAAa;EAC9B,MAAM,aAAa,WAAW,MAAM,sBAAsB,SAAS,GAAG;AAEtE,SAAO,MAAM,MAAM,KAAK;GACtB,GAAG;GACH,QAAQ,WAAW;GACnB,GAAI,aAAa,EAAE,YAAY,GAAG,EAAE;GACrC,CAAgB;WACT;AACR,eAAa,UAAU;;;;;;AC/C3B,MAAa,iBAAiB,OAAO,gBAA2D;CAC9F,MAAM,WAAW,MAAM,gBAAgB,aAAa,WAAW;AAC/D,KAAI,SAAU,QAAO;AACrB,QAAO,sBAAsB,YAAY;;;;;ACP3C,MAAa,0BACX,gBACa;AACb,KAAI,uBAAuB,IACzB,QAAO,CAAC,GAAG,YAAY;AAGzB,KAAI,MAAM,QAAQ,YAAY,CAC5B,QAAO,YAAY,QAAQ,UAA2B,OAAO,UAAU,SAAS;AAGlF,KAAI,CAAC,cAAc,YAAY,CAC7B,QAAO,EAAE;CAGX,MAAM,kBAA4B,EAAE;AAEpC,MAAK,MAAM,cAAc,OAAO,OAAO,YAAY,EAAE;AACnD,MAAI,CAAC,cAAc,WAAW,CAAE;AAEhC,OAAK,MAAM,SAAS,OAAO,OAAO,WAAW,CAC3C,KAAI,cAAc,MAAM,IAAI,OAAO,MAAM,aAAa,SACpD,iBAAgB,KAAK,MAAM,SAAS;;AAK1C,QAAO;;;;;ACpBT,MAAM,oBAA4C;CAChD,OAAO;CACP,SAAS;CACT,OAAO;CACP,YAAY;CACb;AAED,MAAM,mBAA2C;CAC/C,OAAO;CACP,SAAS;CACT,OAAO;CACP,YAAY;CACb;AAED,MAAM,oBAAyD;CAC7D,OAAO;CACP,SAAS;CACT,OAAO;CACP,YAAY;CACb;AAED,MAAM,uBACJ,SACA,WACA,kBACiB;CACjB,MAAM,cAA4B,EAAE;AAEpC,MAAK,MAAM,UAAU,OAAO,OAAO,QAAQ,CACzC,MAAK,MAAM,SAAS,OAAO,OAAO,OAAO,CACvC,aAAY,KAAK;EACf,UAAU,KAAK,SAAS,eAAe,MAAM,SAAS;EACtD,QAAQ;EACR,MAAM;EACN,UAAU,kBAAkB,cAAc;EAC1C,SAAS,GAAG,iBAAiB,WAAW,IAAI,MAAM;EAClD,MAAM;EACN,MAAM;EACN,QAAQ;EACR,UAAU,kBAAkB,cAAc;EAC1C,QAAQ;EACT,CAAC;AAIN,QAAO;;AAIT,MAAM,WAAW,OAAU,OAAqC;CAC9D,MAAM,cAAc,QAAQ;CAC5B,MAAM,eAAe,QAAQ;CAC7B,MAAM,eAAe,QAAQ;CAC7B,MAAM,gBAAgB,QAAQ;AAC9B,SAAQ,YAAY;AACpB,SAAQ,aAAa;AACrB,SAAQ,aAAa;AACrB,SAAQ,cAAc;AACtB,KAAI;AACF,SAAO,MAAM,IAAI;WACT;AACR,UAAQ,MAAM;AACd,UAAQ,OAAO;AACf,UAAQ,OAAO;AACf,UAAQ,QAAQ;;;AAIpB,MAAM,+BAA+B;AAErC,MAAM,2BAA2B,UAAkC;AAEjE,QADc,OAAO,MAAM,CAAC,MAAM,6BAA6B,GAChD,MAAM;;AAGvB,MAAM,qBAAqB,CAAC,sBAAsB,gBAAgB;AAElE,MAAM,uBAAuB,cAC3B,mBAAmB,MAAM,aAAa,GAAG,WAAW,KAAK,KAAK,WAAW,SAAS,CAAC,CAAC;AAEtF,MAAM,qBAAqB,OACzB,SACA,kBACyB;CACzB,MAAM,eAAe,oBAAoB,QAAQ;CACjD,MAAM,UAAU,MAAM,eACpB,cAAc;EACZ,KAAK;EACL,gBAAgB;EAChB,GAAI,gBAAgB,EAAE,WAAW,eAAe,GAAG,EAAE;EACrD,GAAI,eAAe,EAAE,cAAc,GAAG,EAAE;EACzC,CAAC,CACH;CAED,MAAM,eAAe,QAAQ;AAE7B,MAAK,IAAI,UAAU,GAAG,WAAW,kBAAkB,UACjD,KAAI;AACF,SAAQ,MAAM,eAAe,KAAK,QAAQ,CAAC;UACpC,OAAO;EACd,MAAM,eAAe,wBAAwB,MAAM;AACnD,MAAI,CAAC,gBAAgB,YAAY,iBAC/B,OAAM;AAER,eAAa,gBAAgB;;AAIjC,OAAM,IAAI,MAAM,cAAc;;AAGhC,MAAM,kBAAkB,cAA+B;CACrD,MAAM,kBAAkB,KAAK,KAAK,WAAW,eAAe;AAC5D,QAAO,GAAG,WAAW,gBAAgB,IAAI,GAAG,SAAS,gBAAgB,CAAC,aAAa;;AAGrF,MAAa,UAAU,OAAO,kBAAiD;CAC7E,MAAM,eAAe,iBAAiB,cAAc;AAIpD,KAAI,EAFF,eAAe,cAAc,IAAK,iBAAiB,QAAQ,eAAe,aAAa,EAGvF,QAAO,EAAE;CAGX,IAAI;AAEJ,KAAI,cAAc;EAChB,MAAM,kBAAkB,KAAK,KAAK,eAAe,eAAe;EAIhE,MAAM,iBAHc,OAAO,gBAAgB,GACvC,KAAK,MAAM,GAAG,aAAa,iBAAiB,QAAQ,CAAC,GACrD,EAAE,EAC4B,QAAQ,KAAK,SAAS,cAAc;AAEtE,MAAI;AACF,gBAAa,MAAM,mBAAmB,cAAc,cAAc;UAC5D;AACN,gBAAa,MAAM,mBAAmB,cAAc;;OAGtD,cAAa,MAAM,mBAAmB,cAAc;CAGtD,MAAM,EAAE,WAAW;CACnB,MAAM,cAA4B,EAAE;AAEpC,MAAK,MAAM,kBAAkB,uBAAuB,OAAO,MAAM,CAC/D,aAAY,KAAK;EACf,UAAU,KAAK,SAAS,eAAe,eAAe;EACtD,QAAQ;EACR,MAAM;EACN,UAAU,kBAAkB;EAC5B,SAAS,iBAAiB;EAC1B,MAAM;EACN,MAAM;EACN,QAAQ;EACR,UAAU,kBAAkB;EAC5B,QAAQ;EACT,CAAC;AAKJ,MAAK,MAAM,aAFS;EAAC;EAAW;EAAS;EAAa,CAGpD,aAAY,KAAK,GAAG,oBAAoB,OAAO,YAAY,WAAW,cAAc,CAAC;AAGvF,QAAO;;;;;AC9KT,MAAMA,eAAa,cAAc,OAAO,KAAK,IAAI;AAEjD,MAAM,eAAuC;CAC3C,sCAAsC;CACtC,8CAA8C;CAC9C,oCAAoC;CACpC,6DAA6D;CAC7D,uDAAuD;CACvD,wCAAwC;CACxC,+CAA+C;CAC/C,gDAAgD;CAChD,2CAA2C;CAC3C,wCAAwC;CACxC,gDAAgD;CAChD,oCAAoC;CACpC,mCAAmC;CACnC,0CAA0C;CAC1C,sCAAsC;CACtC,qDAAqD;CACtD;AAED,MAAM,qBAA6C;CACjD,+BAA+B;CAC/B,yCAAyC;CACzC,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CACjD,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CAClD;AAED,MAAM,uBAA+C;CACnD,oDAAoD;CACpD,yDAAyD;CACzD,wDAAwD;CACxD,kDAAkD;CAClD,oDAAoD;CACpD,iDAAiD;CACjD,sDAAsD;CACtD,qDAAqD;CACrD,2DAA2D;CAC3D,wDAAwD;CACxD,oDAAoD;CACpD,4CAA4C;CAC5C,qDAAqD;CACrD,qDAAqD;CACtD;AAED,MAAM,uBAA+C;CACnD,sCAAsC;CACtC,+BAA+B;CAC/B,uBAAuB;CACvB,yBAAyB;CACzB,wBAAwB;CACxB,sCAAsC;CACtC,0BAA0B;CAC1B,mCAAmC;CACnC,8CAA8C;CAC9C,qCAAqC;CACrC,2CAA2C;CAC3C,oCAAoC;CACpC,2BAA2B;CAC3B,gCAAgC;CAChC,uCAAuC;CACvC,uBAAuB;CACxB;AASD,MAAM,sBAA8C;CAClD,wBAAwB;CACxB,kCAAkC;CAClC,gCAAgC;CAChC,iBAAiB;CACjB,0BAA0B;CAC1B,mBAAmB;CACnB,2BAA2B;CAC3B,gCAAgC;CAChC,wBAAwB;CACxB,uBAAuB;CACvB,+BAA+B;CAC/B,6BAA6B;CAC9B;AAED,MAAM,qBAA6C;CACjD,qBAAqB;CACrB,4BAA4B;CAC5B,yCAAyC;CACzC,2CAA2C;CAC3C,yCAAyC;CACzC,yBAAyB;CACzB,gCAAgC;CAChC,0BAA0B;CAC1B,+BAA+B;CAC/B,kBAAkB;CAClB,iCAAiC;CACjC,yCAAyC;CACzC,oCAAoC;CACpC,6BAA6B;CAC9B;AAED,MAAa,sBAAsB,EACjC,YACA,WACA,kBACA,kBAAkB,aACQ;CAC1B,YAAY;EACV,aAAa;EACb,YAAY;EACZ,UAAU;EACV,MAAM;EACN,aAAa;EACb,OAAO;EACP,SAAS;EACV;CACD,SAAS;EAAC;EAAS;EAAY,GAAI,mBAAmB,EAAE,GAAG,CAAC,aAAa;EAAE;CAC3E,WAAW,CACT,GAAI,oBAAoB,CAAC,kBACrB,CAAC;EAAE,MAAM;EAAkB,WAAWA,aAAW,QAAQ,4BAA4B;EAAE,CAAC,GACxF,EAAE,EACN,WACD;CACD,OAAO;EACL,GAAI,kBAAkB,EAAE,GAAG;EAC3B,GAAI,kBAAkB,EAAE,GAAG;EAC3B,GAAI,oBAAoB,CAAC,kBAAkB,uBAAuB,EAAE;EAEpE,wCAAwC;EACxC,mCAAmC;EACnC,uCAAuC;EACvC,wCAAwC;EACxC,oCAAoC;EACpC,kCAAkC;EAClC,yCAAyC;EACzC,6CAA6C;EAC7C,sCAAsC;EAEtC,mCAAmC;EACnC,oCAAoC;EACpC,+CAA+C;EAE/C,6CAA6C;EAC7C,6CAA6C;EAC7C,iDAAiD;EACjD,8CAA8C;EAC9C,iDAAiD;EACjD,+CAA+C;EAC/C,6CAA6C;EAE7C,kCAAkC;EAClC,iDAAiD;EACjD,uCAAuC;EACvC,mCAAmC;EACnC,yCAAyC;EAEzC,0CAA0C;EAE1C,kCAAkC;EAElC,iCAAiC;EACjC,sCAAsC;EACtC,0BAA0B;EAC1B,sCAAsC;EACtC,gCAAgC;EAChC,0CAA0C;EAE1C,sCAAsC;EACtC,6CAA6C;EAC7C,mCAAmC;EAEnC,oCAAoC;EACpC,yCAAyC;EAEzC,+CAA+C;EAE/C,0CAA0C;EAC1C,4CAA4C;EAC5C,uCAAuC;EACvC,yCAAyC;EACzC,oDAAoD;EACpD,+CAA+C;EAE/C,wCAAwC;EACxC,gCAAgC;EAChC,2CAA2C;EAC3C,mCAAmC;EACnC,yCAAyC;EACzC,iCAAiC;EACjC,kCAAkC;EAClC,kCAAkC;EAClC,6BAA6B;EAC7B,uCAAuC;EACvC,8CAA8C;EAC9C,4CAA4C;EAC5C,iCAAiC;EACjC,gCAAgC;EAChC,4CAA4C;EAE5C,+BAA+B;EAC/B,GAAI,cAAc,WAAW,eAAe,EAAE;EAC9C,GAAI,cAAc,UAAU,cAAc,iBAAiB,qBAAqB,EAAE;EAClF,GAAI,cAAc,mBAAmB,uBAAuB,EAAE;EAC/D;CACF;;;;AChND,MAAM,kCACJ,eACA,iBACa;CACb,MAAM,WAAW;EAAC;EAAQ;EAAM;EAAe;EAAM;EAA0B;AAC/E,KAAI,gBAAgB,aAAa,SAAS,EACxC,UAAS,KAAK,MAAM,GAAG,aAAa;CAGtC,MAAM,SAAS,UAAU,OAAO,UAAU;EACxC,KAAK;EACL,UAAU;EACV,WAAW;EACZ,CAAC;AAEF,KAAI,OAAO,SAAS,OAAO,WAAW,KAAM,QAAO,EAAE;AACrD,KAAI,OAAO,WAAW,KAAK,OAAO,OAAO,MAAM,CAAC,WAAW,EAAG,QAAO,EAAE;AAEvE,QAAO,OAAO,OACX,MAAM,KAAK,CACX,QAAQ,aAAa,SAAS,SAAS,KAAK,oBAAoB,KAAK,SAAS,CAAC;;AAGpF,MAAM,qBAAqB,YACzB,QACG,WAAW,kBAAkB,iBAAiB,CAC9C,WAAW,kBAAkB,iBAAiB;AAEnD,MAAa,+BACX,eACA,iBACiB;CACjB,MAAM,YAAY,+BAA+B,eAAe,aAAa;CAC7E,MAAM,mCAAmB,IAAI,KAAqB;AAElD,MAAK,MAAM,gBAAgB,WAAW;EACpC,MAAM,eAAe,KAAK,KAAK,eAAe,aAAa;EAE3D,IAAI;AACJ,MAAI;AACF,qBAAkB,GAAG,aAAa,cAAc,QAAQ;UAClD;AACN;;EAGF,MAAM,qBAAqB,kBAAkB,gBAAgB;AAC7D,MAAI,uBAAuB,iBAAiB;AAC1C,oBAAiB,IAAI,cAAc,gBAAgB;AACnD,MAAG,cAAc,cAAc,mBAAmB;;;AAItD,cAAa;AACX,OAAK,MAAM,CAAC,cAAc,oBAAoB,iBAC5C,IAAG,cAAc,cAAc,gBAAgB;;;;;;AC3CrD,MAAM,aAAa,cAAc,OAAO,KAAK,IAAI;AAEjD,MAAM,sBAA8C;CAClD,OAAO;CACP,eAAe;CACf,kBAAkB;CAClB,cAAc;CACd,YAAY;CACb;AAED,MAAM,oBAA4C;CAChD,wCAAwC;CACxC,mCAAmC;CACnC,uCAAuC;CACvC,wCAAwC;CACxC,oCAAoC;CACpC,kCAAkC;CAClC,yCAAyC;CACzC,6CAA6C;CAC7C,sCAAsC;CAEtC,yCAAyC;CACzC,mCAAmC;CACnC,oCAAoC;CACpC,+CAA+C;CAE/C,6CAA6C;CAC7C,6CAA6C;CAC7C,iDAAiD;CACjD,8CAA8C;CAC9C,gDAAgD;CAChD,+CAA+C;CAC/C,6CAA6C;CAE7C,kCAAkC;CAClC,iDAAiD;CACjD,uCAAuC;CACvC,mCAAmC;CACnC,yCAAyC;CAEzC,0CAA0C;CAE1C,iCAAiC;CACjC,sCAAsC;CACtC,0BAA0B;CAC1B,sCAAsC;CACtC,gCAAgC;CAChC,0CAA0C;CAE1C,sCAAsC;CACtC,6CAA6C;CAC7C,mCAAmC;CACnC,sCAAsC;CACtC,8CAA8C;CAC9C,oCAAoC;CACpC,6DAA6D;CAC7D,uDAAuD;CACvD,wCAAwC;CACxC,+CAA+C;CAC/C,gDAAgD;CAChD,2CAA2C;CAC3C,wCAAwC;CACxC,gDAAgD;CAChD,oCAAoC;CACpC,mCAAmC;CACnC,0CAA0C;CAC1C,sCAAsC;CACtC,qDAAqD;CAErD,oCAAoC;CACpC,yCAAyC;CAEzC,+CAA+C;CAE/C,0CAA0C;CAC1C,4CAA4C;CAC5C,uCAAuC;CACvC,yCAAyC;CACzC,oDAAoD;CACpD,+CAA+C;CAE/C,wCAAwC;CACxC,gCAAgC;CAChC,2CAA2C;CAC3C,mCAAmC;CACnC,yCAAyC;CACzC,iCAAiC;CACjC,kCAAkC;CAClC,kCAAkC;CAClC,6BAA6B;CAC7B,uCAAuC;CACvC,8CAA8C;CAC9C,4CAA4C;CAC5C,iCAAiC;CACjC,gCAAgC;CAChC,4CAA4C;CAE5C,kCAAkC;CAElC,+BAA+B;CAE/B,+BAA+B;CAC/B,yCAAyC;CACzC,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CACjD,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CAEjD,oDAAoD;CACpD,yDAAyD;CACzD,wDAAwD;CACxD,kDAAkD;CAClD,oDAAoD;CACpD,iDAAiD;CACjD,sDAAsD;CACtD,qDAAqD;CACrD,2DAA2D;CAC3D,wDAAwD;CACxD,oDAAoD;CACpD,4CAA4C;CAC5C,qDAAqD;CACrD,qDAAqD;CACtD;AAED,MAAM,gBAAwC;CAC5C,2BACE;CACF,sBACE;CACF,0BACE;CACF,2BACE;CACF,uBACE;CACF,qBACE;CACF,4BACE;CACF,gCACE;CACF,yBACE;CAEF,4BACE;CACF,sBACE;CACF,uBACE;CACF,kCACE;CAEF,gCACE;CACF,gCACE;CACF,oCACE;CACF,iCACE;CACF,mCACE;CACF,kCACE;CACF,gCACE;CAEF,qBACE;CACF,oCACE;CACF,0BACE;CACF,sBACE;CACF,4BACE;CAEF,6BACE;CAEF,oBACE;CACF,yBACE;CACF,aACE;CACF,yBACE;CACF,mBACE;CACF,6BACE;CAEF,2BACE;CACF,mBACE;CACF,8BACE;CACF,sBACE;CACF,4BACE;CACF,oBACE;CACF,qBACE;CACF,qBACE;CACF,gBACE;CACF,0BACE;CACF,iCACE;CACF,+BACE;CACF,oBACE;CACF,mBACE;CACF,+BACE;CAEF,yBACE;CACF,gCACE;CACF,sBACE;CAEF,yBACE;CACF,iCACE;CACF,uBACE;CACF,gDACE;CACF,0CACE;CACF,2BACE;CACF,kCACE;CACF,mCACE;CACF,8BACE;CACF,2BACE;CACF,mCACE;CACF,uBACE;CACF,sBACE;CACF,6BACE;CACF,yBACE;CACF,wCACE;CAEF,uBACE;CACF,4BACE;CAEF,kCACE;CAEF,6BACE;CACF,+BACE;CACF,0BACE;CACF,4BACE;CACF,uCACE;CACF,kCACE;CAEF,qBACE;CAEF,kBACE;CAEF,kBACE;CACF,4BACE;CACF,8BACE;CACF,wBACE;CACF,oCACE;CACF,8BACE;CACF,wBACE;CACF,oCACE;CAEF,uCACE;CACF,4CACE;CACF,2CACE;CACF,qCACE;CACF,uCACE;CACF,oCACE;CACF,yCACE;CACF,wCACE;CACF,8CACE;CACF,2CACE;CACF,uCACE;CACF,+BACE;CACF,wCACE;CACF,wCACE;CACH;AAED,MAAM,iCAAiC;AAEvC,MAAM,yBAAyB;AAE/B,MAAM,0BACJ,SACA,MACA,QACA,SACsB;AACtB,KAAI,WAAW,iBAEb,QAAO;EAAE,SAAS;EAAwB,MADvB,QAAQ,QAAQ,gCAAgC,GAAG,CAAC,MAAM,IACf;EAAM;AAGtE,QAAO;EAAE,SADO,QAAQ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"}
1
+ {"version":3,"file":"index.js","names":["esmRequire"],"sources":["../src/core/build-diagnose-result.ts","../src/utils/match-glob-pattern.ts","../src/utils/is-ignored-file.ts","../src/utils/filter-diagnostics.ts","../src/utils/merge-and-filter-diagnostics.ts","../src/core/build-result.ts","../src/constants.ts","../src/utils/jsx-include-paths.ts","../src/core/diagnose-core.ts","../src/plugin/constants.ts","../src/utils/is-file.ts","../src/utils/read-package-json.ts","../src/utils/check-reduced-motion.ts","../src/utils/find-monorepo-root.ts","../src/utils/is-plain-object.ts","../src/utils/discover-project.ts","../src/utils/load-config.ts","../src/utils/read-file-lines-node.ts","../src/utils/resolve-lint-include-paths.ts","../src/core/calculate-score-locally.ts","../src/core/try-score-from-api.ts","../src/utils/proxy-fetch.ts","../src/utils/calculate-score-node.ts","../src/utils/collect-unused-file-paths.ts","../src/utils/format-error-chain.ts","../src/utils/extract-failed-plugin-name.ts","../src/utils/has-knip-config.ts","../src/utils/run-knip.ts","../src/oxlint-config.ts","../src/utils/neutralize-disable-directives.ts","../src/utils/run-oxlint.ts","../src/utils/get-diff-files.ts","../src/index.ts"],"sourcesContent":["import type { Diagnostic, ProjectInfo, ScoreResult } from \"../types.js\";\n\ninterface BuildDiagnoseResultParams {\n diagnostics: Diagnostic[];\n project: ProjectInfo;\n elapsedMilliseconds: number;\n score: ScoreResult | null;\n}\n\ninterface DiagnoseResultShape {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n project: ProjectInfo;\n elapsedMilliseconds: number;\n}\n\nexport const buildDiagnoseResult = (params: BuildDiagnoseResultParams): DiagnoseResultShape => ({\n diagnostics: params.diagnostics,\n score: params.score,\n project: params.project,\n elapsedMilliseconds: params.elapsedMilliseconds,\n});\n","const REGEX_SPECIAL_CHARACTERS = /[.+^${}()|[\\]\\\\]/g;\n\nexport const compileGlobPattern = (pattern: string): RegExp => {\n const normalizedPattern = pattern.replace(/\\\\/g, \"/\").replace(/^\\//, \"\");\n\n let regexSource = \"^\";\n let characterIndex = 0;\n\n while (characterIndex < normalizedPattern.length) {\n if (\n normalizedPattern[characterIndex] === \"*\" &&\n normalizedPattern[characterIndex + 1] === \"*\"\n ) {\n if (normalizedPattern[characterIndex + 2] === \"/\") {\n regexSource += \"(?:.+/)?\";\n characterIndex += 3;\n } else {\n regexSource += \".*\";\n characterIndex += 2;\n }\n } else if (normalizedPattern[characterIndex] === \"*\") {\n regexSource += \"[^/]*\";\n characterIndex++;\n } else if (normalizedPattern[characterIndex] === \"?\") {\n regexSource += \"[^/]\";\n characterIndex++;\n } else {\n regexSource += normalizedPattern[characterIndex].replace(REGEX_SPECIAL_CHARACTERS, \"\\\\$&\");\n characterIndex++;\n }\n }\n\n regexSource += \"$\";\n return new RegExp(regexSource);\n};\n\nexport const matchGlobPattern = (filePath: string, pattern: string): boolean => {\n const normalizedPath = filePath.replace(/\\\\/g, \"/\");\n return compileGlobPattern(pattern).test(normalizedPath);\n};\n","import type { ReactDoctorConfig } from \"../types.js\";\nimport { compileGlobPattern } from \"./match-glob-pattern.js\";\n\nconst toRelativePath = (filePath: string, rootDirectory: string): string => {\n const normalizedFilePath = filePath.replace(/\\\\/g, \"/\");\n const normalizedRoot = rootDirectory.replace(/\\\\/g, \"/\").replace(/\\/$/, \"\") + \"/\";\n\n if (normalizedFilePath.startsWith(normalizedRoot)) {\n return normalizedFilePath.slice(normalizedRoot.length);\n }\n\n return normalizedFilePath.replace(/^\\.\\//, \"\");\n};\n\nexport const compileIgnoredFilePatterns = (userConfig: ReactDoctorConfig | null): RegExp[] =>\n Array.isArray(userConfig?.ignore?.files) ? userConfig.ignore.files.map(compileGlobPattern) : [];\n\nexport const isFileIgnoredByPatterns = (\n filePath: string,\n rootDirectory: string,\n patterns: RegExp[],\n): boolean => {\n if (patterns.length === 0) {\n return false;\n }\n\n const relativePath = toRelativePath(filePath, rootDirectory);\n return patterns.some((pattern) => pattern.test(relativePath));\n};\n","import type { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { compileIgnoredFilePatterns, isFileIgnoredByPatterns } from \"./is-ignored-file.js\";\n\nconst resolveCandidateReadPath = (rootDirectory: string, filePath: string): string => {\n const normalizedFile = filePath.replace(/\\\\/g, \"/\");\n if (\n normalizedFile.startsWith(\"/\") ||\n /^[a-zA-Z]:\\//.test(normalizedFile) ||\n /^[a-zA-Z]:\\\\/.test(filePath)\n ) {\n return filePath;\n }\n const root = rootDirectory.replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n return `${root}/${normalizedFile.replace(/^\\.\\//, \"\")}`;\n};\n\nconst OPENING_TAG_PATTERN = /<([A-Z][\\w.]*)/;\nconst DISABLE_NEXT_LINE_PATTERN = /\\/\\/\\s*react-doctor-disable-next-line\\b(?:\\s+(.+))?/;\nconst DISABLE_LINE_PATTERN = /\\/\\/\\s*react-doctor-disable-line\\b(?:\\s+(.+))?/;\n\nconst createFileLinesCache = (\n rootDirectory: string,\n readFileLinesSync: (filePath: string) => string[] | null,\n) => {\n const cache = new Map<string, string[] | null>();\n\n return (filePath: string): string[] | null => {\n const cached = cache.get(filePath);\n if (cached !== undefined) return cached;\n const absolutePath = resolveCandidateReadPath(rootDirectory, filePath);\n const lines = readFileLinesSync(absolutePath);\n cache.set(filePath, lines);\n return lines;\n };\n};\n\nconst isInsideTextComponent = (\n lines: string[],\n diagnosticLine: number,\n textComponentNames: Set<string>,\n): boolean => {\n for (let lineIndex = diagnosticLine - 1; lineIndex >= 0; lineIndex--) {\n const match = lines[lineIndex].match(OPENING_TAG_PATTERN);\n if (!match) continue;\n const fullTagName = match[1];\n const leafTagName = fullTagName.includes(\".\")\n ? (fullTagName.split(\".\").at(-1) ?? fullTagName)\n : fullTagName;\n return textComponentNames.has(fullTagName) || textComponentNames.has(leafTagName);\n }\n return false;\n};\n\nconst isRuleSuppressed = (commentRules: string | undefined, ruleId: string): boolean => {\n if (!commentRules?.trim()) return true;\n return commentRules.split(/[,\\s]+/).some((rule) => rule.trim() === ruleId);\n};\n\nexport const filterIgnoredDiagnostics = (\n diagnostics: Diagnostic[],\n config: ReactDoctorConfig,\n rootDirectory: string,\n readFileLinesSync: (filePath: string) => string[] | null,\n): Diagnostic[] => {\n const ignoredRules = new Set(Array.isArray(config.ignore?.rules) ? config.ignore.rules : []);\n const ignoredFilePatterns = compileIgnoredFilePatterns(config);\n const textComponentNames = new Set(\n Array.isArray(config.textComponents) ? config.textComponents : [],\n );\n const hasTextComponents = textComponentNames.size > 0;\n const getFileLines = createFileLinesCache(rootDirectory, readFileLinesSync);\n\n return diagnostics.filter((diagnostic) => {\n const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;\n if (ignoredRules.has(ruleIdentifier)) {\n return false;\n }\n\n if (isFileIgnoredByPatterns(diagnostic.filePath, rootDirectory, ignoredFilePatterns)) {\n return false;\n }\n\n if (hasTextComponents && diagnostic.rule === \"rn-no-raw-text\" && diagnostic.line > 0) {\n const lines = getFileLines(diagnostic.filePath);\n if (lines && isInsideTextComponent(lines, diagnostic.line, textComponentNames)) {\n return false;\n }\n }\n\n return true;\n });\n};\n\nexport const filterInlineSuppressions = (\n diagnostics: Diagnostic[],\n rootDirectory: string,\n readFileLinesSync: (filePath: string) => string[] | null,\n): Diagnostic[] => {\n const getFileLines = createFileLinesCache(rootDirectory, readFileLinesSync);\n\n return diagnostics.filter((diagnostic) => {\n if (diagnostic.line <= 0) return true;\n\n const lines = getFileLines(diagnostic.filePath);\n if (!lines) return true;\n\n const ruleId = `${diagnostic.plugin}/${diagnostic.rule}`;\n\n const currentLine = lines[diagnostic.line - 1];\n if (currentLine) {\n const lineMatch = currentLine.match(DISABLE_LINE_PATTERN);\n if (lineMatch && isRuleSuppressed(lineMatch[1], ruleId)) return false;\n }\n\n if (diagnostic.line >= 2) {\n const previousLine = lines[diagnostic.line - 2];\n if (previousLine) {\n const nextLineMatch = previousLine.match(DISABLE_NEXT_LINE_PATTERN);\n if (nextLineMatch && isRuleSuppressed(nextLineMatch[1], ruleId)) return false;\n }\n }\n\n return true;\n });\n};\n","import type { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { filterIgnoredDiagnostics, filterInlineSuppressions } from \"./filter-diagnostics.js\";\n\nexport const mergeAndFilterDiagnostics = (\n mergedDiagnostics: Diagnostic[],\n directory: string,\n userConfig: ReactDoctorConfig | null,\n readFileLinesSync: (filePath: string) => string[] | null,\n): Diagnostic[] => {\n const filtered = userConfig\n ? filterIgnoredDiagnostics(mergedDiagnostics, userConfig, directory, readFileLinesSync)\n : mergedDiagnostics;\n return filterInlineSuppressions(filtered, directory, readFileLinesSync);\n};\n","import type { Diagnostic, ReactDoctorConfig, ScoreResult } from \"../types.js\";\nimport { mergeAndFilterDiagnostics } from \"../utils/merge-and-filter-diagnostics.js\";\n\nexport interface BuildDiagnoseResultInput {\n mergedDiagnostics: Diagnostic[];\n rootDirectory: string;\n userConfig: ReactDoctorConfig | null;\n readFileLinesSync: (filePath: string) => string[] | null;\n startTime: number;\n score?: ScoreResult | null;\n calculateDiagnosticsScore: (diagnostics: Diagnostic[]) => Promise<ScoreResult | null>;\n}\n\nexport interface BuildDiagnoseTimedResult {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n elapsedMilliseconds: number;\n}\n\nexport const buildDiagnoseTimedResult = async (\n input: BuildDiagnoseResultInput,\n): Promise<BuildDiagnoseTimedResult> => {\n const diagnostics = mergeAndFilterDiagnostics(\n input.mergedDiagnostics,\n input.rootDirectory,\n input.userConfig,\n input.readFileLinesSync,\n );\n const elapsedMilliseconds = globalThis.performance.now() - input.startTime;\n const score =\n input.score !== undefined ? input.score : await input.calculateDiagnosticsScore(diagnostics);\n return { diagnostics, score, elapsedMilliseconds };\n};\n","export const SOURCE_FILE_PATTERN = /\\.(tsx?|jsx?)$/;\n\nexport const JSX_FILE_PATTERN = /\\.(tsx|jsx)$/;\n\nexport const MILLISECONDS_PER_SECOND = 1000;\n\nexport const ERROR_PREVIEW_LENGTH_CHARS = 200;\n\nexport const PERFECT_SCORE = 100;\n\nexport const SCORE_GOOD_THRESHOLD = 75;\n\nexport const SCORE_OK_THRESHOLD = 50;\n\nexport const SCORE_BAR_WIDTH_CHARS = 50;\n\nexport const SUMMARY_BOX_HORIZONTAL_PADDING_CHARS = 1;\n\nexport const SUMMARY_BOX_OUTER_INDENT_CHARS = 2;\n\nexport const SCORE_API_URL = \"https://www.react.doctor/api/score\";\n\nexport const SHARE_BASE_URL = \"https://www.react.doctor/share\";\n\nexport const FETCH_TIMEOUT_MS = 10_000;\n\nexport const GIT_LS_FILES_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\n// HACK: Windows CreateProcessW limits total command-line length to 32,767 chars.\n// Use a conservative threshold to leave room for the executable path and quoting overhead.\nexport const SPAWN_ARGS_MAX_LENGTH_CHARS = 24_000;\n\n// HACK: oxlint can SIGABRT on very large file sets due to memory pressure.\n// Cap each batch to avoid OOM crashes on projects with 100+ source files.\nexport const OXLINT_MAX_FILES_PER_BATCH = 500;\n\nexport const OFFLINE_MESSAGE = \"Score calculated locally (offline mode).\";\n\nexport const DEFAULT_BRANCH_CANDIDATES = [\"main\", \"master\"];\n\nexport const ERROR_RULE_PENALTY = 1.5;\n\nexport const WARNING_RULE_PENALTY = 0.75;\n\nexport const MAX_KNIP_RETRIES = 5;\n\nexport const KNIP_CONFIG_LOCATIONS = [\n \"knip.json\",\n \"knip.jsonc\",\n \".knip.json\",\n \".knip.jsonc\",\n \"knip.ts\",\n \"knip.js\",\n \"knip.config.ts\",\n \"knip.config.js\",\n];\n\nexport const OXLINT_NODE_REQUIREMENT = \"^20.19.0 || >=22.12.0\";\n\nexport const OXLINT_RECOMMENDED_NODE_MAJOR = 24;\n\nexport const GIT_SHOW_MAX_BUFFER_BYTES = 10 * 1024 * 1024;\n\nexport const IGNORED_DIRECTORIES = new Set([\"node_modules\", \"dist\", \"build\", \"coverage\"]);\n","import { JSX_FILE_PATTERN } from \"../constants.js\";\n\nexport const computeJsxIncludePaths = (includePaths: string[]): string[] | undefined =>\n includePaths.length > 0\n ? includePaths.filter((filePath) => JSX_FILE_PATTERN.test(filePath))\n : undefined;\n","import type { Diagnostic, ProjectInfo, ReactDoctorConfig, ScoreResult } from \"../types.js\";\nimport { buildDiagnoseResult } from \"./build-diagnose-result.js\";\nimport { buildDiagnoseTimedResult } from \"./build-result.js\";\nimport { computeJsxIncludePaths } from \"../utils/jsx-include-paths.js\";\n\nexport interface DiagnoseCoreOptions {\n lint?: boolean;\n deadCode?: boolean;\n includePaths?: string[];\n lintIncludePaths?: string[] | undefined;\n}\n\nexport interface DiagnoseCoreResult {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n project: ProjectInfo;\n elapsedMilliseconds: number;\n}\n\nexport interface DiagnoseRunnerContext {\n resolvedDirectory: string;\n projectInfo: ProjectInfo;\n userConfig: ReactDoctorConfig | null;\n lintIncludePaths: string[] | undefined;\n isDiffMode: boolean;\n}\n\nexport interface DiagnoseCoreDeps {\n rootDirectory: string;\n readFileLinesSync: (filePath: string) => string[] | null;\n loadUserConfig: () => ReactDoctorConfig | null;\n discoverProjectInfo: () => ProjectInfo;\n calculateDiagnosticsScore: (diagnostics: Diagnostic[]) => Promise<ScoreResult | null>;\n getExtraDiagnostics?: () => Diagnostic[];\n createRunners: (context: DiagnoseRunnerContext) => {\n runLint: () => Promise<Diagnostic[]>;\n runDeadCode: () => Promise<Diagnostic[]>;\n };\n}\n\nexport const diagnoseCore = async (\n deps: DiagnoseCoreDeps,\n options: DiagnoseCoreOptions = {},\n): Promise<DiagnoseCoreResult> => {\n const { includePaths = [] } = options;\n const isDiffMode = includePaths.length > 0;\n\n const startTime = globalThis.performance.now();\n const resolvedDirectory = deps.rootDirectory;\n const projectInfo = deps.discoverProjectInfo();\n const userConfig = deps.loadUserConfig();\n\n const effectiveLint = options.lint ?? userConfig?.lint ?? true;\n const effectiveDeadCode = options.deadCode ?? userConfig?.deadCode ?? true;\n\n if (!projectInfo.reactVersion) {\n throw new Error(\"No React dependency found in package.json\");\n }\n\n const lintIncludePaths =\n options.lintIncludePaths !== undefined\n ? options.lintIncludePaths\n : computeJsxIncludePaths(includePaths);\n\n const { runLint, runDeadCode } = deps.createRunners({\n resolvedDirectory,\n projectInfo,\n userConfig,\n lintIncludePaths,\n isDiffMode,\n });\n\n const emptyDiagnostics: Diagnostic[] = [];\n\n const lintPromise = effectiveLint\n ? runLint().catch((error: unknown) => {\n console.error(\"Lint failed:\", error);\n return emptyDiagnostics;\n })\n : Promise.resolve(emptyDiagnostics);\n\n const deadCodePromise =\n effectiveDeadCode && !isDiffMode\n ? runDeadCode().catch((error: unknown) => {\n console.error(\"Dead code analysis failed:\", error);\n return emptyDiagnostics;\n })\n : Promise.resolve(emptyDiagnostics);\n\n const [lintDiagnostics, deadCodeDiagnostics] = await Promise.all([lintPromise, deadCodePromise]);\n const environmentDiagnostics = deps.getExtraDiagnostics?.() ?? [];\n const mergedDiagnostics = [...lintDiagnostics, ...deadCodeDiagnostics, ...environmentDiagnostics];\n const timed = await buildDiagnoseTimedResult({\n mergedDiagnostics,\n rootDirectory: resolvedDirectory,\n userConfig,\n readFileLinesSync: deps.readFileLinesSync,\n startTime,\n calculateDiagnosticsScore: deps.calculateDiagnosticsScore,\n });\n\n return buildDiagnoseResult({\n diagnostics: timed.diagnostics,\n score: timed.score,\n project: projectInfo,\n elapsedMilliseconds: timed.elapsedMilliseconds,\n });\n};\n","export const GIANT_COMPONENT_LINE_THRESHOLD = 300;\nexport const CASCADING_SET_STATE_THRESHOLD = 3;\nexport const RELATED_USE_STATE_THRESHOLD = 5;\nexport const DEEP_NESTING_THRESHOLD = 3;\nexport const DUPLICATE_STORAGE_READ_THRESHOLD = 2;\nexport const SEQUENTIAL_AWAIT_THRESHOLD = 3;\nexport const SECRET_MIN_LENGTH_CHARS = 8;\nexport const AUTH_CHECK_LOOKAHEAD_STATEMENTS = 3;\n\nexport const LAYOUT_PROPERTIES = new Set([\n \"width\",\n \"height\",\n \"top\",\n \"left\",\n \"right\",\n \"bottom\",\n \"padding\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"margin\",\n \"marginTop\",\n \"marginRight\",\n \"marginBottom\",\n \"marginLeft\",\n \"borderWidth\",\n \"fontSize\",\n \"lineHeight\",\n \"gap\",\n]);\n\nexport const MOTION_ANIMATE_PROPS = new Set([\n \"animate\",\n \"initial\",\n \"exit\",\n \"whileHover\",\n \"whileTap\",\n \"whileFocus\",\n \"whileDrag\",\n \"whileInView\",\n]);\n\nexport const HEAVY_LIBRARIES = new Set([\n \"@monaco-editor/react\",\n \"monaco-editor\",\n \"recharts\",\n \"@react-pdf/renderer\",\n \"react-quill\",\n \"@codemirror/view\",\n \"@codemirror/state\",\n \"chart.js\",\n \"react-chartjs-2\",\n \"@toast-ui/editor\",\n \"draft-js\",\n]);\n\nexport const FETCH_CALLEE_NAMES = new Set([\"fetch\"]);\nexport const FETCH_MEMBER_OBJECTS = new Set([\"axios\", \"ky\", \"got\"]);\nexport const INDEX_PARAMETER_NAMES = new Set([\"index\", \"idx\", \"i\"]);\nexport const BARREL_INDEX_SUFFIXES = [\n \"/index\",\n \"/index.js\",\n \"/index.ts\",\n \"/index.tsx\",\n \"/index.mjs\",\n];\nexport const PASSIVE_EVENT_NAMES = new Set([\n \"scroll\",\n \"wheel\",\n \"touchstart\",\n \"touchmove\",\n \"touchend\",\n]);\n\nexport const LOOP_TYPES = [\n \"ForStatement\",\n \"ForInStatement\",\n \"ForOfStatement\",\n \"WhileStatement\",\n \"DoWhileStatement\",\n];\n\nexport const AUTH_FUNCTION_NAMES = new Set([\n \"auth\",\n \"getSession\",\n \"getServerSession\",\n \"getUser\",\n \"requireAuth\",\n \"checkAuth\",\n \"verifyAuth\",\n \"authenticate\",\n \"currentUser\",\n \"getAuth\",\n \"validateSession\",\n]);\n\nexport const SECRET_PATTERNS = [\n /^sk_live_/,\n /^sk_test_/,\n /^AKIA[0-9A-Z]{16}$/,\n /^ghp_[a-zA-Z0-9]{36}$/,\n /^gho_[a-zA-Z0-9]{36}$/,\n /^github_pat_/,\n /^glpat-/,\n /^xox[bporas]-/,\n /^sk-[a-zA-Z0-9]{32,}$/,\n];\n\nexport const SECRET_VARIABLE_PATTERN = /(?:api_?key|secret|token|password|credential|auth)/i;\n\nexport const SECRET_FALSE_POSITIVE_SUFFIXES = new Set([\n \"modal\",\n \"label\",\n \"text\",\n \"title\",\n \"name\",\n \"id\",\n \"key\",\n \"url\",\n \"path\",\n \"route\",\n \"page\",\n \"param\",\n \"field\",\n \"column\",\n \"header\",\n \"placeholder\",\n \"description\",\n \"type\",\n \"icon\",\n \"class\",\n \"style\",\n \"variant\",\n \"event\",\n \"action\",\n \"status\",\n \"state\",\n \"mode\",\n \"flag\",\n \"option\",\n \"config\",\n \"message\",\n \"error\",\n \"display\",\n \"view\",\n \"component\",\n \"element\",\n \"container\",\n \"wrapper\",\n \"button\",\n \"link\",\n \"input\",\n \"select\",\n \"dialog\",\n \"menu\",\n \"form\",\n \"step\",\n \"index\",\n \"count\",\n \"length\",\n \"role\",\n \"scope\",\n \"context\",\n \"provider\",\n \"ref\",\n \"handler\",\n \"query\",\n \"schema\",\n \"constant\",\n]);\n\nexport const LOADING_STATE_PATTERN = /^(?:isLoading|isPending)$/;\n\nexport const TANSTACK_ROUTE_FILE_PATTERN = /\\/routes\\//;\nexport const TANSTACK_ROOT_ROUTE_FILE_PATTERN = /__root\\.(tsx?|jsx?)$/;\n\nexport const TANSTACK_ROUTE_PROPERTY_ORDER = [\n \"params\",\n \"validateSearch\",\n \"loaderDeps\",\n \"search.middlewares\",\n \"ssr\",\n \"context\",\n \"beforeLoad\",\n \"loader\",\n \"onEnter\",\n \"onStay\",\n \"onLeave\",\n \"head\",\n \"scripts\",\n \"headers\",\n \"remountDeps\",\n];\n\nexport const TANSTACK_ROUTE_CREATION_FUNCTIONS = new Set([\n \"createFileRoute\",\n \"createRoute\",\n \"createRootRoute\",\n \"createRootRouteWithContext\",\n]);\n\nexport const TANSTACK_SERVER_FN_NAMES = new Set([\"createServerFn\"]);\n\nexport const TANSTACK_MIDDLEWARE_METHOD_ORDER = [\n \"middleware\",\n \"inputValidator\",\n \"client\",\n \"server\",\n \"handler\",\n];\n\nexport const TANSTACK_REDIRECT_FUNCTIONS = new Set([\"redirect\", \"notFound\"]);\n\nexport const TANSTACK_SERVER_FN_FILE_PATTERN = /\\.functions(\\.[jt]sx?)?$/;\n\nexport const SEQUENTIAL_AWAIT_THRESHOLD_FOR_LOADER = 2;\n\nexport const TANSTACK_QUERY_HOOKS = new Set([\n \"useQuery\",\n \"useInfiniteQuery\",\n \"useSuspenseQuery\",\n \"useSuspenseInfiniteQuery\",\n]);\n\nexport const TANSTACK_MUTATION_HOOKS = new Set([\"useMutation\"]);\n\nexport const TANSTACK_QUERY_CLIENT_CLASS = \"QueryClient\";\n\nexport const STABLE_HOOK_WRAPPERS = new Set([\"useState\", \"useMemo\", \"useRef\"]);\n\nexport const SCRIPT_LOADING_ATTRIBUTES = new Set([\"defer\", \"async\"]);\n\nexport const GENERIC_EVENT_SUFFIXES = new Set([\"Click\", \"Change\", \"Input\", \"Blur\", \"Focus\"]);\n\nexport const TRIVIAL_INITIALIZER_NAMES = new Set([\n \"Boolean\",\n \"String\",\n \"Number\",\n \"Array\",\n \"Object\",\n \"parseInt\",\n \"parseFloat\",\n]);\n\nexport const SETTER_PATTERN = /^set[A-Z]/;\nexport const RENDER_FUNCTION_PATTERN = /^render[A-Z]/;\nexport const UPPERCASE_PATTERN = /^[A-Z]/;\nexport const PAGE_FILE_PATTERN = /\\/page\\.(tsx?|jsx?)$/;\nexport const PAGE_OR_LAYOUT_FILE_PATTERN = /\\/(page|layout)\\.(tsx?|jsx?)$/;\n\nexport const INTERNAL_PAGE_PATH_PATTERN =\n /\\/(?:(?:\\((?:dashboard|admin|settings|account|internal|manage|console|portal|auth|onboarding|app|ee|protected)\\))|(?:dashboard|admin|settings|account|internal|manage|console|portal))\\//i;\n\nexport const TEST_FILE_PATTERN = /\\.(?:test|spec|stories)\\.[tj]sx?$/;\nexport const OG_ROUTE_PATTERN = /\\/og\\b/i;\n\nexport const PAGES_DIRECTORY_PATTERN = /\\/pages\\//;\nexport const SERVER_ACTION_FILE_PATTERN = /actions?\\.(tsx?|jsx?)$/;\nexport const SERVER_ACTION_DIRECTORY_PATTERN = /\\/actions\\//;\n\nexport const NEXTJS_NAVIGATION_FUNCTIONS = new Set([\n \"redirect\",\n \"permanentRedirect\",\n \"notFound\",\n \"forbidden\",\n \"unauthorized\",\n]);\n\nexport const GOOGLE_FONTS_PATTERN = /fonts\\.googleapis\\.com/;\n\nexport const POLYFILL_SCRIPT_PATTERN = /polyfill\\.io|polyfill\\.min\\.js|cdn\\.polyfill/;\n\nexport const EXECUTABLE_SCRIPT_TYPES = new Set([\n \"text/javascript\",\n \"application/javascript\",\n \"module\",\n]);\n\nexport const APP_DIRECTORY_PATTERN = /\\/app\\//;\n\nexport const ROUTE_HANDLER_FILE_PATTERN = /\\/route\\.(tsx?|jsx?)$/;\n\nexport const MUTATION_METHOD_NAMES = new Set([\n \"create\",\n \"insert\",\n \"insertInto\",\n \"update\",\n \"upsert\",\n \"delete\",\n \"remove\",\n \"destroy\",\n \"set\",\n \"append\",\n]);\n\nexport const MUTATING_HTTP_METHODS = new Set([\"POST\", \"PUT\", \"DELETE\", \"PATCH\"]);\n\nexport const MUTATING_ROUTE_SEGMENTS = new Set([\n \"logout\",\n \"log-out\",\n \"signout\",\n \"sign-out\",\n \"unsubscribe\",\n \"delete\",\n \"remove\",\n \"revoke\",\n \"cancel\",\n \"deactivate\",\n]);\n\nexport const EFFECT_HOOK_NAMES = new Set([\"useEffect\", \"useLayoutEffect\"]);\nexport const HOOKS_WITH_DEPS = new Set([\"useEffect\", \"useLayoutEffect\", \"useMemo\", \"useCallback\"]);\nexport const CHAINABLE_ITERATION_METHODS = new Set([\"map\", \"filter\", \"forEach\", \"flatMap\"]);\nexport const STORAGE_OBJECTS = new Set([\"localStorage\", \"sessionStorage\"]);\n\nexport const LARGE_BLUR_THRESHOLD_PX = 10;\nexport const BLUR_VALUE_PATTERN = /blur\\((\\d+(?:\\.\\d+)?)px\\)/;\nexport const ANIMATION_CALLBACK_NAMES = new Set([\"requestAnimationFrame\", \"setInterval\"]);\nexport const MOTION_LIBRARY_PACKAGES = new Set([\"framer-motion\", \"motion\"]);\n\nexport const RAW_TEXT_PREVIEW_MAX_CHARS = 30;\n\nexport const REACT_NATIVE_TEXT_COMPONENTS = new Set([\n \"Text\",\n \"TextInput\",\n \"Typography\",\n \"Paragraph\",\n \"Span\",\n \"H1\",\n \"H2\",\n \"H3\",\n \"H4\",\n \"H5\",\n \"H6\",\n]);\n\nexport const REACT_NATIVE_TEXT_COMPONENT_KEYWORDS = new Set([\n \"Text\",\n \"Title\",\n \"Label\",\n \"Heading\",\n \"Caption\",\n \"Subtitle\",\n \"Typography\",\n \"Paragraph\",\n \"Description\",\n \"Body\",\n]);\n\nexport const DEPRECATED_RN_MODULE_REPLACEMENTS: Record<string, string> = {\n AsyncStorage: \"@react-native-async-storage/async-storage\",\n Picker: \"@react-native-picker/picker\",\n PickerIOS: \"@react-native-picker/picker\",\n DatePickerIOS: \"@react-native-community/datetimepicker\",\n DatePickerAndroid: \"@react-native-community/datetimepicker\",\n ProgressBarAndroid: \"a community alternative\",\n ProgressViewIOS: \"a community alternative\",\n SafeAreaView: \"react-native-safe-area-context\",\n Slider: \"@react-native-community/slider\",\n ViewPagerAndroid: \"react-native-pager-view\",\n WebView: \"react-native-webview\",\n NetInfo: \"@react-native-community/netinfo\",\n CameraRoll: \"@react-native-camera-roll/camera-roll\",\n Clipboard: \"@react-native-clipboard/clipboard\",\n ImageEditor: \"@react-native-community/image-editor\",\n MaskedViewIOS: \"@react-native-masked-view/masked-view\",\n};\n\nexport const LEGACY_EXPO_PACKAGE_REPLACEMENTS: Record<string, string> = {\n \"expo-av\": \"expo-audio for audio and expo-video for video\",\n \"expo-permissions\": \"the permissions API in each module (e.g. Camera.requestPermissionsAsync())\",\n \"@expo/vector-icons\":\n \"expo-symbols or expo-image (see https://docs.expo.dev/versions/latest/sdk/symbols/)\",\n};\n\nexport const REACT_NATIVE_LIST_COMPONENTS = new Set([\n \"FlatList\",\n \"SectionList\",\n \"VirtualizedList\",\n \"FlashList\",\n]);\n\nexport const LEGACY_SHADOW_STYLE_PROPERTIES = new Set([\n \"shadowColor\",\n \"shadowOffset\",\n \"shadowOpacity\",\n \"shadowRadius\",\n \"elevation\",\n]);\n\nexport const BOUNCE_ANIMATION_NAMES = new Set([\"bounce\", \"elastic\", \"wobble\", \"jiggle\", \"spring\"]);\n\nexport const Z_INDEX_ABSURD_THRESHOLD = 100;\n\nexport const INLINE_STYLE_PROPERTY_THRESHOLD = 8;\n\nexport const SIDE_TAB_BORDER_WIDTH_WITHOUT_RADIUS_PX = 3;\n\nexport const SIDE_TAB_BORDER_WIDTH_WITH_RADIUS_PX = 1;\n\nexport const SIDE_TAB_TAILWIND_WIDTH_WITHOUT_RADIUS = 4;\n\nexport const DARK_GLOW_BLUR_THRESHOLD_PX = 4;\n\nexport const DARK_BACKGROUND_CHANNEL_MAX = 35;\n\nexport const COLOR_CHROMA_THRESHOLD = 30;\n\nexport const TINY_TEXT_THRESHOLD_PX = 12;\n\nexport const WIDE_TRACKING_THRESHOLD_EM = 0.05;\n\nexport const LONG_TRANSITION_DURATION_THRESHOLD_MS = 1000;\n","import fs from \"node:fs\";\n\nexport const isFile = (filePath: string): boolean => {\n try {\n return fs.statSync(filePath).isFile();\n } catch {\n return false;\n }\n};\n","import fs from \"node:fs\";\nimport type { PackageJson } from \"../types.js\";\n\nexport const readPackageJson = (packageJsonPath: string): PackageJson => {\n try {\n return JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n } catch (error) {\n if (error instanceof SyntaxError) {\n return {};\n }\n if (error instanceof Error && \"code\" in error) {\n const { code } = error as { code: string };\n if (code === \"EISDIR\" || code === \"EACCES\") {\n return {};\n }\n }\n throw error;\n }\n};\n","import { execSync } from \"node:child_process\";\nimport path from \"node:path\";\nimport { MOTION_LIBRARY_PACKAGES } from \"../plugin/constants.js\";\nimport type { Diagnostic } from \"../types.js\";\nimport { isFile } from \"./is-file.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REDUCED_MOTION_GREP_PATTERN =\n \"prefers-reduced-motion|useReducedMotion|MotionConfig|reducedMotion\";\nconst REDUCED_MOTION_FILE_GLOBS = '\"*.ts\" \"*.tsx\" \"*.js\" \"*.jsx\" \"*.css\" \"*.scss\"';\n\nconst MISSING_REDUCED_MOTION_DIAGNOSTIC: Diagnostic = {\n filePath: \"package.json\",\n plugin: \"react-doctor\",\n rule: \"require-reduced-motion\",\n severity: \"error\",\n message:\n \"Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)\",\n help: \"Add `useReducedMotion()` from your animation library, or a `@media (prefers-reduced-motion: reduce)` CSS query\",\n line: 0,\n column: 0,\n category: \"Accessibility\",\n weight: 2,\n};\n\nexport const checkReducedMotion = (rootDirectory: string): Diagnostic[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!isFile(packageJsonPath)) return [];\n\n let hasMotionLibrary = false;\n try {\n const packageJson = readPackageJson(packageJsonPath);\n const allDependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };\n hasMotionLibrary = Object.keys(allDependencies).some((packageName) =>\n MOTION_LIBRARY_PACKAGES.has(packageName),\n );\n } catch {\n return [];\n }\n if (!hasMotionLibrary) return [];\n\n try {\n execSync(`git grep -ql -E \"${REDUCED_MOTION_GREP_PATTERN}\" -- ${REDUCED_MOTION_FILE_GLOBS}`, {\n cwd: rootDirectory,\n stdio: \"pipe\",\n });\n return [];\n } catch {\n return [MISSING_REDUCED_MOTION_DIAGNOSTIC];\n }\n};\n","import path from \"node:path\";\nimport { isFile } from \"./is-file.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nexport const isMonorepoRoot = (directory: string): boolean => {\n if (isFile(path.join(directory, \"pnpm-workspace.yaml\"))) return true;\n if (isFile(path.join(directory, \"nx.json\"))) return true;\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!isFile(packageJsonPath)) return false;\n const packageJson = readPackageJson(packageJsonPath);\n return Array.isArray(packageJson.workspaces) || Boolean(packageJson.workspaces?.packages);\n};\n\nexport const findMonorepoRoot = (startDirectory: string): string | null => {\n let currentDirectory = path.dirname(startDirectory);\n\n while (currentDirectory !== path.dirname(currentDirectory)) {\n if (isMonorepoRoot(currentDirectory)) return currentDirectory;\n currentDirectory = path.dirname(currentDirectory);\n }\n\n return null;\n};\n","export const isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport {\n GIT_LS_FILES_MAX_BUFFER_BYTES,\n IGNORED_DIRECTORIES,\n SOURCE_FILE_PATTERN,\n} from \"../constants.js\";\nimport type {\n DependencyInfo,\n Framework,\n PackageJson,\n ProjectInfo,\n WorkspacePackage,\n} from \"../types.js\";\nimport { findMonorepoRoot, isMonorepoRoot } from \"./find-monorepo-root.js\";\nimport { isFile } from \"./is-file.js\";\nimport { isPlainObject } from \"./is-plain-object.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REACT_COMPILER_PACKAGES = new Set([\n \"babel-plugin-react-compiler\",\n \"react-compiler-runtime\",\n \"eslint-plugin-react-compiler\",\n]);\n\nconst NEXT_CONFIG_FILENAMES = [\n \"next.config.js\",\n \"next.config.mjs\",\n \"next.config.ts\",\n \"next.config.cjs\",\n];\n\nconst BABEL_CONFIG_FILENAMES = [\n \".babelrc\",\n \".babelrc.json\",\n \"babel.config.js\",\n \"babel.config.json\",\n \"babel.config.cjs\",\n \"babel.config.mjs\",\n];\n\nconst VITE_CONFIG_FILENAMES = [\n \"vite.config.js\",\n \"vite.config.ts\",\n \"vite.config.mjs\",\n \"vite.config.cjs\",\n];\n\nconst EXPO_APP_CONFIG_FILENAMES = [\"app.json\", \"app.config.js\", \"app.config.ts\"];\n\nconst REACT_COMPILER_PACKAGE_REFERENCE_PATTERN =\n /babel-plugin-react-compiler|react-compiler-runtime|eslint-plugin-react-compiler|[\"']react-compiler[\"']/;\nconst REACT_COMPILER_ENABLED_FLAG_PATTERN = /[\"']?reactCompiler[\"']?\\s*:\\s*true\\b/;\n\nconst FRAMEWORK_PACKAGES: Record<string, Framework> = {\n next: \"nextjs\",\n \"@tanstack/react-start\": \"tanstack-start\",\n vite: \"vite\",\n \"react-scripts\": \"cra\",\n \"@remix-run/react\": \"remix\",\n gatsby: \"gatsby\",\n expo: \"expo\",\n \"react-native\": \"react-native\",\n};\n\nconst FRAMEWORK_DISPLAY_NAMES: Record<Framework, string> = {\n nextjs: \"Next.js\",\n \"tanstack-start\": \"TanStack Start\",\n vite: \"Vite\",\n cra: \"Create React App\",\n remix: \"Remix\",\n gatsby: \"Gatsby\",\n expo: \"Expo\",\n \"react-native\": \"React Native\",\n unknown: \"React\",\n};\n\nexport const formatFrameworkName = (framework: Framework): string =>\n FRAMEWORK_DISPLAY_NAMES[framework];\n\nconst countSourceFilesViaFilesystem = (rootDirectory: string): number => {\n let count = 0;\n const stack = [rootDirectory];\n\n while (stack.length > 0) {\n const currentDirectory = stack.pop()!;\n const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (!entry.name.startsWith(\".\") && !IGNORED_DIRECTORIES.has(entry.name)) {\n stack.push(path.join(currentDirectory, entry.name));\n }\n continue;\n }\n if (entry.isFile() && SOURCE_FILE_PATTERN.test(entry.name)) {\n count++;\n }\n }\n }\n\n return count;\n};\n\nconst countSourceFilesViaGit = (rootDirectory: string): number | null => {\n const result = spawnSync(\"git\", [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"], {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,\n });\n\n if (result.error || result.status !== 0) {\n return null;\n }\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath)).length;\n};\n\nconst countSourceFiles = (rootDirectory: string): number =>\n countSourceFilesViaGit(rootDirectory) ?? countSourceFilesViaFilesystem(rootDirectory);\n\nconst collectAllDependencies = (packageJson: PackageJson): Record<string, string> => ({\n ...packageJson.peerDependencies,\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n});\n\nconst detectFramework = (dependencies: Record<string, string>): Framework => {\n for (const [packageName, frameworkName] of Object.entries(FRAMEWORK_PACKAGES)) {\n if (dependencies[packageName]) {\n return frameworkName;\n }\n }\n return \"unknown\";\n};\n\nconst isCatalogReference = (version: string): boolean => version.startsWith(\"catalog:\");\n\nconst extractCatalogName = (version: string): string | null => {\n if (!isCatalogReference(version)) return null;\n const name = version.slice(\"catalog:\".length).trim();\n return name.length > 0 ? name : null;\n};\n\nconst resolveVersionFromCatalog = (\n catalog: Record<string, unknown>,\n packageName: string,\n): string | null => {\n const version = catalog[packageName];\n if (typeof version === \"string\" && !isCatalogReference(version)) return version;\n return null;\n};\n\ninterface CatalogCollection {\n defaultCatalog: Record<string, string>;\n namedCatalogs: Record<string, Record<string, string>>;\n}\n\nconst parsePnpmWorkspaceCatalogs = (rootDirectory: string): CatalogCollection => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!isFile(workspacePath)) return { defaultCatalog: {}, namedCatalogs: {} };\n\n const content = fs.readFileSync(workspacePath, \"utf-8\");\n const defaultCatalog: Record<string, string> = {};\n const namedCatalogs: Record<string, Record<string, string>> = {};\n\n let currentSection: \"none\" | \"catalog\" | \"catalogs\" | \"named-catalog\" = \"none\";\n let currentCatalogName = \"\";\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed.length === 0 || trimmed.startsWith(\"#\")) continue;\n\n const indentLevel = line.search(/\\S/);\n\n if (indentLevel === 0 && trimmed === \"catalog:\") {\n currentSection = \"catalog\";\n continue;\n }\n if (indentLevel === 0 && trimmed === \"catalogs:\") {\n currentSection = \"catalogs\";\n continue;\n }\n if (indentLevel === 0) {\n currentSection = \"none\";\n continue;\n }\n\n if (currentSection === \"catalog\" && indentLevel > 0) {\n const colonIndex = trimmed.indexOf(\":\");\n if (colonIndex > 0) {\n const key = trimmed.slice(0, colonIndex).trim().replace(/[\"']/g, \"\");\n const value = trimmed\n .slice(colonIndex + 1)\n .trim()\n .replace(/[\"']/g, \"\");\n if (key && value) defaultCatalog[key] = value;\n }\n continue;\n }\n\n if (currentSection === \"catalogs\" && indentLevel > 0) {\n if (trimmed.endsWith(\":\") && !trimmed.includes(\" \")) {\n currentCatalogName = trimmed.slice(0, -1).replace(/[\"']/g, \"\");\n currentSection = \"named-catalog\";\n namedCatalogs[currentCatalogName] = {};\n continue;\n }\n }\n\n if (currentSection === \"named-catalog\" && indentLevel > 0) {\n if (indentLevel <= 2 && trimmed.endsWith(\":\") && !trimmed.includes(\" \")) {\n currentCatalogName = trimmed.slice(0, -1).replace(/[\"']/g, \"\");\n namedCatalogs[currentCatalogName] = {};\n continue;\n }\n const colonIndex = trimmed.indexOf(\":\");\n if (colonIndex > 0 && currentCatalogName) {\n const key = trimmed.slice(0, colonIndex).trim().replace(/[\"']/g, \"\");\n const value = trimmed\n .slice(colonIndex + 1)\n .trim()\n .replace(/[\"']/g, \"\");\n if (key && value) namedCatalogs[currentCatalogName][key] = value;\n }\n }\n }\n\n return { defaultCatalog, namedCatalogs };\n};\n\nconst resolveCatalogVersionFromCollection = (\n catalogs: CatalogCollection,\n packageName: string,\n catalogReference?: string | null,\n): string | null => {\n if (catalogReference) {\n const namedCatalog = catalogs.namedCatalogs[catalogReference];\n if (namedCatalog?.[packageName]) return namedCatalog[packageName];\n }\n\n if (catalogs.defaultCatalog[packageName]) return catalogs.defaultCatalog[packageName];\n\n for (const namedCatalog of Object.values(catalogs.namedCatalogs)) {\n if (namedCatalog[packageName]) return namedCatalog[packageName];\n }\n\n return null;\n};\n\nconst resolveCatalogVersion = (\n packageJson: PackageJson,\n packageName: string,\n rootDirectory?: string,\n): string | null => {\n const allDependencies = collectAllDependencies(packageJson);\n const rawVersion = allDependencies[packageName];\n const catalogName = rawVersion ? extractCatalogName(rawVersion) : null;\n\n const raw = packageJson as Record<string, unknown>;\n\n if (isPlainObject(raw.catalog)) {\n const version = resolveVersionFromCatalog(raw.catalog, packageName);\n if (version) return version;\n }\n\n if (isPlainObject(raw.catalogs)) {\n if (catalogName && isPlainObject((raw.catalogs as Record<string, unknown>)[catalogName])) {\n const version = resolveVersionFromCatalog(\n (raw.catalogs as Record<string, unknown>)[catalogName] as Record<string, unknown>,\n packageName,\n );\n if (version) return version;\n }\n for (const catalogEntries of Object.values(raw.catalogs)) {\n if (isPlainObject(catalogEntries)) {\n const version = resolveVersionFromCatalog(catalogEntries, packageName);\n if (version) return version;\n }\n }\n }\n\n const workspaces = packageJson.workspaces;\n if (workspaces && !Array.isArray(workspaces) && isPlainObject(workspaces.catalog)) {\n const version = resolveVersionFromCatalog(\n workspaces.catalog as Record<string, unknown>,\n packageName,\n );\n if (version) return version;\n }\n\n if (rootDirectory) {\n const pnpmCatalogs = parsePnpmWorkspaceCatalogs(rootDirectory);\n const pnpmVersion = resolveCatalogVersionFromCollection(pnpmCatalogs, packageName, catalogName);\n if (pnpmVersion) return pnpmVersion;\n }\n\n return null;\n};\n\nconst extractDependencyInfo = (packageJson: PackageJson): DependencyInfo => {\n const allDependencies = collectAllDependencies(packageJson);\n const rawVersion = allDependencies.react ?? null;\n const reactVersion = rawVersion && !isCatalogReference(rawVersion) ? rawVersion : null;\n return {\n reactVersion,\n framework: detectFramework(allDependencies),\n };\n};\n\nconst parsePnpmWorkspacePatterns = (rootDirectory: string): string[] => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!isFile(workspacePath)) return [];\n\n const content = fs.readFileSync(workspacePath, \"utf-8\");\n const patterns: string[] = [];\n let isInsidePackagesBlock = false;\n\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed === \"packages:\") {\n isInsidePackagesBlock = true;\n continue;\n }\n if (isInsidePackagesBlock && trimmed.startsWith(\"-\")) {\n patterns.push(trimmed.replace(/^-\\s*/, \"\").replace(/[\"']/g, \"\"));\n } else if (isInsidePackagesBlock && trimmed.length > 0 && !trimmed.startsWith(\"#\")) {\n isInsidePackagesBlock = false;\n }\n }\n\n return patterns;\n};\n\nconst getWorkspacePatterns = (rootDirectory: string, packageJson: PackageJson): string[] => {\n const pnpmPatterns = parsePnpmWorkspacePatterns(rootDirectory);\n if (pnpmPatterns.length > 0) return pnpmPatterns;\n\n if (Array.isArray(packageJson.workspaces)) {\n return packageJson.workspaces;\n }\n\n if (packageJson.workspaces?.packages) {\n return packageJson.workspaces.packages;\n }\n\n return [];\n};\n\nconst resolveWorkspaceDirectories = (rootDirectory: string, pattern: string): string[] => {\n const cleanPattern = pattern.replace(/[\"']/g, \"\").replace(/\\/\\*\\*$/, \"/*\");\n\n if (!cleanPattern.includes(\"*\")) {\n const directoryPath = path.join(rootDirectory, cleanPattern);\n if (fs.existsSync(directoryPath) && isFile(path.join(directoryPath, \"package.json\"))) {\n return [directoryPath];\n }\n return [];\n }\n\n const wildcardIndex = cleanPattern.indexOf(\"*\");\n const baseDirectory = path.join(rootDirectory, cleanPattern.slice(0, wildcardIndex));\n const suffixAfterWildcard = cleanPattern.slice(wildcardIndex + 1);\n\n if (!fs.existsSync(baseDirectory) || !fs.statSync(baseDirectory).isDirectory()) {\n return [];\n }\n\n return fs\n .readdirSync(baseDirectory)\n .map((entry) => path.join(baseDirectory, entry, suffixAfterWildcard))\n .filter(\n (entryPath) =>\n fs.existsSync(entryPath) &&\n fs.statSync(entryPath).isDirectory() &&\n isFile(path.join(entryPath, \"package.json\")),\n );\n};\n\nconst findDependencyInfoFromMonorepoRoot = (directory: string): DependencyInfo => {\n const monorepoRoot = findMonorepoRoot(directory);\n if (!monorepoRoot) return { reactVersion: null, framework: \"unknown\" };\n\n const monorepoPackageJsonPath = path.join(monorepoRoot, \"package.json\");\n if (!isFile(monorepoPackageJsonPath)) return { reactVersion: null, framework: \"unknown\" };\n\n const rootPackageJson = readPackageJson(monorepoPackageJsonPath);\n const rootInfo = extractDependencyInfo(rootPackageJson);\n const catalogVersion = resolveCatalogVersion(rootPackageJson, \"react\", monorepoRoot);\n const workspaceInfo = findReactInWorkspaces(monorepoRoot, rootPackageJson);\n\n return {\n reactVersion: rootInfo.reactVersion ?? catalogVersion ?? workspaceInfo.reactVersion,\n framework: rootInfo.framework !== \"unknown\" ? rootInfo.framework : workspaceInfo.framework,\n };\n};\n\nconst findReactInWorkspaces = (rootDirectory: string, packageJson: PackageJson): DependencyInfo => {\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n const result: DependencyInfo = { reactVersion: null, framework: \"unknown\" };\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n const info = extractDependencyInfo(workspacePackageJson);\n\n if (info.reactVersion && !result.reactVersion) {\n result.reactVersion = info.reactVersion;\n }\n if (info.framework !== \"unknown\" && result.framework === \"unknown\") {\n result.framework = info.framework;\n }\n\n if (result.reactVersion && result.framework !== \"unknown\") {\n return result;\n }\n }\n }\n\n return result;\n};\n\nconst REACT_DEPENDENCY_NAMES = new Set([\"react\", \"react-native\", \"next\"]);\n\nconst hasReactDependency = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some((packageName) =>\n REACT_DEPENDENCY_NAMES.has(packageName),\n );\n};\n\nexport const discoverReactSubprojects = (rootDirectory: string): WorkspacePackage[] => {\n if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];\n\n const packages: WorkspacePackage[] = [];\n\n const rootPackageJsonPath = path.join(rootDirectory, \"package.json\");\n if (isFile(rootPackageJsonPath)) {\n const rootPackageJson = readPackageJson(rootPackageJsonPath);\n if (hasReactDependency(rootPackageJson)) {\n const name = rootPackageJson.name ?? path.basename(rootDirectory);\n packages.push({ name, directory: rootDirectory });\n }\n }\n\n const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n continue;\n }\n\n const subdirectory = path.join(rootDirectory, entry.name);\n const packageJsonPath = path.join(subdirectory, \"package.json\");\n if (!isFile(packageJsonPath)) continue;\n\n const packageJson = readPackageJson(packageJsonPath);\n if (!hasReactDependency(packageJson)) continue;\n\n const name = packageJson.name ?? entry.name;\n packages.push({ name, directory: subdirectory });\n }\n\n return packages;\n};\n\nexport const listWorkspacePackages = (rootDirectory: string): WorkspacePackage[] => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (!isFile(packageJsonPath)) return [];\n\n const packageJson = readPackageJson(packageJsonPath);\n const patterns = getWorkspacePatterns(rootDirectory, packageJson);\n if (patterns.length === 0) return [];\n\n const packages: WorkspacePackage[] = [];\n\n if (hasReactDependency(packageJson)) {\n const rootName = packageJson.name ?? path.basename(rootDirectory);\n packages.push({ name: rootName, directory: rootDirectory });\n }\n\n for (const pattern of patterns) {\n const directories = resolveWorkspaceDirectories(rootDirectory, pattern);\n for (const workspaceDirectory of directories) {\n const workspacePackageJson = readPackageJson(path.join(workspaceDirectory, \"package.json\"));\n\n if (!hasReactDependency(workspacePackageJson)) continue;\n\n const name = workspacePackageJson.name ?? path.basename(workspaceDirectory);\n packages.push({ name, directory: workspaceDirectory });\n }\n }\n\n return packages;\n};\n\nconst hasCompilerPackage = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some((packageName) =>\n REACT_COMPILER_PACKAGES.has(packageName),\n );\n};\n\nconst fileContainsPattern = (filePath: string, pattern: RegExp): boolean => {\n if (!isFile(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return pattern.test(content);\n};\n\nconst hasCompilerInConfigFile = (filePath: string): boolean => {\n if (!isFile(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return (\n REACT_COMPILER_ENABLED_FLAG_PATTERN.test(content) ||\n REACT_COMPILER_PACKAGE_REFERENCE_PATTERN.test(content)\n );\n};\n\nconst hasCompilerInConfigFiles = (directory: string, filenames: string[]): boolean =>\n filenames.some((filename) => hasCompilerInConfigFile(path.join(directory, filename)));\n\nconst detectReactCompiler = (directory: string, packageJson: PackageJson): boolean => {\n if (hasCompilerPackage(packageJson)) return true;\n\n if (hasCompilerInConfigFiles(directory, NEXT_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, BABEL_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, VITE_CONFIG_FILENAMES)) return true;\n if (hasCompilerInConfigFiles(directory, EXPO_APP_CONFIG_FILENAMES)) return true;\n\n let ancestorDirectory = path.dirname(directory);\n while (ancestorDirectory !== path.dirname(ancestorDirectory)) {\n const ancestorPackagePath = path.join(ancestorDirectory, \"package.json\");\n if (isFile(ancestorPackagePath)) {\n const ancestorPackageJson = readPackageJson(ancestorPackagePath);\n if (hasCompilerPackage(ancestorPackageJson)) return true;\n }\n ancestorDirectory = path.dirname(ancestorDirectory);\n }\n\n return false;\n};\n\nexport const discoverProject = (directory: string): ProjectInfo => {\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!isFile(packageJsonPath)) {\n throw new Error(`No package.json found in ${directory}`);\n }\n\n const packageJson = readPackageJson(packageJsonPath);\n let { reactVersion, framework } = extractDependencyInfo(packageJson);\n\n if (!reactVersion) {\n reactVersion = resolveCatalogVersion(packageJson, \"react\", directory);\n }\n\n if (!reactVersion) {\n const monorepoRoot = findMonorepoRoot(directory);\n if (monorepoRoot) {\n const monorepoPackageJsonPath = path.join(monorepoRoot, \"package.json\");\n if (isFile(monorepoPackageJsonPath)) {\n const rootPackageJson = readPackageJson(monorepoPackageJsonPath);\n reactVersion = resolveCatalogVersion(rootPackageJson, \"react\", monorepoRoot);\n }\n }\n }\n\n if (!reactVersion || framework === \"unknown\") {\n const workspaceInfo = findReactInWorkspaces(directory, packageJson);\n if (!reactVersion && workspaceInfo.reactVersion) {\n reactVersion = workspaceInfo.reactVersion;\n }\n if (framework === \"unknown\" && workspaceInfo.framework !== \"unknown\") {\n framework = workspaceInfo.framework;\n }\n }\n\n if ((!reactVersion || framework === \"unknown\") && !isMonorepoRoot(directory)) {\n const monorepoInfo = findDependencyInfoFromMonorepoRoot(directory);\n if (!reactVersion) {\n reactVersion = monorepoInfo.reactVersion;\n }\n if (framework === \"unknown\") {\n framework = monorepoInfo.framework;\n }\n }\n\n const projectName = packageJson.name ?? path.basename(directory);\n const hasTypeScript = fs.existsSync(path.join(directory, \"tsconfig.json\"));\n const sourceFileCount = countSourceFiles(directory);\n\n const hasReactCompiler = detectReactCompiler(directory, packageJson);\n\n return {\n rootDirectory: directory,\n projectName,\n reactVersion,\n framework,\n hasTypeScript,\n hasReactCompiler,\n sourceFileCount,\n };\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { ReactDoctorConfig } from \"../types.js\";\nimport { isFile } from \"./is-file.js\";\nimport { isPlainObject } from \"./is-plain-object.js\";\n\nconst CONFIG_FILENAME = \"react-doctor.config.json\";\nconst PACKAGE_JSON_CONFIG_KEY = \"reactDoctor\";\n\nconst loadConfigFromDirectory = (directory: string): ReactDoctorConfig | null => {\n const configFilePath = path.join(directory, CONFIG_FILENAME);\n\n if (isFile(configFilePath)) {\n try {\n const fileContent = fs.readFileSync(configFilePath, \"utf-8\");\n const parsed: unknown = JSON.parse(fileContent);\n if (isPlainObject(parsed)) {\n return parsed as ReactDoctorConfig;\n }\n console.warn(`Warning: ${CONFIG_FILENAME} must be a JSON object, ignoring.`);\n } catch (error) {\n console.warn(\n `Warning: Failed to parse ${CONFIG_FILENAME}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n const packageJsonPath = path.join(directory, \"package.json\");\n if (isFile(packageJsonPath)) {\n try {\n const fileContent = fs.readFileSync(packageJsonPath, \"utf-8\");\n const packageJson = JSON.parse(fileContent);\n const embeddedConfig = packageJson[PACKAGE_JSON_CONFIG_KEY];\n if (isPlainObject(embeddedConfig)) {\n return embeddedConfig as ReactDoctorConfig;\n }\n } catch {\n return null;\n }\n }\n\n return null;\n};\n\nexport const loadConfig = (rootDirectory: string): ReactDoctorConfig | null => {\n const localConfig = loadConfigFromDirectory(rootDirectory);\n if (localConfig) return localConfig;\n\n let ancestorDirectory = path.dirname(rootDirectory);\n while (ancestorDirectory !== path.dirname(ancestorDirectory)) {\n const ancestorConfig = loadConfigFromDirectory(ancestorDirectory);\n if (ancestorConfig) return ancestorConfig;\n ancestorDirectory = path.dirname(ancestorDirectory);\n }\n\n return null;\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\nexport const createNodeReadFileLinesSync = (\n rootDirectory: string,\n): ((filePath: string) => string[] | null) => {\n return (filePath: string): string[] | null => {\n const absolutePath = path.isAbsolute(filePath) ? filePath : path.join(rootDirectory, filePath);\n try {\n return fs.readFileSync(absolutePath, \"utf-8\").split(\"\\n\");\n } catch {\n return null;\n }\n };\n};\n","import { spawnSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n GIT_LS_FILES_MAX_BUFFER_BYTES,\n IGNORED_DIRECTORIES,\n JSX_FILE_PATTERN,\n SOURCE_FILE_PATTERN,\n} from \"../constants.js\";\nimport type { ReactDoctorConfig } from \"../types.js\";\nimport { compileIgnoredFilePatterns, isFileIgnoredByPatterns } from \"./is-ignored-file.js\";\n\nconst listSourceFilesViaGit = (rootDirectory: string): string[] | null => {\n const result = spawnSync(\"git\", [\"ls-files\", \"--cached\", \"--others\", \"--exclude-standard\"], {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,\n });\n\n if (result.error || result.status !== 0) {\n return null;\n }\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath));\n};\n\nconst listSourceFilesViaFilesystem = (rootDirectory: string): string[] => {\n const filePaths: string[] = [];\n const stack = [rootDirectory];\n\n while (stack.length > 0) {\n const currentDirectory = stack.pop()!;\n const entries = fs.readdirSync(currentDirectory, { withFileTypes: true });\n\n for (const entry of entries) {\n const absolutePath = path.join(currentDirectory, entry.name);\n\n if (entry.isDirectory()) {\n if (!entry.name.startsWith(\".\") && !IGNORED_DIRECTORIES.has(entry.name)) {\n stack.push(absolutePath);\n }\n continue;\n }\n\n if (entry.isFile() && SOURCE_FILE_PATTERN.test(entry.name)) {\n filePaths.push(path.relative(rootDirectory, absolutePath).replace(/\\\\/g, \"/\"));\n }\n }\n }\n\n return filePaths;\n};\n\nconst listSourceFiles = (rootDirectory: string): string[] =>\n listSourceFilesViaGit(rootDirectory) ?? listSourceFilesViaFilesystem(rootDirectory);\n\nexport const resolveLintIncludePaths = (\n rootDirectory: string,\n userConfig: ReactDoctorConfig | null,\n): string[] | undefined => {\n if (!Array.isArray(userConfig?.ignore?.files) || userConfig.ignore.files.length === 0) {\n return undefined;\n }\n\n const ignoredPatterns = compileIgnoredFilePatterns(userConfig);\n\n const includedPaths = listSourceFiles(rootDirectory).filter((filePath) => {\n if (!JSX_FILE_PATTERN.test(filePath)) {\n return false;\n }\n\n return !isFileIgnoredByPatterns(filePath, rootDirectory, ignoredPatterns);\n });\n\n return includedPaths;\n};\n","import {\n ERROR_RULE_PENALTY,\n PERFECT_SCORE,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n WARNING_RULE_PENALTY,\n} from \"../constants.js\";\nimport type { Diagnostic, ScoreResult } from \"../types.js\";\n\nconst getScoreLabel = (score: number): string => {\n if (score >= SCORE_GOOD_THRESHOLD) return \"Great\";\n if (score >= SCORE_OK_THRESHOLD) return \"Needs work\";\n return \"Critical\";\n};\n\nconst countUniqueRules = (\n diagnostics: Diagnostic[],\n): { errorRuleCount: number; warningRuleCount: number } => {\n const errorRules = new Set<string>();\n const warningRules = new Set<string>();\n\n for (const diagnostic of diagnostics) {\n const ruleKey = `${diagnostic.plugin}/${diagnostic.rule}`;\n if (diagnostic.severity === \"error\") {\n errorRules.add(ruleKey);\n } else {\n warningRules.add(ruleKey);\n }\n }\n\n return { errorRuleCount: errorRules.size, warningRuleCount: warningRules.size };\n};\n\nconst scoreFromRuleCounts = (errorRuleCount: number, warningRuleCount: number): number => {\n const penalty = errorRuleCount * ERROR_RULE_PENALTY + warningRuleCount * WARNING_RULE_PENALTY;\n return Math.max(0, Math.round(PERFECT_SCORE - penalty));\n};\n\nexport const calculateScoreLocally = (diagnostics: Diagnostic[]): ScoreResult => {\n const { errorRuleCount, warningRuleCount } = countUniqueRules(diagnostics);\n const score = scoreFromRuleCounts(errorRuleCount, warningRuleCount);\n return { score, label: getScoreLabel(score) };\n};\n","import { FETCH_TIMEOUT_MS, SCORE_API_URL } from \"../constants.js\";\nimport type { Diagnostic, ScoreResult } from \"../types.js\";\n\ninterface ScoreRequestFetch {\n (input: string | URL, init?: RequestInit): Promise<Response>;\n}\n\nconst parseScoreResult = (value: unknown): ScoreResult | null => {\n if (typeof value !== \"object\" || value === null) return null;\n if (!(\"score\" in value) || !(\"label\" in value)) return null;\n const scoreValue = Reflect.get(value, \"score\");\n const labelValue = Reflect.get(value, \"label\");\n if (typeof scoreValue !== \"number\" || typeof labelValue !== \"string\") return null;\n return { score: scoreValue, label: labelValue };\n};\n\nexport const tryScoreFromApi = async (\n diagnostics: Diagnostic[],\n fetchImplementation: ScoreRequestFetch,\n): Promise<ScoreResult | null> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n try {\n const response = await fetchImplementation(SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics }),\n signal: controller.signal,\n });\n\n if (!response.ok) return null;\n\n return parseScoreResult(await response.json());\n } catch {\n return null;\n } finally {\n clearTimeout(timeoutId);\n }\n};\n","import { FETCH_TIMEOUT_MS } from \"../constants.js\";\n\ninterface GlobalProcessLike {\n env?: Record<string, string | undefined>;\n versions?: { node?: string };\n}\n\nconst getGlobalProcess = (): GlobalProcessLike | undefined => {\n const candidate = (globalThis as { process?: GlobalProcessLike }).process;\n return candidate?.versions?.node ? candidate : undefined;\n};\n\nconst readEnvProxy = (): string | undefined => {\n const proc = getGlobalProcess();\n if (!proc?.env) return undefined;\n return proc.env.HTTPS_PROXY ?? proc.env.https_proxy ?? proc.env.HTTP_PROXY ?? proc.env.http_proxy;\n};\n\nlet isProxyUrlResolved = false;\nlet resolvedProxyUrl: string | undefined;\n\nconst getProxyUrl = (): string | undefined => {\n if (isProxyUrlResolved) return resolvedProxyUrl;\n isProxyUrlResolved = true;\n resolvedProxyUrl = readEnvProxy();\n return resolvedProxyUrl;\n};\n\nconst createProxyDispatcher = async (proxyUrl: string): Promise<object | null> => {\n try {\n // @ts-expect-error undici is bundled with Node.js 18+ but lacks standalone type declarations\n const { ProxyAgent } = await import(\"undici\");\n return new ProxyAgent(proxyUrl);\n } catch {\n return null;\n }\n};\n\n// HACK: Node.js's global fetch (undici) accepts `dispatcher` for proxy routing,\n// which isn't part of the standard RequestInit type.\nexport const proxyFetch = async (url: string | URL, init?: RequestInit): Promise<Response> => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n\n try {\n const proxyUrl = getProxyUrl();\n const dispatcher = proxyUrl ? await createProxyDispatcher(proxyUrl) : null;\n\n return await fetch(url, {\n ...init,\n signal: controller.signal,\n ...(dispatcher ? { dispatcher } : {}),\n } as RequestInit);\n } finally {\n clearTimeout(timeoutId);\n }\n};\n","import type { Diagnostic, ScoreResult } from \"../types.js\";\nimport { calculateScoreLocally } from \"../core/calculate-score-locally.js\";\nimport { tryScoreFromApi } from \"../core/try-score-from-api.js\";\nimport { proxyFetch } from \"./proxy-fetch.js\";\n\nexport { calculateScoreLocally } from \"../core/calculate-score-locally.js\";\n\nexport const calculateScore = async (diagnostics: Diagnostic[]): Promise<ScoreResult | null> => {\n const apiScore = await tryScoreFromApi(diagnostics, proxyFetch);\n if (apiScore) return apiScore;\n return calculateScoreLocally(diagnostics);\n};\n","import type { KnipIssueRecords } from \"../types.js\";\nimport { isPlainObject } from \"./is-plain-object.js\";\n\nexport const collectUnusedFilePaths = (\n filesIssues: KnipIssueRecords | Set<string> | string[] | unknown,\n): string[] => {\n if (filesIssues instanceof Set) {\n return [...filesIssues];\n }\n\n if (Array.isArray(filesIssues)) {\n return filesIssues.filter((entry): entry is string => typeof entry === \"string\");\n }\n\n if (!isPlainObject(filesIssues)) {\n return [];\n }\n\n const unusedFilePaths: string[] = [];\n\n for (const innerValue of Object.values(filesIssues)) {\n if (!isPlainObject(innerValue)) continue;\n\n for (const issue of Object.values(innerValue)) {\n if (isPlainObject(issue) && typeof issue.filePath === \"string\") {\n unusedFilePaths.push(issue.filePath);\n }\n }\n }\n\n return unusedFilePaths;\n};\n","const collectErrorChain = (rootError: unknown): unknown[] => {\n const errorChain: unknown[] = [];\n const visitedErrors = new Set<unknown>();\n let currentError: unknown = rootError;\n while (currentError !== undefined && !visitedErrors.has(currentError)) {\n visitedErrors.add(currentError);\n errorChain.push(currentError);\n currentError = currentError instanceof Error ? currentError.cause : undefined;\n }\n return errorChain;\n};\n\nconst formatErrorMessage = (error: unknown): string =>\n error instanceof Error ? error.message || error.name : String(error);\n\nexport const formatErrorChain = (rootError: unknown): string =>\n collectErrorChain(rootError).map(formatErrorMessage).join(\" → \");\n\nexport const getErrorChainMessages = (rootError: unknown): string[] =>\n collectErrorChain(rootError).map(formatErrorMessage);\n","import { getErrorChainMessages } from \"./format-error-chain.js\";\n\nconst PLUGIN_CONFIG_PATTERN = /(?:^|[/\\\\\\s])([a-z][a-z0-9-]*)\\.config\\./i;\n\nexport const extractFailedPluginName = (error: unknown): string | null => {\n for (const errorMessage of getErrorChainMessages(error)) {\n const pluginNameMatch = errorMessage.match(PLUGIN_CONFIG_PATTERN);\n if (pluginNameMatch?.[1]) return pluginNameMatch[1].toLowerCase();\n }\n return null;\n};\n","import path from \"node:path\";\nimport { KNIP_CONFIG_LOCATIONS } from \"../constants.js\";\nimport { isFile } from \"./is-file.js\";\n\nexport const hasKnipConfig = (directory: string): boolean =>\n KNIP_CONFIG_LOCATIONS.some((configFilename) => isFile(path.join(directory, configFilename)));\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { main } from \"knip\";\nimport { createOptions } from \"knip/session\";\nimport { MAX_KNIP_RETRIES } from \"../constants.js\";\nimport type { Diagnostic, KnipIssueRecords, KnipResults } from \"../types.js\";\nimport { collectUnusedFilePaths } from \"./collect-unused-file-paths.js\";\nimport { extractFailedPluginName } from \"./extract-failed-plugin-name.js\";\nimport { findMonorepoRoot } from \"./find-monorepo-root.js\";\nimport { hasKnipConfig } from \"./has-knip-config.js\";\nimport { isFile } from \"./is-file.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst KNIP_CATEGORY_MAP: Record<string, string> = {\n files: \"Dead Code\",\n exports: \"Dead Code\",\n types: \"Dead Code\",\n duplicates: \"Dead Code\",\n};\n\nconst KNIP_MESSAGE_MAP: Record<string, string> = {\n files: \"Unused file\",\n exports: \"Unused export\",\n types: \"Unused type\",\n duplicates: \"Duplicate export\",\n};\n\nconst KNIP_SEVERITY_MAP: Record<string, \"error\" | \"warning\"> = {\n files: \"warning\",\n exports: \"warning\",\n types: \"warning\",\n duplicates: \"warning\",\n};\n\nconst collectIssueRecords = (\n records: KnipIssueRecords,\n issueType: string,\n rootDirectory: string,\n): Diagnostic[] => {\n const diagnostics: Diagnostic[] = [];\n\n for (const issues of Object.values(records)) {\n for (const issue of Object.values(issues)) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, issue.filePath),\n plugin: \"knip\",\n rule: issueType,\n severity: KNIP_SEVERITY_MAP[issueType] ?? \"warning\",\n message: `${KNIP_MESSAGE_MAP[issueType]}: ${issue.symbol}`,\n help: \"\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[issueType] ?? \"Dead Code\",\n weight: 1,\n });\n }\n }\n\n return diagnostics;\n};\n\n// HACK: knip triggers dotenv which logs to stdout/stderr via console methods\nconst silenced = async <T>(fn: () => Promise<T>): Promise<T> => {\n const originalLog = console.log;\n const originalInfo = console.info;\n const originalWarn = console.warn;\n const originalError = console.error;\n console.log = () => {};\n console.info = () => {};\n console.warn = () => {};\n console.error = () => {};\n try {\n return await fn();\n } finally {\n console.log = originalLog;\n console.info = originalInfo;\n console.warn = originalWarn;\n console.error = originalError;\n }\n};\n\nconst TSCONFIG_FILENAMES = [\"tsconfig.base.json\", \"tsconfig.json\"];\n\nconst resolveTsConfigFile = (directory: string): string | undefined =>\n TSCONFIG_FILENAMES.find((filename) => fs.existsSync(path.join(directory, filename)));\n\nconst tryDisableFailedPlugin = (\n error: unknown,\n parsedConfig: Record<string, unknown>,\n disabledPlugins: Set<string>,\n): boolean => {\n const failedPlugin = extractFailedPluginName(error);\n if (!failedPlugin || !(failedPlugin in parsedConfig) || disabledPlugins.has(failedPlugin)) {\n return false;\n }\n disabledPlugins.add(failedPlugin);\n parsedConfig[failedPlugin] = false;\n return true;\n};\n\nconst runKnipWithOptions = async (\n knipCwd: string,\n workspaceName?: string,\n): Promise<KnipResults> => {\n const tsConfigFile = resolveTsConfigFile(knipCwd);\n const options = await silenced(() =>\n createOptions({\n cwd: knipCwd,\n isShowProgress: false,\n ...(workspaceName ? { workspace: workspaceName } : {}),\n ...(tsConfigFile ? { tsConfigFile } : {}),\n }),\n );\n\n const parsedConfig = options.parsedConfig as Record<string, unknown>;\n const disabledPlugins = new Set<string>();\n let lastKnipError: unknown;\n\n for (let attempt = 0; attempt <= MAX_KNIP_RETRIES; attempt++) {\n try {\n return (await silenced(() => main(options))) as KnipResults;\n } catch (error) {\n lastKnipError = error;\n if (!tryDisableFailedPlugin(error, parsedConfig, disabledPlugins)) {\n throw error;\n }\n }\n }\n\n throw lastKnipError;\n};\n\nconst hasNodeModules = (directory: string): boolean => {\n const nodeModulesPath = path.join(directory, \"node_modules\");\n return fs.existsSync(nodeModulesPath) && fs.statSync(nodeModulesPath).isDirectory();\n};\n\nconst resolveWorkspaceName = (rootDirectory: string): string => {\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n const packageJson = isFile(packageJsonPath) ? readPackageJson(packageJsonPath) : {};\n return packageJson.name ?? path.basename(rootDirectory);\n};\n\n// HACK: knip ignores workspace-local config when run from the monorepo root with\n// --workspace, so prefer the workspace cwd when it owns its config (issue #136).\nconst runKnipForProject = async (\n rootDirectory: string,\n monorepoRoot: string | null,\n): Promise<KnipResults> => {\n if (!monorepoRoot || hasKnipConfig(rootDirectory)) {\n return runKnipWithOptions(rootDirectory);\n }\n try {\n return await runKnipWithOptions(monorepoRoot, resolveWorkspaceName(rootDirectory));\n } catch {\n return runKnipWithOptions(rootDirectory);\n }\n};\n\nexport const runKnip = async (rootDirectory: string): Promise<Diagnostic[]> => {\n const monorepoRoot = findMonorepoRoot(rootDirectory);\n const hasInstalledDependencies =\n hasNodeModules(rootDirectory) || (monorepoRoot !== null && hasNodeModules(monorepoRoot));\n\n if (!hasInstalledDependencies) {\n return [];\n }\n\n const knipResult = await runKnipForProject(rootDirectory, monorepoRoot);\n\n const { issues } = knipResult;\n const diagnostics: Diagnostic[] = [];\n\n for (const unusedFilePath of collectUnusedFilePaths(issues.files)) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, unusedFilePath),\n plugin: \"knip\",\n rule: \"files\",\n severity: KNIP_SEVERITY_MAP[\"files\"],\n message: KNIP_MESSAGE_MAP[\"files\"],\n help: \"This file is not imported by any other file in the project.\",\n line: 0,\n column: 0,\n category: KNIP_CATEGORY_MAP[\"files\"],\n weight: 1,\n });\n }\n\n const recordTypes = [\"exports\", \"types\", \"duplicates\"] as const;\n\n for (const issueType of recordTypes) {\n diagnostics.push(...collectIssueRecords(issues[issueType], issueType, rootDirectory));\n }\n\n return diagnostics;\n};\n","import { createRequire } from \"node:module\";\nimport type { Framework } from \"./types.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst NEXTJS_RULES: Record<string, string> = {\n \"react-doctor/nextjs-no-img-element\": \"warn\",\n \"react-doctor/nextjs-async-client-component\": \"error\",\n \"react-doctor/nextjs-no-a-element\": \"warn\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"warn\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"warn\",\n \"react-doctor/nextjs-missing-metadata\": \"warn\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"warn\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"warn\",\n \"react-doctor/nextjs-image-missing-sizes\": \"warn\",\n \"react-doctor/nextjs-no-native-script\": \"warn\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"warn\",\n \"react-doctor/nextjs-no-font-link\": \"warn\",\n \"react-doctor/nextjs-no-css-link\": \"warn\",\n \"react-doctor/nextjs-no-polyfill-script\": \"warn\",\n \"react-doctor/nextjs-no-head-import\": \"error\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"error\",\n};\n\nconst REACT_NATIVE_RULES: Record<string, string> = {\n \"react-doctor/rn-no-raw-text\": \"error\",\n \"react-doctor/rn-no-deprecated-modules\": \"error\",\n \"react-doctor/rn-no-legacy-expo-packages\": \"warn\",\n \"react-doctor/rn-no-dimensions-get\": \"warn\",\n \"react-doctor/rn-no-inline-flatlist-renderitem\": \"warn\",\n \"react-doctor/rn-no-legacy-shadow-styles\": \"warn\",\n \"react-doctor/rn-prefer-reanimated\": \"warn\",\n \"react-doctor/rn-no-single-element-style-array\": \"warn\",\n};\n\nconst TANSTACK_START_RULES: Record<string, string> = {\n \"react-doctor/tanstack-start-route-property-order\": \"error\",\n \"react-doctor/tanstack-start-no-direct-fetch-in-loader\": \"warn\",\n \"react-doctor/tanstack-start-server-fn-validate-input\": \"warn\",\n \"react-doctor/tanstack-start-no-useeffect-fetch\": \"warn\",\n \"react-doctor/tanstack-start-missing-head-content\": \"warn\",\n \"react-doctor/tanstack-start-no-anchor-element\": \"warn\",\n \"react-doctor/tanstack-start-server-fn-method-order\": \"error\",\n \"react-doctor/tanstack-start-no-navigate-in-render\": \"warn\",\n \"react-doctor/tanstack-start-no-dynamic-server-fn-import\": \"error\",\n \"react-doctor/tanstack-start-no-use-server-in-handler\": \"error\",\n \"react-doctor/tanstack-start-no-secrets-in-loader\": \"error\",\n \"react-doctor/tanstack-start-get-mutation\": \"warn\",\n \"react-doctor/tanstack-start-redirect-in-try-catch\": \"warn\",\n \"react-doctor/tanstack-start-loader-parallel-fetch\": \"warn\",\n};\n\nconst REACT_COMPILER_RULES: Record<string, string> = {\n \"react-hooks-js/set-state-in-render\": \"error\",\n \"react-hooks-js/immutability\": \"error\",\n \"react-hooks-js/refs\": \"error\",\n \"react-hooks-js/purity\": \"error\",\n \"react-hooks-js/hooks\": \"error\",\n \"react-hooks-js/set-state-in-effect\": \"error\",\n \"react-hooks-js/globals\": \"error\",\n \"react-hooks-js/error-boundaries\": \"error\",\n \"react-hooks-js/preserve-manual-memoization\": \"error\",\n \"react-hooks-js/unsupported-syntax\": \"error\",\n \"react-hooks-js/component-hook-factories\": \"error\",\n \"react-hooks-js/static-components\": \"error\",\n \"react-hooks-js/use-memo\": \"error\",\n \"react-hooks-js/void-use-memo\": \"error\",\n \"react-hooks-js/incompatible-library\": \"error\",\n \"react-hooks-js/todo\": \"error\",\n};\n\ninterface OxlintConfigOptions {\n pluginPath: string;\n framework: Framework;\n hasReactCompiler: boolean;\n customRulesOnly?: boolean;\n}\n\nconst BUILTIN_REACT_RULES: Record<string, string> = {\n \"react/rules-of-hooks\": \"error\",\n \"react/no-direct-mutation-state\": \"error\",\n \"react/jsx-no-duplicate-props\": \"error\",\n \"react/jsx-key\": \"error\",\n \"react/no-children-prop\": \"warn\",\n \"react/no-danger\": \"warn\",\n \"react/jsx-no-script-url\": \"error\",\n \"react/no-render-return-value\": \"warn\",\n \"react/no-string-refs\": \"warn\",\n \"react/no-is-mounted\": \"warn\",\n \"react/require-render-return\": \"error\",\n \"react/no-unknown-property\": \"warn\",\n};\n\nconst BUILTIN_A11Y_RULES: Record<string, string> = {\n \"jsx-a11y/alt-text\": \"error\",\n \"jsx-a11y/anchor-is-valid\": \"warn\",\n \"jsx-a11y/click-events-have-key-events\": \"warn\",\n \"jsx-a11y/no-static-element-interactions\": \"warn\",\n \"jsx-a11y/role-has-required-aria-props\": \"error\",\n \"jsx-a11y/no-autofocus\": \"warn\",\n \"jsx-a11y/heading-has-content\": \"warn\",\n \"jsx-a11y/html-has-lang\": \"warn\",\n \"jsx-a11y/no-redundant-roles\": \"warn\",\n \"jsx-a11y/scope\": \"warn\",\n \"jsx-a11y/tabindex-no-positive\": \"warn\",\n \"jsx-a11y/label-has-associated-control\": \"warn\",\n \"jsx-a11y/no-distracting-elements\": \"error\",\n \"jsx-a11y/iframe-has-title\": \"warn\",\n};\n\nexport const createOxlintConfig = ({\n pluginPath,\n framework,\n hasReactCompiler,\n customRulesOnly = false,\n}: OxlintConfigOptions) => ({\n categories: {\n correctness: \"off\",\n suspicious: \"off\",\n pedantic: \"off\",\n perf: \"off\",\n restriction: \"off\",\n style: \"off\",\n nursery: \"off\",\n },\n plugins: [\"react\", \"jsx-a11y\", ...(hasReactCompiler ? [] : [\"react-perf\"])],\n jsPlugins: [\n ...(hasReactCompiler && !customRulesOnly\n ? [{ name: \"react-hooks-js\", specifier: esmRequire.resolve(\"eslint-plugin-react-hooks\") }]\n : []),\n pluginPath,\n ],\n rules: {\n ...(customRulesOnly ? {} : BUILTIN_REACT_RULES),\n ...(customRulesOnly ? {} : BUILTIN_A11Y_RULES),\n ...(hasReactCompiler && !customRulesOnly ? REACT_COMPILER_RULES : {}),\n\n \"react-doctor/no-derived-state-effect\": \"error\",\n \"react-doctor/no-fetch-in-effect\": \"error\",\n \"react-doctor/no-cascading-set-state\": \"warn\",\n \"react-doctor/no-effect-event-handler\": \"warn\",\n \"react-doctor/no-derived-useState\": \"warn\",\n \"react-doctor/prefer-useReducer\": \"warn\",\n \"react-doctor/rerender-lazy-state-init\": \"warn\",\n \"react-doctor/rerender-functional-setstate\": \"warn\",\n \"react-doctor/rerender-dependencies\": \"error\",\n\n \"react-doctor/no-giant-component\": \"warn\",\n \"react-doctor/no-render-in-render\": \"warn\",\n \"react-doctor/no-nested-component-definition\": \"error\",\n\n \"react-doctor/no-usememo-simple-expression\": \"warn\",\n \"react-doctor/no-layout-property-animation\": \"error\",\n \"react-doctor/rerender-memo-with-default-value\": \"warn\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"warn\",\n \"react-doctor/no-inline-prop-on-memo-component\": \"warn\",\n \"react-doctor/rendering-hydration-no-flicker\": \"warn\",\n \"react-doctor/rendering-script-defer-async\": \"warn\",\n\n \"react-doctor/no-transition-all\": \"warn\",\n \"react-doctor/no-global-css-variable-animation\": \"error\",\n \"react-doctor/no-large-animated-blur\": \"warn\",\n \"react-doctor/no-scale-from-zero\": \"warn\",\n \"react-doctor/no-permanent-will-change\": \"warn\",\n\n \"react-doctor/no-secrets-in-client-code\": \"error\",\n\n \"react-doctor/js-flatmap-filter\": \"warn\",\n\n \"react-doctor/no-barrel-import\": \"warn\",\n \"react-doctor/no-full-lodash-import\": \"warn\",\n \"react-doctor/no-moment\": \"warn\",\n \"react-doctor/prefer-dynamic-import\": \"warn\",\n \"react-doctor/use-lazy-motion\": \"warn\",\n \"react-doctor/no-undeferred-third-party\": \"warn\",\n\n \"react-doctor/no-array-index-as-key\": \"warn\",\n \"react-doctor/rendering-conditional-render\": \"warn\",\n \"react-doctor/no-prevent-default\": \"warn\",\n\n \"react-doctor/server-auth-actions\": \"error\",\n \"react-doctor/server-after-nonblocking\": \"warn\",\n\n \"react-doctor/client-passive-event-listeners\": \"warn\",\n\n \"react-doctor/query-stable-query-client\": \"error\",\n \"react-doctor/query-no-rest-destructuring\": \"warn\",\n \"react-doctor/query-no-void-query-fn\": \"warn\",\n \"react-doctor/query-no-query-in-effect\": \"warn\",\n \"react-doctor/query-mutation-missing-invalidation\": \"warn\",\n \"react-doctor/query-no-usequery-for-mutation\": \"warn\",\n\n \"react-doctor/no-inline-bounce-easing\": \"warn\",\n \"react-doctor/no-z-index-9999\": \"warn\",\n \"react-doctor/no-inline-exhaustive-style\": \"warn\",\n \"react-doctor/no-side-tab-border\": \"warn\",\n \"react-doctor/no-pure-black-background\": \"warn\",\n \"react-doctor/no-gradient-text\": \"warn\",\n \"react-doctor/no-dark-mode-glow\": \"warn\",\n \"react-doctor/no-justified-text\": \"warn\",\n \"react-doctor/no-tiny-text\": \"warn\",\n \"react-doctor/no-wide-letter-spacing\": \"warn\",\n \"react-doctor/no-gray-on-colored-background\": \"warn\",\n \"react-doctor/no-layout-transition-inline\": \"warn\",\n \"react-doctor/no-disabled-zoom\": \"error\",\n \"react-doctor/no-outline-none\": \"warn\",\n \"react-doctor/no-long-transition-duration\": \"warn\",\n\n \"react-doctor/async-parallel\": \"warn\",\n ...(framework === \"nextjs\" ? NEXTJS_RULES : {}),\n ...(framework === \"expo\" || framework === \"react-native\" ? REACT_NATIVE_RULES : {}),\n ...(framework === \"tanstack-start\" ? TANSTACK_START_RULES : {}),\n },\n});\n","import { spawnSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { GIT_LS_FILES_MAX_BUFFER_BYTES, SOURCE_FILE_PATTERN } from \"../constants.js\";\n\nconst findFilesWithDisableDirectives = (\n rootDirectory: string,\n includePaths?: string[],\n): string[] => {\n const grepArgs = [\"grep\", \"-l\", \"--untracked\", \"-E\", \"(eslint|oxlint)-disable\"];\n if (includePaths && includePaths.length > 0) {\n grepArgs.push(\"--\", ...includePaths);\n }\n\n const result = spawnSync(\"git\", grepArgs, {\n cwd: rootDirectory,\n encoding: \"utf-8\",\n maxBuffer: GIT_LS_FILES_MAX_BUFFER_BYTES,\n });\n\n if (result.error || result.status === null) return [];\n if (result.status !== 0 && result.stdout.trim().length === 0) return [];\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath));\n};\n\nconst neutralizeContent = (content: string): string =>\n content\n .replaceAll(\"eslint-disable\", \"eslint_disable\")\n .replaceAll(\"oxlint-disable\", \"oxlint_disable\");\n\nexport const neutralizeDisableDirectives = (\n rootDirectory: string,\n includePaths?: string[],\n): (() => void) => {\n const filePaths = findFilesWithDisableDirectives(rootDirectory, includePaths);\n const originalContents = new Map<string, string>();\n\n for (const relativePath of filePaths) {\n const absolutePath = path.join(rootDirectory, relativePath);\n\n let originalContent: string;\n try {\n originalContent = fs.readFileSync(absolutePath, \"utf-8\");\n } catch {\n continue;\n }\n\n const neutralizedContent = neutralizeContent(originalContent);\n if (neutralizedContent !== originalContent) {\n originalContents.set(absolutePath, originalContent);\n fs.writeFileSync(absolutePath, neutralizedContent);\n }\n }\n\n return () => {\n for (const [absolutePath, originalContent] of originalContents) {\n fs.writeFileSync(absolutePath, originalContent);\n }\n };\n};\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n ERROR_PREVIEW_LENGTH_CHARS,\n JSX_FILE_PATTERN,\n OXLINT_MAX_FILES_PER_BATCH,\n SPAWN_ARGS_MAX_LENGTH_CHARS,\n} from \"../constants.js\";\nimport { createOxlintConfig } from \"../oxlint-config.js\";\nimport type { CleanedDiagnostic, Diagnostic, Framework, OxlintOutput } from \"../types.js\";\nimport { neutralizeDisableDirectives } from \"./neutralize-disable-directives.js\";\n\nconst esmRequire = createRequire(import.meta.url);\n\nconst PLUGIN_CATEGORY_MAP: Record<string, string> = {\n react: \"Correctness\",\n \"react-hooks\": \"Correctness\",\n \"react-hooks-js\": \"React Compiler\",\n \"react-perf\": \"Performance\",\n \"jsx-a11y\": \"Accessibility\",\n};\n\nconst RULE_CATEGORY_MAP: Record<string, string> = {\n \"react-doctor/no-derived-state-effect\": \"State & Effects\",\n \"react-doctor/no-fetch-in-effect\": \"State & Effects\",\n \"react-doctor/no-cascading-set-state\": \"State & Effects\",\n \"react-doctor/no-effect-event-handler\": \"State & Effects\",\n \"react-doctor/no-derived-useState\": \"State & Effects\",\n \"react-doctor/prefer-useReducer\": \"State & Effects\",\n \"react-doctor/rerender-lazy-state-init\": \"Performance\",\n \"react-doctor/rerender-functional-setstate\": \"Performance\",\n \"react-doctor/rerender-dependencies\": \"State & Effects\",\n\n \"react-doctor/no-generic-handler-names\": \"Architecture\",\n \"react-doctor/no-giant-component\": \"Architecture\",\n \"react-doctor/no-render-in-render\": \"Architecture\",\n \"react-doctor/no-nested-component-definition\": \"Correctness\",\n\n \"react-doctor/no-usememo-simple-expression\": \"Performance\",\n \"react-doctor/no-layout-property-animation\": \"Performance\",\n \"react-doctor/rerender-memo-with-default-value\": \"Performance\",\n \"react-doctor/rendering-animate-svg-wrapper\": \"Performance\",\n \"react-doctor/rendering-usetransition-loading\": \"Performance\",\n \"react-doctor/rendering-hydration-no-flicker\": \"Performance\",\n \"react-doctor/rendering-script-defer-async\": \"Performance\",\n\n \"react-doctor/no-transition-all\": \"Performance\",\n \"react-doctor/no-global-css-variable-animation\": \"Performance\",\n \"react-doctor/no-large-animated-blur\": \"Performance\",\n \"react-doctor/no-scale-from-zero\": \"Performance\",\n \"react-doctor/no-permanent-will-change\": \"Performance\",\n\n \"react-doctor/no-secrets-in-client-code\": \"Security\",\n\n \"react-doctor/no-barrel-import\": \"Bundle Size\",\n \"react-doctor/no-full-lodash-import\": \"Bundle Size\",\n \"react-doctor/no-moment\": \"Bundle Size\",\n \"react-doctor/prefer-dynamic-import\": \"Bundle Size\",\n \"react-doctor/use-lazy-motion\": \"Bundle Size\",\n \"react-doctor/no-undeferred-third-party\": \"Bundle Size\",\n\n \"react-doctor/no-array-index-as-key\": \"Correctness\",\n \"react-doctor/rendering-conditional-render\": \"Correctness\",\n \"react-doctor/no-prevent-default\": \"Correctness\",\n \"react-doctor/nextjs-no-img-element\": \"Next.js\",\n \"react-doctor/nextjs-async-client-component\": \"Next.js\",\n \"react-doctor/nextjs-no-a-element\": \"Next.js\",\n \"react-doctor/nextjs-no-use-search-params-without-suspense\": \"Next.js\",\n \"react-doctor/nextjs-no-client-fetch-for-server-data\": \"Next.js\",\n \"react-doctor/nextjs-missing-metadata\": \"Next.js\",\n \"react-doctor/nextjs-no-client-side-redirect\": \"Next.js\",\n \"react-doctor/nextjs-no-redirect-in-try-catch\": \"Next.js\",\n \"react-doctor/nextjs-image-missing-sizes\": \"Next.js\",\n \"react-doctor/nextjs-no-native-script\": \"Next.js\",\n \"react-doctor/nextjs-inline-script-missing-id\": \"Next.js\",\n \"react-doctor/nextjs-no-font-link\": \"Next.js\",\n \"react-doctor/nextjs-no-css-link\": \"Next.js\",\n \"react-doctor/nextjs-no-polyfill-script\": \"Next.js\",\n \"react-doctor/nextjs-no-head-import\": \"Next.js\",\n \"react-doctor/nextjs-no-side-effect-in-get-handler\": \"Security\",\n\n \"react-doctor/server-auth-actions\": \"Server\",\n \"react-doctor/server-after-nonblocking\": \"Server\",\n\n \"react-doctor/client-passive-event-listeners\": \"Performance\",\n\n \"react-doctor/query-stable-query-client\": \"TanStack Query\",\n \"react-doctor/query-no-rest-destructuring\": \"TanStack Query\",\n \"react-doctor/query-no-void-query-fn\": \"TanStack Query\",\n \"react-doctor/query-no-query-in-effect\": \"TanStack Query\",\n \"react-doctor/query-mutation-missing-invalidation\": \"TanStack Query\",\n \"react-doctor/query-no-usequery-for-mutation\": \"TanStack Query\",\n\n \"react-doctor/no-inline-bounce-easing\": \"Performance\",\n \"react-doctor/no-z-index-9999\": \"Architecture\",\n \"react-doctor/no-inline-exhaustive-style\": \"Architecture\",\n \"react-doctor/no-side-tab-border\": \"Architecture\",\n \"react-doctor/no-pure-black-background\": \"Architecture\",\n \"react-doctor/no-gradient-text\": \"Architecture\",\n \"react-doctor/no-dark-mode-glow\": \"Architecture\",\n \"react-doctor/no-justified-text\": \"Accessibility\",\n \"react-doctor/no-tiny-text\": \"Accessibility\",\n \"react-doctor/no-wide-letter-spacing\": \"Architecture\",\n \"react-doctor/no-gray-on-colored-background\": \"Accessibility\",\n \"react-doctor/no-layout-transition-inline\": \"Performance\",\n \"react-doctor/no-disabled-zoom\": \"Accessibility\",\n \"react-doctor/no-outline-none\": \"Accessibility\",\n \"react-doctor/no-long-transition-duration\": \"Performance\",\n\n \"react-doctor/js-flatmap-filter\": \"Performance\",\n\n \"react-doctor/async-parallel\": \"Performance\",\n\n \"react-doctor/rn-no-raw-text\": \"React Native\",\n \"react-doctor/rn-no-deprecated-modules\": \"React Native\",\n \"react-doctor/rn-no-legacy-expo-packages\": \"React Native\",\n \"react-doctor/rn-no-dimensions-get\": \"React Native\",\n \"react-doctor/rn-no-inline-flatlist-renderitem\": \"React Native\",\n \"react-doctor/rn-no-legacy-shadow-styles\": \"React Native\",\n \"react-doctor/rn-prefer-reanimated\": \"React Native\",\n \"react-doctor/rn-no-single-element-style-array\": \"React Native\",\n\n \"react-doctor/tanstack-start-route-property-order\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-direct-fetch-in-loader\": \"TanStack Start\",\n \"react-doctor/tanstack-start-server-fn-validate-input\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-useeffect-fetch\": \"TanStack Start\",\n \"react-doctor/tanstack-start-missing-head-content\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-anchor-element\": \"TanStack Start\",\n \"react-doctor/tanstack-start-server-fn-method-order\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-navigate-in-render\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-dynamic-server-fn-import\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-use-server-in-handler\": \"TanStack Start\",\n \"react-doctor/tanstack-start-no-secrets-in-loader\": \"Security\",\n \"react-doctor/tanstack-start-get-mutation\": \"Security\",\n \"react-doctor/tanstack-start-redirect-in-try-catch\": \"TanStack Start\",\n \"react-doctor/tanstack-start-loader-parallel-fetch\": \"Performance\",\n};\n\nconst RULE_HELP_MAP: Record<string, string> = {\n \"no-derived-state-effect\":\n \"For derived state, compute inline: `const x = fn(dep)`. For state resets on prop change, use a key prop: `<Component key={prop} />`. See https://react.dev/learn/you-might-not-need-an-effect\",\n \"no-fetch-in-effect\":\n \"Use `useQuery()` from @tanstack/react-query, `useSWR()`, or fetch in a Server Component instead\",\n \"no-cascading-set-state\":\n \"Combine into useReducer: `const [state, dispatch] = useReducer(reducer, initialState)`\",\n \"no-effect-event-handler\":\n \"Move the conditional logic into onClick, onChange, or onSubmit handlers directly\",\n \"no-derived-useState\":\n \"Remove useState and compute the value inline: `const value = transform(propName)`\",\n \"prefer-useReducer\":\n \"Group related state: `const [state, dispatch] = useReducer(reducer, { field1, field2, ... })`\",\n \"rerender-lazy-state-init\":\n \"Wrap in an arrow function so it only runs once: `useState(() => expensiveComputation())`\",\n \"rerender-functional-setstate\":\n \"Use the callback form: `setState(prev => prev + 1)` to always read the latest value\",\n \"rerender-dependencies\":\n \"Extract to a useMemo, useRef, or module-level constant so the reference is stable\",\n\n \"no-generic-handler-names\":\n \"Rename to describe the action: e.g. `handleSubmit` → `saveUserProfile`, `handleClick` → `toggleSidebar`\",\n \"no-giant-component\":\n \"Extract logical sections into focused components: `<UserHeader />`, `<UserActions />`, etc.\",\n \"no-render-in-render\":\n \"Extract to a named component: `const ListItem = ({ item }) => <div>{item.name}</div>`\",\n \"no-nested-component-definition\":\n \"Move to a separate file or to module scope above the parent component\",\n\n \"no-usememo-simple-expression\":\n \"Remove useMemo — property access, math, and ternaries are already cheap without memoization\",\n \"no-layout-property-animation\":\n \"Use `transform: translateX()` or `scale()` instead — they run on the compositor and skip layout/paint\",\n \"rerender-memo-with-default-value\":\n \"Move to module scope: `const EMPTY_ITEMS: Item[] = []` then use as the default value\",\n \"rendering-animate-svg-wrapper\":\n \"Wrap the SVG: `<motion.div animate={...}><svg>...</svg></motion.div>`\",\n \"rendering-usetransition-loading\":\n \"Replace with `const [isPending, startTransition] = useTransition()` — avoids a re-render for the loading state\",\n \"rendering-hydration-no-flicker\":\n \"Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` or add `suppressHydrationWarning` to the element\",\n \"rendering-script-defer-async\":\n 'Add `defer` for DOM-dependent scripts or `async` for independent ones (analytics). In Next.js, use `<Script strategy=\"afterInteractive\" />` instead',\n\n \"no-transition-all\":\n 'List specific properties: `transition: \"opacity 200ms, transform 200ms\"` — or in Tailwind use `transition-colors`, `transition-opacity`, or `transition-transform`',\n \"no-global-css-variable-animation\":\n \"Set the variable on the nearest element instead of a parent, or use `@property` with `inherits: false` to prevent cascade. Better yet, use targeted `element.style.transform` updates\",\n \"no-large-animated-blur\":\n \"Keep blur radius under 10px, or apply blur to a smaller element. Large blurs multiply GPU memory usage with layer size\",\n \"no-scale-from-zero\":\n \"Use `initial={{ scale: 0.95, opacity: 0 }}` — elements should deflate like a balloon, not vanish into a point\",\n \"no-permanent-will-change\":\n \"Add will-change on animation start (`onMouseEnter`) and remove on end (`onAnimationEnd`). Permanent promotion wastes GPU memory and can degrade performance\",\n\n \"no-secrets-in-client-code\":\n \"Move to server-side `process.env.SECRET_NAME`. Only `NEXT_PUBLIC_*` vars are safe for the client (and should not contain secrets)\",\n\n \"no-barrel-import\":\n \"Import from the direct path: `import { Button } from './components/Button'` instead of `./components`\",\n \"no-full-lodash-import\":\n \"Import the specific function: `import debounce from 'lodash/debounce'` — saves ~70kb\",\n \"no-moment\":\n \"Replace with `import { format } from 'date-fns'` (tree-shakeable) or `import dayjs from 'dayjs'` (2kb)\",\n \"prefer-dynamic-import\":\n \"Use `const Component = dynamic(() => import('library'), { ssr: false })` from next/dynamic or React.lazy()\",\n \"use-lazy-motion\":\n 'Use `import { LazyMotion, m } from \"framer-motion\"` with `domAnimation` features — saves ~30kb',\n \"no-undeferred-third-party\":\n 'Use `next/script` with `strategy=\"lazyOnload\"` or add the `defer` attribute',\n\n \"no-inline-bounce-easing\":\n \"Use `cubic-bezier(0.16, 1, 0.3, 1)` (ease-out-expo) for natural deceleration — objects in the real world don't bounce\",\n \"no-z-index-9999\":\n \"Define a z-index scale in your design tokens (e.g. dropdown: 10, modal: 20, toast: 30). Create a new stacking context with `isolation: isolate` instead of escalating values\",\n \"no-inline-exhaustive-style\":\n \"Move styles to a CSS class, CSS module, Tailwind utilities, or a styled component — inline objects with many properties hurt readability and create new references every render\",\n \"no-side-tab-border\":\n \"Use a subtler accent (box-shadow inset, background gradient, or border-bottom) instead of a thick one-sided border\",\n \"no-pure-black-background\":\n \"Tint the background slightly toward your brand hue — e.g. `#0a0a0f` or Tailwind's `bg-gray-950`. Pure black looks harsh on modern displays\",\n \"no-gradient-text\":\n \"Use solid text colors for readability. If you need emphasis, use font weight, size, or a distinct color instead of gradients\",\n \"no-dark-mode-glow\":\n \"Use a subtle `box-shadow` with neutral colors for depth, or `border` with low opacity. Colored glows on dark backgrounds are the default AI-generated aesthetic\",\n \"no-justified-text\":\n \"Use `text-align: left` for body text, or add `hyphens: auto` and `overflow-wrap: break-word` if you must justify\",\n \"no-tiny-text\":\n \"Use at least 12px for body content, 16px is ideal. Small text is hard to read, especially on high-DPI mobile screens\",\n \"no-wide-letter-spacing\":\n \"Reserve wide tracking (letter-spacing > 0.05em) for short uppercase labels, navigation items, and buttons — not body text\",\n \"no-gray-on-colored-background\":\n \"Use a darker shade of the background color for text, or white/near-white for contrast. Gray text on colored backgrounds looks washed out\",\n \"no-layout-transition-inline\":\n \"Use `transform` and `opacity` for transitions — they run on the compositor thread. For height animations, use `grid-template-rows: 0fr → 1fr`\",\n \"no-disabled-zoom\":\n \"Remove `user-scalable=no` and `maximum-scale` from the viewport meta tag. If your layout breaks at 200% zoom, fix the layout — don't punish users with disabilities\",\n \"no-outline-none\":\n \"Use `:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px }` to show focus only for keyboard users while hiding it for mouse clicks\",\n \"no-long-transition-duration\":\n \"Keep UI transitions under 1s — 100-150ms for instant feedback, 200-300ms for state changes, 300-500ms for layout changes. Use longer durations only for page-load hero animations\",\n\n \"no-array-index-as-key\":\n \"Use a stable unique identifier: `key={item.id}` or `key={item.slug}` — index keys break on reorder/filter\",\n \"rendering-conditional-render\":\n \"Change to `{items.length > 0 && <List />}` or use a ternary: `{items.length ? <List /> : null}`\",\n \"no-prevent-default\":\n \"Use `<form action={serverAction}>` (works without JS) or `<button>` instead of `<a>` with preventDefault\",\n\n \"nextjs-no-img-element\":\n \"`import Image from 'next/image'` — provides automatic WebP/AVIF, lazy loading, and responsive srcset\",\n \"nextjs-async-client-component\":\n \"Fetch data in a parent Server Component and pass it as props, or use useQuery/useSWR in the client component\",\n \"nextjs-no-a-element\":\n \"`import Link from 'next/link'` — enables client-side navigation, prefetching, and preserves scroll position\",\n \"nextjs-no-use-search-params-without-suspense\":\n \"Wrap the component using useSearchParams: `<Suspense fallback={<Skeleton />}><SearchComponent /></Suspense>`\",\n \"nextjs-no-client-fetch-for-server-data\":\n \"Remove 'use client' and fetch directly in the Server Component — no API round-trip, secrets stay on server\",\n \"nextjs-missing-metadata\":\n \"Add `export const metadata = { title: '...', description: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-client-side-redirect\":\n \"Avoid redirects inside useEffect. Use an event handler, middleware, or server-side redirect (App Router: redirect() from next/navigation; Pages Router: getServerSideProps redirect)\",\n \"nextjs-no-redirect-in-try-catch\":\n \"Move the redirect/notFound call outside the try block, or add `unstable_rethrow(error)` in the catch\",\n \"nextjs-image-missing-sizes\":\n 'Add sizes for responsive behavior: `sizes=\"(max-width: 768px) 100vw, 50vw\"` matching your layout breakpoints',\n \"nextjs-no-native-script\":\n '`import Script from \"next/script\"` — use `strategy=\"afterInteractive\"` for analytics or `\"lazyOnload\"` for widgets',\n \"nextjs-inline-script-missing-id\":\n 'Add `id=\"descriptive-name\"` so Next.js can track, deduplicate, and re-execute the script correctly',\n \"nextjs-no-font-link\":\n '`import { Inter } from \"next/font/google\"` — self-hosted, zero layout shift, no render-blocking requests',\n \"nextjs-no-css-link\":\n \"Import CSS directly: `import './styles.css'` or use CSS Modules: `import styles from './Button.module.css'`\",\n \"nextjs-no-polyfill-script\":\n \"Next.js includes polyfills for fetch, Promise, Object.assign, Array.from, and 50+ others automatically\",\n \"nextjs-no-head-import\":\n \"Use the Metadata API instead: `export const metadata = { title: '...' }` or `export async function generateMetadata()`\",\n \"nextjs-no-side-effect-in-get-handler\":\n \"Move the side effect to a POST handler and use a <form> or fetch with method POST — GET requests can be triggered by prefetching and are vulnerable to CSRF\",\n\n \"server-auth-actions\":\n \"Add `const session = await auth()` at the top and throw/redirect if unauthorized before any data access\",\n \"server-after-nonblocking\":\n \"`import { after } from 'next/server'` then wrap: `after(() => analytics.track(...))` — response isn't blocked\",\n\n \"client-passive-event-listeners\":\n \"Add `{ passive: true }` as the third argument: `addEventListener('scroll', handler, { passive: true })`\",\n\n \"query-stable-query-client\":\n \"Move `new QueryClient()` to module scope or wrap in `useState(() => new QueryClient())` — recreating it on every render resets the entire cache\",\n \"query-no-rest-destructuring\":\n \"Destructure only the fields you need: `const { data, isLoading } = useQuery(...)` — rest destructuring subscribes to all fields and causes extra re-renders\",\n \"query-no-void-query-fn\":\n \"queryFn must return a value for the cache. Use the `enabled` option to conditionally disable the query instead of returning undefined\",\n \"query-no-query-in-effect\":\n \"React Query manages refetching automatically via queryKey dependencies and the `enabled` option — manual refetch() in useEffect is usually unnecessary\",\n \"query-mutation-missing-invalidation\":\n \"Add `onSuccess: () => queryClient.invalidateQueries({ queryKey: ['...'] })` so cached data stays in sync after the mutation\",\n \"query-no-usequery-for-mutation\":\n \"Use `useMutation()` for POST/PUT/DELETE — it provides onSuccess/onError callbacks, doesn't auto-refetch, and correctly models write operations\",\n\n \"js-flatmap-filter\":\n \"Use `.flatMap(item => condition ? [value] : [])` — transforms and filters in a single pass instead of creating an intermediate array\",\n\n \"async-parallel\":\n \"Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to run independent operations concurrently\",\n\n \"rn-no-raw-text\":\n \"Wrap text in a `<Text>` component: `<Text>{value}</Text>` — raw strings outside `<Text>` crash on React Native\",\n \"rn-no-deprecated-modules\":\n \"Import from the community package instead — deprecated modules were removed from the react-native core\",\n \"rn-no-legacy-expo-packages\":\n \"Migrate to the recommended replacement package — legacy Expo packages are no longer maintained\",\n \"rn-no-dimensions-get\":\n \"Use `const { width, height } = useWindowDimensions()` — it updates reactively on rotation and resize\",\n \"rn-no-inline-flatlist-renderitem\":\n \"Extract renderItem to a named function or wrap in useCallback to avoid re-creating on every render\",\n \"rn-no-legacy-shadow-styles\":\n \"Use `boxShadow` for cross-platform shadows on the new architecture instead of platform-specific shadow properties\",\n \"rn-prefer-reanimated\":\n \"Use `import Animated from 'react-native-reanimated'` — animations run on the UI thread instead of the JS thread\",\n \"rn-no-single-element-style-array\":\n \"Use `style={value}` instead of `style={[value]}` — single-element arrays add unnecessary allocation\",\n\n \"tanstack-start-route-property-order\":\n \"Follow the order: params/validateSearch → loaderDeps → context → beforeLoad → loader → head. See https://tanstack.com/router/latest/docs/eslint/create-route-property-order\",\n \"tanstack-start-no-direct-fetch-in-loader\":\n \"Use `createServerFn()` from @tanstack/react-start — provides type-safe RPC, input validation, and proper server/client code splitting\",\n \"tanstack-start-server-fn-validate-input\":\n \"Add `.inputValidator(schema)` before `.handler()` — data crosses a network boundary and must be validated at runtime\",\n \"tanstack-start-no-useeffect-fetch\":\n \"Fetch data in the route `loader` instead — the router coordinates loading before rendering to avoid waterfalls\",\n \"tanstack-start-missing-head-content\":\n \"Add `<HeadContent />` inside `<head>` in your __root route — without it, route `head()` meta tags are silently dropped\",\n \"tanstack-start-no-anchor-element\":\n \"`import { Link } from '@tanstack/react-router'` — enables type-safe routes, preloading via `preload=\\\"intent\\\"`, and client-side navigation\",\n \"tanstack-start-server-fn-method-order\":\n \"Chain methods in order: .middleware() → .inputValidator() → .client() → .server() → .handler() — types depend on this sequence\",\n \"tanstack-start-no-navigate-in-render\":\n \"Use `throw redirect({ to: '/path' })` in `beforeLoad` or `loader` instead — navigate() during render causes hydration issues\",\n \"tanstack-start-no-dynamic-server-fn-import\":\n \"Use `import { myFn } from '~/utils/my.functions'` — the bundler replaces server code with RPC stubs only for static imports\",\n \"tanstack-start-no-use-server-in-handler\":\n 'TanStack Start handles server boundaries automatically via the Vite plugin — \"use server\" inside createServerFn causes compilation errors',\n \"tanstack-start-no-secrets-in-loader\":\n \"Loaders are isomorphic (run on both server and client). Wrap secret access in `createServerFn()` so it stays server-only\",\n \"tanstack-start-get-mutation\":\n \"Use `createServerFn({ method: 'POST' })` for data modifications — GET requests can be triggered by prefetching and are vulnerable to CSRF\",\n \"tanstack-start-redirect-in-try-catch\":\n \"TanStack Router's `redirect()` and `notFound()` throw special errors caught by the router. Move them outside the try block or re-throw in the catch\",\n \"tanstack-start-loader-parallel-fetch\":\n \"Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to avoid request waterfalls in route loaders\",\n};\n\nconst FILEPATH_WITH_LOCATION_PATTERN = /\\S+\\.\\w+:\\d+:\\d+[\\s\\S]*$/;\n\nconst REACT_COMPILER_MESSAGE = \"React Compiler can't optimize this code\";\n\nconst cleanDiagnosticMessage = (\n message: string,\n help: string,\n plugin: string,\n rule: string,\n): CleanedDiagnostic => {\n if (plugin === \"react-hooks-js\") {\n const rawMessage = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: REACT_COMPILER_MESSAGE, help: rawMessage || help };\n }\n const cleaned = message.replace(FILEPATH_WITH_LOCATION_PATTERN, \"\").trim();\n return { message: cleaned || message, help: help || RULE_HELP_MAP[rule] || \"\" };\n};\n\nconst parseRuleCode = (code: string): { plugin: string; rule: string } => {\n const match = code.match(/^(.+)\\((.+)\\)$/);\n if (!match) return { plugin: \"unknown\", rule: code };\n return { plugin: match[1].replace(/^eslint-plugin-/, \"\"), rule: match[2] };\n};\n\nconst resolveOxlintBinary = (): string => {\n const oxlintMainPath = esmRequire.resolve(\"oxlint\");\n const oxlintPackageDirectory = path.resolve(path.dirname(oxlintMainPath), \"..\");\n return path.join(oxlintPackageDirectory, \"bin\", \"oxlint\");\n};\n\nconst resolvePluginPath = (): string => {\n const currentDirectory = path.dirname(fileURLToPath(import.meta.url));\n const pluginPath = path.join(currentDirectory, \"react-doctor-plugin.js\");\n if (fs.existsSync(pluginPath)) return pluginPath;\n\n const distPluginPath = path.resolve(currentDirectory, \"../../dist/react-doctor-plugin.js\");\n if (fs.existsSync(distPluginPath)) return distPluginPath;\n\n return pluginPath;\n};\n\nconst resolveDiagnosticCategory = (plugin: string, rule: string): string => {\n const ruleKey = `${plugin}/${rule}`;\n return RULE_CATEGORY_MAP[ruleKey] ?? PLUGIN_CATEGORY_MAP[plugin] ?? \"Other\";\n};\n\nconst estimateArgsLength = (args: string[]): number =>\n args.reduce((total, argument) => total + argument.length + 1, 0);\n\nconst batchIncludePaths = (baseArgs: string[], includePaths: string[]): string[][] => {\n const baseArgsLength = estimateArgsLength(baseArgs);\n const batches: string[][] = [];\n let currentBatch: string[] = [];\n let currentBatchLength = baseArgsLength;\n\n for (const filePath of includePaths) {\n const entryLength = filePath.length + 1;\n const exceedsArgLength =\n currentBatch.length > 0 && currentBatchLength + entryLength > SPAWN_ARGS_MAX_LENGTH_CHARS;\n const exceedsFileCount = currentBatch.length >= OXLINT_MAX_FILES_PER_BATCH;\n\n if (exceedsArgLength || exceedsFileCount) {\n batches.push(currentBatch);\n currentBatch = [];\n currentBatchLength = baseArgsLength;\n }\n currentBatch.push(filePath);\n currentBatchLength += entryLength;\n }\n\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n};\n\nconst spawnOxlint = (\n args: string[],\n rootDirectory: string,\n nodeBinaryPath: string,\n): Promise<string> =>\n new Promise<string>((resolve, reject) => {\n const child = spawn(nodeBinaryPath, args, {\n cwd: rootDirectory,\n });\n\n const stdoutBuffers: Buffer[] = [];\n const stderrBuffers: Buffer[] = [];\n\n child.stdout.on(\"data\", (buffer: Buffer) => stdoutBuffers.push(buffer));\n child.stderr.on(\"data\", (buffer: Buffer) => stderrBuffers.push(buffer));\n\n child.on(\"error\", (error) => reject(new Error(`Failed to run oxlint: ${error.message}`)));\n child.on(\"close\", (code, signal) => {\n if (signal) {\n const stderrOutput = Buffer.concat(stderrBuffers).toString(\"utf-8\").trim();\n const hint =\n signal === \"SIGABRT\" ? \" (out of memory — try scanning fewer files with --diff)\" : \"\";\n const detail = stderrOutput ? `: ${stderrOutput}` : \"\";\n reject(new Error(`oxlint was killed by ${signal}${hint}${detail}`));\n return;\n }\n const output = Buffer.concat(stdoutBuffers).toString(\"utf-8\").trim();\n if (!output) {\n const stderrOutput = Buffer.concat(stderrBuffers).toString(\"utf-8\").trim();\n if (stderrOutput) {\n reject(new Error(`Failed to run oxlint: ${stderrOutput}`));\n return;\n }\n }\n resolve(output);\n });\n });\n\nconst parseOxlintOutput = (stdout: string): Diagnostic[] => {\n if (!stdout) return [];\n\n let output: OxlintOutput;\n try {\n output = JSON.parse(stdout) as OxlintOutput;\n } catch {\n throw new Error(\n `Failed to parse oxlint output: ${stdout.slice(0, ERROR_PREVIEW_LENGTH_CHARS)}`,\n );\n }\n\n return output.diagnostics\n .filter((diagnostic) => diagnostic.code && JSX_FILE_PATTERN.test(diagnostic.filename))\n .map((diagnostic) => {\n const { plugin, rule } = parseRuleCode(diagnostic.code);\n const primaryLabel = diagnostic.labels[0];\n\n const cleaned = cleanDiagnosticMessage(diagnostic.message, diagnostic.help, plugin, rule);\n\n return {\n filePath: diagnostic.filename,\n plugin,\n rule,\n severity: diagnostic.severity,\n message: cleaned.message,\n help: cleaned.help,\n line: primaryLabel?.span.line ?? 0,\n column: primaryLabel?.span.column ?? 0,\n category: resolveDiagnosticCategory(plugin, rule),\n };\n });\n};\n\nexport const runOxlint = async (\n rootDirectory: string,\n hasTypeScript: boolean,\n framework: Framework,\n hasReactCompiler: boolean,\n includePaths?: string[],\n nodeBinaryPath: string = process.execPath,\n customRulesOnly = false,\n): Promise<Diagnostic[]> => {\n if (includePaths !== undefined && includePaths.length === 0) {\n return [];\n }\n\n const configPath = path.join(os.tmpdir(), `react-doctor-oxlintrc-${process.pid}.json`);\n const pluginPath = resolvePluginPath();\n const config = createOxlintConfig({ pluginPath, framework, hasReactCompiler, customRulesOnly });\n const restoreDisableDirectives = neutralizeDisableDirectives(rootDirectory, includePaths);\n\n try {\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2));\n\n const oxlintBinary = resolveOxlintBinary();\n const baseArgs = [oxlintBinary, \"-c\", configPath, \"--format\", \"json\"];\n\n if (hasTypeScript) {\n baseArgs.push(\"--tsconfig\", \"./tsconfig.json\");\n }\n\n const fileBatches =\n includePaths !== undefined ? batchIncludePaths(baseArgs, includePaths) : [[\".\"]];\n\n const allDiagnostics: Diagnostic[] = [];\n for (const batch of fileBatches) {\n const batchArgs = [...baseArgs, ...batch];\n const stdout = await spawnOxlint(batchArgs, rootDirectory, nodeBinaryPath);\n allDiagnostics.push(...parseOxlintOutput(stdout));\n }\n\n return allDiagnostics;\n } finally {\n restoreDisableDirectives();\n if (fs.existsSync(configPath)) {\n fs.unlinkSync(configPath);\n }\n }\n};\n","import { execSync } from \"node:child_process\";\nimport { DEFAULT_BRANCH_CANDIDATES, SOURCE_FILE_PATTERN } from \"../constants.js\";\nimport type { DiffInfo } from \"../types.js\";\n\nconst getCurrentBranch = (directory: string): string | null => {\n try {\n const branch = execSync(\"git rev-parse --abbrev-ref HEAD\", {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n return branch === \"HEAD\" ? null : branch;\n } catch {\n return null;\n }\n};\n\nconst detectDefaultBranch = (directory: string): string | null => {\n try {\n const reference = execSync(\"git symbolic-ref refs/remotes/origin/HEAD\", {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n return reference.replace(\"refs/remotes/origin/\", \"\");\n } catch {\n for (const candidate of DEFAULT_BRANCH_CANDIDATES) {\n try {\n execSync(`git rev-parse --verify ${candidate}`, {\n cwd: directory,\n stdio: \"pipe\",\n });\n return candidate;\n } catch {}\n }\n return null;\n }\n};\n\nconst getChangedFilesSinceBranch = (directory: string, baseBranch: string): string[] => {\n try {\n const mergeBase = execSync(`git merge-base ${baseBranch} HEAD`, {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n\n const output = execSync(`git diff --name-only --diff-filter=ACMR --relative ${mergeBase}`, {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n\n if (!output) return [];\n return output.split(\"\\n\").filter(Boolean);\n } catch {\n return [];\n }\n};\n\nconst getUncommittedChangedFiles = (directory: string): string[] => {\n try {\n const output = execSync(\"git diff --name-only --diff-filter=ACMR --relative HEAD\", {\n cwd: directory,\n stdio: \"pipe\",\n })\n .toString()\n .trim();\n if (!output) return [];\n return output.split(\"\\n\").filter(Boolean);\n } catch {\n return [];\n }\n};\n\nexport const getDiffInfo = (directory: string, explicitBaseBranch?: string): DiffInfo | null => {\n const currentBranch = getCurrentBranch(directory);\n if (!currentBranch) return null;\n\n const baseBranch = explicitBaseBranch ?? detectDefaultBranch(directory);\n if (!baseBranch) return null;\n\n if (currentBranch === baseBranch) {\n const uncommittedFiles = getUncommittedChangedFiles(directory);\n if (uncommittedFiles.length === 0) return null;\n return { currentBranch, baseBranch, changedFiles: uncommittedFiles, isCurrentChanges: true };\n }\n\n const changedFiles = getChangedFilesSinceBranch(directory, baseBranch);\n return { currentBranch, baseBranch, changedFiles };\n};\n\nexport const filterSourceFiles = (filePaths: string[]): string[] =>\n filePaths.filter((filePath) => SOURCE_FILE_PATTERN.test(filePath));\n","import path from \"node:path\";\nimport type { Diagnostic, DiffInfo, ProjectInfo, ReactDoctorConfig, ScoreResult } from \"./types.js\";\nimport { diagnoseCore } from \"./core/diagnose-core.js\";\nimport { computeJsxIncludePaths } from \"./utils/jsx-include-paths.js\";\nimport { checkReducedMotion } from \"./utils/check-reduced-motion.js\";\nimport { discoverProject } from \"./utils/discover-project.js\";\nimport { loadConfig } from \"./utils/load-config.js\";\nimport { createNodeReadFileLinesSync } from \"./utils/read-file-lines-node.js\";\nimport { resolveLintIncludePaths } from \"./utils/resolve-lint-include-paths.js\";\nimport { calculateScore } from \"./utils/calculate-score-node.js\";\nimport { runKnip } from \"./utils/run-knip.js\";\nimport { runOxlint } from \"./utils/run-oxlint.js\";\n\nexport type { Diagnostic, DiffInfo, ProjectInfo, ReactDoctorConfig, ScoreResult };\nexport { getDiffInfo, filterSourceFiles } from \"./utils/get-diff-files.js\";\n\nexport interface DiagnoseOptions {\n lint?: boolean;\n deadCode?: boolean;\n includePaths?: string[];\n}\n\nexport interface DiagnoseResult {\n diagnostics: Diagnostic[];\n score: ScoreResult | null;\n project: ProjectInfo;\n elapsedMilliseconds: number;\n}\n\nexport const diagnose = async (\n directory: string,\n options: DiagnoseOptions = {},\n): Promise<DiagnoseResult> => {\n const resolvedDirectory = path.resolve(directory);\n const userConfig = loadConfig(resolvedDirectory);\n const includePaths = options.includePaths ?? [];\n const isDiffMode = includePaths.length > 0;\n const lintIncludePaths =\n computeJsxIncludePaths(includePaths) ?? resolveLintIncludePaths(resolvedDirectory, userConfig);\n const readFileLinesSync = createNodeReadFileLinesSync(resolvedDirectory);\n\n return diagnoseCore(\n {\n rootDirectory: resolvedDirectory,\n readFileLinesSync,\n loadUserConfig: () => userConfig,\n discoverProjectInfo: () => discoverProject(resolvedDirectory),\n calculateDiagnosticsScore: calculateScore,\n getExtraDiagnostics: () => (isDiffMode ? [] : checkReducedMotion(resolvedDirectory)),\n createRunners: ({ resolvedDirectory: projectRoot, projectInfo, userConfig: config }) => ({\n runLint: () =>\n runOxlint(\n projectRoot,\n projectInfo.hasTypeScript,\n projectInfo.framework,\n projectInfo.hasReactCompiler,\n lintIncludePaths,\n undefined,\n config?.customRulesOnly ?? false,\n ),\n runDeadCode: () => runKnip(projectRoot),\n }),\n },\n { ...options, lintIncludePaths },\n );\n};\n"],"mappings":"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CAC5C,uCAAuC;CACvC,yCAAyC;CACzC,oDAAoD;CACpD,+CAA+C;CAE/C,wCAAwC;CACxC,gCAAgC;CAChC,2CAA2C;CAC3C,mCAAmC;CACnC,yCAAyC;CACzC,iCAAiC;CACjC,kCAAkC;CAClC,kCAAkC;CAClC,6BAA6B;CAC7B,uCAAuC;CACvC,8CAA8C;CAC9C,4CAA4C;CAC5C,iCAAiC;CACjC,gCAAgC;CAChC,4CAA4C;CAE5C,kCAAkC;CAElC,+BAA+B;CAE/B,+BAA+B;CAC/B,yCAAyC;CACzC,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CACjD,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CAEjD,oDAAoD;CACpD,yDAAyD;CACzD,wDAAwD;CACxD,kDAAkD;CAClD,oDAAoD;CACpD,iDAAiD;CACjD,sDAAsD;CACtD,qDAAqD;CACrD,2DAA2D;CAC3D,wDAAwD;CACxD,oDAAoD;CACpD,4CAA4C;CAC5C,qDAAqD;CACrD,qDAAqD;CACtD;AAED,MAAM,gBAAwC;CAC5C,2BACE;CACF,sBACE;CACF,0BACE;CACF,2BACE;CACF,uBACE;CACF,qBACE;CACF,4BACE;CACF,gCACE;CACF,yBACE;CAEF,4BACE;CACF,sBACE;CACF,uBACE;CACF,kCACE;CAEF,gCACE;CACF,gCACE;CACF,oCACE;CACF,iCACE;CACF,mCACE;CACF,kCACE;CACF,gCACE;CAEF,qBACE;CACF,oCACE;CACF,0BACE;CACF,sBACE;CACF,4BACE;CAEF,6BACE;CAEF,oBACE;CACF,yBACE;CACF,aACE;CACF,yBACE;CACF,mBACE;CACF,6BACE;CAEF,2BACE;CACF,mBACE;CACF,8BACE;CACF,sBACE;CACF,4BACE;CACF,oBACE;CACF,qBACE;CACF,qBACE;CACF,gBACE;CACF,0BACE;CACF,iCACE;CACF,+BACE;CACF,oBACE;CACF,mBACE;CACF,+BACE;CAEF,yBACE;CACF,gCACE;CACF,sBACE;CAEF,yBACE;CACF,iCACE;CACF,uBACE;CACF,gDACE;CACF,0CACE;CACF,2BACE;CA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"}