react-doctor 0.0.27 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":["esmRequire","main"],"sources":["../src/constants.ts","../src/utils/proxy-fetch.ts","../src/utils/calculate-score.ts","../src/utils/highlighter.ts","../src/utils/colorize-by-score.ts","../src/plugin/constants.ts","../src/utils/read-package-json.ts","../src/utils/check-reduced-motion.ts","../src/utils/match-glob-pattern.ts","../src/utils/filter-diagnostics.ts","../src/utils/combine-diagnostics.ts","../src/utils/find-monorepo-root.ts","../src/utils/discover-project.ts","../src/utils/logger.ts","../src/utils/framed-box.ts","../src/utils/group-by.ts","../src/utils/indent-multiline-text.ts","../src/utils/load-config.ts","../src/utils/run-knip.ts","../src/oxlint-config.ts","../src/utils/neutralize-disable-directives.ts","../src/utils/run-oxlint.ts","../src/utils/spinner.ts","../src/scan.ts","../src/utils/get-diff-files.ts","../src/utils/handle-error.ts","../src/utils/should-auto-select-current-choice.ts","../src/utils/should-select-all-choices.ts","../src/utils/prompts.ts","../src/utils/select-projects.ts","../src/utils/skill-prompt.ts","../src/cli.ts"],"sourcesContent":["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 ESTIMATE_SCORE_API_URL = \"https://www.react.doctor/api/estimate-score\";\n\nexport const SHARE_BASE_URL = \"https://www.react.doctor/share\";\n\nexport const OPEN_BASE_URL = \"https://www.react.doctor/open\";\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\nexport const OFFLINE_MESSAGE =\n \"You are offline, could not calculate score. Reconnect to calculate.\";\n\nexport const OFFLINE_FLAG_MESSAGE = \"Score not calculated. Remove --offline to calculate score.\";\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 ERROR_ESTIMATED_FIX_RATE = 0.85;\n\nexport const WARNING_ESTIMATED_FIX_RATE = 0.8;\n\nexport const MAX_KNIP_RETRIES = 5;\n\nexport const AMI_WEBSITE_URL = \"https://ami.dev\";\n\nexport const AMI_INSTALL_URL = `${AMI_WEBSITE_URL}/install.sh`;\n\nexport const AMI_RELEASES_URL = \"https://github.com/millionco/ami-releases/releases\";\n","import { execSync } from \"node:child_process\";\nimport { FETCH_TIMEOUT_MS } from \"../constants.js\";\n\nconst readNpmConfigValue = (key: string): string | undefined => {\n try {\n const value = execSync(`npm config get ${key}`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n }).trim();\n if (value && value !== \"null\" && value !== \"undefined\") return value;\n } catch {}\n return undefined;\n};\n\nconst resolveProxyUrl = (): string | undefined =>\n process.env.HTTPS_PROXY ??\n process.env.https_proxy ??\n process.env.HTTP_PROXY ??\n process.env.http_proxy ??\n readNpmConfigValue(\"https-proxy\") ??\n readNpmConfigValue(\"proxy\");\n\nlet isProxyUrlResolved = false;\nlet resolvedProxyUrl: string | undefined;\n\nconst getProxyUrl = (): string | undefined => {\n if (isProxyUrlResolved) return resolvedProxyUrl;\n isProxyUrlResolved = true;\n resolvedProxyUrl = resolveProxyUrl();\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 {\n ERROR_ESTIMATED_FIX_RATE,\n ERROR_RULE_PENALTY,\n ESTIMATE_SCORE_API_URL,\n PERFECT_SCORE,\n SCORE_API_URL,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n WARNING_ESTIMATED_FIX_RATE,\n WARNING_RULE_PENALTY,\n} from \"../constants.js\";\nimport type { Diagnostic, EstimatedScoreResult, ScoreResult } from \"../types.js\";\nimport { proxyFetch } from \"./proxy-fetch.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\nconst estimateScoreLocally = (diagnostics: Diagnostic[]): EstimatedScoreResult => {\n const { errorRuleCount, warningRuleCount } = countUniqueRules(diagnostics);\n\n const currentScore = scoreFromRuleCounts(errorRuleCount, warningRuleCount);\n const estimatedUnfixedErrorRuleCount = Math.round(\n errorRuleCount * (1 - ERROR_ESTIMATED_FIX_RATE),\n );\n const estimatedUnfixedWarningRuleCount = Math.round(\n warningRuleCount * (1 - WARNING_ESTIMATED_FIX_RATE),\n );\n const estimatedScore = scoreFromRuleCounts(\n estimatedUnfixedErrorRuleCount,\n estimatedUnfixedWarningRuleCount,\n );\n\n return {\n currentScore,\n currentLabel: getScoreLabel(currentScore),\n estimatedScore,\n estimatedLabel: getScoreLabel(estimatedScore),\n };\n};\n\nexport const calculateScore = async (diagnostics: Diagnostic[]): Promise<ScoreResult | null> => {\n try {\n const response = await proxyFetch(SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics }),\n });\n\n if (!response.ok) return null;\n\n return (await response.json()) as ScoreResult;\n } catch {\n return null;\n }\n};\n\nexport const fetchEstimatedScore = async (\n diagnostics: Diagnostic[],\n): Promise<EstimatedScoreResult | null> => {\n try {\n const response = await proxyFetch(ESTIMATE_SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics }),\n });\n\n if (!response.ok) return estimateScoreLocally(diagnostics);\n\n return (await response.json()) as EstimatedScoreResult;\n } catch {\n return estimateScoreLocally(diagnostics);\n }\n};\n","import pc from \"picocolors\";\n\nexport const highlighter = {\n error: pc.red,\n warn: pc.yellow,\n info: pc.cyan,\n success: pc.green,\n dim: pc.dim,\n};\n","import { SCORE_GOOD_THRESHOLD, SCORE_OK_THRESHOLD } from \"../constants.js\";\nimport { highlighter } from \"./highlighter.js\";\n\nexport const colorizeByScore = (text: string, score: number): string => {\n if (score >= SCORE_GOOD_THRESHOLD) return highlighter.success(text);\n if (score >= SCORE_OK_THRESHOLD) return highlighter.warn(text);\n return highlighter.error(text);\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 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 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([\"Text\", \"TextInput\"]);\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\": \"expo-image with sf: source URIs\",\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","import fs from \"node:fs\";\nimport type { PackageJson } from \"../types.js\";\n\nexport const readPackageJson = (packageJsonPath: string): PackageJson =>\n JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n","import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { MOTION_LIBRARY_PACKAGES } from \"../plugin/constants.js\";\nimport type { Diagnostic } from \"../types.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REDUCED_MOTION_GREP_PATTERN = \"prefers-reduced-motion|useReducedMotion\";\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 (!fs.existsSync(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","const REGEX_SPECIAL_CHARACTERS = /[.+^${}()|[\\]\\\\]/g;\n\nexport const compileGlobPattern = (pattern: string): RegExp => {\n const normalizedPattern = pattern.replace(/\\\\/g, \"/\");\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 { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { compileGlobPattern } from \"./match-glob-pattern.js\";\n\nexport const filterIgnoredDiagnostics = (\n diagnostics: Diagnostic[],\n config: ReactDoctorConfig,\n): Diagnostic[] => {\n const ignoredRules = new Set(Array.isArray(config.ignore?.rules) ? config.ignore.rules : []);\n const ignoredFilePatterns = Array.isArray(config.ignore?.files)\n ? config.ignore.files.map(compileGlobPattern)\n : [];\n\n if (ignoredRules.size === 0 && ignoredFilePatterns.length === 0) {\n return diagnostics;\n }\n\n return diagnostics.filter((diagnostic) => {\n const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;\n if (ignoredRules.has(ruleIdentifier)) {\n return false;\n }\n\n const normalizedPath = diagnostic.filePath.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n if (ignoredFilePatterns.some((pattern) => pattern.test(normalizedPath))) {\n return false;\n }\n\n return true;\n });\n};\n","import { JSX_FILE_PATTERN } from \"../constants.js\";\nimport type { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { checkReducedMotion } from \"./check-reduced-motion.js\";\nimport { filterIgnoredDiagnostics } from \"./filter-diagnostics.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\nexport const combineDiagnostics = (\n lintDiagnostics: Diagnostic[],\n deadCodeDiagnostics: Diagnostic[],\n directory: string,\n isDiffMode: boolean,\n userConfig: ReactDoctorConfig | null,\n): Diagnostic[] => {\n const allDiagnostics = [\n ...lintDiagnostics,\n ...deadCodeDiagnostics,\n ...(isDiffMode ? [] : checkReducedMotion(directory)),\n ];\n return userConfig ? filterIgnoredDiagnostics(allDiagnostics, userConfig) : allDiagnostics;\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nexport const isMonorepoRoot = (directory: string): boolean => {\n if (fs.existsSync(path.join(directory, \"pnpm-workspace.yaml\"))) return true;\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!fs.existsSync(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","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { GIT_LS_FILES_MAX_BUFFER_BYTES, SOURCE_FILE_PATTERN } 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 { 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_CONFIG_PATTERN = /react-compiler|reactCompiler/;\n\nconst FRAMEWORK_PACKAGES: Record<string, Framework> = {\n next: \"nextjs\",\n vite: \"vite\",\n \"react-scripts\": \"cra\",\n \"@remix-run/react\": \"remix\",\n gatsby: \"gatsby\",\n};\n\nconst FRAMEWORK_DISPLAY_NAMES: Record<Framework, string> = {\n nextjs: \"Next.js\",\n vite: \"Vite\",\n cra: \"Create React App\",\n remix: \"Remix\",\n gatsby: \"Gatsby\",\n unknown: \"React\",\n};\n\nexport const formatFrameworkName = (framework: Framework): string =>\n FRAMEWORK_DISPLAY_NAMES[framework];\n\nconst countSourceFiles = (rootDirectory: string): number => {\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 0;\n }\n\n return result.stdout\n .split(\"\\n\")\n .filter((filePath) => filePath.length > 0 && SOURCE_FILE_PATTERN.test(filePath)).length;\n};\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 extractDependencyInfo = (packageJson: PackageJson): DependencyInfo => {\n const allDependencies = collectAllDependencies(packageJson);\n return {\n reactVersion: allDependencies.react ?? null,\n framework: detectFramework(allDependencies),\n };\n};\n\nconst parsePnpmWorkspacePatterns = (rootDirectory: string): string[] => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!fs.existsSync(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) && fs.existsSync(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 fs.existsSync(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 rootPackageJson = readPackageJson(path.join(monorepoRoot, \"package.json\"));\n const rootInfo = extractDependencyInfo(rootPackageJson);\n const workspaceInfo = findReactInWorkspaces(monorepoRoot, rootPackageJson);\n\n return {\n reactVersion: rootInfo.reactVersion ?? 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 hasReactDependency = (packageJson: PackageJson): boolean => {\n const allDependencies = collectAllDependencies(packageJson);\n return Object.keys(allDependencies).some(\n (packageName) => packageName === \"next\" || packageName.includes(\"react\"),\n );\n};\n\nexport const discoverReactSubprojects = (rootDirectory: string): WorkspacePackage[] => {\n if (!fs.existsSync(rootDirectory) || !fs.statSync(rootDirectory).isDirectory()) return [];\n\n const entries = fs.readdirSync(rootDirectory, { withFileTypes: true });\n const packages: WorkspacePackage[] = [];\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 (!fs.existsSync(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 (!fs.existsSync(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 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 (!fs.existsSync(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return pattern.test(content);\n};\n\nconst hasCompilerInConfigFiles = (directory: string, filenames: string[]): boolean =>\n filenames.some((filename) =>\n fileContainsPattern(path.join(directory, filename), REACT_COMPILER_CONFIG_PATTERN),\n );\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 (fs.existsSync(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 (!fs.existsSync(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 || 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 { highlighter } from \"./highlighter.js\";\n\nexport const logger = {\n error(...args: unknown[]) {\n console.log(highlighter.error(args.join(\" \")));\n },\n warn(...args: unknown[]) {\n console.log(highlighter.warn(args.join(\" \")));\n },\n info(...args: unknown[]) {\n console.log(highlighter.info(args.join(\" \")));\n },\n success(...args: unknown[]) {\n console.log(highlighter.success(args.join(\" \")));\n },\n dim(...args: unknown[]) {\n console.log(highlighter.dim(args.join(\" \")));\n },\n log(...args: unknown[]) {\n console.log(args.join(\" \"));\n },\n break() {\n console.log(\"\");\n },\n};\n","import {\n SUMMARY_BOX_HORIZONTAL_PADDING_CHARS,\n SUMMARY_BOX_OUTER_INDENT_CHARS,\n} from \"../constants.js\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\n\nexport interface FramedLine {\n plainText: string;\n renderedText: string;\n}\n\nexport const createFramedLine = (\n plainText: string,\n renderedText: string = plainText,\n): FramedLine => ({\n plainText,\n renderedText,\n});\n\nexport const renderFramedBoxString = (framedLines: FramedLine[]): string => {\n if (framedLines.length === 0) return \"\";\n\n const borderColorizer = highlighter.dim;\n const outerIndent = \" \".repeat(SUMMARY_BOX_OUTER_INDENT_CHARS);\n const horizontalPadding = \" \".repeat(SUMMARY_BOX_HORIZONTAL_PADDING_CHARS);\n const maximumLineLength = Math.max(\n ...framedLines.map((framedLine) => framedLine.plainText.length),\n );\n const borderLine = \"─\".repeat(maximumLineLength + SUMMARY_BOX_HORIZONTAL_PADDING_CHARS * 2);\n\n const lines: string[] = [];\n lines.push(`${outerIndent}${borderColorizer(`┌${borderLine}┐`)}`);\n\n for (const framedLine of framedLines) {\n const trailingSpaces = \" \".repeat(maximumLineLength - framedLine.plainText.length);\n lines.push(\n `${outerIndent}${borderColorizer(\"│\")}${horizontalPadding}${framedLine.renderedText}${trailingSpaces}${horizontalPadding}${borderColorizer(\"│\")}`,\n );\n }\n\n lines.push(`${outerIndent}${borderColorizer(`└${borderLine}┘`)}`);\n return lines.join(\"\\n\");\n};\n\nexport const printFramedBox = (framedLines: FramedLine[]): void => {\n const rendered = renderFramedBoxString(framedLines);\n if (rendered) {\n logger.log(rendered);\n }\n};\n","export const groupBy = <T>(items: T[], keyFn: (item: T) => string): Map<string, T[]> => {\n const groups = new Map<string, T[]>();\n\n for (const item of items) {\n const key = keyFn(item);\n const existing = groups.get(key) ?? [];\n existing.push(item);\n groups.set(key, existing);\n }\n\n return groups;\n};\n","export const indentMultilineText = (text: string, linePrefix: string): string =>\n text\n .split(\"\\n\")\n .map((lineText) => `${linePrefix}${lineText}`)\n .join(\"\\n\");\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { ReactDoctorConfig } from \"../types.js\";\n\nconst CONFIG_FILENAME = \"react-doctor.config.json\";\nconst PACKAGE_JSON_CONFIG_KEY = \"reactDoctor\";\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nexport const loadConfig = (rootDirectory: string): ReactDoctorConfig | null => {\n const configFilePath = path.join(rootDirectory, CONFIG_FILENAME);\n\n if (fs.existsSync(configFilePath)) {\n try {\n const fileContent = fs.readFileSync(configFilePath, \"utf-8\");\n const parsed: unknown = JSON.parse(fileContent);\n if (!isPlainObject(parsed)) {\n console.warn(`Warning: ${CONFIG_FILENAME} must be a JSON object, ignoring.`);\n return null;\n }\n return parsed as ReactDoctorConfig;\n } catch (error) {\n console.warn(\n `Warning: Failed to parse ${CONFIG_FILENAME}: ${error instanceof Error ? error.message : String(error)}`,\n );\n return null;\n }\n }\n\n const packageJsonPath = path.join(rootDirectory, \"package.json\");\n if (fs.existsSync(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","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 { findMonorepoRoot } from \"./find-monorepo-root.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 runKnipWithOptions = async (\n knipCwd: string,\n workspaceName?: string,\n): Promise<KnipResults> => {\n const options = await silenced(() =>\n createOptions({\n cwd: knipCwd,\n isShowProgress: false,\n ...(workspaceName ? { workspace: workspaceName } : {}),\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 = fs.existsSync(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 unusedFile of issues.files) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, unusedFile),\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_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}\n\nexport const createOxlintConfig = ({\n pluginPath,\n framework,\n hasReactCompiler,\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\n ? [{ name: \"react-hooks-js\", specifier: esmRequire.resolve(\"eslint-plugin-react-hooks\") }]\n : []),\n pluginPath,\n ],\n rules: {\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 \"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/no-noninteractive-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 ...(hasReactCompiler ? 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\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/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/async-parallel\": \"warn\",\n ...(framework === \"nextjs\" ? NEXTJS_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 = (rootDirectory: string): string[] => {\n const result = spawnSync(\"git\", [\"grep\", \"-l\", \"--untracked\", \"-E\", \"(eslint|oxlint)-disable\"], {\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\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 = (rootDirectory: string): (() => void) => {\n const filePaths = findFilesWithDisableDirectives(rootDirectory);\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 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\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/async-parallel\": \"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} />`\",\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\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-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 \"Use `redirect('/path')` from 'next/navigation' in a Server Component, or handle in middleware\",\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 \"async-parallel\":\n \"Use `const [a, b] = await Promise.all([fetchA(), fetchB()])` to run independent operations concurrently\",\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 if (currentBatch.length > 0 && currentBatchLength + entryLength > SPAWN_ARGS_MAX_LENGTH_CHARS) {\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 = (args: string[], rootDirectory: string): Promise<string> =>\n new Promise<string>((resolve, reject) => {\n const child = spawn(process.execPath, 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\", () => {\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): 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 });\n const restoreDisableDirectives = neutralizeDisableDirectives(rootDirectory);\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);\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 ora from \"ora\";\n\nlet sharedInstance: ReturnType<typeof ora> | null = null;\nlet activeCount = 0;\nconst pendingTexts = new Set<string>();\n\nconst finalize = (method: \"succeed\" | \"fail\", originalText: string, displayText: string) => {\n pendingTexts.delete(originalText);\n activeCount--;\n\n if (activeCount <= 0 || !sharedInstance) {\n sharedInstance?.[method](displayText);\n sharedInstance = null;\n activeCount = 0;\n return;\n }\n\n sharedInstance.stop();\n ora(displayText).start()[method](displayText);\n\n const [remainingText] = pendingTexts;\n if (remainingText) {\n sharedInstance.text = remainingText;\n }\n sharedInstance.start();\n};\n\nexport const spinner = (text: string) => ({\n start() {\n activeCount++;\n pendingTexts.add(text);\n\n if (!sharedInstance) {\n sharedInstance = ora({ text }).start();\n } else {\n sharedInstance.text = text;\n }\n\n return {\n succeed: (displayText: string) => finalize(\"succeed\", text, displayText),\n fail: (displayText: string) => finalize(\"fail\", text, displayText),\n };\n },\n});\n","import { randomUUID } from \"node:crypto\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport {\n MILLISECONDS_PER_SECOND,\n OFFLINE_FLAG_MESSAGE,\n OFFLINE_MESSAGE,\n PERFECT_SCORE,\n SCORE_BAR_WIDTH_CHARS,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n SHARE_BASE_URL,\n} from \"./constants.js\";\nimport type {\n Diagnostic,\n ProjectInfo,\n ReactDoctorConfig,\n ScanOptions,\n ScanResult,\n ScoreResult,\n} from \"./types.js\";\nimport { calculateScore } from \"./utils/calculate-score.js\";\nimport { colorizeByScore } from \"./utils/colorize-by-score.js\";\nimport { combineDiagnostics, computeJsxIncludePaths } from \"./utils/combine-diagnostics.js\";\nimport { discoverProject, formatFrameworkName } from \"./utils/discover-project.js\";\nimport { type FramedLine, createFramedLine, printFramedBox } from \"./utils/framed-box.js\";\nimport { groupBy } from \"./utils/group-by.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { indentMultilineText } from \"./utils/indent-multiline-text.js\";\nimport { loadConfig } from \"./utils/load-config.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { runKnip } from \"./utils/run-knip.js\";\nimport { runOxlint } from \"./utils/run-oxlint.js\";\nimport { spinner } from \"./utils/spinner.js\";\n\ninterface ScoreBarSegments {\n filledSegment: string;\n emptySegment: string;\n}\n\nconst SEVERITY_ORDER: Record<Diagnostic[\"severity\"], number> = {\n error: 0,\n warning: 1,\n};\n\nconst colorizeBySeverity = (text: string, severity: Diagnostic[\"severity\"]): string =>\n severity === \"error\" ? highlighter.error(text) : highlighter.warn(text);\n\nconst sortBySeverity = (diagnosticGroups: [string, Diagnostic[]][]): [string, Diagnostic[]][] =>\n diagnosticGroups.toSorted(([, diagnosticsA], [, diagnosticsB]) => {\n const severityA = SEVERITY_ORDER[diagnosticsA[0].severity];\n const severityB = SEVERITY_ORDER[diagnosticsB[0].severity];\n return severityA - severityB;\n });\n\nconst collectAffectedFiles = (diagnostics: Diagnostic[]): Set<string> =>\n new Set(diagnostics.map((diagnostic) => diagnostic.filePath));\n\nconst buildFileLineMap = (diagnostics: Diagnostic[]): Map<string, number[]> => {\n const fileLines = new Map<string, number[]>();\n for (const diagnostic of diagnostics) {\n const lines = fileLines.get(diagnostic.filePath) ?? [];\n if (diagnostic.line > 0) {\n lines.push(diagnostic.line);\n }\n fileLines.set(diagnostic.filePath, lines);\n }\n return fileLines;\n};\n\nconst printDiagnostics = (diagnostics: Diagnostic[], isVerbose: boolean): void => {\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [, ruleDiagnostics] of sortedRuleGroups) {\n const firstDiagnostic = ruleDiagnostics[0];\n const severitySymbol = firstDiagnostic.severity === \"error\" ? \"✗\" : \"⚠\";\n const icon = colorizeBySeverity(severitySymbol, firstDiagnostic.severity);\n const count = ruleDiagnostics.length;\n const countLabel = count > 1 ? colorizeBySeverity(` (${count})`, firstDiagnostic.severity) : \"\";\n\n logger.log(` ${icon} ${firstDiagnostic.message}${countLabel}`);\n if (firstDiagnostic.help) {\n logger.dim(indentMultilineText(firstDiagnostic.help, \" \"));\n }\n\n if (isVerbose) {\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n logger.dim(` ${filePath}${lineLabel}`);\n }\n }\n\n logger.break();\n }\n};\n\nconst formatElapsedTime = (elapsedMilliseconds: number): string => {\n if (elapsedMilliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(elapsedMilliseconds)}ms`;\n }\n return `${(elapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1)}s`;\n};\n\nconst formatRuleSummary = (ruleKey: string, ruleDiagnostics: Diagnostic[]): string => {\n const firstDiagnostic = ruleDiagnostics[0];\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n const sections = [\n `Rule: ${ruleKey}`,\n `Severity: ${firstDiagnostic.severity}`,\n `Category: ${firstDiagnostic.category}`,\n `Count: ${ruleDiagnostics.length}`,\n \"\",\n firstDiagnostic.message,\n ];\n\n if (firstDiagnostic.help) {\n sections.push(\"\", `Suggestion: ${firstDiagnostic.help}`);\n }\n\n sections.push(\"\", \"Files:\");\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n sections.push(` ${filePath}${lineLabel}`);\n }\n\n return sections.join(\"\\n\") + \"\\n\";\n};\n\nconst writeDiagnosticsDirectory = (diagnostics: Diagnostic[]): string => {\n const outputDirectory = join(tmpdir(), `react-doctor-${randomUUID()}`);\n mkdirSync(outputDirectory);\n\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [ruleKey, ruleDiagnostics] of sortedRuleGroups) {\n const fileName = ruleKey.replace(/\\//g, \"--\") + \".txt\";\n writeFileSync(join(outputDirectory, fileName), formatRuleSummary(ruleKey, ruleDiagnostics));\n }\n\n writeFileSync(join(outputDirectory, \"diagnostics.json\"), JSON.stringify(diagnostics, null, 2));\n\n return outputDirectory;\n};\n\nconst buildScoreBarSegments = (score: number): ScoreBarSegments => {\n const filledCount = Math.round((score / PERFECT_SCORE) * SCORE_BAR_WIDTH_CHARS);\n const emptyCount = SCORE_BAR_WIDTH_CHARS - filledCount;\n\n return {\n filledSegment: \"█\".repeat(filledCount),\n emptySegment: \"░\".repeat(emptyCount),\n };\n};\n\nconst buildPlainScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return `${filledSegment}${emptySegment}`;\n};\n\nconst buildScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return colorizeByScore(filledSegment, score) + highlighter.dim(emptySegment);\n};\n\nconst printScoreGauge = (score: number, label: string): void => {\n const scoreDisplay = colorizeByScore(`${score}`, score);\n const labelDisplay = colorizeByScore(label, score);\n logger.log(` ${scoreDisplay} / ${PERFECT_SCORE} ${labelDisplay}`);\n logger.break();\n logger.log(` ${buildScoreBar(score)}`);\n logger.break();\n};\n\nconst getDoctorFace = (score: number): string[] => {\n if (score >= SCORE_GOOD_THRESHOLD) return [\"◠ ◠\", \" ▽ \"];\n if (score >= SCORE_OK_THRESHOLD) return [\"• •\", \" ─ \"];\n return [\"x x\", \" ▽ \"];\n};\n\nconst printBranding = (score?: number): void => {\n if (score !== undefined) {\n const [eyes, mouth] = getDoctorFace(score);\n const colorize = (text: string) => colorizeByScore(text, score);\n logger.log(colorize(\" ┌─────┐\"));\n logger.log(colorize(` │ ${eyes} │`));\n logger.log(colorize(` │ ${mouth} │`));\n logger.log(colorize(\" └─────┘\"));\n }\n logger.log(` React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`);\n logger.break();\n};\n\nconst buildShareUrl = (\n diagnostics: Diagnostic[],\n scoreResult: ScoreResult | null,\n projectName: string,\n): string => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n\n const params = new URLSearchParams();\n params.set(\"p\", projectName);\n if (scoreResult) params.set(\"s\", String(scoreResult.score));\n if (errorCount > 0) params.set(\"e\", String(errorCount));\n if (warningCount > 0) params.set(\"w\", String(warningCount));\n if (affectedFileCount > 0) params.set(\"f\", String(affectedFileCount));\n\n return `${SHARE_BASE_URL}?${params.toString()}`;\n};\n\nconst buildBrandingLines = (\n scoreResult: ScoreResult | null,\n noScoreMessage: string,\n): FramedLine[] => {\n const lines: FramedLine[] = [];\n\n if (scoreResult) {\n const [eyes, mouth] = getDoctorFace(scoreResult.score);\n const scoreColorizer = (text: string): string => colorizeByScore(text, scoreResult.score);\n\n lines.push(createFramedLine(\"┌─────┐\", scoreColorizer(\"┌─────┐\")));\n lines.push(createFramedLine(`│ ${eyes} │`, scoreColorizer(`│ ${eyes} │`)));\n lines.push(createFramedLine(`│ ${mouth} │`, scoreColorizer(`│ ${mouth} │`)));\n lines.push(createFramedLine(\"└─────┘\", scoreColorizer(\"└─────┘\")));\n lines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n lines.push(createFramedLine(\"\"));\n\n const scoreLinePlainText = `${scoreResult.score} / ${PERFECT_SCORE} ${scoreResult.label}`;\n const scoreLineRenderedText = `${colorizeByScore(String(scoreResult.score), scoreResult.score)} / ${PERFECT_SCORE} ${colorizeByScore(scoreResult.label, scoreResult.score)}`;\n lines.push(createFramedLine(scoreLinePlainText, scoreLineRenderedText));\n lines.push(createFramedLine(\"\"));\n lines.push(\n createFramedLine(buildPlainScoreBar(scoreResult.score), buildScoreBar(scoreResult.score)),\n );\n lines.push(createFramedLine(\"\"));\n } else {\n lines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n lines.push(createFramedLine(\"\"));\n lines.push(createFramedLine(noScoreMessage, highlighter.dim(noScoreMessage)));\n lines.push(createFramedLine(\"\"));\n }\n\n return lines;\n};\n\nconst buildCountsSummaryLine = (\n diagnostics: Diagnostic[],\n totalSourceFileCount: number,\n elapsedMilliseconds: number,\n): FramedLine => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n const elapsed = formatElapsedTime(elapsedMilliseconds);\n\n const plainParts: string[] = [];\n const renderedParts: string[] = [];\n\n if (errorCount > 0) {\n const errorText = `✗ ${errorCount} error${errorCount === 1 ? \"\" : \"s\"}`;\n plainParts.push(errorText);\n renderedParts.push(highlighter.error(errorText));\n }\n if (warningCount > 0) {\n const warningText = `⚠ ${warningCount} warning${warningCount === 1 ? \"\" : \"s\"}`;\n plainParts.push(warningText);\n renderedParts.push(highlighter.warn(warningText));\n }\n\n const fileCountText =\n totalSourceFileCount > 0\n ? `across ${affectedFileCount}/${totalSourceFileCount} files`\n : `across ${affectedFileCount} file${affectedFileCount === 1 ? \"\" : \"s\"}`;\n const elapsedTimeText = `in ${elapsed}`;\n\n plainParts.push(fileCountText, elapsedTimeText);\n renderedParts.push(highlighter.dim(fileCountText), highlighter.dim(elapsedTimeText));\n\n return createFramedLine(plainParts.join(\" \"), renderedParts.join(\" \"));\n};\n\nconst printSummary = (\n diagnostics: Diagnostic[],\n elapsedMilliseconds: number,\n scoreResult: ScoreResult | null,\n projectName: string,\n totalSourceFileCount: number,\n noScoreMessage: string,\n): void => {\n const summaryFramedLines = [\n ...buildBrandingLines(scoreResult, noScoreMessage),\n buildCountsSummaryLine(diagnostics, totalSourceFileCount, elapsedMilliseconds),\n ];\n printFramedBox(summaryFramedLines);\n\n try {\n const diagnosticsDirectory = writeDiagnosticsDirectory(diagnostics);\n logger.break();\n logger.dim(` Full diagnostics written to ${diagnosticsDirectory}`);\n } catch {\n logger.break();\n }\n\n const shareUrl = buildShareUrl(diagnostics, scoreResult, projectName);\n logger.break();\n logger.dim(` Share your results: ${highlighter.info(shareUrl)}`);\n};\n\ninterface ResolvedScanOptions {\n lint: boolean;\n deadCode: boolean;\n verbose: boolean;\n scoreOnly: boolean;\n offline: boolean;\n includePaths: string[];\n}\n\nconst mergeScanOptions = (\n inputOptions: ScanOptions,\n userConfig: ReactDoctorConfig | null,\n): ResolvedScanOptions => ({\n lint: inputOptions.lint ?? userConfig?.lint ?? true,\n deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,\n verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,\n scoreOnly: inputOptions.scoreOnly ?? false,\n offline: inputOptions.offline ?? false,\n includePaths: inputOptions.includePaths ?? [],\n});\n\nconst printProjectDetection = (\n projectInfo: ProjectInfo,\n userConfig: ReactDoctorConfig | null,\n isDiffMode: boolean,\n includePaths: string[],\n): void => {\n const frameworkLabel = formatFrameworkName(projectInfo.framework);\n const languageLabel = projectInfo.hasTypeScript ? \"TypeScript\" : \"JavaScript\";\n\n const completeStep = (message: string) => {\n spinner(message).start().succeed(message);\n };\n\n completeStep(`Detecting framework. Found ${highlighter.info(frameworkLabel)}.`);\n completeStep(\n `Detecting React version. Found ${highlighter.info(`React ${projectInfo.reactVersion}`)}.`,\n );\n completeStep(`Detecting language. Found ${highlighter.info(languageLabel)}.`);\n completeStep(\n `Detecting React Compiler. ${projectInfo.hasReactCompiler ? highlighter.info(\"Found React Compiler.\") : \"Not found.\"}`,\n );\n\n if (isDiffMode) {\n completeStep(`Scanning ${highlighter.info(`${includePaths.length}`)} changed source files.`);\n } else {\n completeStep(`Found ${highlighter.info(`${projectInfo.sourceFileCount}`)} source files.`);\n }\n\n if (userConfig) {\n completeStep(`Loaded ${highlighter.info(\"react-doctor config\")}.`);\n }\n\n logger.break();\n};\n\nexport const scan = async (\n directory: string,\n inputOptions: ScanOptions = {},\n): Promise<ScanResult> => {\n const startTime = performance.now();\n const projectInfo = discoverProject(directory);\n const userConfig = loadConfig(directory);\n const options = mergeScanOptions(inputOptions, userConfig);\n const { includePaths } = options;\n const isDiffMode = includePaths.length > 0;\n\n if (!projectInfo.reactVersion) {\n throw new Error(\"No React dependency found in package.json\");\n }\n\n if (!options.scoreOnly) {\n printProjectDetection(projectInfo, userConfig, isDiffMode, includePaths);\n }\n\n const jsxIncludePaths = computeJsxIncludePaths(includePaths);\n\n let didLintFail = false;\n let didDeadCodeFail = false;\n\n const lintPromise = options.lint\n ? (async () => {\n const lintSpinner = options.scoreOnly ? null : spinner(\"Running lint checks...\").start();\n try {\n const lintDiagnostics = await runOxlint(\n directory,\n projectInfo.hasTypeScript,\n projectInfo.framework,\n projectInfo.hasReactCompiler,\n jsxIncludePaths,\n );\n lintSpinner?.succeed(\"Running lint checks.\");\n return lintDiagnostics;\n } catch (error) {\n didLintFail = true;\n lintSpinner?.fail(\"Lint checks failed (non-fatal, skipping).\");\n if (error instanceof Error) {\n logger.error(error.message);\n if (error.stack) {\n logger.dim(error.stack);\n }\n } else {\n logger.error(String(error));\n }\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const deadCodePromise =\n options.deadCode && !isDiffMode\n ? (async () => {\n const deadCodeSpinner = options.scoreOnly\n ? null\n : spinner(\"Detecting dead code...\").start();\n try {\n const knipDiagnostics = await runKnip(directory);\n deadCodeSpinner?.succeed(\"Detecting dead code.\");\n return knipDiagnostics;\n } catch (error) {\n didDeadCodeFail = true;\n deadCodeSpinner?.fail(\"Dead code detection failed (non-fatal, skipping).\");\n logger.error(String(error));\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const [lintDiagnostics, deadCodeDiagnostics] = await Promise.all([lintPromise, deadCodePromise]);\n const diagnostics = combineDiagnostics(\n lintDiagnostics,\n deadCodeDiagnostics,\n directory,\n isDiffMode,\n userConfig,\n );\n\n const elapsedMilliseconds = performance.now() - startTime;\n\n const skippedChecks: string[] = [];\n if (didLintFail) skippedChecks.push(\"lint\");\n if (didDeadCodeFail) skippedChecks.push(\"dead code\");\n const hasSkippedChecks = skippedChecks.length > 0;\n\n const scoreResult = options.offline ? null : await calculateScore(diagnostics);\n const noScoreMessage = options.offline ? OFFLINE_FLAG_MESSAGE : OFFLINE_MESSAGE;\n\n if (options.scoreOnly) {\n if (scoreResult) {\n logger.log(`${scoreResult.score}`);\n } else {\n logger.dim(noScoreMessage);\n }\n return { diagnostics, scoreResult, skippedChecks };\n }\n\n if (diagnostics.length === 0) {\n if (hasSkippedChecks) {\n const skippedLabel = skippedChecks.join(\" and \");\n logger.warn(\n `No issues detected, but ${skippedLabel} checks failed — results are incomplete.`,\n );\n } else {\n logger.success(\"No issues found!\");\n }\n logger.break();\n if (hasSkippedChecks) {\n printBranding();\n logger.dim(\" Score not shown — some checks could not complete.\");\n } else if (scoreResult) {\n printBranding(scoreResult.score);\n printScoreGauge(scoreResult.score, scoreResult.label);\n } else {\n logger.dim(` ${noScoreMessage}`);\n }\n return { diagnostics, scoreResult, skippedChecks };\n }\n\n printDiagnostics(diagnostics, options.verbose);\n\n const displayedSourceFileCount = isDiffMode ? includePaths.length : projectInfo.sourceFileCount;\n\n printSummary(\n diagnostics,\n elapsedMilliseconds,\n scoreResult,\n projectInfo.projectName,\n displayedSourceFileCount,\n noScoreMessage,\n );\n\n if (hasSkippedChecks) {\n const skippedLabel = skippedChecks.join(\" and \");\n logger.break();\n logger.warn(` Note: ${skippedLabel} checks failed — score may be incomplete.`);\n }\n\n return { diagnostics, scoreResult, skippedChecks };\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 { logger } from \"./logger.js\";\nimport type { HandleErrorOptions } from \"../types.js\";\n\nconst DEFAULT_HANDLE_ERROR_OPTIONS: HandleErrorOptions = {\n shouldExit: true,\n};\n\nexport const handleError = (\n error: unknown,\n options: HandleErrorOptions = DEFAULT_HANDLE_ERROR_OPTIONS,\n): void => {\n logger.break();\n logger.error(\"Something went wrong. Please check the error below for more details.\");\n logger.error(\"If the problem persists, please open an issue on GitHub.\");\n logger.error(\"\");\n if (error instanceof Error) {\n logger.error(error.message);\n }\n logger.break();\n if (options.shouldExit) {\n process.exit(1);\n }\n process.exitCode = 1;\n};\n","import type { PromptMultiselectChoiceState } from \"../types.js\";\n\nexport const shouldAutoSelectCurrentChoice = (\n choiceStates: PromptMultiselectChoiceState[],\n cursor: number,\n): boolean => {\n const hasSelection = choiceStates.some((choiceState) => choiceState.selected);\n if (hasSelection) return false;\n\n const currentChoice = choiceStates[cursor];\n return Boolean(currentChoice) && !currentChoice.disabled;\n};\n","import type { PromptMultiselectChoiceState } from \"../types.js\";\n\nexport const shouldSelectAllChoices = (choiceStates: PromptMultiselectChoiceState[]): boolean => {\n const enabledChoiceStates = choiceStates.filter((choiceState) => !choiceState.disabled);\n return enabledChoiceStates.some((choiceState) => choiceState.selected !== true);\n};\n","import { createRequire } from \"node:module\";\nimport basePrompts, { type PromptObject, type Answers } from \"prompts\";\nimport type { PromptMultiselectContext } from \"../types.js\";\nimport { logger } from \"./logger.js\";\nimport { shouldAutoSelectCurrentChoice } from \"./should-auto-select-current-choice.js\";\nimport { shouldSelectAllChoices } from \"./should-select-all-choices.js\";\n\nconst require = createRequire(import.meta.url);\nconst PROMPTS_MULTISELECT_MODULE_PATH = \"prompts/lib/elements/multiselect\";\nconst PROMPTS_SELECT_MODULE_PATH = \"prompts/lib/elements/select\";\nlet didPatchMultiselectToggleAll = false;\nlet didPatchMultiselectSubmit = false;\nlet didPatchSelectBanner = false;\n\nconst selectBannerMap = new Map<number, string>();\n\nexport const setSelectBanner = (banner: string, targetIndex: number): void => {\n selectBannerMap.set(targetIndex, banner);\n};\n\nexport const clearSelectBanner = (): void => {\n selectBannerMap.clear();\n};\n\nconst onCancel = () => {\n logger.break();\n logger.log(\"Cancelled.\");\n logger.dim(\"Run `npx react-doctor@latest --fix` to fix issues.\");\n logger.break();\n process.exit(0);\n};\n\nconst patchMultiselectToggleAll = (): void => {\n if (didPatchMultiselectToggleAll) return;\n didPatchMultiselectToggleAll = true;\n\n const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);\n\n multiselectPromptConstructor.prototype.toggleAll = function (\n this: PromptMultiselectContext,\n ): void {\n const isCurrentChoiceDisabled = Boolean(this.value[this.cursor]?.disabled);\n if (this.maxChoices !== undefined || isCurrentChoiceDisabled) {\n this.bell();\n return;\n }\n\n const shouldSelectAllEnabledChoices = shouldSelectAllChoices(this.value);\n\n for (const choiceState of this.value) {\n if (choiceState.disabled) continue;\n choiceState.selected = shouldSelectAllEnabledChoices;\n }\n\n this.render();\n };\n};\n\nconst patchMultiselectSubmit = (): void => {\n if (didPatchMultiselectSubmit) return;\n didPatchMultiselectSubmit = true;\n\n const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);\n const originalSubmit = multiselectPromptConstructor.prototype.submit;\n\n multiselectPromptConstructor.prototype.submit = function (this: PromptMultiselectContext): void {\n if (shouldAutoSelectCurrentChoice(this.value, this.cursor)) {\n this.value[this.cursor].selected = true;\n }\n originalSubmit.call(this);\n };\n};\n\ninterface SelectPromptInstance {\n closed: boolean;\n done: boolean;\n cursor: number;\n outputText: string;\n out: { write: (data: string) => boolean; columns: number };\n render: () => void;\n}\n\nconst patchSelectBanner = (): void => {\n if (didPatchSelectBanner) return;\n didPatchSelectBanner = true;\n\n const selectConstructor = require(PROMPTS_SELECT_MODULE_PATH);\n const promptsClear = require(\"prompts/lib/util/clear\");\n const originalRender = selectConstructor.prototype.render;\n\n selectConstructor.prototype.render = function (this: SelectPromptInstance): void {\n originalRender.call(this);\n\n const banner = selectBannerMap.get(this.cursor);\n if (!banner || this.closed || this.done) {\n return;\n }\n\n this.out.write(promptsClear(this.outputText, this.out.columns));\n this.outputText = `${banner}\\n\\n${this.outputText}`;\n this.out.write(this.outputText);\n };\n};\n\nexport const prompts = <T extends string = string>(\n questions: PromptObject<T> | PromptObject<T>[],\n): Promise<Answers<T>> => {\n patchMultiselectToggleAll();\n patchMultiselectSubmit();\n patchSelectBanner();\n return basePrompts(questions, { onCancel });\n};\n","import path from \"node:path\";\nimport type { WorkspacePackage } from \"../types.js\";\nimport { discoverReactSubprojects, listWorkspacePackages } from \"./discover-project.js\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nexport const selectProjects = async (\n rootDirectory: string,\n projectFlag: string | undefined,\n skipPrompts: boolean,\n): Promise<string[]> => {\n let packages = listWorkspacePackages(rootDirectory);\n if (packages.length === 0) {\n packages = discoverReactSubprojects(rootDirectory);\n }\n\n if (packages.length === 0) return [rootDirectory];\n if (packages.length === 1) {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages[0].name}`,\n );\n return [packages[0].directory];\n }\n\n if (projectFlag) return resolveProjectFlag(projectFlag, packages);\n\n if (skipPrompts) {\n printDiscoveredProjects(packages);\n return packages.map((workspacePackage) => workspacePackage.directory);\n }\n\n return promptProjectSelection(packages, rootDirectory);\n};\n\nconst resolveProjectFlag = (\n projectFlag: string,\n workspacePackages: WorkspacePackage[],\n): string[] => {\n const requestedNames = projectFlag.split(\",\").map((name) => name.trim());\n const resolvedDirectories: string[] = [];\n\n for (const requestedName of requestedNames) {\n const matched = workspacePackages.find(\n (workspacePackage) =>\n workspacePackage.name === requestedName ||\n path.basename(workspacePackage.directory) === requestedName,\n );\n\n if (!matched) {\n const availableNames = workspacePackages\n .map((workspacePackage) => workspacePackage.name)\n .join(\", \");\n throw new Error(`Project \"${requestedName}\" not found. Available: ${availableNames}`);\n }\n\n resolvedDirectories.push(matched.directory);\n }\n\n return resolvedDirectories;\n};\n\nconst printDiscoveredProjects = (packages: WorkspacePackage[]): void => {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages.map((workspacePackage) => workspacePackage.name).join(\", \")}`,\n );\n};\n\nconst promptProjectSelection = async (\n workspacePackages: WorkspacePackage[],\n rootDirectory: string,\n): Promise<string[]> => {\n const { selectedDirectories } = await prompts({\n type: \"multiselect\",\n name: \"selectedDirectories\",\n message: \"Select projects to scan\",\n choices: workspacePackages.map((workspacePackage) => ({\n title: workspacePackage.name,\n description: path.relative(rootDirectory, workspacePackage.directory),\n value: workspacePackage.directory,\n })),\n min: 1,\n });\n\n return selectedDirectories;\n};\n","import { execSync } from \"node:child_process\";\nimport { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nconst HOME_DIRECTORY = homedir();\nconst CONFIG_DIRECTORY = join(HOME_DIRECTORY, \".react-doctor\");\nconst CONFIG_FILE = join(CONFIG_DIRECTORY, \"config.json\");\n\nconst SKILL_NAME = \"react-doctor\";\nconst WINDSURF_MARKER = \"# React Doctor\";\n\nconst SKILL_DESCRIPTION =\n \"Run after making React changes to catch issues early. Use when reviewing code, finishing a feature, or fixing bugs in a React project.\";\n\nconst SKILL_BODY = `Scans your React codebase for security, performance, correctness, and architecture issues. Outputs a 0-100 score with actionable diagnostics.\n\n## Usage\n\n\\`\\`\\`bash\nnpx -y react-doctor@latest . --verbose --diff\n\\`\\`\\`\n\n## Workflow\n\nRun after making changes to catch issues early. Fix errors first, then re-run to verify the score improved.`;\n\nconst SKILL_CONTENT = `---\nname: ${SKILL_NAME}\ndescription: ${SKILL_DESCRIPTION}\nversion: 1.0.0\n---\n\n# React Doctor\n\n${SKILL_BODY}\n`;\n\nconst AGENTS_CONTENT = `# React Doctor\n\n${SKILL_DESCRIPTION}\n\n${SKILL_BODY}\n`;\n\nconst CODEX_AGENT_CONFIG = `interface:\n display_name: \"${SKILL_NAME}\"\n short_description: \"Diagnose and fix React codebase health issues\"\n`;\n\ninterface SkillPromptConfig {\n skillPromptDismissed?: boolean;\n}\n\ninterface SkillTarget {\n name: string;\n detect: () => boolean;\n install: () => void;\n}\n\nconst readSkillPromptConfig = (): SkillPromptConfig => {\n try {\n if (!existsSync(CONFIG_FILE)) return {};\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf-8\"));\n } catch {\n return {};\n }\n};\n\nconst writeSkillPromptConfig = (config: SkillPromptConfig): void => {\n try {\n mkdirSync(CONFIG_DIRECTORY, { recursive: true });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n } catch {}\n};\n\nconst writeSkillFiles = (directory: string): void => {\n mkdirSync(directory, { recursive: true });\n writeFileSync(join(directory, \"SKILL.md\"), SKILL_CONTENT);\n writeFileSync(join(directory, \"AGENTS.md\"), AGENTS_CONTENT);\n};\n\nconst isCommandAvailable = (command: string): boolean => {\n try {\n const whichCommand = process.platform === \"win32\" ? \"where\" : \"which\";\n execSync(`${whichCommand} ${command}`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n};\n\nconst SKILL_TARGETS: SkillTarget[] = [\n {\n name: \"Claude Code\",\n detect: () => existsSync(join(HOME_DIRECTORY, \".claude\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".claude\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Amp Code\",\n detect: () => existsSync(join(HOME_DIRECTORY, \".amp\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".config\", \"amp\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Cursor\",\n detect: () => existsSync(join(HOME_DIRECTORY, \".cursor\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".cursor\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"OpenCode\",\n detect: () =>\n isCommandAvailable(\"opencode\") || existsSync(join(HOME_DIRECTORY, \".config\", \"opencode\")),\n install: () =>\n writeSkillFiles(join(HOME_DIRECTORY, \".config\", \"opencode\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Windsurf\",\n detect: () =>\n existsSync(join(HOME_DIRECTORY, \".codeium\")) ||\n existsSync(join(HOME_DIRECTORY, \"Library\", \"Application Support\", \"Windsurf\")),\n install: () => {\n const memoriesDirectory = join(HOME_DIRECTORY, \".codeium\", \"windsurf\", \"memories\");\n mkdirSync(memoriesDirectory, { recursive: true });\n const rulesFile = join(memoriesDirectory, \"global_rules.md\");\n\n if (existsSync(rulesFile)) {\n const existingContent = readFileSync(rulesFile, \"utf-8\");\n if (existingContent.includes(WINDSURF_MARKER)) return;\n appendFileSync(rulesFile, `\\n${WINDSURF_MARKER}\\n\\n${SKILL_CONTENT}`);\n } else {\n writeFileSync(rulesFile, `${WINDSURF_MARKER}\\n\\n${SKILL_CONTENT}`);\n }\n },\n },\n {\n name: \"Antigravity\",\n detect: () =>\n isCommandAvailable(\"agy\") || existsSync(join(HOME_DIRECTORY, \".gemini\", \"antigravity\")),\n install: () =>\n writeSkillFiles(join(HOME_DIRECTORY, \".gemini\", \"antigravity\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Gemini CLI\",\n detect: () => isCommandAvailable(\"gemini\") || existsSync(join(HOME_DIRECTORY, \".gemini\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".gemini\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Codex\",\n detect: () => isCommandAvailable(\"codex\") || existsSync(join(HOME_DIRECTORY, \".codex\")),\n install: () => {\n const skillDirectory = join(HOME_DIRECTORY, \".codex\", \"skills\", SKILL_NAME);\n writeSkillFiles(skillDirectory);\n const agentsDirectory = join(skillDirectory, \"agents\");\n mkdirSync(agentsDirectory, { recursive: true });\n writeFileSync(join(agentsDirectory, \"openai.yaml\"), CODEX_AGENT_CONFIG);\n },\n },\n];\n\nconst installSkill = (): void => {\n let installedCount = 0;\n\n for (const target of SKILL_TARGETS) {\n if (!target.detect()) continue;\n try {\n target.install();\n logger.log(` ${highlighter.success(\"✔\")} ${target.name}`);\n installedCount++;\n } catch {\n logger.dim(` ✗ ${target.name} (failed)`);\n }\n }\n\n try {\n const projectSkillDirectory = join(\".agents\", SKILL_NAME);\n writeSkillFiles(projectSkillDirectory);\n logger.log(` ${highlighter.success(\"✔\")} .agents/`);\n installedCount++;\n } catch {\n logger.dim(\" ✗ .agents/ (failed)\");\n }\n\n logger.break();\n if (installedCount === 0) {\n logger.dim(\"No supported tools detected.\");\n } else {\n logger.success(\"Done! The skill will activate when working on React projects.\");\n }\n};\n\nexport const maybePromptSkillInstall = async (shouldSkipPrompts: boolean): Promise<void> => {\n const config = readSkillPromptConfig();\n if (config.skillPromptDismissed) return;\n if (shouldSkipPrompts) return;\n\n logger.break();\n logger.log(`${highlighter.info(\"💡\")} Have your coding agent fix these issues automatically?`);\n logger.dim(\n ` Install the ${highlighter.info(\"react-doctor\")} skill to teach Cursor, Claude Code,`,\n );\n logger.dim(\" Ami, and other AI agents how to diagnose and fix React issues.\");\n logger.break();\n\n const { shouldInstall } = await prompts({\n type: \"confirm\",\n name: \"shouldInstall\",\n message: \"Install skill? (recommended)\",\n initial: true,\n });\n\n if (shouldInstall) {\n logger.break();\n installSkill();\n }\n\n writeSkillPromptConfig({ ...config, skillPromptDismissed: true });\n};\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport { AMI_INSTALL_URL, AMI_RELEASES_URL, AMI_WEBSITE_URL, OPEN_BASE_URL } from \"./constants.js\";\nimport { scan } from \"./scan.js\";\nimport type {\n Diagnostic,\n DiffInfo,\n EstimatedScoreResult,\n ReactDoctorConfig,\n ScanOptions,\n} from \"./types.js\";\nimport { fetchEstimatedScore } from \"./utils/calculate-score.js\";\nimport { colorizeByScore } from \"./utils/colorize-by-score.js\";\nimport { createFramedLine, renderFramedBoxString } from \"./utils/framed-box.js\";\nimport { filterSourceFiles, getDiffInfo } from \"./utils/get-diff-files.js\";\nimport { handleError } from \"./utils/handle-error.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { loadConfig } from \"./utils/load-config.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { clearSelectBanner, prompts, setSelectBanner } from \"./utils/prompts.js\";\nimport { selectProjects } from \"./utils/select-projects.js\";\nimport { maybePromptSkillInstall } from \"./utils/skill-prompt.js\";\n\nconst VERSION = process.env.VERSION ?? \"0.0.0\";\n\ninterface CliFlags {\n lint: boolean;\n deadCode: boolean;\n verbose: boolean;\n score: boolean;\n fix: boolean;\n yes: boolean;\n offline: boolean;\n ami: boolean;\n project?: string;\n diff?: boolean | string;\n}\n\nconst exitWithFixHint = () => {\n logger.break();\n logger.log(\"Cancelled.\");\n logger.dim(\"Run `npx react-doctor@latest --fix` to fix issues.\");\n logger.break();\n process.exit(0);\n};\n\nprocess.on(\"SIGINT\", exitWithFixHint);\nprocess.on(\"SIGTERM\", exitWithFixHint);\n\nconst AUTOMATED_ENVIRONMENT_VARIABLES = [\n \"CI\",\n \"CLAUDECODE\",\n \"CURSOR_AGENT\",\n \"CODEX_CI\",\n \"OPENCODE\",\n \"AMP_HOME\",\n \"AMI\",\n];\n\nconst isAutomatedEnvironment = (): boolean =>\n AUTOMATED_ENVIRONMENT_VARIABLES.some((envVariable) => Boolean(process.env[envVariable]));\n\nconst resolveCliScanOptions = (\n flags: CliFlags,\n userConfig: ReactDoctorConfig | null,\n programInstance: Command,\n): ScanOptions => {\n const isCliOverride = (optionName: string) =>\n programInstance.getOptionValueSource(optionName) === \"cli\";\n\n return {\n lint: isCliOverride(\"lint\") ? flags.lint : (userConfig?.lint ?? flags.lint),\n deadCode: isCliOverride(\"deadCode\") ? flags.deadCode : (userConfig?.deadCode ?? flags.deadCode),\n verbose: isCliOverride(\"verbose\") ? Boolean(flags.verbose) : (userConfig?.verbose ?? false),\n scoreOnly: flags.score,\n offline: flags.offline,\n };\n};\n\nconst resolveDiffMode = async (\n diffInfo: DiffInfo | null,\n effectiveDiff: boolean | string | undefined,\n shouldSkipPrompts: boolean,\n isScoreOnly: boolean,\n): Promise<boolean> => {\n if (effectiveDiff !== undefined && effectiveDiff !== false) {\n if (diffInfo) return true;\n if (!isScoreOnly) {\n logger.warn(\"No feature branch or uncommitted changes detected. Running full scan.\");\n logger.break();\n }\n return false;\n }\n\n if (effectiveDiff === false || !diffInfo) return false;\n\n const changedSourceFiles = filterSourceFiles(diffInfo.changedFiles);\n if (changedSourceFiles.length === 0) return false;\n if (shouldSkipPrompts) return true;\n if (isScoreOnly) return false;\n\n const promptMessage = diffInfo.isCurrentChanges\n ? `Found ${changedSourceFiles.length} uncommitted changed files. Only scan current changes?`\n : `On branch ${diffInfo.currentBranch} (${changedSourceFiles.length} changed files vs ${diffInfo.baseBranch}). Only scan this branch?`;\n\n const { shouldScanChangedOnly } = await prompts({\n type: \"confirm\",\n name: \"shouldScanChangedOnly\",\n message: promptMessage,\n initial: true,\n });\n return Boolean(shouldScanChangedOnly);\n};\n\nconst program = new Command()\n .name(\"react-doctor\")\n .description(\"Diagnose React codebase health\")\n .version(VERSION, \"-v, --version\", \"display the version number\")\n .argument(\"[directory]\", \"project directory to scan\", \".\")\n .option(\"--no-lint\", \"skip linting\")\n .option(\"--no-dead-code\", \"skip dead code detection\")\n .option(\"--verbose\", \"show file details per rule\")\n .option(\"--score\", \"output only the score\")\n .option(\"-y, --yes\", \"skip prompts, scan all workspace projects\")\n .option(\"--project <name>\", \"select workspace project (comma-separated for multiple)\")\n .option(\"--diff [base]\", \"scan only files changed vs base branch\")\n .option(\"--offline\", \"skip telemetry (anonymous, not stored, only used to calculate score)\")\n .option(\"--no-ami\", \"skip Ami-related prompts\")\n .option(\"--fix\", \"open Ami to auto-fix all issues\")\n .action(async (directory: string, flags: CliFlags) => {\n const isScoreOnly = flags.score;\n\n try {\n const resolvedDirectory = path.resolve(directory);\n const userConfig = loadConfig(resolvedDirectory);\n\n if (!isScoreOnly) {\n logger.log(`react-doctor v${VERSION}`);\n logger.break();\n }\n\n const scanOptions = resolveCliScanOptions(flags, userConfig, program);\n const shouldSkipPrompts = flags.yes || isAutomatedEnvironment() || !process.stdin.isTTY;\n const shouldSkipAmiPrompts = shouldSkipPrompts || !flags.ami;\n const projectDirectories = await selectProjects(\n resolvedDirectory,\n flags.project,\n shouldSkipPrompts,\n );\n\n const isDiffCliOverride = program.getOptionValueSource(\"diff\") === \"cli\";\n const effectiveDiff = isDiffCliOverride ? flags.diff : userConfig?.diff;\n const explicitBaseBranch = typeof effectiveDiff === \"string\" ? effectiveDiff : undefined;\n const diffInfo = getDiffInfo(resolvedDirectory, explicitBaseBranch);\n const isDiffMode = await resolveDiffMode(\n diffInfo,\n effectiveDiff,\n shouldSkipPrompts,\n isScoreOnly,\n );\n\n if (isDiffMode && diffInfo && !isScoreOnly) {\n if (diffInfo.isCurrentChanges) {\n logger.log(\"Scanning uncommitted changes\");\n } else {\n logger.log(\n `Scanning changes: ${highlighter.info(diffInfo.currentBranch)} → ${highlighter.info(diffInfo.baseBranch)}`,\n );\n }\n logger.break();\n }\n\n const allDiagnostics: Diagnostic[] = [];\n\n for (const projectDirectory of projectDirectories) {\n let includePaths: string[] | undefined;\n if (isDiffMode) {\n const projectDiffInfo = getDiffInfo(projectDirectory, explicitBaseBranch);\n if (projectDiffInfo) {\n const changedSourceFiles = filterSourceFiles(projectDiffInfo.changedFiles);\n if (changedSourceFiles.length === 0) {\n if (!isScoreOnly) {\n logger.dim(`No changed source files in ${projectDirectory}, skipping.`);\n logger.break();\n }\n continue;\n }\n includePaths = changedSourceFiles;\n }\n }\n\n if (!isScoreOnly) {\n logger.dim(`Scanning ${projectDirectory}...`);\n logger.break();\n }\n const scanResult = await scan(projectDirectory, { ...scanOptions, includePaths });\n allDiagnostics.push(...scanResult.diagnostics);\n if (!isScoreOnly) {\n logger.break();\n }\n }\n\n if (flags.fix) {\n openAmiToFix(resolvedDirectory);\n }\n\n if (!isScoreOnly && !shouldSkipAmiPrompts && !flags.fix) {\n await maybePromptSkillInstall(shouldSkipAmiPrompts);\n const estimatedScoreResult = flags.offline\n ? null\n : await fetchEstimatedScore(allDiagnostics);\n await maybePromptFix(resolvedDirectory, allDiagnostics, estimatedScoreResult);\n }\n } catch (error) {\n handleError(error);\n }\n })\n .addHelpText(\n \"after\",\n `\n${highlighter.dim(\"Learn more:\")}\n ${highlighter.info(\"https://github.com/millionco/react-doctor\")}\n`,\n );\n\nconst DEEPLINK_FIX_PROMPT = \"/{slash-command:ami:react-doctor}\";\n\nconst isAmiInstalled = (): boolean => {\n if (process.platform === \"darwin\") {\n return (\n existsSync(\"/Applications/Ami.app\") ||\n existsSync(path.join(os.homedir(), \"Applications\", \"Ami.app\"))\n );\n }\n\n if (process.platform === \"win32\") {\n const { LOCALAPPDATA, PROGRAMFILES } = process.env;\n return (\n Boolean(LOCALAPPDATA && existsSync(path.join(LOCALAPPDATA, \"Programs\", \"Ami\", \"Ami.exe\"))) ||\n Boolean(PROGRAMFILES && existsSync(path.join(PROGRAMFILES, \"Ami\", \"Ami.exe\")))\n );\n }\n\n try {\n execSync(\"which ami\", { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n};\n\nconst installAmi = (): void => {\n logger.log(\"Installing Ami...\");\n logger.break();\n try {\n execSync(`curl -fsSL ${AMI_INSTALL_URL} | bash`, { stdio: \"inherit\" });\n } catch {\n logger.error(`Failed to install Ami. Visit ${AMI_WEBSITE_URL} to install manually.`);\n process.exit(1);\n }\n logger.break();\n};\n\nconst openUrl = (url: string): void => {\n if (process.platform === \"win32\") {\n // HACK: cmd.exe interprets %XX% as env var expansion, which mangles encoded URLs.\n // Escaping % as %% produces literal % in cmd output.\n const cmdEscapedUrl = url.replace(/%/g, \"%%\");\n execSync(`start \"\" \"${cmdEscapedUrl}\"`, { stdio: \"ignore\" });\n return;\n }\n const openCommand = process.platform === \"darwin\" ? `open \"${url}\"` : `xdg-open \"${url}\"`;\n execSync(openCommand, { stdio: \"ignore\" });\n};\n\nconst buildDeeplinkParams = (directory: string): URLSearchParams => {\n const params = new URLSearchParams();\n params.set(\"cwd\", path.resolve(directory));\n params.set(\"prompt\", DEEPLINK_FIX_PROMPT);\n params.set(\"mode\", \"agent\");\n params.set(\"autoSubmit\", \"true\");\n params.set(\"source\", \"react-doctor\");\n return params;\n};\n\nconst buildDeeplink = (directory: string): string =>\n `ami://open-project?${buildDeeplinkParams(directory).toString()}`;\n\nconst buildWebDeeplink = (directory: string): string =>\n `${OPEN_BASE_URL}?${buildDeeplinkParams(directory).toString()}`;\n\nconst openAmiToFix = (directory: string): void => {\n const isInstalled = isAmiInstalled();\n const deeplink = buildDeeplink(directory);\n const webDeeplink = buildWebDeeplink(directory);\n\n if (!isInstalled) {\n if (process.platform === \"darwin\") {\n installAmi();\n logger.success(\"Ami installed successfully.\");\n } else {\n logger.error(\"Ami is not installed.\");\n logger.dim(`Download at ${highlighter.info(AMI_RELEASES_URL)}`);\n }\n logger.break();\n logger.dim(\"Open this link to start fixing:\");\n logger.info(webDeeplink);\n return;\n }\n\n logger.log(\"Opening Ami...\");\n\n try {\n openUrl(deeplink);\n logger.success(\"Ami opened. Fixing your issues now.\");\n } catch {\n logger.break();\n logger.dim(\"Could not open Ami automatically. Open this link instead:\");\n logger.info(webDeeplink);\n }\n};\n\nconst FIX_METHOD_AMI = \"ami\";\nconst FIX_COMMAND_HINT = \"npx react-doctor@latest --fix\";\n\nconst buildAmiBanner = (\n issueCount: number,\n currentScore: number,\n estimatedScore: number,\n): string => {\n const currentScoreDisplay = colorizeByScore(String(currentScore), currentScore);\n const estimatedScoreDisplay = colorizeByScore(`~${estimatedScore}`, estimatedScore);\n const issueLabel = issueCount === 1 ? \"issue\" : \"issues\";\n\n return renderFramedBoxString([\n createFramedLine(\n `Score: ${currentScore} → ~${estimatedScore}`,\n `Score: ${currentScoreDisplay} ${highlighter.dim(\"→\")} ${estimatedScoreDisplay}`,\n ),\n createFramedLine(\"\"),\n createFramedLine(\n `Ami is a coding agent built for React. It reads`,\n `${highlighter.info(\"Ami\")} is a coding agent built for React. It reads`,\n ),\n createFramedLine(\"your react-doctor report, understands your codebase,\"),\n createFramedLine(\n `and fixes ${issueCount} ${issueLabel} one by one — then re-runs the`,\n `and fixes ${highlighter.warn(String(issueCount))} ${issueLabel} one by one — then re-runs the`,\n ),\n createFramedLine(\"scan to verify the score improved.\"),\n createFramedLine(\"\"),\n createFramedLine(\n `Free to use. ${AMI_WEBSITE_URL}`,\n `Free to use. ${highlighter.info(AMI_WEBSITE_URL)}`,\n ),\n ]);\n};\n\nconst buildSkipBanner = (issueCount: number, estimatedScore: number): string => {\n const issueLabel = issueCount === 1 ? \"issue\" : \"issues\";\n const estimatedScoreDisplay = colorizeByScore(`~${estimatedScore}`, estimatedScore);\n\n return renderFramedBoxString([\n createFramedLine(\n `Skip fixing ${issueCount} ${issueLabel} and reaching ~${estimatedScore}?`,\n `Skip fixing ${highlighter.warn(String(issueCount))} ${issueLabel} and reaching ${estimatedScoreDisplay}?`,\n ),\n createFramedLine(\"\"),\n createFramedLine(\n `Run ${FIX_COMMAND_HINT} anytime to come back.`,\n `Run ${highlighter.info(FIX_COMMAND_HINT)} anytime to come back.`,\n ),\n ]);\n};\n\nconst configureFixBanners = (\n issueCount: number,\n estimatedScoreResult: EstimatedScoreResult,\n): void => {\n const { currentScore, estimatedScore } = estimatedScoreResult;\n setSelectBanner(buildAmiBanner(issueCount, currentScore, estimatedScore), 0);\n setSelectBanner(buildSkipBanner(issueCount, estimatedScore), 1);\n};\n\nconst maybePromptFix = async (\n directory: string,\n diagnostics: Diagnostic[],\n estimatedScoreResult: EstimatedScoreResult | null,\n): Promise<void> => {\n if (diagnostics.length === 0) return;\n\n logger.break();\n\n if (estimatedScoreResult) {\n configureFixBanners(diagnostics.length, estimatedScoreResult);\n }\n\n const { fixMethod } = await prompts({\n type: \"select\",\n name: \"fixMethod\",\n message: \"Fix issues?\",\n choices: [\n {\n title: \"Use Ami (recommended)\",\n description: \"Optimized coding agent for React Doctor\",\n value: FIX_METHOD_AMI,\n },\n { title: \"Skip\", value: \"skip\" },\n ],\n });\n\n clearSelectBanner();\n\n if (fixMethod === FIX_METHOD_AMI) {\n openAmiToFix(directory);\n } else {\n logger.break();\n logger.dim(` Run ${highlighter.info(FIX_COMMAND_HINT)} anytime to fix issues.`);\n }\n};\n\nconst fixAction = (directory: string) => {\n try {\n openAmiToFix(directory);\n } catch (error) {\n handleError(error);\n }\n};\n\nconst fixCommand = new Command(\"fix\")\n .description(\"Open Ami to auto-fix react-doctor issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nconst installAmiCommand = new Command(\"install-ami\")\n .description(\"Install Ami and open it to auto-fix issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nprogram.addCommand(fixCommand);\nprogram.addCommand(installAmiCommand);\n\nconst main = async () => {\n await program.parseAsync();\n};\n\nmain();\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,MAAa,sBAAsB;AAEnC,MAAa,mBAAmB;AAEhC,MAAa,0BAA0B;AAEvC,MAAa,6BAA6B;AAE1C,MAAa,gBAAgB;AAE7B,MAAa,uBAAuB;AAEpC,MAAa,qBAAqB;AAElC,MAAa,wBAAwB;AAErC,MAAa,uCAAuC;AAEpD,MAAa,iCAAiC;AAE9C,MAAa,gBAAgB;AAE7B,MAAa,yBAAyB;AAEtC,MAAa,iBAAiB;AAE9B,MAAa,gBAAgB;AAE7B,MAAa,mBAAmB;AAEhC,MAAa,gCAAgC,KAAK,OAAO;AAIzD,MAAa,8BAA8B;AAE3C,MAAa,kBACX;AAEF,MAAa,uBAAuB;AAEpC,MAAa,4BAA4B,CAAC,QAAQ,SAAS;AAE3D,MAAa,qBAAqB;AAElC,MAAa,uBAAuB;AAEpC,MAAa,2BAA2B;AAExC,MAAa,6BAA6B;AAE1C,MAAa,mBAAmB;AAEhC,MAAa,kBAAkB;AAE/B,MAAa,kBAAkB,GAAG,gBAAgB;AAElD,MAAa,mBAAmB;;;;ACtDhC,MAAM,sBAAsB,QAAoC;AAC9D,KAAI;EACF,MAAM,QAAQ,SAAS,kBAAkB,OAAO;GAC9C,UAAU;GACV,OAAO;IAAC;IAAQ;IAAQ;IAAS;GAClC,CAAC,CAAC,MAAM;AACT,MAAI,SAAS,UAAU,UAAU,UAAU,YAAa,QAAO;SACzD;;AAIV,MAAM,wBACJ,QAAQ,IAAI,eACZ,QAAQ,IAAI,eACZ,QAAQ,IAAI,cACZ,QAAQ,IAAI,cACZ,mBAAmB,cAAc,IACjC,mBAAmB,QAAQ;AAE7B,IAAI,qBAAqB;AACzB,IAAI;AAEJ,MAAM,oBAAwC;AAC5C,KAAI,mBAAoB,QAAO;AAC/B,sBAAqB;AACrB,oBAAmB,iBAAiB;AACpC,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;;;;;;AC5C3B,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,MAAM,wBAAwB,gBAAoD;CAChF,MAAM,EAAE,gBAAgB,qBAAqB,iBAAiB,YAAY;CAE1E,MAAM,eAAe,oBAAoB,gBAAgB,iBAAiB;CAO1E,MAAM,iBAAiB,oBANgB,KAAK,MAC1C,kBAAkB,IAAI,0BACvB,EACwC,KAAK,MAC5C,oBAAoB,IAAI,4BACzB,CAIA;AAED,QAAO;EACL;EACA,cAAc,cAAc,aAAa;EACzC;EACA,gBAAgB,cAAc,eAAe;EAC9C;;AAGH,MAAa,iBAAiB,OAAO,gBAA2D;AAC9F,KAAI;EACF,MAAM,WAAW,MAAM,WAAW,eAAe;GAC/C,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU,EAAE,aAAa,CAAC;GACtC,CAAC;AAEF,MAAI,CAAC,SAAS,GAAI,QAAO;AAEzB,SAAQ,MAAM,SAAS,MAAM;SACvB;AACN,SAAO;;;AAIX,MAAa,sBAAsB,OACjC,gBACyC;AACzC,KAAI;EACF,MAAM,WAAW,MAAM,WAAW,wBAAwB;GACxD,QAAQ;GACR,SAAS,EAAE,gBAAgB,oBAAoB;GAC/C,MAAM,KAAK,UAAU,EAAE,aAAa,CAAC;GACtC,CAAC;AAEF,MAAI,CAAC,SAAS,GAAI,QAAO,qBAAqB,YAAY;AAE1D,SAAQ,MAAM,SAAS,MAAM;SACvB;AACN,SAAO,qBAAqB,YAAY;;;;;;AC9F5C,MAAa,cAAc;CACzB,OAAO,GAAG;CACV,MAAM,GAAG;CACT,MAAM,GAAG;CACT,SAAS,GAAG;CACZ,KAAK,GAAG;CACT;;;;ACLD,MAAa,mBAAmB,MAAc,UAA0B;AACtE,KAAI,SAAS,qBAAsB,QAAO,YAAY,QAAQ,KAAK;AACnE,KAAI,SAAS,mBAAoB,QAAO,YAAY,KAAK,KAAK;AAC9D,QAAO,YAAY,MAAM,KAAK;;;;;ACwPhC,MAAa,0BAA0B,IAAI,IAAI,CAAC,iBAAiB,SAAS,CAAC;;;;AC3P3E,MAAa,mBAAmB,oBAC9B,KAAK,MAAM,GAAG,aAAa,iBAAiB,QAAQ,CAAC;;;;ACGvD,MAAM,8BAA8B;AACpC,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,GAAG,WAAW,gBAAgB,CAAE,QAAO,EAAE;CAE9C,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;;;;;;AC/C9C,MAAM,2BAA2B;AAEjC,MAAa,sBAAsB,YAA4B;CAC7D,MAAM,oBAAoB,QAAQ,QAAQ,OAAO,IAAI;CAErD,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,MAAa,4BACX,aACA,WACiB;CACjB,MAAM,eAAe,IAAI,IAAI,MAAM,QAAQ,OAAO,QAAQ,MAAM,GAAG,OAAO,OAAO,QAAQ,EAAE,CAAC;CAC5F,MAAM,sBAAsB,MAAM,QAAQ,OAAO,QAAQ,MAAM,GAC3D,OAAO,OAAO,MAAM,IAAI,mBAAmB,GAC3C,EAAE;AAEN,KAAI,aAAa,SAAS,KAAK,oBAAoB,WAAW,EAC5D,QAAO;AAGT,QAAO,YAAY,QAAQ,eAAe;EACxC,MAAM,iBAAiB,GAAG,WAAW,OAAO,GAAG,WAAW;AAC1D,MAAI,aAAa,IAAI,eAAe,CAClC,QAAO;EAGT,MAAM,iBAAiB,WAAW,SAAS,QAAQ,OAAO,IAAI,CAAC,QAAQ,SAAS,GAAG;AACnF,MAAI,oBAAoB,MAAM,YAAY,QAAQ,KAAK,eAAe,CAAC,CACrE,QAAO;AAGT,SAAO;GACP;;;;;ACvBJ,MAAa,0BAA0B,iBACrC,aAAa,SAAS,IAClB,aAAa,QAAQ,aAAa,iBAAiB,KAAK,SAAS,CAAC,GAClE;AAEN,MAAa,sBACX,iBACA,qBACA,WACA,YACA,eACiB;CACjB,MAAM,iBAAiB;EACrB,GAAG;EACH,GAAG;EACH,GAAI,aAAa,EAAE,GAAG,mBAAmB,UAAU;EACpD;AACD,QAAO,aAAa,yBAAyB,gBAAgB,WAAW,GAAG;;;;;AClB7E,MAAa,kBAAkB,cAA+B;AAC5D,KAAI,GAAG,WAAW,KAAK,KAAK,WAAW,sBAAsB,CAAC,CAAE,QAAO;CACvE,MAAM,kBAAkB,KAAK,KAAK,WAAW,eAAe;AAC5D,KAAI,CAAC,GAAG,WAAW,gBAAgB,CAAE,QAAO;CAC5C,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;;;;;ACNT,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,gCAAgC;AAEtC,MAAM,qBAAgD;CACpD,MAAM;CACN,MAAM;CACN,iBAAiB;CACjB,oBAAoB;CACpB,QAAQ;CACT;AAED,MAAM,0BAAqD;CACzD,QAAQ;CACR,MAAM;CACN,KAAK;CACL,OAAO;CACP,QAAQ;CACR,SAAS;CACV;AAED,MAAa,uBAAuB,cAClC,wBAAwB;AAE1B,MAAM,oBAAoB,kBAAkC;CAC1D,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,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,yBAAyB,gBAA6C;CAC1E,MAAM,kBAAkB,uBAAuB,YAAY;AAC3D,QAAO;EACL,cAAc,gBAAgB,SAAS;EACvC,WAAW,gBAAgB,gBAAgB;EAC5C;;AAGH,MAAM,8BAA8B,kBAAoC;CACtE,MAAM,gBAAgB,KAAK,KAAK,eAAe,sBAAsB;AACrE,KAAI,CAAC,GAAG,WAAW,cAAc,CAAE,QAAO,EAAE;CAE5C,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,GAAG,WAAW,KAAK,KAAK,eAAe,eAAe,CAAC,CACzF,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,GAAG,WAAW,KAAK,KAAK,WAAW,eAAe,CAAC,CACtD;;AAGL,MAAM,sCAAsC,cAAsC;CAChF,MAAM,eAAe,iBAAiB,UAAU;AAChD,KAAI,CAAC,aAAc,QAAO;EAAE,cAAc;EAAM,WAAW;EAAW;CAEtE,MAAM,kBAAkB,gBAAgB,KAAK,KAAK,cAAc,eAAe,CAAC;CAChF,MAAM,WAAW,sBAAsB,gBAAgB;CACvD,MAAM,gBAAgB,sBAAsB,cAAc,gBAAgB;AAE1E,QAAO;EACL,cAAc,SAAS,gBAAgB,cAAc;EACrD,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;;AAGT,MAAM,sBAAsB,gBAAsC;CAChE,MAAM,kBAAkB,uBAAuB,YAAY;AAC3D,QAAO,OAAO,KAAK,gBAAgB,CAAC,MACjC,gBAAgB,gBAAgB,UAAU,YAAY,SAAS,QAAQ,CACzE;;AAGH,MAAa,4BAA4B,kBAA8C;AACrF,KAAI,CAAC,GAAG,WAAW,cAAc,IAAI,CAAC,GAAG,SAAS,cAAc,CAAC,aAAa,CAAE,QAAO,EAAE;CAEzF,MAAM,UAAU,GAAG,YAAY,eAAe,EAAE,eAAe,MAAM,CAAC;CACtE,MAAM,WAA+B,EAAE;AAEvC,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,CAAC,MAAM,aAAa,IAAI,MAAM,KAAK,WAAW,IAAI,IAAI,MAAM,SAAS,eACvE;EAGF,MAAM,eAAe,KAAK,KAAK,eAAe,MAAM,KAAK;EACzD,MAAM,kBAAkB,KAAK,KAAK,cAAc,eAAe;AAC/D,MAAI,CAAC,GAAG,WAAW,gBAAgB,CAAE;EAErC,MAAM,cAAc,gBAAgB,gBAAgB;AACpD,MAAI,CAAC,mBAAmB,YAAY,CAAE;EAEtC,MAAM,OAAO,YAAY,QAAQ,MAAM;AACvC,WAAS,KAAK;GAAE;GAAM,WAAW;GAAc,CAAC;;AAGlD,QAAO;;AAGT,MAAa,yBAAyB,kBAA8C;CAClF,MAAM,kBAAkB,KAAK,KAAK,eAAe,eAAe;AAChE,KAAI,CAAC,GAAG,WAAW,gBAAgB,CAAE,QAAO,EAAE;CAG9C,MAAM,WAAW,qBAAqB,eADlB,gBAAgB,gBAAgB,CACa;AACjE,KAAI,SAAS,WAAW,EAAG,QAAO,EAAE;CAEpC,MAAM,WAA+B,EAAE;AAEvC,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,cAAc,4BAA4B,eAAe,QAAQ;AACvE,OAAK,MAAM,sBAAsB,aAAa;GAC5C,MAAM,uBAAuB,gBAAgB,KAAK,KAAK,oBAAoB,eAAe,CAAC;AAE3F,OAAI,CAAC,mBAAmB,qBAAqB,CAAE;GAE/C,MAAM,OAAO,qBAAqB,QAAQ,KAAK,SAAS,mBAAmB;AAC3E,YAAS,KAAK;IAAE;IAAM,WAAW;IAAoB,CAAC;;;AAI1D,QAAO;;AAGT,MAAM,sBAAsB,gBAAsC;CAChE,MAAM,kBAAkB,uBAAuB,YAAY;AAC3D,QAAO,OAAO,KAAK,gBAAgB,CAAC,MAAM,gBACxC,wBAAwB,IAAI,YAAY,CACzC;;AAGH,MAAM,uBAAuB,UAAkB,YAA6B;AAC1E,KAAI,CAAC,GAAG,WAAW,SAAS,CAAE,QAAO;CACrC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;AAClD,QAAO,QAAQ,KAAK,QAAQ;;AAG9B,MAAM,4BAA4B,WAAmB,cACnD,UAAU,MAAM,aACd,oBAAoB,KAAK,KAAK,WAAW,SAAS,EAAE,8BAA8B,CACnF;AAEH,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,GAAG,WAAW,oBAAoB,EAEpC;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,GAAG,WAAW,gBAAgB,CACjC,OAAM,IAAI,MAAM,4BAA4B,YAAY;CAG1D,MAAM,cAAc,gBAAgB,gBAAgB;CACpD,IAAI,EAAE,cAAc,cAAc,sBAAsB,YAAY;AAEpE,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;;;;;ACjWH,MAAa,SAAS;CACpB,MAAM,GAAG,MAAiB;AACxB,UAAQ,IAAI,YAAY,MAAM,KAAK,KAAK,IAAI,CAAC,CAAC;;CAEhD,KAAK,GAAG,MAAiB;AACvB,UAAQ,IAAI,YAAY,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;;CAE/C,KAAK,GAAG,MAAiB;AACvB,UAAQ,IAAI,YAAY,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC;;CAE/C,QAAQ,GAAG,MAAiB;AAC1B,UAAQ,IAAI,YAAY,QAAQ,KAAK,KAAK,IAAI,CAAC,CAAC;;CAElD,IAAI,GAAG,MAAiB;AACtB,UAAQ,IAAI,YAAY,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;;CAE9C,IAAI,GAAG,MAAiB;AACtB,UAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;;CAE7B,QAAQ;AACN,UAAQ,IAAI,GAAG;;CAElB;;;;ACZD,MAAa,oBACX,WACA,eAAuB,eACP;CAChB;CACA;CACD;AAED,MAAa,yBAAyB,gBAAsC;AAC1E,KAAI,YAAY,WAAW,EAAG,QAAO;CAErC,MAAM,kBAAkB,YAAY;CACpC,MAAM,cAAc,IAAI,OAAO,+BAA+B;CAC9D,MAAM,oBAAoB,IAAI,OAAO,qCAAqC;CAC1E,MAAM,oBAAoB,KAAK,IAC7B,GAAG,YAAY,KAAK,eAAe,WAAW,UAAU,OAAO,CAChE;CACD,MAAM,aAAa,IAAI,OAAO,oBAAoB,uCAAuC,EAAE;CAE3F,MAAM,QAAkB,EAAE;AAC1B,OAAM,KAAK,GAAG,cAAc,gBAAgB,IAAI,WAAW,GAAG,GAAG;AAEjE,MAAK,MAAM,cAAc,aAAa;EACpC,MAAM,iBAAiB,IAAI,OAAO,oBAAoB,WAAW,UAAU,OAAO;AAClF,QAAM,KACJ,GAAG,cAAc,gBAAgB,IAAI,GAAG,oBAAoB,WAAW,eAAe,iBAAiB,oBAAoB,gBAAgB,IAAI,GAChJ;;AAGH,OAAM,KAAK,GAAG,cAAc,gBAAgB,IAAI,WAAW,GAAG,GAAG;AACjE,QAAO,MAAM,KAAK,KAAK;;AAGzB,MAAa,kBAAkB,gBAAoC;CACjE,MAAM,WAAW,sBAAsB,YAAY;AACnD,KAAI,SACF,QAAO,IAAI,SAAS;;;;;AChDxB,MAAa,WAAc,OAAY,UAAiD;CACtF,MAAM,yBAAS,IAAI,KAAkB;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,MAAM,MAAM,KAAK;EACvB,MAAM,WAAW,OAAO,IAAI,IAAI,IAAI,EAAE;AACtC,WAAS,KAAK,KAAK;AACnB,SAAO,IAAI,KAAK,SAAS;;AAG3B,QAAO;;;;;ACVT,MAAa,uBAAuB,MAAc,eAChD,KACG,MAAM,KAAK,CACX,KAAK,aAAa,GAAG,aAAa,WAAW,CAC7C,KAAK,KAAK;;;;ACAf,MAAM,kBAAkB;AACxB,MAAM,0BAA0B;AAEhC,MAAM,iBAAiB,UACrB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;AAEtE,MAAa,cAAc,kBAAoD;CAC7E,MAAM,iBAAiB,KAAK,KAAK,eAAe,gBAAgB;AAEhE,KAAI,GAAG,WAAW,eAAe,CAC/B,KAAI;EACF,MAAM,cAAc,GAAG,aAAa,gBAAgB,QAAQ;EAC5D,MAAM,SAAkB,KAAK,MAAM,YAAY;AAC/C,MAAI,CAAC,cAAc,OAAO,EAAE;AAC1B,WAAQ,KAAK,YAAY,gBAAgB,mCAAmC;AAC5E,UAAO;;AAET,SAAO;UACA,OAAO;AACd,UAAQ,KACN,4BAA4B,gBAAgB,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACvG;AACD,SAAO;;CAIX,MAAM,kBAAkB,KAAK,KAAK,eAAe,eAAe;AAChE,KAAI,GAAG,WAAW,gBAAgB,CAChC,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;;;;;ACpCT,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,OACzB,SACA,kBACyB;CACzB,MAAM,UAAU,MAAM,eACpB,cAAc;EACZ,KAAK;EACL,gBAAgB;EAChB,GAAI,gBAAgB,EAAE,WAAW,eAAe,GAAG,EAAE;EACtD,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,GAAG,WAAW,gBAAgB,GAC9C,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,cAAc,OAAO,MAC9B,aAAY,KAAK;EACf,UAAU,KAAK,SAAS,eAAe,WAAW;EAClD,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;;;;;ACrKT,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,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;AAQD,MAAa,sBAAsB,EACjC,YACA,WACA,wBAC0B;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,mBACA,CAAC;EAAE,MAAM;EAAkB,WAAWA,aAAW,QAAQ,4BAA4B;EAAE,CAAC,GACxF,EAAE,EACN,WACD;CACD,OAAO;EACL,wBAAwB;EACxB,kCAAkC;EAClC,gCAAgC;EAChC,iBAAiB;EACjB,0BAA0B;EAC1B,mBAAmB;EACnB,2BAA2B;EAC3B,gCAAgC;EAChC,wBAAwB;EACxB,uBAAuB;EACvB,+BAA+B;EAC/B,6BAA6B;EAE7B,qBAAqB;EACrB,4BAA4B;EAC5B,yCAAyC;EACzC,2CAA2C;EAC3C,mDAAmD;EACnD,yCAAyC;EACzC,yBAAyB;EACzB,gCAAgC;EAChC,0BAA0B;EAC1B,+BAA+B;EAC/B,kBAAkB;EAClB,iCAAiC;EACjC,yCAAyC;EACzC,oCAAoC;EACpC,6BAA6B;EAE7B,GAAI,mBAAmB,uBAAuB,EAAE;EAEhD,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;EAE/C,kCAAkC;EAClC,iDAAiD;EACjD,uCAAuC;EACvC,mCAAmC;EACnC,yCAAyC;EAEzC,0CAA0C;EAE1C,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,+BAA+B;EAC/B,GAAI,cAAc,WAAW,eAAe,EAAE;EAC/C;CACF;;;;ACjJD,MAAM,kCAAkC,kBAAoC;CAC1E,MAAM,SAAS,UAAU,OAAO;EAAC;EAAQ;EAAM;EAAe;EAAM;EAA0B,EAAE;EAC9F,KAAK;EACL,UAAU;EACV,WAAW;EACZ,CAAC;AAEF,KAAI,OAAO,SAAS,OAAO,WAAW,KAAM,QAAO,EAAE;AAErD,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,+BAA+B,kBAAwC;CAClF,MAAM,YAAY,+BAA+B,cAAc;CAC/D,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;;;;;;AChCrD,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;CAE/C,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,+BAA+B;CAChC;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;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,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,kBACE;CACH;AAED,MAAM,iCA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"}
1
+ {"version":3,"file":"cli.js","names":["esmRequire","main"],"sources":["../src/constants.ts","../src/utils/proxy-fetch.ts","../src/utils/calculate-score.ts","../src/utils/highlighter.ts","../src/utils/colorize-by-score.ts","../src/plugin/constants.ts","../src/utils/read-package-json.ts","../src/utils/check-reduced-motion.ts","../src/utils/match-glob-pattern.ts","../src/utils/filter-diagnostics.ts","../src/utils/combine-diagnostics.ts","../src/utils/find-monorepo-root.ts","../src/utils/discover-project.ts","../src/utils/logger.ts","../src/utils/framed-box.ts","../src/utils/group-by.ts","../src/utils/indent-multiline-text.ts","../src/utils/load-config.ts","../src/utils/should-auto-select-current-choice.ts","../src/utils/should-select-all-choices.ts","../src/utils/prompts.ts","../src/utils/resolve-compatible-node.ts","../src/utils/run-knip.ts","../src/oxlint-config.ts","../src/utils/neutralize-disable-directives.ts","../src/utils/run-oxlint.ts","../src/utils/spinner.ts","../src/scan.ts","../src/utils/get-diff-files.ts","../src/utils/handle-error.ts","../src/utils/select-projects.ts","../src/utils/skill-prompt.ts","../src/cli.ts"],"sourcesContent":["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 ESTIMATE_SCORE_API_URL = \"https://www.react.doctor/api/estimate-score\";\n\nexport const SHARE_BASE_URL = \"https://www.react.doctor/share\";\n\nexport const OPEN_BASE_URL = \"https://www.react.doctor/open\";\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\nexport const OFFLINE_MESSAGE =\n \"You are offline, could not calculate score. Reconnect to calculate.\";\n\nexport const OFFLINE_FLAG_MESSAGE = \"Score not calculated. Remove --offline to calculate score.\";\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 ERROR_ESTIMATED_FIX_RATE = 0.85;\n\nexport const WARNING_ESTIMATED_FIX_RATE = 0.8;\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 AMI_WEBSITE_URL = \"https://ami.dev\";\n\nexport const AMI_INSTALL_URL = `${AMI_WEBSITE_URL}/install.sh`;\n\nexport const AMI_RELEASES_URL = \"https://github.com/millionco/ami-releases/releases\";\n","import { execSync } from \"node:child_process\";\nimport { FETCH_TIMEOUT_MS } from \"../constants.js\";\n\nconst readNpmConfigValue = (key: string): string | undefined => {\n try {\n const value = execSync(`npm config get ${key}`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n }).trim();\n if (value && value !== \"null\" && value !== \"undefined\") return value;\n } catch {}\n return undefined;\n};\n\nconst resolveProxyUrl = (): string | undefined =>\n process.env.HTTPS_PROXY ??\n process.env.https_proxy ??\n process.env.HTTP_PROXY ??\n process.env.http_proxy ??\n readNpmConfigValue(\"https-proxy\") ??\n readNpmConfigValue(\"proxy\");\n\nlet isProxyUrlResolved = false;\nlet resolvedProxyUrl: string | undefined;\n\nconst getProxyUrl = (): string | undefined => {\n if (isProxyUrlResolved) return resolvedProxyUrl;\n isProxyUrlResolved = true;\n resolvedProxyUrl = resolveProxyUrl();\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 {\n ERROR_ESTIMATED_FIX_RATE,\n ERROR_RULE_PENALTY,\n ESTIMATE_SCORE_API_URL,\n PERFECT_SCORE,\n SCORE_API_URL,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n WARNING_ESTIMATED_FIX_RATE,\n WARNING_RULE_PENALTY,\n} from \"../constants.js\";\nimport type { Diagnostic, EstimatedScoreResult, ScoreResult } from \"../types.js\";\nimport { proxyFetch } from \"./proxy-fetch.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\nconst estimateScoreLocally = (diagnostics: Diagnostic[]): EstimatedScoreResult => {\n const { errorRuleCount, warningRuleCount } = countUniqueRules(diagnostics);\n\n const currentScore = scoreFromRuleCounts(errorRuleCount, warningRuleCount);\n const estimatedUnfixedErrorRuleCount = Math.round(\n errorRuleCount * (1 - ERROR_ESTIMATED_FIX_RATE),\n );\n const estimatedUnfixedWarningRuleCount = Math.round(\n warningRuleCount * (1 - WARNING_ESTIMATED_FIX_RATE),\n );\n const estimatedScore = scoreFromRuleCounts(\n estimatedUnfixedErrorRuleCount,\n estimatedUnfixedWarningRuleCount,\n );\n\n return {\n currentScore,\n currentLabel: getScoreLabel(currentScore),\n estimatedScore,\n estimatedLabel: getScoreLabel(estimatedScore),\n };\n};\n\nexport const calculateScore = async (diagnostics: Diagnostic[]): Promise<ScoreResult | null> => {\n try {\n const response = await proxyFetch(SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics }),\n });\n\n if (!response.ok) return null;\n\n return (await response.json()) as ScoreResult;\n } catch {\n return null;\n }\n};\n\nexport const fetchEstimatedScore = async (\n diagnostics: Diagnostic[],\n): Promise<EstimatedScoreResult | null> => {\n try {\n const response = await proxyFetch(ESTIMATE_SCORE_API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ diagnostics }),\n });\n\n if (!response.ok) return estimateScoreLocally(diagnostics);\n\n return (await response.json()) as EstimatedScoreResult;\n } catch {\n return estimateScoreLocally(diagnostics);\n }\n};\n","import pc from \"picocolors\";\n\nexport const highlighter = {\n error: pc.red,\n warn: pc.yellow,\n info: pc.cyan,\n success: pc.green,\n dim: pc.dim,\n};\n","import { SCORE_GOOD_THRESHOLD, SCORE_OK_THRESHOLD } from \"../constants.js\";\nimport { highlighter } from \"./highlighter.js\";\n\nexport const colorizeByScore = (text: string, score: number): string => {\n if (score >= SCORE_GOOD_THRESHOLD) return highlighter.success(text);\n if (score >= SCORE_OK_THRESHOLD) return highlighter.warn(text);\n return highlighter.error(text);\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 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([\"Text\", \"TextInput\"]);\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\": \"expo-image with sf: source URIs\",\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","import fs from \"node:fs\";\nimport type { PackageJson } from \"../types.js\";\n\nexport const readPackageJson = (packageJsonPath: string): PackageJson =>\n JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\"));\n","import { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { MOTION_LIBRARY_PACKAGES } from \"../plugin/constants.js\";\nimport type { Diagnostic } from \"../types.js\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nconst REDUCED_MOTION_GREP_PATTERN = \"prefers-reduced-motion|useReducedMotion\";\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 (!fs.existsSync(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","const REGEX_SPECIAL_CHARACTERS = /[.+^${}()|[\\]\\\\]/g;\n\nexport const compileGlobPattern = (pattern: string): RegExp => {\n const normalizedPattern = pattern.replace(/\\\\/g, \"/\");\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 { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { compileGlobPattern } from \"./match-glob-pattern.js\";\n\nexport const filterIgnoredDiagnostics = (\n diagnostics: Diagnostic[],\n config: ReactDoctorConfig,\n): Diagnostic[] => {\n const ignoredRules = new Set(Array.isArray(config.ignore?.rules) ? config.ignore.rules : []);\n const ignoredFilePatterns = Array.isArray(config.ignore?.files)\n ? config.ignore.files.map(compileGlobPattern)\n : [];\n\n if (ignoredRules.size === 0 && ignoredFilePatterns.length === 0) {\n return diagnostics;\n }\n\n return diagnostics.filter((diagnostic) => {\n const ruleIdentifier = `${diagnostic.plugin}/${diagnostic.rule}`;\n if (ignoredRules.has(ruleIdentifier)) {\n return false;\n }\n\n const normalizedPath = diagnostic.filePath.replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n if (ignoredFilePatterns.some((pattern) => pattern.test(normalizedPath))) {\n return false;\n }\n\n return true;\n });\n};\n","import { JSX_FILE_PATTERN } from \"../constants.js\";\nimport type { Diagnostic, ReactDoctorConfig } from \"../types.js\";\nimport { checkReducedMotion } from \"./check-reduced-motion.js\";\nimport { filterIgnoredDiagnostics } from \"./filter-diagnostics.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\nexport const combineDiagnostics = (\n lintDiagnostics: Diagnostic[],\n deadCodeDiagnostics: Diagnostic[],\n directory: string,\n isDiffMode: boolean,\n userConfig: ReactDoctorConfig | null,\n): Diagnostic[] => {\n const allDiagnostics = [\n ...lintDiagnostics,\n ...deadCodeDiagnostics,\n ...(isDiffMode ? [] : checkReducedMotion(directory)),\n ];\n return userConfig ? filterIgnoredDiagnostics(allDiagnostics, userConfig) : allDiagnostics;\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { readPackageJson } from \"./read-package-json.js\";\n\nexport const isMonorepoRoot = (directory: string): boolean => {\n if (fs.existsSync(path.join(directory, \"pnpm-workspace.yaml\"))) return true;\n if (fs.existsSync(path.join(directory, \"nx.json\"))) return true;\n const packageJsonPath = path.join(directory, \"package.json\");\n if (!fs.existsSync(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","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { GIT_LS_FILES_MAX_BUFFER_BYTES, SOURCE_FILE_PATTERN } 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 { 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_CONFIG_PATTERN = /react-compiler|reactCompiler/;\n\nconst FRAMEWORK_PACKAGES: Record<string, Framework> = {\n next: \"nextjs\",\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 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 IGNORED_DIRECTORIES = new Set([\"node_modules\", \"dist\", \"build\", \"coverage\"]);\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 extractDependencyInfo = (packageJson: PackageJson): DependencyInfo => {\n const allDependencies = collectAllDependencies(packageJson);\n return {\n reactVersion: allDependencies.react ?? null,\n framework: detectFramework(allDependencies),\n };\n};\n\nconst parsePnpmWorkspacePatterns = (rootDirectory: string): string[] => {\n const workspacePath = path.join(rootDirectory, \"pnpm-workspace.yaml\");\n if (!fs.existsSync(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) && fs.existsSync(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 fs.existsSync(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 rootPackageJson = readPackageJson(path.join(monorepoRoot, \"package.json\"));\n const rootInfo = extractDependencyInfo(rootPackageJson);\n const workspaceInfo = findReactInWorkspaces(monorepoRoot, rootPackageJson);\n\n return {\n reactVersion: rootInfo.reactVersion ?? 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 (fs.existsSync(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 (!fs.existsSync(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 (!fs.existsSync(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 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 (!fs.existsSync(filePath)) return false;\n const content = fs.readFileSync(filePath, \"utf-8\");\n return pattern.test(content);\n};\n\nconst hasCompilerInConfigFiles = (directory: string, filenames: string[]): boolean =>\n filenames.some((filename) =>\n fileContainsPattern(path.join(directory, filename), REACT_COMPILER_CONFIG_PATTERN),\n );\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 (fs.existsSync(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 (!fs.existsSync(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 || 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 { highlighter } from \"./highlighter.js\";\n\nexport const logger = {\n error(...args: unknown[]) {\n console.log(highlighter.error(args.join(\" \")));\n },\n warn(...args: unknown[]) {\n console.log(highlighter.warn(args.join(\" \")));\n },\n info(...args: unknown[]) {\n console.log(highlighter.info(args.join(\" \")));\n },\n success(...args: unknown[]) {\n console.log(highlighter.success(args.join(\" \")));\n },\n dim(...args: unknown[]) {\n console.log(highlighter.dim(args.join(\" \")));\n },\n log(...args: unknown[]) {\n console.log(args.join(\" \"));\n },\n break() {\n console.log(\"\");\n },\n};\n","import {\n SUMMARY_BOX_HORIZONTAL_PADDING_CHARS,\n SUMMARY_BOX_OUTER_INDENT_CHARS,\n} from \"../constants.js\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\n\nexport interface FramedLine {\n plainText: string;\n renderedText: string;\n}\n\nexport const createFramedLine = (\n plainText: string,\n renderedText: string = plainText,\n): FramedLine => ({\n plainText,\n renderedText,\n});\n\nexport const renderFramedBoxString = (framedLines: FramedLine[]): string => {\n if (framedLines.length === 0) return \"\";\n\n const borderColorizer = highlighter.dim;\n const outerIndent = \" \".repeat(SUMMARY_BOX_OUTER_INDENT_CHARS);\n const horizontalPadding = \" \".repeat(SUMMARY_BOX_HORIZONTAL_PADDING_CHARS);\n const maximumLineLength = Math.max(\n ...framedLines.map((framedLine) => framedLine.plainText.length),\n );\n const borderLine = \"─\".repeat(maximumLineLength + SUMMARY_BOX_HORIZONTAL_PADDING_CHARS * 2);\n\n const lines: string[] = [];\n lines.push(`${outerIndent}${borderColorizer(`┌${borderLine}┐`)}`);\n\n for (const framedLine of framedLines) {\n const trailingSpaces = \" \".repeat(maximumLineLength - framedLine.plainText.length);\n lines.push(\n `${outerIndent}${borderColorizer(\"│\")}${horizontalPadding}${framedLine.renderedText}${trailingSpaces}${horizontalPadding}${borderColorizer(\"│\")}`,\n );\n }\n\n lines.push(`${outerIndent}${borderColorizer(`└${borderLine}┘`)}`);\n return lines.join(\"\\n\");\n};\n\nexport const printFramedBox = (framedLines: FramedLine[]): void => {\n const rendered = renderFramedBoxString(framedLines);\n if (rendered) {\n logger.log(rendered);\n }\n};\n","export const groupBy = <T>(items: T[], keyFn: (item: T) => string): Map<string, T[]> => {\n const groups = new Map<string, T[]>();\n\n for (const item of items) {\n const key = keyFn(item);\n const existing = groups.get(key) ?? [];\n existing.push(item);\n groups.set(key, existing);\n }\n\n return groups;\n};\n","export const indentMultilineText = (text: string, linePrefix: string): string =>\n text\n .split(\"\\n\")\n .map((lineText) => `${linePrefix}${lineText}`)\n .join(\"\\n\");\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { ReactDoctorConfig } from \"../types.js\";\n\nconst CONFIG_FILENAME = \"react-doctor.config.json\";\nconst PACKAGE_JSON_CONFIG_KEY = \"reactDoctor\";\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nexport const loadConfig = (rootDirectory: string): ReactDoctorConfig | null => {\n const configFilePath = path.join(rootDirectory, CONFIG_FILENAME);\n\n if (fs.existsSync(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(rootDirectory, \"package.json\");\n if (fs.existsSync(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","import type { PromptMultiselectChoiceState } from \"../types.js\";\n\nexport const shouldAutoSelectCurrentChoice = (\n choiceStates: PromptMultiselectChoiceState[],\n cursor: number,\n): boolean => {\n const hasSelection = choiceStates.some((choiceState) => choiceState.selected);\n if (hasSelection) return false;\n\n const currentChoice = choiceStates[cursor];\n return Boolean(currentChoice) && !currentChoice.disabled;\n};\n","import type { PromptMultiselectChoiceState } from \"../types.js\";\n\nexport const shouldSelectAllChoices = (choiceStates: PromptMultiselectChoiceState[]): boolean => {\n const enabledChoiceStates = choiceStates.filter((choiceState) => !choiceState.disabled);\n return enabledChoiceStates.some((choiceState) => choiceState.selected !== true);\n};\n","import { createRequire } from \"node:module\";\nimport basePrompts, { type PromptObject, type Answers } from \"prompts\";\nimport type { PromptMultiselectContext } from \"../types.js\";\nimport { logger } from \"./logger.js\";\nimport { shouldAutoSelectCurrentChoice } from \"./should-auto-select-current-choice.js\";\nimport { shouldSelectAllChoices } from \"./should-select-all-choices.js\";\n\nconst require = createRequire(import.meta.url);\nconst PROMPTS_MULTISELECT_MODULE_PATH = \"prompts/lib/elements/multiselect\";\nconst PROMPTS_SELECT_MODULE_PATH = \"prompts/lib/elements/select\";\nlet didPatchMultiselectToggleAll = false;\nlet didPatchMultiselectSubmit = false;\nlet didPatchSelectBanner = false;\n\nconst selectBannerMap = new Map<number, string>();\n\nexport const setSelectBanner = (banner: string, targetIndex: number): void => {\n selectBannerMap.set(targetIndex, banner);\n};\n\nexport const clearSelectBanner = (): void => {\n selectBannerMap.clear();\n};\n\nconst onCancel = () => {\n logger.break();\n logger.log(\"Cancelled.\");\n logger.dim(\"Run `npx react-doctor@latest --fix` to fix issues.\");\n logger.break();\n process.exit(0);\n};\n\nconst patchMultiselectToggleAll = (): void => {\n if (didPatchMultiselectToggleAll) return;\n didPatchMultiselectToggleAll = true;\n\n const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);\n\n multiselectPromptConstructor.prototype.toggleAll = function (\n this: PromptMultiselectContext,\n ): void {\n const isCurrentChoiceDisabled = Boolean(this.value[this.cursor]?.disabled);\n if (this.maxChoices !== undefined || isCurrentChoiceDisabled) {\n this.bell();\n return;\n }\n\n const shouldSelectAllEnabledChoices = shouldSelectAllChoices(this.value);\n\n for (const choiceState of this.value) {\n if (choiceState.disabled) continue;\n choiceState.selected = shouldSelectAllEnabledChoices;\n }\n\n this.render();\n };\n};\n\nconst patchMultiselectSubmit = (): void => {\n if (didPatchMultiselectSubmit) return;\n didPatchMultiselectSubmit = true;\n\n const multiselectPromptConstructor = require(PROMPTS_MULTISELECT_MODULE_PATH);\n const originalSubmit = multiselectPromptConstructor.prototype.submit;\n\n multiselectPromptConstructor.prototype.submit = function (this: PromptMultiselectContext): void {\n if (shouldAutoSelectCurrentChoice(this.value, this.cursor)) {\n this.value[this.cursor].selected = true;\n }\n originalSubmit.call(this);\n };\n};\n\ninterface SelectPromptInstance {\n closed: boolean;\n done: boolean;\n cursor: number;\n outputText: string;\n out: { write: (data: string) => boolean; columns: number };\n render: () => void;\n}\n\nconst patchSelectBanner = (): void => {\n if (didPatchSelectBanner) return;\n didPatchSelectBanner = true;\n\n const selectConstructor = require(PROMPTS_SELECT_MODULE_PATH);\n const promptsClear = require(\"prompts/lib/util/clear\");\n const originalRender = selectConstructor.prototype.render;\n\n selectConstructor.prototype.render = function (this: SelectPromptInstance): void {\n originalRender.call(this);\n\n const banner = selectBannerMap.get(this.cursor);\n if (!banner || this.closed || this.done) {\n return;\n }\n\n this.out.write(promptsClear(this.outputText, this.out.columns));\n this.outputText = `${banner}\\n\\n${this.outputText}`;\n this.out.write(this.outputText);\n };\n};\n\nexport const prompts = <T extends string = string>(\n questions: PromptObject<T> | PromptObject<T>[],\n): Promise<Answers<T>> => {\n patchMultiselectToggleAll();\n patchMultiselectSubmit();\n patchSelectBanner();\n return basePrompts(questions, { onCancel });\n};\n","import { execSync } from \"node:child_process\";\nimport { existsSync, readdirSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { OXLINT_RECOMMENDED_NODE_MAJOR } from \"../constants.js\";\n\ninterface NodeVersion {\n major: number;\n minor: number;\n patch: number;\n}\n\ninterface NodeResolution {\n binaryPath: string;\n isCurrentNode: boolean;\n version: string;\n}\n\nconst parseNodeVersion = (versionString: string): NodeVersion => {\n const cleaned = versionString.replace(/^v/, \"\").trim();\n const [major = 0, minor = 0, patch = 0] = cleaned.split(\".\").map(Number);\n return { major, minor, patch };\n};\n\nconst isNodeVersionCompatibleWithOxlint = ({ major, minor }: NodeVersion): boolean => {\n if (major === 20 && minor >= 19) return true;\n if (major === 22 && minor >= 12) return true;\n if (major > 22) return true;\n return false;\n};\n\nconst isCurrentNodeCompatibleWithOxlint = (): boolean =>\n isNodeVersionCompatibleWithOxlint(parseNodeVersion(process.version));\n\nconst getNvmDirectory = (): string | null => {\n const envNvmDirectory = process.env.NVM_DIR;\n if (envNvmDirectory && existsSync(envNvmDirectory)) return envNvmDirectory;\n\n const defaultNvmDirectory = path.join(os.homedir(), \".nvm\");\n if (existsSync(defaultNvmDirectory)) return defaultNvmDirectory;\n\n return null;\n};\n\nexport const isNvmInstalled = (): boolean => getNvmDirectory() !== null;\n\nconst findCompatibleNvmBinary = (): string | null => {\n const nvmDirectory = getNvmDirectory();\n if (!nvmDirectory) return null;\n\n const versionsDirectory = path.join(nvmDirectory, \"versions\", \"node\");\n if (!existsSync(versionsDirectory)) return null;\n\n const compatibleVersions = readdirSync(versionsDirectory)\n .filter((directoryName) => directoryName.startsWith(\"v\"))\n .map((directoryName) => ({ directoryName, ...parseNodeVersion(directoryName) }))\n .filter((version) => isNodeVersionCompatibleWithOxlint(version))\n .sort(\n (versionA, versionB) =>\n versionB.major - versionA.major ||\n versionB.minor - versionA.minor ||\n versionB.patch - versionA.patch,\n );\n\n if (compatibleVersions.length === 0) return null;\n\n const bestVersion = compatibleVersions[0];\n const binaryPath = path.join(versionsDirectory, bestVersion.directoryName, \"bin\", \"node\");\n return existsSync(binaryPath) ? binaryPath : null;\n};\n\nconst getNodeVersionFromBinary = (binaryPath: string): string | null => {\n try {\n return execSync(`\"${binaryPath}\" --version`, { encoding: \"utf-8\" }).trim();\n } catch {\n return null;\n }\n};\n\nexport const installNodeViaNvm = (): boolean => {\n const nvmDirectory = getNvmDirectory();\n if (!nvmDirectory) return false;\n\n const nvmScript = path.join(nvmDirectory, \"nvm.sh\");\n if (!existsSync(nvmScript)) return false;\n\n try {\n execSync(`bash -c \". '${nvmScript}' && nvm install ${OXLINT_RECOMMENDED_NODE_MAJOR}\"`, {\n stdio: \"inherit\",\n });\n return findCompatibleNvmBinary() !== null;\n } catch {\n return false;\n }\n};\n\nexport const resolveNodeForOxlint = (): NodeResolution | null => {\n if (isCurrentNodeCompatibleWithOxlint()) {\n return {\n binaryPath: process.execPath,\n isCurrentNode: true,\n version: process.version,\n };\n }\n\n const nvmBinaryPath = findCompatibleNvmBinary();\n if (!nvmBinaryPath) return null;\n\n const version = getNodeVersionFromBinary(nvmBinaryPath);\n if (!version) return null;\n\n return { binaryPath: nvmBinaryPath, isCurrentNode: false, version };\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 { findMonorepoRoot } from \"./find-monorepo-root.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 = fs.existsSync(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 unusedFile of issues.files) {\n diagnostics.push({\n filePath: path.relative(rootDirectory, unusedFile),\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 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}\n\nexport const createOxlintConfig = ({\n pluginPath,\n framework,\n hasReactCompiler,\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\n ? [{ name: \"react-hooks-js\", specifier: esmRequire.resolve(\"eslint-plugin-react-hooks\") }]\n : []),\n pluginPath,\n ],\n rules: {\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 \"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/no-noninteractive-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 ...(hasReactCompiler ? 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\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/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/async-parallel\": \"warn\",\n ...(framework === \"nextjs\" ? NEXTJS_RULES : {}),\n ...(framework === \"expo\" || framework === \"react-native\" ? REACT_NATIVE_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 = (rootDirectory: string): string[] => {\n const result = spawnSync(\"git\", [\"grep\", \"-l\", \"--untracked\", \"-E\", \"(eslint|oxlint)-disable\"], {\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\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 = (rootDirectory: string): (() => void) => {\n const filePaths = findFilesWithDisableDirectives(rootDirectory);\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 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\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/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\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} />`\",\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\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-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 \"Use `redirect('/path')` from 'next/navigation' in a Server Component, or handle in middleware\",\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 \"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\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 if (currentBatch.length > 0 && currentBatchLength + entryLength > SPAWN_ARGS_MAX_LENGTH_CHARS) {\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\", () => {\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): 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 });\n const restoreDisableDirectives = neutralizeDisableDirectives(rootDirectory);\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 ora from \"ora\";\n\nlet sharedInstance: ReturnType<typeof ora> | null = null;\nlet activeCount = 0;\nconst pendingTexts = new Set<string>();\n\nconst finalize = (method: \"succeed\" | \"fail\", originalText: string, displayText: string) => {\n pendingTexts.delete(originalText);\n activeCount--;\n\n if (activeCount <= 0 || !sharedInstance) {\n sharedInstance?.[method](displayText);\n sharedInstance = null;\n activeCount = 0;\n return;\n }\n\n sharedInstance.stop();\n ora(displayText).start()[method](displayText);\n\n const [remainingText] = pendingTexts;\n if (remainingText) {\n sharedInstance.text = remainingText;\n }\n sharedInstance.start();\n};\n\nexport const spinner = (text: string) => ({\n start() {\n activeCount++;\n pendingTexts.add(text);\n\n if (!sharedInstance) {\n sharedInstance = ora({ text }).start();\n } else {\n sharedInstance.text = text;\n }\n\n return {\n succeed: (displayText: string) => finalize(\"succeed\", text, displayText),\n fail: (displayText: string) => finalize(\"fail\", text, displayText),\n };\n },\n});\n","import { randomUUID } from \"node:crypto\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { performance } from \"node:perf_hooks\";\nimport {\n MILLISECONDS_PER_SECOND,\n OFFLINE_FLAG_MESSAGE,\n OFFLINE_MESSAGE,\n OXLINT_NODE_REQUIREMENT,\n OXLINT_RECOMMENDED_NODE_MAJOR,\n PERFECT_SCORE,\n SCORE_BAR_WIDTH_CHARS,\n SCORE_GOOD_THRESHOLD,\n SCORE_OK_THRESHOLD,\n SHARE_BASE_URL,\n} from \"./constants.js\";\nimport type {\n Diagnostic,\n ProjectInfo,\n ReactDoctorConfig,\n ScanOptions,\n ScanResult,\n ScoreResult,\n} from \"./types.js\";\nimport { calculateScore } from \"./utils/calculate-score.js\";\nimport { colorizeByScore } from \"./utils/colorize-by-score.js\";\nimport { combineDiagnostics, computeJsxIncludePaths } from \"./utils/combine-diagnostics.js\";\nimport { discoverProject, formatFrameworkName } from \"./utils/discover-project.js\";\nimport { type FramedLine, createFramedLine, printFramedBox } from \"./utils/framed-box.js\";\nimport { groupBy } from \"./utils/group-by.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { indentMultilineText } from \"./utils/indent-multiline-text.js\";\nimport { loadConfig } from \"./utils/load-config.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { prompts } from \"./utils/prompts.js\";\nimport {\n installNodeViaNvm,\n isNvmInstalled,\n resolveNodeForOxlint,\n} from \"./utils/resolve-compatible-node.js\";\nimport { runKnip } from \"./utils/run-knip.js\";\nimport { runOxlint } from \"./utils/run-oxlint.js\";\nimport { spinner } from \"./utils/spinner.js\";\n\ninterface ScoreBarSegments {\n filledSegment: string;\n emptySegment: string;\n}\n\nconst SEVERITY_ORDER: Record<Diagnostic[\"severity\"], number> = {\n error: 0,\n warning: 1,\n};\n\nconst colorizeBySeverity = (text: string, severity: Diagnostic[\"severity\"]): string =>\n severity === \"error\" ? highlighter.error(text) : highlighter.warn(text);\n\nconst sortBySeverity = (diagnosticGroups: [string, Diagnostic[]][]): [string, Diagnostic[]][] =>\n diagnosticGroups.toSorted(([, diagnosticsA], [, diagnosticsB]) => {\n const severityA = SEVERITY_ORDER[diagnosticsA[0].severity];\n const severityB = SEVERITY_ORDER[diagnosticsB[0].severity];\n return severityA - severityB;\n });\n\nconst collectAffectedFiles = (diagnostics: Diagnostic[]): Set<string> =>\n new Set(diagnostics.map((diagnostic) => diagnostic.filePath));\n\nconst buildFileLineMap = (diagnostics: Diagnostic[]): Map<string, number[]> => {\n const fileLines = new Map<string, number[]>();\n for (const diagnostic of diagnostics) {\n const lines = fileLines.get(diagnostic.filePath) ?? [];\n if (diagnostic.line > 0) {\n lines.push(diagnostic.line);\n }\n fileLines.set(diagnostic.filePath, lines);\n }\n return fileLines;\n};\n\nconst printDiagnostics = (diagnostics: Diagnostic[], isVerbose: boolean): void => {\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [, ruleDiagnostics] of sortedRuleGroups) {\n const firstDiagnostic = ruleDiagnostics[0];\n const severitySymbol = firstDiagnostic.severity === \"error\" ? \"✗\" : \"⚠\";\n const icon = colorizeBySeverity(severitySymbol, firstDiagnostic.severity);\n const count = ruleDiagnostics.length;\n const countLabel = count > 1 ? colorizeBySeverity(` (${count})`, firstDiagnostic.severity) : \"\";\n\n logger.log(` ${icon} ${firstDiagnostic.message}${countLabel}`);\n if (firstDiagnostic.help) {\n logger.dim(indentMultilineText(firstDiagnostic.help, \" \"));\n }\n\n if (isVerbose) {\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n logger.dim(` ${filePath}${lineLabel}`);\n }\n }\n\n logger.break();\n }\n};\n\nconst formatElapsedTime = (elapsedMilliseconds: number): string => {\n if (elapsedMilliseconds < MILLISECONDS_PER_SECOND) {\n return `${Math.round(elapsedMilliseconds)}ms`;\n }\n return `${(elapsedMilliseconds / MILLISECONDS_PER_SECOND).toFixed(1)}s`;\n};\n\nconst formatRuleSummary = (ruleKey: string, ruleDiagnostics: Diagnostic[]): string => {\n const firstDiagnostic = ruleDiagnostics[0];\n const fileLines = buildFileLineMap(ruleDiagnostics);\n\n const sections = [\n `Rule: ${ruleKey}`,\n `Severity: ${firstDiagnostic.severity}`,\n `Category: ${firstDiagnostic.category}`,\n `Count: ${ruleDiagnostics.length}`,\n \"\",\n firstDiagnostic.message,\n ];\n\n if (firstDiagnostic.help) {\n sections.push(\"\", `Suggestion: ${firstDiagnostic.help}`);\n }\n\n sections.push(\"\", \"Files:\");\n for (const [filePath, lines] of fileLines) {\n const lineLabel = lines.length > 0 ? `: ${lines.join(\", \")}` : \"\";\n sections.push(` ${filePath}${lineLabel}`);\n }\n\n return sections.join(\"\\n\") + \"\\n\";\n};\n\nconst writeDiagnosticsDirectory = (diagnostics: Diagnostic[]): string => {\n const outputDirectory = join(tmpdir(), `react-doctor-${randomUUID()}`);\n mkdirSync(outputDirectory);\n\n const ruleGroups = groupBy(\n diagnostics,\n (diagnostic) => `${diagnostic.plugin}/${diagnostic.rule}`,\n );\n const sortedRuleGroups = sortBySeverity([...ruleGroups.entries()]);\n\n for (const [ruleKey, ruleDiagnostics] of sortedRuleGroups) {\n const fileName = ruleKey.replace(/\\//g, \"--\") + \".txt\";\n writeFileSync(join(outputDirectory, fileName), formatRuleSummary(ruleKey, ruleDiagnostics));\n }\n\n writeFileSync(join(outputDirectory, \"diagnostics.json\"), JSON.stringify(diagnostics, null, 2));\n\n return outputDirectory;\n};\n\nconst buildScoreBarSegments = (score: number): ScoreBarSegments => {\n const filledCount = Math.round((score / PERFECT_SCORE) * SCORE_BAR_WIDTH_CHARS);\n const emptyCount = SCORE_BAR_WIDTH_CHARS - filledCount;\n\n return {\n filledSegment: \"█\".repeat(filledCount),\n emptySegment: \"░\".repeat(emptyCount),\n };\n};\n\nconst buildPlainScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return `${filledSegment}${emptySegment}`;\n};\n\nconst buildScoreBar = (score: number): string => {\n const { filledSegment, emptySegment } = buildScoreBarSegments(score);\n return colorizeByScore(filledSegment, score) + highlighter.dim(emptySegment);\n};\n\nconst printScoreGauge = (score: number, label: string): void => {\n const scoreDisplay = colorizeByScore(`${score}`, score);\n const labelDisplay = colorizeByScore(label, score);\n logger.log(` ${scoreDisplay} / ${PERFECT_SCORE} ${labelDisplay}`);\n logger.break();\n logger.log(` ${buildScoreBar(score)}`);\n logger.break();\n};\n\nconst getDoctorFace = (score: number): string[] => {\n if (score >= SCORE_GOOD_THRESHOLD) return [\"◠ ◠\", \" ▽ \"];\n if (score >= SCORE_OK_THRESHOLD) return [\"• •\", \" ─ \"];\n return [\"x x\", \" ▽ \"];\n};\n\nconst printBranding = (score?: number): void => {\n if (score !== undefined) {\n const [eyes, mouth] = getDoctorFace(score);\n const colorize = (text: string) => colorizeByScore(text, score);\n logger.log(colorize(\" ┌─────┐\"));\n logger.log(colorize(` │ ${eyes} │`));\n logger.log(colorize(` │ ${mouth} │`));\n logger.log(colorize(\" └─────┘\"));\n }\n logger.log(` React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`);\n logger.break();\n};\n\nconst buildShareUrl = (\n diagnostics: Diagnostic[],\n scoreResult: ScoreResult | null,\n projectName: string,\n): string => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n\n const params = new URLSearchParams();\n params.set(\"p\", projectName);\n if (scoreResult) params.set(\"s\", String(scoreResult.score));\n if (errorCount > 0) params.set(\"e\", String(errorCount));\n if (warningCount > 0) params.set(\"w\", String(warningCount));\n if (affectedFileCount > 0) params.set(\"f\", String(affectedFileCount));\n\n return `${SHARE_BASE_URL}?${params.toString()}`;\n};\n\nconst buildBrandingLines = (\n scoreResult: ScoreResult | null,\n noScoreMessage: string,\n): FramedLine[] => {\n const lines: FramedLine[] = [];\n\n if (scoreResult) {\n const [eyes, mouth] = getDoctorFace(scoreResult.score);\n const scoreColorizer = (text: string): string => colorizeByScore(text, scoreResult.score);\n\n lines.push(createFramedLine(\"┌─────┐\", scoreColorizer(\"┌─────┐\")));\n lines.push(createFramedLine(`│ ${eyes} │`, scoreColorizer(`│ ${eyes} │`)));\n lines.push(createFramedLine(`│ ${mouth} │`, scoreColorizer(`│ ${mouth} │`)));\n lines.push(createFramedLine(\"└─────┘\", scoreColorizer(\"└─────┘\")));\n lines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n lines.push(createFramedLine(\"\"));\n\n const scoreLinePlainText = `${scoreResult.score} / ${PERFECT_SCORE} ${scoreResult.label}`;\n const scoreLineRenderedText = `${colorizeByScore(String(scoreResult.score), scoreResult.score)} / ${PERFECT_SCORE} ${colorizeByScore(scoreResult.label, scoreResult.score)}`;\n lines.push(createFramedLine(scoreLinePlainText, scoreLineRenderedText));\n lines.push(createFramedLine(\"\"));\n lines.push(\n createFramedLine(buildPlainScoreBar(scoreResult.score), buildScoreBar(scoreResult.score)),\n );\n lines.push(createFramedLine(\"\"));\n } else {\n lines.push(\n createFramedLine(\n \"React Doctor (www.react.doctor)\",\n `React Doctor ${highlighter.dim(\"(www.react.doctor)\")}`,\n ),\n );\n lines.push(createFramedLine(\"\"));\n lines.push(createFramedLine(noScoreMessage, highlighter.dim(noScoreMessage)));\n lines.push(createFramedLine(\"\"));\n }\n\n return lines;\n};\n\nconst buildCountsSummaryLine = (\n diagnostics: Diagnostic[],\n totalSourceFileCount: number,\n elapsedMilliseconds: number,\n): FramedLine => {\n const errorCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"error\").length;\n const warningCount = diagnostics.filter((diagnostic) => diagnostic.severity === \"warning\").length;\n const affectedFileCount = collectAffectedFiles(diagnostics).size;\n const elapsed = formatElapsedTime(elapsedMilliseconds);\n\n const plainParts: string[] = [];\n const renderedParts: string[] = [];\n\n if (errorCount > 0) {\n const errorText = `✗ ${errorCount} error${errorCount === 1 ? \"\" : \"s\"}`;\n plainParts.push(errorText);\n renderedParts.push(highlighter.error(errorText));\n }\n if (warningCount > 0) {\n const warningText = `⚠ ${warningCount} warning${warningCount === 1 ? \"\" : \"s\"}`;\n plainParts.push(warningText);\n renderedParts.push(highlighter.warn(warningText));\n }\n\n const fileCountText =\n totalSourceFileCount > 0\n ? `across ${affectedFileCount}/${totalSourceFileCount} files`\n : `across ${affectedFileCount} file${affectedFileCount === 1 ? \"\" : \"s\"}`;\n const elapsedTimeText = `in ${elapsed}`;\n\n plainParts.push(fileCountText, elapsedTimeText);\n renderedParts.push(highlighter.dim(fileCountText), highlighter.dim(elapsedTimeText));\n\n return createFramedLine(plainParts.join(\" \"), renderedParts.join(\" \"));\n};\n\nconst printSummary = (\n diagnostics: Diagnostic[],\n elapsedMilliseconds: number,\n scoreResult: ScoreResult | null,\n projectName: string,\n totalSourceFileCount: number,\n noScoreMessage: string,\n): void => {\n const summaryFramedLines = [\n ...buildBrandingLines(scoreResult, noScoreMessage),\n buildCountsSummaryLine(diagnostics, totalSourceFileCount, elapsedMilliseconds),\n ];\n printFramedBox(summaryFramedLines);\n\n try {\n const diagnosticsDirectory = writeDiagnosticsDirectory(diagnostics);\n logger.break();\n logger.dim(` Full diagnostics written to ${diagnosticsDirectory}`);\n } catch {\n logger.break();\n }\n\n const shareUrl = buildShareUrl(diagnostics, scoreResult, projectName);\n logger.break();\n logger.dim(` Share your results: ${highlighter.info(shareUrl)}`);\n};\n\nconst resolveOxlintNode = async (\n isLintEnabled: boolean,\n isScoreOnly: boolean,\n): Promise<string | null> => {\n if (!isLintEnabled) return null;\n\n const nodeResolution = resolveNodeForOxlint();\n\n if (nodeResolution) {\n if (!nodeResolution.isCurrentNode && !isScoreOnly) {\n logger.warn(\n `Node ${process.version} is unsupported by oxlint. Using Node ${nodeResolution.version} from nvm.`,\n );\n logger.break();\n }\n return nodeResolution.binaryPath;\n }\n\n if (isScoreOnly) return null;\n\n logger.warn(\n `Node ${process.version} is not compatible with oxlint (requires ${OXLINT_NODE_REQUIREMENT}). Lint checks will be skipped.`,\n );\n\n if (isNvmInstalled() && process.stdin.isTTY) {\n const { shouldInstallNode } = await prompts({\n type: \"confirm\",\n name: \"shouldInstallNode\",\n message: `Install Node ${OXLINT_RECOMMENDED_NODE_MAJOR} via nvm to enable lint checks?`,\n initial: true,\n });\n\n if (shouldInstallNode) {\n logger.break();\n const freshResolution = installNodeViaNvm() ? resolveNodeForOxlint() : null;\n if (freshResolution) {\n logger.break();\n logger.success(`Node ${freshResolution.version} installed. Using it for lint checks.`);\n logger.break();\n return freshResolution.binaryPath;\n }\n logger.break();\n logger.warn(\"Failed to install Node via nvm. Skipping lint checks.\");\n logger.break();\n return null;\n }\n } else if (isNvmInstalled()) {\n logger.dim(` Run: nvm install ${OXLINT_RECOMMENDED_NODE_MAJOR}`);\n } else {\n logger.dim(\n ` Install nvm (https://github.com/nvm-sh/nvm) and run: nvm install ${OXLINT_RECOMMENDED_NODE_MAJOR}`,\n );\n }\n\n logger.break();\n return null;\n};\n\ninterface ResolvedScanOptions {\n lint: boolean;\n deadCode: boolean;\n verbose: boolean;\n scoreOnly: boolean;\n offline: boolean;\n includePaths: string[];\n}\n\nconst mergeScanOptions = (\n inputOptions: ScanOptions,\n userConfig: ReactDoctorConfig | null,\n): ResolvedScanOptions => ({\n lint: inputOptions.lint ?? userConfig?.lint ?? true,\n deadCode: inputOptions.deadCode ?? userConfig?.deadCode ?? true,\n verbose: inputOptions.verbose ?? userConfig?.verbose ?? false,\n scoreOnly: inputOptions.scoreOnly ?? false,\n offline: inputOptions.offline ?? false,\n includePaths: inputOptions.includePaths ?? [],\n});\n\nconst printProjectDetection = (\n projectInfo: ProjectInfo,\n userConfig: ReactDoctorConfig | null,\n isDiffMode: boolean,\n includePaths: string[],\n): void => {\n const frameworkLabel = formatFrameworkName(projectInfo.framework);\n const languageLabel = projectInfo.hasTypeScript ? \"TypeScript\" : \"JavaScript\";\n\n const completeStep = (message: string) => {\n spinner(message).start().succeed(message);\n };\n\n completeStep(`Detecting framework. Found ${highlighter.info(frameworkLabel)}.`);\n completeStep(\n `Detecting React version. Found ${highlighter.info(`React ${projectInfo.reactVersion}`)}.`,\n );\n completeStep(`Detecting language. Found ${highlighter.info(languageLabel)}.`);\n completeStep(\n `Detecting React Compiler. ${projectInfo.hasReactCompiler ? highlighter.info(\"Found React Compiler.\") : \"Not found.\"}`,\n );\n\n if (isDiffMode) {\n completeStep(`Scanning ${highlighter.info(`${includePaths.length}`)} changed source files.`);\n } else {\n completeStep(`Found ${highlighter.info(`${projectInfo.sourceFileCount}`)} source files.`);\n }\n\n if (userConfig) {\n completeStep(`Loaded ${highlighter.info(\"react-doctor config\")}.`);\n }\n\n logger.break();\n};\n\nexport const scan = async (\n directory: string,\n inputOptions: ScanOptions = {},\n): Promise<ScanResult> => {\n const startTime = performance.now();\n const projectInfo = discoverProject(directory);\n const userConfig = loadConfig(directory);\n const options = mergeScanOptions(inputOptions, userConfig);\n const { includePaths } = options;\n const isDiffMode = includePaths.length > 0;\n\n if (!projectInfo.reactVersion) {\n throw new Error(\"No React dependency found in package.json\");\n }\n\n if (!options.scoreOnly) {\n printProjectDetection(projectInfo, userConfig, isDiffMode, includePaths);\n }\n\n const jsxIncludePaths = computeJsxIncludePaths(includePaths);\n\n let didLintFail = false;\n let didDeadCodeFail = false;\n\n const resolvedNodeBinaryPath = await resolveOxlintNode(options.lint, options.scoreOnly);\n if (options.lint && !resolvedNodeBinaryPath) didLintFail = true;\n\n const lintPromise = resolvedNodeBinaryPath\n ? (async () => {\n const lintSpinner = options.scoreOnly ? null : spinner(\"Running lint checks...\").start();\n try {\n const lintDiagnostics = await runOxlint(\n directory,\n projectInfo.hasTypeScript,\n projectInfo.framework,\n projectInfo.hasReactCompiler,\n jsxIncludePaths,\n resolvedNodeBinaryPath,\n );\n lintSpinner?.succeed(\"Running lint checks.\");\n return lintDiagnostics;\n } catch (error) {\n didLintFail = true;\n if (!options.scoreOnly) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const isNativeBindingError = errorMessage.includes(\"native binding\");\n\n if (isNativeBindingError) {\n lintSpinner?.fail(\n `Lint checks failed — oxlint native binding not found (Node ${process.version}).`,\n );\n logger.dim(\n ` Upgrade to Node ${OXLINT_NODE_REQUIREMENT} or run: npx -p oxlint@latest react-doctor@latest`,\n );\n } else {\n lintSpinner?.fail(\"Lint checks failed (non-fatal, skipping).\");\n logger.error(errorMessage);\n }\n }\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const deadCodePromise =\n options.deadCode && !isDiffMode\n ? (async () => {\n const deadCodeSpinner = options.scoreOnly\n ? null\n : spinner(\"Detecting dead code...\").start();\n try {\n const knipDiagnostics = await runKnip(directory);\n deadCodeSpinner?.succeed(\"Detecting dead code.\");\n return knipDiagnostics;\n } catch (error) {\n didDeadCodeFail = true;\n if (!options.scoreOnly) {\n deadCodeSpinner?.fail(\"Dead code detection failed (non-fatal, skipping).\");\n logger.error(String(error));\n }\n return [];\n }\n })()\n : Promise.resolve<Diagnostic[]>([]);\n\n const [lintDiagnostics, deadCodeDiagnostics] = await Promise.all([lintPromise, deadCodePromise]);\n const diagnostics = combineDiagnostics(\n lintDiagnostics,\n deadCodeDiagnostics,\n directory,\n isDiffMode,\n userConfig,\n );\n\n const elapsedMilliseconds = performance.now() - startTime;\n\n const skippedChecks: string[] = [];\n if (didLintFail) skippedChecks.push(\"lint\");\n if (didDeadCodeFail) skippedChecks.push(\"dead code\");\n const hasSkippedChecks = skippedChecks.length > 0;\n\n const scoreResult = options.offline ? null : await calculateScore(diagnostics);\n const noScoreMessage = options.offline ? OFFLINE_FLAG_MESSAGE : OFFLINE_MESSAGE;\n\n if (options.scoreOnly) {\n if (scoreResult) {\n logger.log(`${scoreResult.score}`);\n } else {\n logger.dim(noScoreMessage);\n }\n return { diagnostics, scoreResult, skippedChecks };\n }\n\n if (diagnostics.length === 0) {\n if (hasSkippedChecks) {\n const skippedLabel = skippedChecks.join(\" and \");\n logger.warn(\n `No issues detected, but ${skippedLabel} checks failed — results are incomplete.`,\n );\n } else {\n logger.success(\"No issues found!\");\n }\n logger.break();\n if (hasSkippedChecks) {\n printBranding();\n logger.dim(\" Score not shown — some checks could not complete.\");\n } else if (scoreResult) {\n printBranding(scoreResult.score);\n printScoreGauge(scoreResult.score, scoreResult.label);\n } else {\n logger.dim(` ${noScoreMessage}`);\n }\n return { diagnostics, scoreResult, skippedChecks };\n }\n\n printDiagnostics(diagnostics, options.verbose);\n\n const displayedSourceFileCount = isDiffMode ? includePaths.length : projectInfo.sourceFileCount;\n\n printSummary(\n diagnostics,\n elapsedMilliseconds,\n scoreResult,\n projectInfo.projectName,\n displayedSourceFileCount,\n noScoreMessage,\n );\n\n if (hasSkippedChecks) {\n const skippedLabel = skippedChecks.join(\" and \");\n logger.break();\n logger.warn(` Note: ${skippedLabel} checks failed — score may be incomplete.`);\n }\n\n return { diagnostics, scoreResult, skippedChecks };\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 { logger } from \"./logger.js\";\nimport type { HandleErrorOptions } from \"../types.js\";\n\nconst DEFAULT_HANDLE_ERROR_OPTIONS: HandleErrorOptions = {\n shouldExit: true,\n};\n\nexport const handleError = (\n error: unknown,\n options: HandleErrorOptions = DEFAULT_HANDLE_ERROR_OPTIONS,\n): void => {\n logger.break();\n logger.error(\"Something went wrong. Please check the error below for more details.\");\n logger.error(\"If the problem persists, please open an issue on GitHub.\");\n logger.error(\"\");\n if (error instanceof Error) {\n logger.error(error.message);\n }\n logger.break();\n if (options.shouldExit) {\n process.exit(1);\n }\n process.exitCode = 1;\n};\n","import path from \"node:path\";\nimport type { WorkspacePackage } from \"../types.js\";\nimport { discoverReactSubprojects, listWorkspacePackages } from \"./discover-project.js\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nexport const selectProjects = async (\n rootDirectory: string,\n projectFlag: string | undefined,\n skipPrompts: boolean,\n): Promise<string[]> => {\n let packages = listWorkspacePackages(rootDirectory);\n if (packages.length === 0) {\n packages = discoverReactSubprojects(rootDirectory);\n }\n\n if (packages.length === 0) return [rootDirectory];\n if (packages.length === 1) {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages[0].name}`,\n );\n return [packages[0].directory];\n }\n\n if (projectFlag) return resolveProjectFlag(projectFlag, packages);\n\n if (skipPrompts) {\n printDiscoveredProjects(packages);\n return packages.map((workspacePackage) => workspacePackage.directory);\n }\n\n return promptProjectSelection(packages, rootDirectory);\n};\n\nconst resolveProjectFlag = (\n projectFlag: string,\n workspacePackages: WorkspacePackage[],\n): string[] => {\n const requestedNames = projectFlag.split(\",\").map((name) => name.trim());\n const resolvedDirectories: string[] = [];\n\n for (const requestedName of requestedNames) {\n const matched = workspacePackages.find(\n (workspacePackage) =>\n workspacePackage.name === requestedName ||\n path.basename(workspacePackage.directory) === requestedName,\n );\n\n if (!matched) {\n const availableNames = workspacePackages\n .map((workspacePackage) => workspacePackage.name)\n .join(\", \");\n throw new Error(`Project \"${requestedName}\" not found. Available: ${availableNames}`);\n }\n\n resolvedDirectories.push(matched.directory);\n }\n\n return resolvedDirectories;\n};\n\nconst printDiscoveredProjects = (packages: WorkspacePackage[]): void => {\n logger.log(\n `${highlighter.success(\"✔\")} Select projects to scan ${highlighter.dim(\"›\")} ${packages.map((workspacePackage) => workspacePackage.name).join(\", \")}`,\n );\n};\n\nconst promptProjectSelection = async (\n workspacePackages: WorkspacePackage[],\n rootDirectory: string,\n): Promise<string[]> => {\n const { selectedDirectories } = await prompts({\n type: \"multiselect\",\n name: \"selectedDirectories\",\n message: \"Select projects to scan\",\n choices: workspacePackages.map((workspacePackage) => ({\n title: workspacePackage.name,\n description: path.relative(rootDirectory, workspacePackage.directory),\n value: workspacePackage.directory,\n })),\n min: 1,\n });\n\n return selectedDirectories;\n};\n","import { execSync } from \"node:child_process\";\nimport { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { highlighter } from \"./highlighter.js\";\nimport { logger } from \"./logger.js\";\nimport { prompts } from \"./prompts.js\";\n\nconst HOME_DIRECTORY = homedir();\nconst CONFIG_DIRECTORY = join(HOME_DIRECTORY, \".react-doctor\");\nconst CONFIG_FILE = join(CONFIG_DIRECTORY, \"config.json\");\n\nconst SKILL_NAME = \"react-doctor\";\nconst WINDSURF_MARKER = \"# React Doctor\";\n\nconst SKILL_DESCRIPTION =\n \"Run after making React changes to catch issues early. Use when reviewing code, finishing a feature, or fixing bugs in a React project.\";\n\nconst SKILL_BODY = `Scans your React codebase for security, performance, correctness, and architecture issues. Outputs a 0-100 score with actionable diagnostics.\n\n## Usage\n\n\\`\\`\\`bash\nnpx -y react-doctor@latest . --verbose --diff\n\\`\\`\\`\n\n## Workflow\n\nRun after making changes to catch issues early. Fix errors first, then re-run to verify the score improved.`;\n\nconst SKILL_CONTENT = `---\nname: ${SKILL_NAME}\ndescription: ${SKILL_DESCRIPTION}\nversion: 1.0.0\n---\n\n# React Doctor\n\n${SKILL_BODY}\n`;\n\nconst AGENTS_CONTENT = `# React Doctor\n\n${SKILL_DESCRIPTION}\n\n${SKILL_BODY}\n`;\n\nconst CODEX_AGENT_CONFIG = `interface:\n display_name: \"${SKILL_NAME}\"\n short_description: \"Diagnose and fix React codebase health issues\"\n`;\n\ninterface SkillPromptConfig {\n skillPromptDismissed?: boolean;\n}\n\ninterface SkillTarget {\n name: string;\n detect: () => boolean;\n install: () => void;\n}\n\nconst readSkillPromptConfig = (): SkillPromptConfig => {\n try {\n if (!existsSync(CONFIG_FILE)) return {};\n return JSON.parse(readFileSync(CONFIG_FILE, \"utf-8\"));\n } catch {\n return {};\n }\n};\n\nconst writeSkillPromptConfig = (config: SkillPromptConfig): void => {\n try {\n mkdirSync(CONFIG_DIRECTORY, { recursive: true });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));\n } catch {}\n};\n\nconst writeSkillFiles = (directory: string): void => {\n mkdirSync(directory, { recursive: true });\n writeFileSync(join(directory, \"SKILL.md\"), SKILL_CONTENT);\n writeFileSync(join(directory, \"AGENTS.md\"), AGENTS_CONTENT);\n};\n\nconst isCommandAvailable = (command: string): boolean => {\n try {\n const whichCommand = process.platform === \"win32\" ? \"where\" : \"which\";\n execSync(`${whichCommand} ${command}`, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n};\n\nconst SKILL_TARGETS: SkillTarget[] = [\n {\n name: \"Claude Code\",\n detect: () => existsSync(join(HOME_DIRECTORY, \".claude\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".claude\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Amp Code\",\n detect: () => existsSync(join(HOME_DIRECTORY, \".amp\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".config\", \"amp\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Cursor\",\n detect: () => existsSync(join(HOME_DIRECTORY, \".cursor\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".cursor\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"OpenCode\",\n detect: () =>\n isCommandAvailable(\"opencode\") || existsSync(join(HOME_DIRECTORY, \".config\", \"opencode\")),\n install: () =>\n writeSkillFiles(join(HOME_DIRECTORY, \".config\", \"opencode\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Windsurf\",\n detect: () =>\n existsSync(join(HOME_DIRECTORY, \".codeium\")) ||\n existsSync(join(HOME_DIRECTORY, \"Library\", \"Application Support\", \"Windsurf\")),\n install: () => {\n const memoriesDirectory = join(HOME_DIRECTORY, \".codeium\", \"windsurf\", \"memories\");\n mkdirSync(memoriesDirectory, { recursive: true });\n const rulesFile = join(memoriesDirectory, \"global_rules.md\");\n\n if (existsSync(rulesFile)) {\n const existingContent = readFileSync(rulesFile, \"utf-8\");\n if (existingContent.includes(WINDSURF_MARKER)) return;\n appendFileSync(rulesFile, `\\n${WINDSURF_MARKER}\\n\\n${SKILL_CONTENT}`);\n } else {\n writeFileSync(rulesFile, `${WINDSURF_MARKER}\\n\\n${SKILL_CONTENT}`);\n }\n },\n },\n {\n name: \"Antigravity\",\n detect: () =>\n isCommandAvailable(\"agy\") || existsSync(join(HOME_DIRECTORY, \".gemini\", \"antigravity\")),\n install: () =>\n writeSkillFiles(join(HOME_DIRECTORY, \".gemini\", \"antigravity\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Gemini CLI\",\n detect: () => isCommandAvailable(\"gemini\") || existsSync(join(HOME_DIRECTORY, \".gemini\")),\n install: () => writeSkillFiles(join(HOME_DIRECTORY, \".gemini\", \"skills\", SKILL_NAME)),\n },\n {\n name: \"Codex\",\n detect: () => isCommandAvailable(\"codex\") || existsSync(join(HOME_DIRECTORY, \".codex\")),\n install: () => {\n const skillDirectory = join(HOME_DIRECTORY, \".codex\", \"skills\", SKILL_NAME);\n writeSkillFiles(skillDirectory);\n const agentsDirectory = join(skillDirectory, \"agents\");\n mkdirSync(agentsDirectory, { recursive: true });\n writeFileSync(join(agentsDirectory, \"openai.yaml\"), CODEX_AGENT_CONFIG);\n },\n },\n];\n\nconst installSkill = (): void => {\n let installedCount = 0;\n\n for (const target of SKILL_TARGETS) {\n if (!target.detect()) continue;\n try {\n target.install();\n logger.log(` ${highlighter.success(\"✔\")} ${target.name}`);\n installedCount++;\n } catch {\n logger.dim(` ✗ ${target.name} (failed)`);\n }\n }\n\n try {\n const projectSkillDirectory = join(\".agents\", SKILL_NAME);\n writeSkillFiles(projectSkillDirectory);\n logger.log(` ${highlighter.success(\"✔\")} .agents/`);\n installedCount++;\n } catch {\n logger.dim(\" ✗ .agents/ (failed)\");\n }\n\n logger.break();\n if (installedCount === 0) {\n logger.dim(\"No supported tools detected.\");\n } else {\n logger.success(\"Done! The skill will activate when working on React projects.\");\n }\n};\n\nexport const maybePromptSkillInstall = async (shouldSkipPrompts: boolean): Promise<void> => {\n const config = readSkillPromptConfig();\n if (config.skillPromptDismissed) return;\n if (shouldSkipPrompts) return;\n\n logger.break();\n logger.log(`${highlighter.info(\"💡\")} Have your coding agent fix these issues automatically?`);\n logger.dim(\n ` Install the ${highlighter.info(\"react-doctor\")} skill to teach Cursor, Claude Code,`,\n );\n logger.dim(\" Ami, and other AI agents how to diagnose and fix React issues.\");\n logger.break();\n\n const { shouldInstall } = await prompts({\n type: \"confirm\",\n name: \"shouldInstall\",\n message: \"Install skill? (recommended)\",\n initial: true,\n });\n\n if (shouldInstall) {\n logger.break();\n installSkill();\n }\n\n writeSkillPromptConfig({ ...config, skillPromptDismissed: true });\n};\n","import { execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { Command } from \"commander\";\nimport { AMI_INSTALL_URL, AMI_RELEASES_URL, AMI_WEBSITE_URL, OPEN_BASE_URL } from \"./constants.js\";\nimport { scan } from \"./scan.js\";\nimport type {\n Diagnostic,\n DiffInfo,\n EstimatedScoreResult,\n FailOnLevel,\n ReactDoctorConfig,\n ScanOptions,\n} from \"./types.js\";\nimport { fetchEstimatedScore } from \"./utils/calculate-score.js\";\nimport { colorizeByScore } from \"./utils/colorize-by-score.js\";\nimport { createFramedLine, renderFramedBoxString } from \"./utils/framed-box.js\";\nimport { filterSourceFiles, getDiffInfo } from \"./utils/get-diff-files.js\";\nimport { handleError } from \"./utils/handle-error.js\";\nimport { highlighter } from \"./utils/highlighter.js\";\nimport { loadConfig } from \"./utils/load-config.js\";\nimport { logger } from \"./utils/logger.js\";\nimport { clearSelectBanner, prompts, setSelectBanner } from \"./utils/prompts.js\";\nimport { selectProjects } from \"./utils/select-projects.js\";\nimport { maybePromptSkillInstall } from \"./utils/skill-prompt.js\";\n\nconst VERSION = process.env.VERSION ?? \"0.0.0\";\n\ninterface CliFlags {\n lint: boolean;\n deadCode: boolean;\n verbose: boolean;\n score: boolean;\n fix: boolean;\n yes: boolean;\n offline: boolean;\n ami: boolean;\n project?: string;\n diff?: boolean | string;\n failOn: string;\n}\n\nconst VALID_FAIL_ON_LEVELS = new Set<FailOnLevel>([\"error\", \"warning\", \"none\"]);\n\nconst isValidFailOnLevel = (level: string): level is FailOnLevel =>\n VALID_FAIL_ON_LEVELS.has(level as FailOnLevel);\n\nconst shouldFailForDiagnostics = (diagnostics: Diagnostic[], failOnLevel: FailOnLevel): boolean => {\n if (failOnLevel === \"none\") return false;\n if (failOnLevel === \"warning\") return diagnostics.length > 0;\n return diagnostics.some((diagnostic) => diagnostic.severity === \"error\");\n};\n\nconst exitWithFixHint = () => {\n logger.break();\n logger.log(\"Cancelled.\");\n logger.dim(\"Run `npx react-doctor@latest --fix` to fix issues.\");\n logger.break();\n process.exit(0);\n};\n\nprocess.on(\"SIGINT\", exitWithFixHint);\nprocess.on(\"SIGTERM\", exitWithFixHint);\n\nconst AUTOMATED_ENVIRONMENT_VARIABLES = [\n \"CI\",\n \"CLAUDECODE\",\n \"CURSOR_AGENT\",\n \"CODEX_CI\",\n \"OPENCODE\",\n \"AMP_HOME\",\n \"AMI\",\n];\n\nconst isAutomatedEnvironment = (): boolean =>\n AUTOMATED_ENVIRONMENT_VARIABLES.some((envVariable) => Boolean(process.env[envVariable]));\n\nconst resolveCliScanOptions = (\n flags: CliFlags,\n userConfig: ReactDoctorConfig | null,\n programInstance: Command,\n): ScanOptions => {\n const isCliOverride = (optionName: string) =>\n programInstance.getOptionValueSource(optionName) === \"cli\";\n\n return {\n lint: isCliOverride(\"lint\") ? flags.lint : (userConfig?.lint ?? true),\n deadCode: isCliOverride(\"deadCode\") ? flags.deadCode : (userConfig?.deadCode ?? true),\n verbose: isCliOverride(\"verbose\") ? Boolean(flags.verbose) : (userConfig?.verbose ?? false),\n scoreOnly: flags.score,\n offline: flags.offline,\n };\n};\n\nconst resolveDiffMode = async (\n diffInfo: DiffInfo | null,\n effectiveDiff: boolean | string | undefined,\n shouldSkipPrompts: boolean,\n isScoreOnly: boolean,\n): Promise<boolean> => {\n if (effectiveDiff !== undefined && effectiveDiff !== false) {\n if (diffInfo) return true;\n if (!isScoreOnly) {\n logger.warn(\"No feature branch or uncommitted changes detected. Running full scan.\");\n logger.break();\n }\n return false;\n }\n\n if (effectiveDiff === false || !diffInfo) return false;\n\n const changedSourceFiles = filterSourceFiles(diffInfo.changedFiles);\n if (changedSourceFiles.length === 0) return false;\n if (shouldSkipPrompts) return true;\n if (isScoreOnly) return false;\n\n const promptMessage = diffInfo.isCurrentChanges\n ? `Found ${changedSourceFiles.length} uncommitted changed files. Only scan current changes?`\n : `On branch ${diffInfo.currentBranch} (${changedSourceFiles.length} changed files vs ${diffInfo.baseBranch}). Only scan this branch?`;\n\n const { shouldScanChangedOnly } = await prompts({\n type: \"confirm\",\n name: \"shouldScanChangedOnly\",\n message: promptMessage,\n initial: true,\n });\n return Boolean(shouldScanChangedOnly);\n};\n\nconst program = new Command()\n .name(\"react-doctor\")\n .description(\"Diagnose React codebase health\")\n .version(VERSION, \"-v, --version\", \"display the version number\")\n .argument(\"[directory]\", \"project directory to scan\", \".\")\n .option(\"--lint\", \"enable linting\")\n .option(\"--no-lint\", \"skip linting\")\n .option(\"--dead-code\", \"enable dead code detection\")\n .option(\"--no-dead-code\", \"skip dead code detection\")\n .option(\"--verbose\", \"show file details per rule\")\n .option(\"--score\", \"output only the score\")\n .option(\"-y, --yes\", \"skip prompts, scan all workspace projects\")\n .option(\"--project <name>\", \"select workspace project (comma-separated for multiple)\")\n .option(\"--diff [base]\", \"scan only files changed vs base branch\")\n .option(\"--offline\", \"skip telemetry (anonymous, not stored, only used to calculate score)\")\n .option(\"--no-ami\", \"skip Ami-related prompts\")\n .option(\"--fail-on <level>\", \"exit with error code on diagnostics: error, warning, none\", \"none\")\n .option(\"--fix\", \"open Ami to auto-fix all issues\")\n .action(async (directory: string, flags: CliFlags) => {\n const isScoreOnly = flags.score;\n\n try {\n const resolvedDirectory = path.resolve(directory);\n const userConfig = loadConfig(resolvedDirectory);\n\n if (!isScoreOnly) {\n logger.log(`react-doctor v${VERSION}`);\n logger.break();\n }\n\n const scanOptions = resolveCliScanOptions(flags, userConfig, program);\n const shouldSkipPrompts = flags.yes || isAutomatedEnvironment() || !process.stdin.isTTY;\n const shouldSkipAmiPrompts = shouldSkipPrompts || !flags.ami;\n const projectDirectories = await selectProjects(\n resolvedDirectory,\n flags.project,\n shouldSkipPrompts,\n );\n\n const isDiffCliOverride = program.getOptionValueSource(\"diff\") === \"cli\";\n const effectiveDiff = isDiffCliOverride ? flags.diff : userConfig?.diff;\n const explicitBaseBranch = typeof effectiveDiff === \"string\" ? effectiveDiff : undefined;\n const diffInfo = getDiffInfo(resolvedDirectory, explicitBaseBranch);\n const isDiffMode = await resolveDiffMode(\n diffInfo,\n effectiveDiff,\n shouldSkipPrompts,\n isScoreOnly,\n );\n\n if (isDiffMode && diffInfo && !isScoreOnly) {\n if (diffInfo.isCurrentChanges) {\n logger.log(\"Scanning uncommitted changes\");\n } else {\n logger.log(\n `Scanning changes: ${highlighter.info(diffInfo.currentBranch)} → ${highlighter.info(diffInfo.baseBranch)}`,\n );\n }\n logger.break();\n }\n\n const allDiagnostics: Diagnostic[] = [];\n\n for (const projectDirectory of projectDirectories) {\n let includePaths: string[] | undefined;\n if (isDiffMode) {\n const projectDiffInfo = getDiffInfo(projectDirectory, explicitBaseBranch);\n if (projectDiffInfo) {\n const changedSourceFiles = filterSourceFiles(projectDiffInfo.changedFiles);\n if (changedSourceFiles.length === 0) {\n if (!isScoreOnly) {\n logger.dim(`No changed source files in ${projectDirectory}, skipping.`);\n logger.break();\n }\n continue;\n }\n includePaths = changedSourceFiles;\n }\n }\n\n if (!isScoreOnly) {\n logger.dim(`Scanning ${projectDirectory}...`);\n logger.break();\n }\n const scanResult = await scan(projectDirectory, { ...scanOptions, includePaths });\n allDiagnostics.push(...scanResult.diagnostics);\n if (!isScoreOnly) {\n logger.break();\n }\n }\n\n const resolvedFailOn =\n program.getOptionValueSource(\"failOn\") === \"cli\"\n ? flags.failOn\n : (userConfig?.failOn ?? flags.failOn);\n const effectiveFailOn: FailOnLevel = isValidFailOnLevel(resolvedFailOn)\n ? resolvedFailOn\n : \"none\";\n\n if (shouldFailForDiagnostics(allDiagnostics, effectiveFailOn)) {\n process.exitCode = 1;\n }\n\n if (flags.fix) {\n openAmiToFix(resolvedDirectory);\n }\n\n if (!isScoreOnly && !shouldSkipAmiPrompts && !flags.fix) {\n await maybePromptSkillInstall(shouldSkipAmiPrompts);\n const estimatedScoreResult = flags.offline\n ? null\n : await fetchEstimatedScore(allDiagnostics);\n await maybePromptFix(resolvedDirectory, allDiagnostics, estimatedScoreResult);\n }\n } catch (error) {\n handleError(error);\n }\n })\n .addHelpText(\n \"after\",\n `\n${highlighter.dim(\"Learn more:\")}\n ${highlighter.info(\"https://github.com/millionco/react-doctor\")}\n`,\n );\n\nconst DEEPLINK_FIX_PROMPT = \"/{slash-command:ami:react-doctor}\";\n\nconst isAmiInstalled = (): boolean => {\n if (process.platform === \"darwin\") {\n return (\n existsSync(\"/Applications/Ami.app\") ||\n existsSync(path.join(os.homedir(), \"Applications\", \"Ami.app\"))\n );\n }\n\n if (process.platform === \"win32\") {\n const { LOCALAPPDATA, PROGRAMFILES } = process.env;\n return (\n Boolean(LOCALAPPDATA && existsSync(path.join(LOCALAPPDATA, \"Programs\", \"Ami\", \"Ami.exe\"))) ||\n Boolean(PROGRAMFILES && existsSync(path.join(PROGRAMFILES, \"Ami\", \"Ami.exe\")))\n );\n }\n\n try {\n execSync(\"which ami\", { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n};\n\nconst installAmi = (): void => {\n logger.log(\"Installing Ami...\");\n logger.break();\n try {\n execSync(`curl -fsSL ${AMI_INSTALL_URL} | bash`, { stdio: \"inherit\" });\n } catch {\n logger.error(`Failed to install Ami. Visit ${AMI_WEBSITE_URL} to install manually.`);\n process.exit(1);\n }\n logger.break();\n};\n\nconst openUrl = (url: string): void => {\n if (process.platform === \"win32\") {\n // HACK: cmd.exe interprets %XX% as env var expansion, which mangles encoded URLs.\n // Escaping % as %% produces literal % in cmd output.\n const cmdEscapedUrl = url.replace(/%/g, \"%%\");\n execSync(`start \"\" \"${cmdEscapedUrl}\"`, { stdio: \"ignore\" });\n return;\n }\n const openCommand = process.platform === \"darwin\" ? `open \"${url}\"` : `xdg-open \"${url}\"`;\n execSync(openCommand, { stdio: \"ignore\" });\n};\n\nconst buildDeeplinkParams = (directory: string): URLSearchParams => {\n const params = new URLSearchParams();\n params.set(\"cwd\", path.resolve(directory));\n params.set(\"prompt\", DEEPLINK_FIX_PROMPT);\n params.set(\"mode\", \"agent\");\n params.set(\"autoSubmit\", \"true\");\n params.set(\"source\", \"react-doctor\");\n return params;\n};\n\nconst buildDeeplink = (directory: string): string =>\n `ami://open-project?${buildDeeplinkParams(directory).toString()}`;\n\nconst buildWebDeeplink = (directory: string): string =>\n `${OPEN_BASE_URL}?${buildDeeplinkParams(directory).toString()}`;\n\nconst openAmiToFix = (directory: string): void => {\n const isInstalled = isAmiInstalled();\n const deeplink = buildDeeplink(directory);\n const webDeeplink = buildWebDeeplink(directory);\n\n if (!isInstalled) {\n if (process.platform === \"darwin\") {\n installAmi();\n if (isAmiInstalled()) {\n logger.success(\"Ami installed successfully.\");\n } else {\n logger.error(\"Installation could not be verified.\");\n logger.dim(`Install manually at ${highlighter.info(AMI_WEBSITE_URL)}`);\n }\n } else {\n logger.error(\"Ami is not installed.\");\n logger.dim(`Download at ${highlighter.info(AMI_RELEASES_URL)}`);\n }\n logger.break();\n logger.dim(\"Open this link to start fixing:\");\n logger.info(webDeeplink);\n return;\n }\n\n logger.log(\"Opening Ami...\");\n\n try {\n openUrl(deeplink);\n logger.success(\"Ami opened. Fixing your issues now.\");\n } catch {\n logger.break();\n logger.dim(\"Could not open Ami automatically. Open this link instead:\");\n logger.info(webDeeplink);\n }\n};\n\nconst FIX_METHOD_AMI = \"ami\";\nconst FIX_COMMAND_HINT = \"npx react-doctor@latest --fix\";\n\nconst buildAmiBanner = (\n issueCount: number,\n currentScore: number,\n estimatedScore: number,\n): string => {\n const currentScoreDisplay = colorizeByScore(String(currentScore), currentScore);\n const estimatedScoreDisplay = colorizeByScore(`~${estimatedScore}`, estimatedScore);\n const issueLabel = issueCount === 1 ? \"issue\" : \"issues\";\n\n return renderFramedBoxString([\n createFramedLine(\n `Score: ${currentScore} → ~${estimatedScore}`,\n `Score: ${currentScoreDisplay} ${highlighter.dim(\"→\")} ${estimatedScoreDisplay}`,\n ),\n createFramedLine(\"\"),\n createFramedLine(\n `Ami is a coding agent built for React. It reads`,\n `${highlighter.info(\"Ami\")} is a coding agent built for React. It reads`,\n ),\n createFramedLine(\"your react-doctor report, understands your codebase,\"),\n createFramedLine(\n `and fixes ${issueCount} ${issueLabel} one by one — then re-runs the`,\n `and fixes ${highlighter.warn(String(issueCount))} ${issueLabel} one by one — then re-runs the`,\n ),\n createFramedLine(\"scan to verify the score improved.\"),\n createFramedLine(\"\"),\n createFramedLine(\n `Free to use. ${AMI_WEBSITE_URL}`,\n `Free to use. ${highlighter.info(AMI_WEBSITE_URL)}`,\n ),\n ]);\n};\n\nconst buildSkipBanner = (issueCount: number, estimatedScore: number): string => {\n const issueLabel = issueCount === 1 ? \"issue\" : \"issues\";\n const estimatedScoreDisplay = colorizeByScore(`~${estimatedScore}`, estimatedScore);\n\n return renderFramedBoxString([\n createFramedLine(\n `Skip fixing ${issueCount} ${issueLabel} and reaching ~${estimatedScore}?`,\n `Skip fixing ${highlighter.warn(String(issueCount))} ${issueLabel} and reaching ${estimatedScoreDisplay}?`,\n ),\n createFramedLine(\"\"),\n createFramedLine(\n `Run ${FIX_COMMAND_HINT} anytime to come back.`,\n `Run ${highlighter.info(FIX_COMMAND_HINT)} anytime to come back.`,\n ),\n ]);\n};\n\nconst configureFixBanners = (\n issueCount: number,\n estimatedScoreResult: EstimatedScoreResult,\n): void => {\n const { currentScore, estimatedScore } = estimatedScoreResult;\n setSelectBanner(buildAmiBanner(issueCount, currentScore, estimatedScore), 0);\n setSelectBanner(buildSkipBanner(issueCount, estimatedScore), 1);\n};\n\nconst maybePromptFix = async (\n directory: string,\n diagnostics: Diagnostic[],\n estimatedScoreResult: EstimatedScoreResult | null,\n): Promise<void> => {\n if (diagnostics.length === 0) return;\n\n logger.break();\n\n if (estimatedScoreResult) {\n configureFixBanners(diagnostics.length, estimatedScoreResult);\n }\n\n const { fixMethod } = await prompts({\n type: \"select\",\n name: \"fixMethod\",\n message: \"Fix issues?\",\n choices: [\n {\n title: \"Use Ami (recommended)\",\n description: \"Optimized coding agent for React Doctor\",\n value: FIX_METHOD_AMI,\n },\n { title: \"Skip\", value: \"skip\" },\n ],\n });\n\n clearSelectBanner();\n\n if (fixMethod === FIX_METHOD_AMI) {\n openAmiToFix(directory);\n } else {\n logger.break();\n logger.dim(` Run ${highlighter.info(FIX_COMMAND_HINT)} anytime to fix issues.`);\n }\n};\n\nconst fixAction = (directory: string) => {\n try {\n openAmiToFix(directory);\n } catch (error) {\n handleError(error);\n }\n};\n\nconst fixCommand = new Command(\"fix\")\n .description(\"Open Ami to auto-fix react-doctor issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nconst installAmiCommand = new Command(\"install-ami\")\n .description(\"Install Ami and open it to auto-fix issues\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .action(fixAction);\n\nprogram.addCommand(fixCommand);\nprogram.addCommand(installAmiCommand);\n\nconst main = async () => {\n await program.parseAsync();\n};\n\nmain();\n"],"mappings":"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E1C,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,+BAA+B;CAE/B,+BAA+B;CAC/B,yCAAyC;CACzC,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CACjD,2CAA2C;CAC3C,qCAAqC;CACrC,iDAAiD;CAClD;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;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,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,kBACE;CAEF,kBACE;CACF,4BACE;CACF,8BACE;CACF,wBACE;CACF,oCACE;CACF,8BACE;CACF,wBACE;CACF,oCACE;CACH;AAED,MAAM,i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"}