uilint-eslint 0.2.75 → 0.2.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/rules/consistent-dark-mode.js.map +1 -1
- package/dist/rules/enforce-absolute-imports.js.map +1 -1
- package/dist/rules/no-any-in-props.js.map +1 -1
- package/dist/rules/no-direct-store-import.js.map +1 -1
- package/dist/rules/no-mixed-component-libraries.js.map +1 -1
- package/dist/rules/no-prop-drilling-depth.js.map +1 -1
- package/dist/rules/no-secrets-in-code.js.map +1 -1
- package/dist/rules/no-semantic-duplicates.js.map +1 -1
- package/dist/rules/prefer-tailwind.js.map +1 -1
- package/dist/rules/prefer-zustand-state-management.js.map +1 -1
- package/dist/rules/require-input-validation.js.map +1 -1
- package/dist/rules/require-test-coverage.js.map +1 -1
- package/dist/rules/semantic-vision.js.map +1 -1
- package/dist/rules/semantic.js +1 -0
- package/dist/rules/semantic.js.map +1 -1
- package/dist/rules/zustand-use-selectors.js.map +1 -1
- package/package.json +2 -2
- package/src/rules/semantic/index.ts +1 -0
- package/src/utils/create-rule.ts +8 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/create-rule.ts","../src/rules/consistent-dark-mode.ts","../src/rules/no-direct-store-import.ts","../src/rules/prefer-zustand-state-management.ts","../src/rules/no-mixed-component-libraries/lib/export-resolver.ts","../src/rules/no-mixed-component-libraries/lib/component-parser.ts","../src/rules/no-mixed-component-libraries/lib/import-graph.ts","../src/rules/no-mixed-component-libraries/index.ts","../src/rules/semantic/index.ts","../src/rules/semantic/lib/cache.ts","../src/rules/semantic/lib/styleguide-loader.ts","../src/rules/semantic-vision.ts","../src/rules/enforce-absolute-imports.ts","../src/rules/no-any-in-props.ts","../src/rules/zustand-use-selectors.ts","../src/rules/no-prop-drilling-depth.ts","../src/rules/no-secrets-in-code.ts","../src/rules/require-input-validation.ts","../src/rules/no-semantic-duplicates.ts","../src/rules/require-test-coverage/index.ts","../src/rules/require-test-coverage/lib/file-categorizer.ts","../src/rules/require-test-coverage/lib/dependency-graph.ts","../src/rules/require-test-coverage/lib/export-resolver.ts","../src/rules/require-test-coverage/lib/coverage-aggregator.ts","../src/rules/require-test-coverage/lib/jsx-coverage-analyzer.ts","../src/rules/require-test-coverage/lib/chunk-analyzer.ts","../src/rules/prefer-tailwind.ts","../src/category-registry.ts","../src/rule-registry.ts","../src/index.ts"],"sourcesContent":["/**\n * Rule creation helper using @typescript-eslint/utils\n */\n\nimport { ESLintUtils } from \"@typescript-eslint/utils\";\n\nexport const createRule = ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/peter-suggate/uilint/blob/main/packages/uilint-eslint/docs/rules/${name}.md`\n);\n\n/**\n * Schema for prompting user to configure a rule option in the CLI\n */\nexport interface OptionFieldSchema {\n /** Field name in the options object */\n key: string;\n /** Display label for the prompt */\n label: string;\n /** Prompt type */\n type: \"text\" | \"number\" | \"boolean\" | \"select\" | \"multiselect\";\n /** Default value */\n defaultValue: unknown;\n /** Placeholder text (for text/number inputs) */\n placeholder?: string;\n /** Options for select/multiselect */\n options?: Array<{ value: string | number; label: string }>;\n /** Description/hint for the field */\n description?: string;\n}\n\n/**\n * Schema describing how to prompt for rule options during installation\n */\nexport interface RuleOptionSchema {\n /** Fields that can be configured for this rule */\n fields: OptionFieldSchema[];\n}\n\n/**\n * External requirement that a rule needs to function\n */\nexport interface RuleRequirement {\n /** Requirement type for programmatic checks */\n type: \"ollama\" | \"git\" | \"coverage\" | \"semantic-index\" | \"styleguide\";\n /** Human-readable description */\n description: string;\n /** Optional: how to satisfy the requirement */\n setupHint?: string;\n}\n\n/**\n * Rule migration definition for updating rule options between versions\n */\nexport interface RuleMigration {\n /** Source version (semver) */\n from: string;\n /** Target version (semver) */\n to: string;\n /** Human-readable description of what changed */\n description: string;\n /** Function to migrate options from old format to new format */\n migrate: (oldOptions: unknown[]) => unknown[];\n /** Whether this migration contains breaking changes */\n breaking?: boolean;\n}\n\n/**\n * Colocated rule metadata - exported alongside each rule\n *\n * This structure keeps all rule metadata in the same file as the rule implementation,\n * making it easy to maintain and extend as new rules are added.\n */\nexport interface RuleMeta {\n /** Rule identifier (e.g., \"consistent-dark-mode\") - must match filename */\n id: string;\n\n /** Semantic version of the rule (e.g., \"1.0.0\") */\n version: string;\n\n /** Display name for CLI (e.g., \"No Arbitrary Tailwind\") */\n name: string;\n\n /** Short description for CLI selection prompts (one line) */\n description: string;\n\n /** Default severity level */\n defaultSeverity: \"error\" | \"warn\" | \"off\";\n\n /** Category for grouping in CLI */\n category: \"static\" | \"semantic\";\n\n /** Icon for display in CLI/UI (emoji or icon name) */\n icon?: string;\n\n /** Short hint about the rule type/requirements */\n hint?: string;\n\n /** Whether rule is enabled by default during install */\n defaultEnabled?: boolean;\n\n /** External requirements the rule needs */\n requirements?: RuleRequirement[];\n\n /** Instructions to show after installation */\n postInstallInstructions?: string;\n\n /** Framework compatibility */\n frameworks?: (\"next\" | \"vite\" | \"cra\" | \"remix\")[];\n\n /** Whether this rule requires a styleguide file */\n requiresStyleguide?: boolean;\n\n /** Default options for the rule (passed as second element in ESLint config) */\n defaultOptions?: unknown[];\n\n /** Schema for prompting user to configure options during install */\n optionSchema?: RuleOptionSchema;\n\n /**\n * Detailed documentation in markdown format.\n * Should include:\n * - What the rule does\n * - Why it's useful\n * - Examples of incorrect and correct code\n * - Configuration options explained\n */\n docs: string;\n\n /**\n * Internal utility dependencies that this rule requires.\n * When the rule is copied to a target project, these utilities\n * will be transformed to import from \"uilint-eslint\" instead\n * of relative paths.\n *\n * Example: [\"coverage-aggregator\", \"dependency-graph\"]\n */\n internalDependencies?: string[];\n\n /**\n * Whether this rule is directory-based (has lib/ folder with utilities).\n * Directory-based rules are installed as folders with index.ts and lib/ subdirectory.\n * Single-file rules are installed as single .ts files.\n *\n * When true, ESLint config imports will use:\n * ./.uilint/rules/rule-id/index.js\n * When false (default):\n * ./.uilint/rules/rule-id.js\n */\n isDirectoryBased?: boolean;\n\n /**\n * Migrations for updating rule options between versions.\n * Migrations are applied in order to transform options from older versions.\n */\n migrations?: RuleMigration[];\n\n /**\n * Which UI plugin should handle this rule.\n * Defaults based on category:\n * - \"static\" category → \"eslint\" plugin\n * - \"semantic\" category → \"semantic\" plugin\n *\n * Special cases:\n * - \"vision\" for semantic-vision rule\n */\n plugin?: \"eslint\" | \"vision\" | \"semantic\";\n\n /**\n * Custom inspector panel ID to use for this rule's issues.\n * If not specified, uses the plugin's default issue inspector.\n *\n * Examples:\n * - \"vision-issue\" for VisionIssueInspector\n * - \"duplicates\" for DuplicatesInspector\n * - \"semantic-issue\" for SemanticIssueInspector\n */\n customInspector?: string;\n\n /**\n * Custom heatmap color for this rule's issues.\n * CSS color value (hex, rgb, hsl, or named color).\n * If not specified, uses severity-based coloring.\n */\n heatmapColor?: string;\n}\n\n/**\n * Helper to define rule metadata with type safety\n */\nexport function defineRuleMeta(meta: RuleMeta): RuleMeta {\n return meta;\n}\n","/**\n * Rule: consistent-dark-mode\n *\n * Ensures consistent dark mode theming in Tailwind CSS classes.\n * - Error: When some color classes have dark: variants but others don't within the same element\n * - Warning: When Tailwind color classes are used in a file but no dark: theming exists\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"inconsistentDarkMode\" | \"missingDarkMode\";\ntype Options = [\n {\n /** Whether to warn when no dark mode classes are found in a file that uses Tailwind colors. Default: true */\n warnOnMissingDarkMode?: boolean;\n }?\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"consistent-dark-mode\",\n version: \"1.0.0\",\n name: \"Consistent Dark Mode\",\n description: \"Ensure consistent dark: theming (error on mix, warn on missing)\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🌓\",\n hint: \"Ensures dark mode consistency\",\n defaultEnabled: true,\n defaultOptions: [{ warnOnMissingDarkMode: true }],\n optionSchema: {\n fields: [\n {\n key: \"warnOnMissingDarkMode\",\n label: \"Warn when elements lack dark: variant\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Enable warnings for elements missing dark mode variants\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects inconsistent dark mode theming in Tailwind CSS classes. Reports errors when\nsome color classes in an element have \\`dark:\\` variants but others don't, and optionally\nwarns when a file uses color classes without any dark mode theming.\n\n## Why it's useful\n\n- **Prevents broken dark mode**: Catches cases where some colors change in dark mode but others don't\n- **Encourages completeness**: Prompts you to add dark mode support where it's missing\n- **No false positives**: Only flags explicit Tailwind colors, not custom/CSS variable colors\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Some colors have dark variants, others don't\n<div className=\"bg-white dark:bg-slate-900 text-black\">\n// ^^^^^^^^^ missing dark: variant\n\n// Mix of themed and unthemed\n<button className=\"bg-blue-500 dark:bg-blue-600 border-gray-300\">\n// ^^^^^^^^^^^^^^^ missing dark: variant\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// All color classes have dark variants\n<div className=\"bg-white dark:bg-slate-900 text-black dark:text-white\">\n\n// Using semantic/custom colors (automatically themed via CSS variables)\n<div className=\"bg-background text-foreground\">\n<div className=\"bg-brand text-brand-foreground\">\n<div className=\"bg-primary text-primary-foreground\">\n\n// Consistent theming\n<button className=\"bg-blue-500 dark:bg-blue-600 border-gray-300 dark:border-gray-600\">\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/consistent-dark-mode\": [\"error\", {\n warnOnMissingDarkMode: true // Warn if file uses colors without any dark mode\n}]\n\\`\\`\\`\n\n## Notes\n\n- Only explicit Tailwind colors (like \\`blue-500\\`, \\`white\\`, \\`slate-900\\`) require dark variants\n- Custom/semantic colors (\\`background\\`, \\`foreground\\`, \\`brand\\`, \\`primary\\`, etc.) are exempt\n- These are assumed to be CSS variables that handle dark mode automatically\n- Transparent, inherit, and current values are exempt\n- Non-color utilities (like \\`text-lg\\`, \\`border-2\\`) are correctly ignored\n`,\n});\n\n// Color-related class prefixes that should have dark mode variants\nconst COLOR_PREFIXES = [\n \"bg-\",\n \"text-\",\n \"border-\",\n \"border-t-\",\n \"border-r-\",\n \"border-b-\",\n \"border-l-\",\n \"border-x-\",\n \"border-y-\",\n \"ring-\",\n \"ring-offset-\",\n \"divide-\",\n \"outline-\",\n \"shadow-\",\n \"accent-\",\n \"caret-\",\n \"fill-\",\n \"stroke-\",\n \"decoration-\",\n \"placeholder-\",\n \"from-\",\n \"via-\",\n \"to-\",\n];\n\n// Values that don't need dark variants (colorless or inherited)\nconst EXEMPT_SUFFIXES = [\"transparent\", \"inherit\", \"current\", \"auto\", \"none\"];\n\n// Built-in Tailwind CSS color palette names\n// These are the ONLY colors that should trigger dark mode warnings.\n// Custom colors (like 'brand', 'company-primary') are assumed to be\n// CSS variables that handle dark mode automatically.\nconst TAILWIND_COLOR_NAMES = new Set([\n // Special colors\n \"white\",\n \"black\",\n // Gray scale palettes\n \"slate\",\n \"gray\",\n \"zinc\",\n \"neutral\",\n \"stone\",\n // Warm colors\n \"red\",\n \"orange\",\n \"amber\",\n \"yellow\",\n // Green colors\n \"lime\",\n \"green\",\n \"emerald\",\n \"teal\",\n // Blue colors\n \"cyan\",\n \"sky\",\n \"blue\",\n \"indigo\",\n // Purple/Pink colors\n \"violet\",\n \"purple\",\n \"fuchsia\",\n \"pink\",\n \"rose\",\n]);\n\n/**\n * Check if a class has 'dark' in its variant chain\n */\nfunction hasDarkVariant(className: string): boolean {\n const parts = className.split(\":\");\n // All parts except the last are variants\n const variants = parts.slice(0, -1);\n return variants.includes(\"dark\");\n}\n\n/**\n * Get the base class (without any variants like hover:, dark:, md:, etc.)\n */\nfunction getBaseClass(className: string): string {\n const parts = className.split(\":\");\n return parts[parts.length - 1] || \"\";\n}\n\n/**\n * Find the color prefix this class uses, if any\n */\nfunction getColorPrefix(baseClass: string): string | null {\n // Sort by length descending to match more specific prefixes first\n // (e.g., \"border-t-\" before \"border-\")\n const sortedPrefixes = [...COLOR_PREFIXES].sort(\n (a, b) => b.length - a.length\n );\n return sortedPrefixes.find((p) => baseClass.startsWith(p)) || null;\n}\n\n/**\n * Check if the value is an explicit Tailwind color.\n * Uses an allowlist approach: only built-in Tailwind color names trigger warnings.\n * Custom colors (like 'brand', 'primary', 'company-blue') are assumed to be\n * CSS variables that handle dark mode automatically and should NOT trigger.\n *\n * Matches patterns like:\n * - white, black (standalone colors)\n * - blue-500, slate-900 (color-scale)\n * - blue-500/50, gray-900/80 (with opacity modifier)\n */\nfunction isTailwindColor(value: string): boolean {\n // Remove opacity modifier if present (e.g., \"blue-500/50\" -> \"blue-500\")\n const valueWithoutOpacity = value.split(\"/\")[0] || value;\n\n // Check for standalone colors (white, black)\n if (TAILWIND_COLOR_NAMES.has(valueWithoutOpacity)) {\n return true;\n }\n\n // Check for color-scale pattern (e.g., \"blue-500\", \"slate-900\")\n // Pattern: colorName-number where number is 50, 100, 200, ..., 950\n const match = valueWithoutOpacity.match(/^([a-z]+)-(\\d+)$/);\n if (match) {\n const colorName = match[1];\n const scale = match[2];\n // Valid Tailwind scales are: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950\n const validScales = [\n \"50\",\n \"100\",\n \"200\",\n \"300\",\n \"400\",\n \"500\",\n \"600\",\n \"700\",\n \"800\",\n \"900\",\n \"950\",\n ];\n if (colorName && TAILWIND_COLOR_NAMES.has(colorName) && validScales.includes(scale || \"\")) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if the value after the prefix looks like an explicit Tailwind color.\n * Uses allowlist approach: only built-in Tailwind colors should trigger dark mode warnings.\n * Custom/semantic colors (brand, primary, foreground, etc.) are NOT flagged.\n */\nfunction isColorValue(baseClass: string, prefix: string): boolean {\n const value = baseClass.slice(prefix.length);\n\n // Empty value is not a color\n if (!value) {\n return false;\n }\n\n // Only flag explicit Tailwind colors\n // Custom colors, CSS variable colors, and semantic colors are exempt\n return isTailwindColor(value);\n}\n\n/**\n * Check if a class is exempt from dark mode requirements\n */\nfunction isExempt(baseClass: string): boolean {\n return EXEMPT_SUFFIXES.some((suffix) => baseClass.endsWith(suffix));\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"consistent-dark-mode\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Ensure consistent dark mode theming in Tailwind classes\",\n },\n messages: {\n inconsistentDarkMode:\n \"Inconsistent dark mode: '{{unthemed}}' lack dark: variants while other color classes have them.\",\n missingDarkMode:\n \"No dark mode theming detected. Consider adding dark: variants for color classes.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n warnOnMissingDarkMode: {\n type: \"boolean\",\n description:\n \"Whether to warn when no dark mode classes are found in a file that uses Tailwind colors\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ warnOnMissingDarkMode: true }],\n create(context) {\n const options = context.options[0] || {};\n const warnOnMissingDarkMode = options.warnOnMissingDarkMode ?? true;\n\n let fileHasColorClasses = false;\n let fileHasDarkMode = false;\n const reportedNodes = new Set<TSESTree.Node>();\n\n function checkClassString(node: TSESTree.Node, classString: string) {\n const classes = classString.split(/\\s+/).filter(Boolean);\n if (classes.length === 0) return;\n\n // Track usage per color prefix: { hasLight, hasDark, lightClasses }\n const prefixUsage = new Map<\n string,\n { hasLight: boolean; hasDark: boolean; lightClasses: string[] }\n >();\n\n for (const cls of classes) {\n const baseClass = getBaseClass(cls);\n const prefix = getColorPrefix(baseClass);\n\n if (!prefix) continue;\n if (isExempt(baseClass)) continue;\n\n // Verify this is actually a color class, not something like text-lg\n if (!isColorValue(baseClass, prefix)) continue;\n\n if (!prefixUsage.has(prefix)) {\n prefixUsage.set(prefix, {\n hasLight: false,\n hasDark: false,\n lightClasses: [],\n });\n }\n\n const usage = prefixUsage.get(prefix)!;\n\n if (hasDarkVariant(cls)) {\n usage.hasDark = true;\n fileHasDarkMode = true;\n } else {\n usage.hasLight = true;\n usage.lightClasses.push(cls);\n }\n }\n\n // Track if file uses color classes\n if (prefixUsage.size > 0) {\n fileHasColorClasses = true;\n }\n\n // Check for inconsistency: some prefixes have dark variants, others don't\n const entries = Array.from(prefixUsage.entries());\n const hasSomeDark = entries.some(([_, u]) => u.hasDark);\n\n if (hasSomeDark) {\n const unthemedEntries = entries.filter(\n ([_, usage]) => usage.hasLight && !usage.hasDark\n );\n\n if (unthemedEntries.length > 0 && !reportedNodes.has(node)) {\n reportedNodes.add(node);\n // Collect the actual class names that lack dark variants\n const unthemedClasses = unthemedEntries.flatMap(\n ([_, u]) => u.lightClasses\n );\n\n context.report({\n node,\n messageId: \"inconsistentDarkMode\",\n data: { unthemed: unthemedClasses.join(\", \") },\n });\n }\n }\n }\n\n function processStringValue(node: TSESTree.Node, value: string) {\n checkClassString(node, value);\n }\n\n function processTemplateLiteral(node: TSESTree.TemplateLiteral) {\n for (const quasi of node.quasis) {\n checkClassString(quasi, quasi.value.raw);\n }\n }\n\n return {\n // Check className attributes in JSX\n JSXAttribute(node) {\n if (\n node.name.type === \"JSXIdentifier\" &&\n (node.name.name === \"className\" || node.name.name === \"class\")\n ) {\n const value = node.value;\n\n // Handle string literal: className=\"...\"\n if (value?.type === \"Literal\" && typeof value.value === \"string\") {\n processStringValue(value, value.value);\n }\n\n // Handle JSX expression: className={...}\n if (value?.type === \"JSXExpressionContainer\") {\n const expr = value.expression;\n\n // Direct string: className={\"...\"}\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n processStringValue(expr, expr.value);\n }\n\n // Template literal: className={`...`}\n if (expr.type === \"TemplateLiteral\") {\n processTemplateLiteral(expr);\n }\n }\n }\n },\n\n // Check cn(), clsx(), classnames(), cva() calls\n CallExpression(node) {\n if (node.callee.type !== \"Identifier\") return;\n const name = node.callee.name;\n\n if (\n name === \"cn\" ||\n name === \"clsx\" ||\n name === \"classnames\" ||\n name === \"cva\" ||\n name === \"twMerge\"\n ) {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n processStringValue(arg, arg.value);\n }\n if (arg.type === \"TemplateLiteral\") {\n processTemplateLiteral(arg);\n }\n // Handle arrays of class strings\n if (arg.type === \"ArrayExpression\") {\n for (const element of arg.elements) {\n if (\n element?.type === \"Literal\" &&\n typeof element.value === \"string\"\n ) {\n processStringValue(element, element.value);\n }\n if (element?.type === \"TemplateLiteral\") {\n processTemplateLiteral(element);\n }\n }\n }\n }\n }\n },\n\n // At the end of the file, check if Tailwind colors are used without any dark mode\n \"Program:exit\"(node) {\n if (warnOnMissingDarkMode && fileHasColorClasses && !fileHasDarkMode) {\n context.report({\n node,\n messageId: \"missingDarkMode\",\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: no-direct-store-import\n *\n * Forbids direct Zustand store imports - prefer using hooks via context.\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"noDirectImport\";\ntype Options = [\n {\n storePattern?: string;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-direct-store-import\",\n version: \"1.0.0\",\n name: \"No Direct Store Import\",\n description: \"Forbid direct Zustand store imports (use context hooks)\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🏪\",\n hint: \"Encourages testable store access\",\n defaultEnabled: true,\n defaultOptions: [{ storePattern: \"use*Store\" }],\n optionSchema: {\n fields: [\n {\n key: \"storePattern\",\n label: \"Glob pattern for store files\",\n type: \"text\",\n defaultValue: \"use*Store\",\n placeholder: \"use*Store\",\n description: \"Pattern to match store file names\",\n },\n ],\n },\n docs: `\n## What it does\n\nPrevents direct imports of Zustand stores, encouraging the use of context-based hooks\nfor better dependency injection and testability.\n\n## Why it's useful\n\n- **Testability**: Context-based access allows easy mocking in tests\n- **Flexibility**: Store implementation can change without updating all consumers\n- **Dependency Injection**: Stores can be provided at different levels of the component tree\n- **Server Components**: Helps avoid accidentally importing stores in server components\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Directly importing the store\nimport { useAuthStore } from '../stores/auth-store';\nimport { useCartStore } from '@/stores/useCartStore';\n\nfunction MyComponent() {\n const user = useAuthStore((s) => s.user);\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using context-provided hooks\nimport { useAuth } from '../contexts/auth-context';\nimport { useCart } from '@/hooks/useCart';\n\nfunction MyComponent() {\n const { user } = useAuth();\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-direct-store-import\": [\"warn\", {\n storePattern: \"use*Store\" // Pattern to match store names\n}]\n\\`\\`\\`\n\n## Notes\n\n- The pattern uses glob syntax (\\`*\\` matches any characters)\n- Only triggers for imports from paths containing \"store\"\n- Works with both named and default imports\n`,\n});\n\n// Convert glob pattern to regex\nfunction patternToRegex(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\");\n return new RegExp(`^${escaped}$`);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-direct-store-import\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Forbid direct Zustand store imports (use hooks via context)\",\n },\n messages: {\n noDirectImport:\n \"Avoid importing store '{{name}}' directly. Use the store via a context hook instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n storePattern: {\n type: \"string\",\n description: \"Glob pattern for store names\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ storePattern: \"use*Store\" }],\n create(context) {\n const options = context.options[0] || {};\n const pattern = options.storePattern || \"use*Store\";\n const regex = patternToRegex(pattern);\n\n return {\n ImportDeclaration(node) {\n // Check if importing from a store file\n const source = node.source.value as string;\n if (!source.includes(\"store\")) return;\n\n // Check imported specifiers\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportSpecifier\") {\n const importedName =\n specifier.imported.type === \"Identifier\"\n ? specifier.imported.name\n : specifier.imported.value;\n\n if (regex.test(importedName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: importedName },\n });\n }\n }\n\n if (specifier.type === \"ImportDefaultSpecifier\") {\n const localName = specifier.local.name;\n if (regex.test(localName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: localName },\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: prefer-zustand-state-management\n *\n * Detects excessive use of React state hooks (useState, useReducer, useContext)\n * in components and suggests using Zustand stores for better state management.\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"excessiveStateHooks\";\ntype Options = [\n {\n /** Maximum number of state hooks before warning. Default: 3 */\n maxStateHooks?: number;\n /** Whether to count useState calls. Default: true */\n countUseState?: boolean;\n /** Whether to count useReducer calls. Default: true */\n countUseReducer?: boolean;\n /** Whether to count useContext calls. Default: true */\n countUseContext?: boolean;\n }?\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"prefer-zustand-state-management\",\n version: \"1.0.0\",\n name: \"Prefer Zustand State Management\",\n description: \"Detect excessive useState/useReducer/useContext; suggest Zustand\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🐻\",\n hint: \"Suggests centralized state management\",\n defaultEnabled: true,\n defaultOptions: [\n {\n maxStateHooks: 3,\n countUseState: true,\n countUseReducer: true,\n countUseContext: true,\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"maxStateHooks\",\n label: \"Max state hooks before warning\",\n type: \"number\",\n defaultValue: 3,\n placeholder: \"3\",\n description: \"Maximum number of state hooks allowed before warning\",\n },\n {\n key: \"countUseState\",\n label: \"Count useState hooks\",\n type: \"boolean\",\n defaultValue: true,\n },\n {\n key: \"countUseReducer\",\n label: \"Count useReducer hooks\",\n type: \"boolean\",\n defaultValue: true,\n },\n {\n key: \"countUseContext\",\n label: \"Count useContext hooks\",\n type: \"boolean\",\n defaultValue: true,\n },\n ],\n },\n docs: `\n## What it does\n\nDetects components that use many React state hooks (\\`useState\\`, \\`useReducer\\`, \\`useContext\\`)\nand suggests consolidating state into a Zustand store for better maintainability.\n\n## Why it's useful\n\n- **Simplifies components**: Fewer hooks means less cognitive overhead\n- **Centralizes state**: Related state lives together in a store\n- **Better performance**: Zustand's selector pattern prevents unnecessary re-renders\n- **Easier testing**: Store logic can be tested independently of components\n\n## Examples\n\n### ❌ Incorrect (with default maxStateHooks: 3)\n\n\\`\\`\\`tsx\nfunction UserProfile() {\n const [name, setName] = useState('');\n const [email, setEmail] = useState('');\n const [avatar, setAvatar] = useState(null);\n const [isLoading, setIsLoading] = useState(false); // 4 hooks = warning\n // ...\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using a Zustand store\nconst useUserStore = create((set) => ({\n name: '',\n email: '',\n avatar: null,\n isLoading: false,\n setName: (name) => set({ name }),\n // ...\n}));\n\nfunction UserProfile() {\n const { name, email, avatar, isLoading } = useUserStore();\n // Much cleaner!\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/prefer-zustand-state-management\": [\"warn\", {\n maxStateHooks: 3, // Warn when exceeding this count\n countUseState: true, // Include useState in count\n countUseReducer: true, // Include useReducer in count\n countUseContext: true // Include useContext in count\n}]\n\\`\\`\\`\n\n## Notes\n\n- Custom hooks (starting with \\`use\\` lowercase) are exempt from this rule\n- Only counts hooks at the top level of the component, not in nested functions\n- Adjust \\`maxStateHooks\\` based on your team's preferences\n`,\n});\n\ninterface ComponentInfo {\n name: string;\n node: TSESTree.Node;\n hookCount: number;\n functionNode:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression;\n}\n\nconst STATE_HOOKS = new Set([\"useState\", \"useReducer\", \"useContext\"]);\n\nexport default createRule<Options, MessageIds>({\n name: \"prefer-zustand-state-management\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Detect excessive use of React state hooks and suggest Zustand stores\",\n },\n messages: {\n excessiveStateHooks:\n \"Component '{{component}}' has {{count}} state hooks (max: {{max}}). Consider using a Zustand store for state management.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxStateHooks: {\n type: \"number\",\n minimum: 1,\n description: \"Maximum number of state hooks before warning\",\n },\n countUseState: {\n type: \"boolean\",\n description: \"Whether to count useState calls\",\n },\n countUseReducer: {\n type: \"boolean\",\n description: \"Whether to count useReducer calls\",\n },\n countUseContext: {\n type: \"boolean\",\n description: \"Whether to count useContext calls\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n maxStateHooks: 3,\n countUseState: true,\n countUseReducer: true,\n countUseContext: true,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const maxStateHooks = options.maxStateHooks ?? 3;\n const countUseState = options.countUseState ?? true;\n const countUseReducer = options.countUseReducer ?? true;\n const countUseContext = options.countUseContext ?? true;\n\n // Stack to track current component context\n const componentStack: ComponentInfo[] = [];\n\n // Set of function nodes we've identified as components to check\n const componentFunctions = new Map<TSESTree.Node, ComponentInfo>();\n\n /**\n * Check if a function name indicates a React component (PascalCase)\n */\n function isComponentName(name: string | null | undefined): boolean {\n if (!name) return false;\n // Components start with uppercase, hooks start with lowercase \"use\"\n return /^[A-Z]/.test(name);\n }\n\n /**\n * Check if a function name indicates a custom hook (starts with \"use\")\n */\n function isCustomHookName(name: string | null | undefined): boolean {\n if (!name) return false;\n return /^use[A-Z]/.test(name);\n }\n\n /**\n * Get the name of a function from various declaration patterns\n */\n function getFunctionName(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression\n ): string | null {\n // Function declaration: function MyComponent() {}\n if (node.type === \"FunctionDeclaration\" && node.id) {\n return node.id.name;\n }\n\n // Check parent for variable declaration: const MyComponent = () => {}\n const parent = node.parent;\n\n if (\n parent?.type === \"VariableDeclarator\" &&\n parent.id.type === \"Identifier\"\n ) {\n return parent.id.name;\n }\n\n // Check for forwardRef/memo: const MyComponent = forwardRef(function MyComponent() {})\n // or const MyComponent = forwardRef(() => {})\n if (parent?.type === \"CallExpression\") {\n const callParent = parent.parent;\n if (\n callParent?.type === \"VariableDeclarator\" &&\n callParent.id.type === \"Identifier\"\n ) {\n return callParent.id.name;\n }\n }\n\n // Named function expression: const x = function MyComponent() {}\n if (node.type === \"FunctionExpression\" && node.id) {\n return node.id.name;\n }\n\n return null;\n }\n\n /**\n * Check if a hook call should be counted based on options\n */\n function shouldCountHook(hookName: string): boolean {\n switch (hookName) {\n case \"useState\":\n return countUseState;\n case \"useReducer\":\n return countUseReducer;\n case \"useContext\":\n return countUseContext;\n default:\n return false;\n }\n }\n\n /**\n * Get hook name from a call expression (handles both useState and React.useState)\n */\n function getHookName(callee: TSESTree.Expression): string | null {\n // Direct call: useState()\n if (callee.type === \"Identifier\" && STATE_HOOKS.has(callee.name)) {\n return callee.name;\n }\n\n // Member expression: React.useState()\n if (\n callee.type === \"MemberExpression\" &&\n callee.object.type === \"Identifier\" &&\n callee.object.name === \"React\" &&\n callee.property.type === \"Identifier\" &&\n STATE_HOOKS.has(callee.property.name)\n ) {\n return callee.property.name;\n }\n\n return null;\n }\n\n /**\n * Check if we're directly inside a component function (not in a nested function)\n */\n function isDirectChildOfComponent(\n node: TSESTree.Node,\n componentNode: TSESTree.Node\n ): boolean {\n let current: TSESTree.Node | undefined = node.parent;\n\n while (current) {\n // If we hit the component node, we're a direct child\n if (current === componentNode) {\n return true;\n }\n\n // If we hit another function first, we're nested\n if (\n current.type === \"FunctionDeclaration\" ||\n current.type === \"FunctionExpression\" ||\n current.type === \"ArrowFunctionExpression\"\n ) {\n return false;\n }\n\n current = current.parent;\n }\n\n return false;\n }\n\n /**\n * Enter a function that might be a component\n */\n function enterFunction(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression\n ) {\n const name = getFunctionName(node);\n\n // Skip custom hooks - they're allowed to have many state hooks\n if (isCustomHookName(name)) {\n return;\n }\n\n // Skip non-component functions (lowercase names that aren't anonymous)\n if (name && !isComponentName(name)) {\n return;\n }\n\n // Track this as a potential component\n const componentInfo: ComponentInfo = {\n name: name || \"AnonymousComponent\",\n node,\n hookCount: 0,\n functionNode: node,\n };\n\n componentStack.push(componentInfo);\n componentFunctions.set(node, componentInfo);\n }\n\n /**\n * Exit a function and report if it had too many hooks\n */\n function exitFunction(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression\n ) {\n const componentInfo = componentFunctions.get(node);\n\n if (!componentInfo) {\n return;\n }\n\n // Remove from stack\n const index = componentStack.findIndex((c) => c.functionNode === node);\n if (index !== -1) {\n componentStack.splice(index, 1);\n }\n\n // Check if exceeded threshold\n if (componentInfo.hookCount > maxStateHooks) {\n context.report({\n node: componentInfo.node,\n messageId: \"excessiveStateHooks\",\n data: {\n component: componentInfo.name,\n count: componentInfo.hookCount,\n max: maxStateHooks,\n },\n });\n }\n\n componentFunctions.delete(node);\n }\n\n return {\n FunctionDeclaration: enterFunction,\n FunctionExpression: enterFunction,\n ArrowFunctionExpression: enterFunction,\n \"FunctionDeclaration:exit\": exitFunction,\n \"FunctionExpression:exit\": exitFunction,\n \"ArrowFunctionExpression:exit\": exitFunction,\n\n CallExpression(node) {\n const hookName = getHookName(node.callee);\n\n if (!hookName || !shouldCountHook(hookName)) {\n return;\n }\n\n // Find the innermost component this hook belongs to\n // We iterate from the end to find the most recent (innermost) component\n for (let i = componentStack.length - 1; i >= 0; i--) {\n const component = componentStack[i];\n\n if (isDirectChildOfComponent(node, component.functionNode)) {\n component.hookCount++;\n break;\n }\n }\n },\n };\n },\n});\n","/**\n * Export Resolver\n *\n * Resolves import paths and finds export definitions, following re-exports\n * to their original source files.\n */\n\nimport { ResolverFactory } from \"oxc-resolver\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport { readFileSync, existsSync } from \"fs\";\nimport { dirname, join, extname } from \"path\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\n// Module-level resolver instance (reused across calls)\nlet resolverInstance: ReturnType<typeof ResolverFactory.prototype.sync> | null =\n null;\nlet resolverFactory: ResolverFactory | null = null;\n\n/**\n * Information about a resolved export\n */\nexport interface ResolvedExport {\n /** The name of the export (e.g., \"Button\") */\n name: string;\n /** Absolute path to the file containing the actual definition */\n filePath: string;\n /** The local name in the source file (may differ from export name) */\n localName: string;\n /** Whether this is a re-export (export { X } from './other') */\n isReexport: boolean;\n}\n\n/**\n * Cache for file exports to avoid re-parsing\n */\nconst exportCache = new Map<\n string,\n Map<string, { localName: string; reexportSource?: string }>\n>();\n\n/**\n * Cache for parsed ASTs\n */\nconst astCache = new Map<string, TSESTree.Program>();\n\n/**\n * Cache for resolved paths\n */\nconst resolvedPathCache = new Map<string, string | null>();\n\n/**\n * Get or create the resolver factory\n */\nfunction getResolverFactory(): ResolverFactory {\n if (!resolverFactory) {\n resolverFactory = new ResolverFactory({\n extensions: [\".tsx\", \".ts\", \".jsx\", \".js\"],\n mainFields: [\"module\", \"main\"],\n conditionNames: [\"import\", \"require\", \"node\", \"default\"],\n // Enable TypeScript path resolution\n tsconfig: {\n configFile: \"tsconfig.json\",\n references: \"auto\",\n },\n });\n }\n return resolverFactory;\n}\n\n/**\n * Resolve an import path to an absolute file path\n */\nexport function resolveImportPath(\n importSource: string,\n fromFile: string\n): string | null {\n const cacheKey = `${fromFile}::${importSource}`;\n\n if (resolvedPathCache.has(cacheKey)) {\n return resolvedPathCache.get(cacheKey) ?? null;\n }\n\n // Skip node_modules\n if (\n importSource.startsWith(\"react\") ||\n importSource.startsWith(\"next\") ||\n (!importSource.startsWith(\".\") &&\n !importSource.startsWith(\"@/\") &&\n !importSource.startsWith(\"~/\"))\n ) {\n // Check if it's a known external package\n if (\n importSource.includes(\"@mui/\") ||\n importSource.includes(\"@chakra-ui/\") ||\n importSource.includes(\"antd\") ||\n importSource.includes(\"@radix-ui/\")\n ) {\n // Return a marker for external packages - we don't resolve them but track them\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n\n try {\n const factory = getResolverFactory();\n const fromDir = dirname(fromFile);\n const result = factory.sync(fromDir, importSource);\n\n if (result.path) {\n resolvedPathCache.set(cacheKey, result.path);\n return result.path;\n }\n } catch {\n // Fallback: try manual resolution for common patterns\n const resolved = manualResolve(importSource, fromFile);\n resolvedPathCache.set(cacheKey, resolved);\n return resolved;\n }\n\n resolvedPathCache.set(cacheKey, null);\n return null;\n}\n\n/**\n * Manual fallback resolution for common patterns\n */\nfunction manualResolve(importSource: string, fromFile: string): string | null {\n const fromDir = dirname(fromFile);\n const extensions = [\".tsx\", \".ts\", \".jsx\", \".js\"];\n\n // Handle @/ alias - find tsconfig and resolve\n if (importSource.startsWith(\"@/\")) {\n const projectRoot = findProjectRoot(fromFile);\n if (projectRoot) {\n const relativePath = importSource.slice(2); // Remove @/\n for (const ext of extensions) {\n const candidate = join(projectRoot, relativePath + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(projectRoot, relativePath, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n }\n\n // Handle relative imports\n if (importSource.startsWith(\".\")) {\n for (const ext of extensions) {\n const candidate = join(fromDir, importSource + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(fromDir, importSource, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Find the project root by looking for tsconfig.json or package.json\n */\nfunction findProjectRoot(fromFile: string): string | null {\n let dir = dirname(fromFile);\n const root = \"/\";\n\n while (dir !== root) {\n if (existsSync(join(dir, \"tsconfig.json\"))) {\n return dir;\n }\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n\n return null;\n}\n\n/**\n * Parse a file and cache the AST\n */\nexport function parseFile(filePath: string): TSESTree.Program | null {\n if (astCache.has(filePath)) {\n return astCache.get(filePath)!;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n });\n astCache.set(filePath, ast);\n return ast;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract export information from a file\n */\nfunction extractExports(\n filePath: string\n): Map<string, { localName: string; reexportSource?: string }> {\n if (exportCache.has(filePath)) {\n return exportCache.get(filePath)!;\n }\n\n const exports = new Map<\n string,\n { localName: string; reexportSource?: string }\n >();\n const ast = parseFile(filePath);\n\n if (!ast) {\n exportCache.set(filePath, exports);\n return exports;\n }\n\n for (const node of ast.body) {\n // Handle: export function Button() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(node.declaration.id.name, {\n localName: node.declaration.id.name,\n });\n }\n\n // Handle: export const Button = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (decl.id.type === \"Identifier\") {\n exports.set(decl.id.name, { localName: decl.id.name });\n }\n }\n }\n\n // Handle: export { Button } or export { Button as Btn }\n if (node.type === \"ExportNamedDeclaration\" && node.specifiers.length > 0) {\n const source = node.source?.value as string | undefined;\n for (const spec of node.specifiers) {\n if (spec.type === \"ExportSpecifier\") {\n const exportedName =\n spec.exported.type === \"Identifier\"\n ? spec.exported.name\n : spec.exported.value;\n const localName =\n spec.local.type === \"Identifier\"\n ? spec.local.name\n : spec.local.value;\n\n exports.set(exportedName, {\n localName,\n reexportSource: source,\n });\n }\n }\n }\n\n // Handle: export default function Button() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(\"default\", { localName: node.declaration.id.name });\n }\n\n // Handle: export default Button\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"Identifier\"\n ) {\n exports.set(\"default\", { localName: node.declaration.name });\n }\n }\n\n exportCache.set(filePath, exports);\n return exports;\n}\n\n/**\n * Resolve an export to its original definition, following re-exports\n */\nexport function resolveExport(\n exportName: string,\n filePath: string,\n visited = new Set<string>()\n): ResolvedExport | null {\n // Cycle detection\n const key = `${filePath}::${exportName}`;\n if (visited.has(key)) {\n return null;\n }\n visited.add(key);\n\n const exports = extractExports(filePath);\n const exportInfo = exports.get(exportName);\n\n if (!exportInfo) {\n return null;\n }\n\n // If it's a re-export, follow the chain\n if (exportInfo.reexportSource) {\n const resolvedPath = resolveImportPath(exportInfo.reexportSource, filePath);\n if (resolvedPath) {\n return resolveExport(exportInfo.localName, resolvedPath, visited);\n }\n return null;\n }\n\n // This is the actual definition\n return {\n name: exportName,\n filePath,\n localName: exportInfo.localName,\n isReexport: false,\n };\n}\n\n/**\n * Clear all caches (useful for testing or watch mode)\n */\nexport function clearResolverCaches(): void {\n exportCache.clear();\n astCache.clear();\n resolvedPathCache.clear();\n}\n","/**\n * Component Parser\n *\n * Parses a single component's body to extract styling information\n * and identify nested component usage.\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { parseFile } from \"./export-resolver.js\";\n\n/**\n * Known UI library import patterns\n */\nexport type LibraryName = \"shadcn\" | \"mui\" | \"chakra\" | \"antd\";\n\nexport const LIBRARY_PATTERNS: Record<LibraryName, string[]> = {\n shadcn: [\"@/components/ui\", \"@radix-ui/\", \"components/ui/\"],\n mui: [\"@mui/material\", \"@mui/icons-material\", \"@emotion/\"],\n chakra: [\"@chakra-ui/\"],\n antd: [\"antd\", \"@ant-design/\"],\n};\n\n/**\n * Information about a component used within another component\n */\nexport interface UsedComponent {\n /** Component name (e.g., \"Button\", \"Card\") */\n name: string;\n /** Import source path (e.g., \"@mui/material\", \"./button\") */\n importSource: string;\n /** Line number where the component is used */\n line: number;\n /** Column number where the component is used */\n column: number;\n}\n\n/**\n * Styling information extracted from a component\n */\nexport interface ComponentStyleInfo {\n /** Tailwind classes used in the component */\n tailwindClasses: string[];\n /** Inline style objects (as string representations) */\n inlineStyles: string[];\n /** Other components used within this component */\n usedComponents: UsedComponent[];\n /** Directly detected library (from import source) */\n directLibrary: LibraryName | null;\n}\n\n/**\n * Import map for a file: localName -> importSource\n */\nexport type ImportMap = Map<string, string>;\n\n/**\n * Extract imports from a file's AST\n */\nexport function extractImports(ast: TSESTree.Program): ImportMap {\n const imports = new Map<string, string>();\n\n for (const node of ast.body) {\n if (node.type === \"ImportDeclaration\") {\n const source = node.source.value as string;\n for (const spec of node.specifiers) {\n if (spec.type === \"ImportSpecifier\") {\n imports.set(spec.local.name, source);\n } else if (spec.type === \"ImportDefaultSpecifier\") {\n imports.set(spec.local.name, source);\n } else if (spec.type === \"ImportNamespaceSpecifier\") {\n imports.set(spec.local.name, source);\n }\n }\n }\n }\n\n return imports;\n}\n\n/**\n * Detect which UI library an import source belongs to\n */\nexport function detectLibraryFromSource(\n importSource: string\n): LibraryName | null {\n for (const [library, patterns] of Object.entries(LIBRARY_PATTERNS)) {\n if (patterns.some((p) => importSource.includes(p))) {\n return library as LibraryName;\n }\n }\n return null;\n}\n\n/**\n * Find a function/arrow function component definition by name in an AST\n */\nexport function findComponentDefinition(\n ast: TSESTree.Program,\n componentName: string\n): TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | null {\n for (const node of ast.body) {\n // export function ComponentName() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id?.name === componentName\n ) {\n return node.declaration;\n }\n\n // export const ComponentName = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (\n decl.id.type === \"Identifier\" &&\n decl.id.name === componentName &&\n decl.init?.type === \"ArrowFunctionExpression\"\n ) {\n return decl.init;\n }\n }\n }\n\n // function ComponentName() {} (not exported directly)\n if (\n node.type === \"FunctionDeclaration\" &&\n node.id?.name === componentName\n ) {\n return node;\n }\n\n // const ComponentName = () => {}\n if (node.type === \"VariableDeclaration\") {\n for (const decl of node.declarations) {\n if (\n decl.id.type === \"Identifier\" &&\n decl.id.name === componentName &&\n decl.init?.type === \"ArrowFunctionExpression\"\n ) {\n return decl.init;\n }\n }\n }\n\n // export default function ComponentName() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\" &&\n node.declaration.id?.name === componentName\n ) {\n return node.declaration;\n }\n }\n\n return null;\n}\n\n/**\n * Extract Tailwind classes from a className string\n */\nfunction extractTailwindClasses(classString: string): string[] {\n return classString.split(/\\s+/).filter(Boolean);\n}\n\n/**\n * Recursively traverse a node and extract styling info\n */\nfunction traverseForStyling(\n node: TSESTree.Node,\n imports: ImportMap,\n result: ComponentStyleInfo\n): void {\n if (!node || typeof node !== \"object\") return;\n\n // Handle JSX elements\n if (node.type === \"JSXElement\" && node.openingElement) {\n const opening = node.openingElement;\n\n // Check if this is a component (PascalCase) or HTML element\n if (\n opening.name.type === \"JSXIdentifier\" &&\n /^[A-Z]/.test(opening.name.name)\n ) {\n const componentName = opening.name.name;\n const importSource = imports.get(componentName);\n\n if (importSource) {\n result.usedComponents.push({\n name: componentName,\n importSource,\n line: opening.loc.start.line,\n column: opening.loc.start.column,\n });\n\n // Check if this import is from a known UI library\n const library = detectLibraryFromSource(importSource);\n if (library && !result.directLibrary) {\n result.directLibrary = library;\n }\n }\n }\n\n // Handle JSX member expressions like Modal.Header\n if (opening.name.type === \"JSXMemberExpression\") {\n let objectName: string | null = null;\n let current = opening.name.object;\n while (current.type === \"JSXMemberExpression\") {\n current = current.object;\n }\n if (current.type === \"JSXIdentifier\") {\n objectName = current.name;\n }\n\n if (objectName) {\n const importSource = imports.get(objectName);\n if (importSource) {\n const library = detectLibraryFromSource(importSource);\n if (library && !result.directLibrary) {\n result.directLibrary = library;\n }\n }\n }\n }\n\n // Extract className/class attributes\n for (const attr of opening.attributes) {\n if (\n attr.type === \"JSXAttribute\" &&\n attr.name.type === \"JSXIdentifier\" &&\n (attr.name.name === \"className\" || attr.name.name === \"class\")\n ) {\n if (\n attr.value?.type === \"Literal\" &&\n typeof attr.value.value === \"string\"\n ) {\n result.tailwindClasses.push(\n ...extractTailwindClasses(attr.value.value)\n );\n }\n if (attr.value?.type === \"JSXExpressionContainer\") {\n const expr = attr.value.expression;\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n result.tailwindClasses.push(...extractTailwindClasses(expr.value));\n }\n if (expr.type === \"TemplateLiteral\") {\n for (const quasi of expr.quasis) {\n result.tailwindClasses.push(\n ...extractTailwindClasses(quasi.value.raw)\n );\n }\n }\n }\n }\n\n // Extract inline styles\n if (\n attr.type === \"JSXAttribute\" &&\n attr.name.type === \"JSXIdentifier\" &&\n attr.name.name === \"style\"\n ) {\n if (attr.value?.type === \"JSXExpressionContainer\") {\n // Just note that there's an inline style - we don't parse the object\n result.inlineStyles.push(\"[inline style]\");\n }\n }\n }\n }\n\n // Handle cn(), clsx(), twMerge() calls\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"Identifier\" &&\n [\"cn\", \"clsx\", \"classnames\", \"twMerge\"].includes(node.callee.name)\n ) {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n result.tailwindClasses.push(...extractTailwindClasses(arg.value));\n }\n if (arg.type === \"TemplateLiteral\") {\n for (const quasi of arg.quasis) {\n result.tailwindClasses.push(\n ...extractTailwindClasses(quasi.value.raw)\n );\n }\n }\n }\n }\n\n // Recursively traverse all properties\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (node as unknown as Record<string, unknown>)[key];\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\") {\n traverseForStyling(item as TSESTree.Node, imports, result);\n }\n }\n } else if (child && typeof child === \"object\") {\n traverseForStyling(child as TSESTree.Node, imports, result);\n }\n }\n}\n\n/**\n * Parse a component's body and extract styling information\n */\nexport function parseComponentBody(\n filePath: string,\n componentName: string\n): ComponentStyleInfo | null {\n const ast = parseFile(filePath);\n if (!ast) return null;\n\n const imports = extractImports(ast);\n const componentDef = findComponentDefinition(ast, componentName);\n\n if (!componentDef) {\n return null;\n }\n\n const result: ComponentStyleInfo = {\n tailwindClasses: [],\n inlineStyles: [],\n usedComponents: [],\n directLibrary: null,\n };\n\n // Traverse the component body\n if (componentDef.body) {\n traverseForStyling(componentDef.body, imports, result);\n }\n\n // Deduplicate classes\n result.tailwindClasses = [...new Set(result.tailwindClasses)];\n\n return result;\n}\n\n/**\n * Analyze a file and extract all component usages with their libraries\n * (used for the entry file analysis)\n */\nexport function analyzeFileImports(\n filePath: string\n): Map<string, { importSource: string; library: LibraryName | null }> {\n const ast = parseFile(filePath);\n if (!ast) return new Map();\n\n const result = new Map<\n string,\n { importSource: string; library: LibraryName | null }\n >();\n const imports = extractImports(ast);\n\n for (const [name, source] of imports) {\n result.set(name, {\n importSource: source,\n library: detectLibraryFromSource(source),\n });\n }\n\n return result;\n}\n","/**\n * Import Graph Service\n *\n * Provides demand-driven cross-file analysis to detect UI library usage\n * across component trees. Uses in-memory caching for performance.\n */\n\nimport {\n resolveImportPath,\n resolveExport,\n clearResolverCaches,\n} from \"./export-resolver.js\";\nimport {\n parseComponentBody,\n detectLibraryFromSource,\n type LibraryName,\n type ComponentStyleInfo,\n} from \"./component-parser.js\";\n\n/**\n * Information about a component's UI library usage\n */\nexport interface ComponentLibraryInfo {\n /** Direct library (from import source, e.g., \"@mui/material\" -> \"mui\") */\n library: LibraryName | null;\n /** Libraries used internally by this component (for local components) */\n internalLibraries: Set<LibraryName>;\n /** Evidence of which internal components caused the library detection */\n libraryEvidence: Array<{\n componentName: string;\n library: LibraryName;\n }>;\n /** Whether this is a local component (resolved from project files) */\n isLocalComponent: boolean;\n}\n\n/**\n * Cache for analyzed components: \"filePath::componentName\" -> ComponentLibraryInfo\n */\nconst componentLibraryCache = new Map<string, ComponentLibraryInfo>();\n\n/**\n * Get a singleton instance of the import graph service\n */\nexport function getImportGraphService() {\n return {\n getComponentLibrary,\n clearCache,\n };\n}\n\n/**\n * Analyze a component's library usage, including transitive dependencies\n *\n * @param contextFilePath - The file where the component is used (for resolving relative imports)\n * @param componentName - The name of the component (e.g., \"Button\", \"MyCard\")\n * @param importSource - The import source (e.g., \"@mui/material\", \"./components/cards\")\n * @returns Library information including direct and transitive library usage\n */\nexport function getComponentLibrary(\n contextFilePath: string,\n componentName: string,\n importSource: string\n): ComponentLibraryInfo {\n // Check if import source directly indicates a known library\n const directLibrary = detectLibraryFromSource(importSource);\n\n if (directLibrary) {\n // It's a direct import from a known library (e.g., @mui/material)\n return {\n library: directLibrary,\n internalLibraries: new Set(),\n libraryEvidence: [],\n isLocalComponent: false,\n };\n }\n\n // It's a local component - resolve and analyze it\n const resolvedPath = resolveImportPath(importSource, contextFilePath);\n\n if (!resolvedPath) {\n // Could not resolve - might be external or invalid\n return {\n library: null,\n internalLibraries: new Set(),\n libraryEvidence: [],\n isLocalComponent: false,\n };\n }\n\n // Check cache\n const cacheKey = `${resolvedPath}::${componentName}`;\n if (componentLibraryCache.has(cacheKey)) {\n return componentLibraryCache.get(cacheKey)!;\n }\n\n // Resolve re-exports to find the actual component definition\n const resolvedExport = resolveExport(componentName, resolvedPath);\n const actualFilePath = resolvedExport?.filePath ?? resolvedPath;\n const actualComponentName = resolvedExport?.localName ?? componentName;\n\n // Analyze the component body\n const result = analyzeComponentLibraries(\n actualFilePath,\n actualComponentName,\n new Set([cacheKey]) // Track visited to prevent cycles\n );\n\n componentLibraryCache.set(cacheKey, result);\n return result;\n}\n\n/**\n * Recursively analyze a component's library usage\n */\nfunction analyzeComponentLibraries(\n filePath: string,\n componentName: string,\n visited: Set<string>\n): ComponentLibraryInfo {\n const styleInfo = parseComponentBody(filePath, componentName);\n\n if (!styleInfo) {\n return {\n library: null,\n internalLibraries: new Set(),\n libraryEvidence: [],\n isLocalComponent: true,\n };\n }\n\n const internalLibraries = new Set<LibraryName>();\n const libraryEvidence: Array<{\n componentName: string;\n library: LibraryName;\n }> = [];\n\n // Check direct library usage within this component\n if (styleInfo.directLibrary) {\n internalLibraries.add(styleInfo.directLibrary);\n }\n\n // Analyze each used component\n for (const usedComponent of styleInfo.usedComponents) {\n const usedLibrary = detectLibraryFromSource(usedComponent.importSource);\n\n if (usedLibrary) {\n // Direct import from a known library\n internalLibraries.add(usedLibrary);\n libraryEvidence.push({\n componentName: usedComponent.name,\n library: usedLibrary,\n });\n } else {\n // It's a local component - recurse into it\n const resolvedPath = resolveImportPath(\n usedComponent.importSource,\n filePath\n );\n\n if (resolvedPath) {\n const cacheKey = `${resolvedPath}::${usedComponent.name}`;\n\n // Skip if already visited (cycle detection)\n if (!visited.has(cacheKey)) {\n visited.add(cacheKey);\n\n // Check cache first\n let nestedInfo: ComponentLibraryInfo;\n if (componentLibraryCache.has(cacheKey)) {\n nestedInfo = componentLibraryCache.get(cacheKey)!;\n } else {\n // Resolve re-exports\n const resolvedExport = resolveExport(\n usedComponent.name,\n resolvedPath\n );\n const actualFilePath = resolvedExport?.filePath ?? resolvedPath;\n const actualComponentName =\n resolvedExport?.localName ?? usedComponent.name;\n\n nestedInfo = analyzeComponentLibraries(\n actualFilePath,\n actualComponentName,\n visited\n );\n componentLibraryCache.set(cacheKey, nestedInfo);\n }\n\n // Aggregate the nested component's libraries\n if (nestedInfo.library) {\n internalLibraries.add(nestedInfo.library);\n libraryEvidence.push({\n componentName: usedComponent.name,\n library: nestedInfo.library,\n });\n }\n\n for (const lib of nestedInfo.internalLibraries) {\n internalLibraries.add(lib);\n }\n\n // Add evidence from nested components\n for (const evidence of nestedInfo.libraryEvidence) {\n libraryEvidence.push({\n componentName: `${usedComponent.name} → ${evidence.componentName}`,\n library: evidence.library,\n });\n }\n }\n }\n }\n }\n\n return {\n library: styleInfo.directLibrary,\n internalLibraries,\n libraryEvidence,\n isLocalComponent: true,\n };\n}\n\n/**\n * Clear all caches (useful for testing or between ESLint runs)\n */\nexport function clearCache(): void {\n componentLibraryCache.clear();\n clearResolverCaches();\n}\n\n// Re-export types for convenience\nexport type { LibraryName };\n","/**\n * Rule: no-mixed-component-libraries\n *\n * Forbids using non-preferred UI component libraries. Reports errors at\n * the JSX usage site, including transitive usage through local components.\n *\n * Examples:\n * - <MuiButton> from @mui/material -> error at <MuiButton> usage\n * - <MyCard> that internally uses MUI -> error at <MyCard> usage\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { createRule, defineRuleMeta } from \"../../utils/create-rule.js\";\nimport {\n getComponentLibrary,\n type LibraryName,\n} from \"./lib/import-graph.js\";\n\ntype MessageIds = \"nonPreferredLibrary\" | \"transitiveNonPreferred\";\ntype Options = [\n {\n /** The preferred UI library. Components from other libraries will be flagged. */\n preferred: LibraryName;\n /** Additional libraries to detect (defaults to common ones) */\n libraries?: LibraryName[];\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-mixed-component-libraries\",\n version: \"1.0.0\",\n name: \"No Mixed Component Libraries\",\n description: \"Forbid mixing component libraries (e.g., shadcn + MUI)\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🧩\",\n hint: \"Ensures consistent UI library usage\",\n defaultEnabled: true,\n isDirectoryBased: true,\n defaultOptions: [{ preferred: \"shadcn\", libraries: [\"shadcn\", \"mui\"] }],\n optionSchema: {\n fields: [\n {\n key: \"preferred\",\n label: \"Preferred component library\",\n type: \"select\",\n defaultValue: \"shadcn\",\n options: [\n { value: \"shadcn\", label: \"shadcn/ui\" },\n { value: \"mui\", label: \"MUI (Material-UI)\" },\n { value: \"chakra\", label: \"Chakra UI\" },\n { value: \"antd\", label: \"Ant Design\" },\n ],\n description: \"The preferred UI library. Components from other libraries will be flagged.\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects and reports when components from non-preferred UI libraries are used in your codebase.\nThis includes both direct imports and transitive usage through your own components that wrap\nnon-preferred libraries internally.\n\n## Why it's useful\n\n- **Consistency**: Ensures a uniform look and feel across your application\n- **Bundle size**: Prevents accidentally including multiple UI frameworks\n- **Maintenance**: Reduces the number of styling systems to maintain\n- **Migration support**: Helps identify what needs to change when migrating UI libraries\n\n## Examples\n\n### ❌ Incorrect (with preferred: \"shadcn\")\n\n\\`\\`\\`tsx\n// Direct MUI usage\nimport { Button } from '@mui/material';\n<Button>Click me</Button> // Error: Component <Button> is from mui\n\n// Transitive usage through local component\nimport { MyCard } from './components/MyCard'; // MyCard uses MUI internally\n<MyCard /> // Error: Component <MyCard> internally uses mui components\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using the preferred library\nimport { Button } from '@/components/ui/button';\nimport { Card } from '@/components/ui/card';\n\n<Button>Click me</Button>\n<Card>Content</Card>\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-mixed-component-libraries\": [\"error\", {\n preferred: \"shadcn\", // Your preferred library\n libraries: [\"shadcn\", \"mui\", \"chakra\", \"antd\"] // Libraries to detect\n}]\n\\`\\`\\`\n\n## Supported Libraries\n\n- **shadcn**: shadcn/ui components (imports from \\`@/components/ui/\\`)\n- **mui**: Material-UI (\\`@mui/material\\`, \\`@mui/joy\\`)\n- **chakra**: Chakra UI (\\`@chakra-ui/react\\`)\n- **antd**: Ant Design (\\`antd\\`)\n`,\n\n});\n\n/**\n * Information about a component usage in the file\n */\ninterface ComponentUsage {\n /** The JSX element node (for error reporting) */\n node: TSESTree.JSXOpeningElement;\n /** Component name (e.g., \"Button\", \"MuiCard\") */\n componentName: string;\n /** Import source (e.g., \"@mui/material\", \"./components/cards\") */\n importSource: string;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-mixed-component-libraries\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Forbid using non-preferred UI component libraries. Reports at JSX usage sites, including transitive usage.\",\n },\n messages: {\n nonPreferredLibrary:\n \"Component <{{component}}> is from {{library}}, but {{preferred}} is the preferred library.\",\n transitiveNonPreferred:\n \"Component <{{component}}> internally uses {{libraries}} components ({{internalComponents}}). The preferred library is {{preferred}}.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n preferred: {\n type: \"string\",\n enum: [\"shadcn\", \"mui\", \"chakra\", \"antd\"],\n description: \"The preferred UI library\",\n },\n libraries: {\n type: \"array\",\n items: {\n type: \"string\",\n enum: [\"shadcn\", \"mui\", \"chakra\", \"antd\"],\n },\n description: \"Libraries to detect (defaults to all)\",\n },\n },\n required: [\"preferred\"],\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n { preferred: \"shadcn\", libraries: [\"shadcn\", \"mui\", \"chakra\", \"antd\"] },\n ],\n create(context) {\n const options = context.options[0];\n const preferred = options.preferred;\n\n // Track imports: localName -> importSource\n const importMap = new Map<string, string>();\n\n // Track all component usages for analysis at Program:exit\n const componentUsages: ComponentUsage[] = [];\n\n return {\n ImportDeclaration(node) {\n const source = node.source.value as string;\n\n for (const spec of node.specifiers) {\n if (spec.type === \"ImportSpecifier\") {\n importMap.set(spec.local.name, source);\n } else if (spec.type === \"ImportDefaultSpecifier\") {\n importMap.set(spec.local.name, source);\n } else if (spec.type === \"ImportNamespaceSpecifier\") {\n importMap.set(spec.local.name, source);\n }\n }\n },\n\n JSXOpeningElement(node) {\n // Get the component name\n let componentName: string | null = null;\n\n if (node.name.type === \"JSXIdentifier\") {\n componentName = node.name.name;\n } else if (node.name.type === \"JSXMemberExpression\") {\n // Handle Namespace.Component (e.g., Modal.Header)\n let current = node.name.object;\n while (current.type === \"JSXMemberExpression\") {\n current = current.object;\n }\n if (current.type === \"JSXIdentifier\") {\n componentName = current.name;\n }\n }\n\n // Skip HTML elements (lowercase) and missing names\n if (!componentName || !/^[A-Z]/.test(componentName)) {\n return;\n }\n\n // Skip components that aren't imported (might be defined in same file)\n const importSource = importMap.get(componentName);\n if (!importSource) {\n return;\n }\n\n componentUsages.push({\n node,\n componentName,\n importSource,\n });\n },\n\n \"Program:exit\"() {\n const filename = context.filename || context.getFilename();\n\n for (const usage of componentUsages) {\n const libraryInfo = getComponentLibrary(\n filename,\n usage.componentName,\n usage.importSource\n );\n\n // Case 1: Direct import from non-preferred library\n if (libraryInfo.library && libraryInfo.library !== preferred) {\n context.report({\n node: usage.node,\n messageId: \"nonPreferredLibrary\",\n data: {\n component: usage.componentName,\n library: libraryInfo.library,\n preferred,\n },\n });\n continue;\n }\n\n // Case 2: Local component that uses non-preferred library internally\n if (\n libraryInfo.isLocalComponent &&\n libraryInfo.internalLibraries.size > 0\n ) {\n const nonPreferredLibs = [...libraryInfo.internalLibraries].filter(\n (lib) => lib !== preferred\n );\n\n if (nonPreferredLibs.length > 0) {\n // Get evidence of which internal components caused the violation\n const internalComponents = libraryInfo.libraryEvidence\n .filter((e) => e.library !== preferred)\n .map((e) => e.componentName)\n .slice(0, 3) // Limit to first 3 for readability\n .join(\", \");\n\n context.report({\n node: usage.node,\n messageId: \"transitiveNonPreferred\",\n data: {\n component: usage.componentName,\n libraries: nonPreferredLibs.join(\", \"),\n internalComponents: internalComponents || \"unknown\",\n preferred,\n },\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: semantic\n *\n * LLM-powered semantic UI analysis using the project's styleguide.\n * This is the only rule that reads .uilint/styleguide.md.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { spawnSync } from \"child_process\";\nimport { dirname, join, relative } from \"path\";\nimport { createRule, defineRuleMeta } from \"../../utils/create-rule.js\";\nimport {\n getCacheEntry,\n hashContentSync,\n setCacheEntry,\n type CachedIssue,\n} from \"./lib/cache.js\";\nimport { getStyleguide } from \"./lib/styleguide-loader.js\";\nimport { UILINT_DEFAULT_OLLAMA_MODEL } from \"uilint-core\";\nimport { buildSourceScanPrompt } from \"uilint-core\";\n\ntype MessageIds = \"semanticIssue\" | \"styleguideNotFound\" | \"analysisError\";\ntype Options = [\n {\n model?: string;\n styleguidePath?: string;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"semantic\",\n version: \"1.0.0\",\n name: \"Semantic Analysis\",\n description: \"LLM-powered semantic UI analysis using your styleguide\",\n defaultSeverity: \"warn\",\n category: \"semantic\",\n icon: \"🧠\",\n hint: \"LLM-powered UI analysis\",\n defaultEnabled: false,\n requiresStyleguide: true,\n plugin: \"semantic\",\n customInspector: \"semantic-issue\",\n requirements: [\n {\n type: \"ollama\",\n description: \"Requires Ollama running locally\",\n setupHint: \"Run: ollama serve && ollama pull qwen3-coder:30b\",\n },\n {\n type: \"styleguide\",\n description: \"Requires a styleguide file\",\n setupHint: \"Run: uilint genstyleguide\",\n },\n ],\n defaultOptions: [{ model: \"qwen3-coder:30b\", styleguidePath: \".uilint/styleguide.md\" }],\n optionSchema: {\n fields: [\n {\n key: \"model\",\n label: \"Ollama model to use\",\n type: \"text\",\n defaultValue: \"qwen3-coder:30b\",\n placeholder: \"qwen3-coder:30b\",\n description: \"The Ollama model name for semantic analysis\",\n },\n {\n key: \"styleguidePath\",\n label: \"Path to styleguide file\",\n type: \"text\",\n defaultValue: \".uilint/styleguide.md\",\n placeholder: \".uilint/styleguide.md\",\n description: \"Relative path to the styleguide markdown file\",\n },\n ],\n },\n docs: `\n## What it does\n\nUses a local LLM (via Ollama) to analyze your React components against your project's\nstyleguide. It catches semantic issues that pattern-based rules can't detect, like:\n- Using incorrect spacing that doesn't match your design system conventions\n- Inconsistent button styles across similar contexts\n- Missing accessibility patterns defined in your styleguide\n\n## Why it's useful\n\n- **Custom rules**: Enforces your project's unique conventions without writing custom ESLint rules\n- **Context-aware**: Understands component intent, not just syntax\n- **Evolving standards**: Update your styleguide, and the rule adapts automatically\n- **Local & private**: Runs entirely on your machine using Ollama\n\n## Prerequisites\n\n1. **Ollama installed**: \\`brew install ollama\\` or from ollama.ai\n2. **Model pulled**: \\`ollama pull qwen3-coder:30b\\` (or your preferred model)\n3. **Styleguide created**: Create \\`.uilint/styleguide.md\\` describing your conventions\n\n## Example Styleguide\n\n\\`\\`\\`markdown\n# UI Style Guide\n\n## Spacing\n- Use gap-4 for spacing between card elements\n- Use py-2 px-4 for button padding\n\n## Colors\n- Primary actions: bg-primary text-primary-foreground\n- Destructive actions: bg-destructive text-destructive-foreground\n\n## Components\n- All forms must include a Cancel button\n- Modal headers should use text-lg font-semibold\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/semantic\": [\"warn\", {\n model: \"qwen3-coder:30b\", // Ollama model name\n styleguidePath: \".uilint/styleguide.md\" // Path to styleguide\n}]\n\\`\\`\\`\n\n## Notes\n\n- Results are cached based on file content and styleguide hash\n- First run may be slow as the model loads; subsequent runs use cache\n- Works best with detailed, specific styleguide documentation\n- Set to \"off\" in CI to avoid slow builds (use pre-commit hooks locally)\n`,\n isDirectoryBased: true,\n});\n\nexport default createRule<Options, MessageIds>({\n name: \"semantic\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"LLM-powered semantic UI analysis using styleguide\",\n },\n messages: {\n semanticIssue: \"{{message}}\",\n styleguideNotFound:\n \"No styleguide found. Create .uilint/styleguide.md or specify styleguidePath.\",\n analysisError: \"Semantic analysis failed: {{error}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n model: {\n type: \"string\",\n description: \"Ollama model to use\",\n },\n styleguidePath: {\n type: \"string\",\n description: \"Path to styleguide file\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ model: UILINT_DEFAULT_OLLAMA_MODEL }],\n create(context) {\n const options = context.options[0] || {};\n const filePath = context.filename;\n const fileDir = dirname(filePath);\n\n // Get styleguide\n const { path: styleguidePath, content: styleguide } = getStyleguide(\n fileDir,\n options.styleguidePath\n );\n\n // Skip if no styleguide\n if (!styleguide) {\n console.error(\n `[uilint] Styleguide not found (styleguidePath=${String(\n options.styleguidePath ?? \"\"\n )}, startDir=${fileDir})`\n );\n\n return {\n Program(node) {\n context.report({\n node,\n messageId: \"styleguideNotFound\",\n });\n },\n };\n }\n\n // Read and hash file contents\n let fileContent: string;\n try {\n fileContent = readFileSync(filePath, \"utf-8\");\n } catch {\n console.error(`[uilint] Failed to read file ${filePath}`);\n return {\n Program(node) {\n context.report({\n node,\n messageId: \"analysisError\",\n data: { error: `Failed to read source file ${filePath}` },\n });\n },\n };\n }\n\n const fileHash = hashContentSync(fileContent);\n const styleguideHash = hashContentSync(styleguide);\n\n // Check cache\n const projectRoot = findProjectRoot(fileDir);\n const relativeFilePath = relative(projectRoot, filePath);\n const cached = getCacheEntry(\n projectRoot,\n relativeFilePath,\n fileHash,\n styleguideHash\n );\n\n const ENABLE_CACHE = false;\n if (ENABLE_CACHE && cached) {\n console.error(`[uilint] Cache hit for ${filePath}`);\n\n // Report cached issues\n return {\n Program(node) {\n for (const issue of cached.issues) {\n context.report({\n node,\n loc: { line: issue.line, column: issue.column || 0 },\n messageId: \"semanticIssue\",\n data: { message: issue.message },\n });\n }\n },\n };\n }\n\n // Cache miss: run sync analysis now (slow), cache, then report.\n ENABLE_CACHE &&\n console.error(\n `[uilint] Cache miss for ${filePath}, running semantic analysis`\n );\n\n return {\n Program(node) {\n const issues = runSemanticAnalysisSync(\n fileContent,\n styleguide,\n options.model || UILINT_DEFAULT_OLLAMA_MODEL,\n filePath\n );\n\n setCacheEntry(projectRoot, relativeFilePath, {\n fileHash,\n styleguideHash,\n issues,\n timestamp: Date.now(),\n });\n\n for (const issue of issues) {\n context.report({\n node,\n loc: { line: issue.line, column: issue.column || 0 },\n messageId: \"semanticIssue\",\n data: { message: issue.message },\n });\n }\n },\n };\n },\n});\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Run semantic analysis using Ollama (synchronously).\n *\n * Implementation detail:\n * - ESLint rules are synchronous.\n * - Blocking on a Promise (sleep-loop/Atomics) would also block Node's event loop,\n * preventing the HTTP request to Ollama from ever completing.\n * - To keep this simple & debuggable, we run the async LLM call in a child Node\n * process and synchronously wait for it to exit.\n */\nfunction runSemanticAnalysisSync(\n sourceCode: string,\n styleguide: string,\n model: string,\n filePath?: string\n): CachedIssue[] {\n const startTime = Date.now();\n const fileDisplay = filePath ? ` ${filePath}` : \"\";\n\n console.error(`[uilint] Starting semantic analysis (sync)${fileDisplay}`);\n console.error(`[uilint] Model: ${model}`);\n\n // Build prompt in-process (pure string building).\n const prompt = buildSourceScanPrompt(sourceCode, styleguide, {});\n\n // Avoid `uilint-core/node` exports *and* CJS resolution:\n // resolve the installed dependency by file URL relative to this plugin bundle.\n // When built, `import.meta.url` points at `.../uilint-eslint/dist/index.js`,\n // and the dependency lives at `.../uilint-eslint/node_modules/uilint-core/dist/node.js`.\n const coreNodeUrl = new URL(\n \"../node_modules/uilint-core/dist/node.js\",\n import.meta.url\n ).href;\n\n const childScript = `\n import * as coreNode from ${JSON.stringify(coreNodeUrl)};\n const { OllamaClient, logInfo, logWarning, createProgress, pc } = coreNode;\n const chunks = [];\n for await (const c of process.stdin) chunks.push(c);\n const input = JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n const model = input.model;\n const prompt = input.prompt;\n\n const client = new OllamaClient({ model });\n const ok = await client.isAvailable();\n if (!ok) {\n logWarning(\"Ollama not available, skipping semantic analysis\");\n process.stdout.write(JSON.stringify({ issues: [] }));\n process.exit(0);\n }\n\n logInfo(\\`Ollama connected \\${pc.dim(\\`(model: \\${model})\\`)}\\`);\n const progress = createProgress(\"Analyzing with LLM...\");\n try {\n const response = await client.complete(prompt, {\n json: true,\n stream: true,\n onProgress: (latestLine) => {\n const maxLen = 60;\n const display =\n latestLine.length > maxLen\n ? latestLine.slice(0, maxLen) + \"…\"\n : latestLine;\n progress.update(\\`LLM: \\${pc.dim(display || \"...\")}\\`);\n },\n });\n progress.succeed(\"LLM complete\");\n process.stdout.write(response);\n } catch (e) {\n progress.fail(\\`LLM failed: \\${e instanceof Error ? e.message : String(e)}\\`);\n process.exit(1);\n }\n `;\n\n const child = spawnSync(\n process.execPath,\n [\"--input-type=module\", \"-e\", childScript],\n {\n input: JSON.stringify({ model, prompt }),\n encoding: \"utf8\",\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n maxBuffer: 20 * 1024 * 1024,\n }\n );\n\n const elapsed = Date.now() - startTime;\n\n if (child.error) {\n console.error(\n `[uilint] Semantic analysis failed after ${elapsed}ms: ${child.error.message}`\n );\n return [];\n }\n\n if (typeof child.status === \"number\" && child.status !== 0) {\n console.error(\n `[uilint] Semantic analysis failed after ${elapsed}ms: child exited ${child.status}`\n );\n return [];\n }\n\n const responseText = (child.stdout || \"\").trim();\n if (!responseText) {\n console.error(\n `[uilint] Semantic analysis returned empty response (${elapsed}ms)`\n );\n return [];\n }\n\n try {\n const parsed = JSON.parse(responseText) as {\n issues?: Array<{ line?: number; column?: number; message?: string }>;\n };\n\n const issues = (parsed.issues || []).map((issue) => ({\n line: issue.line || 1,\n column: issue.column,\n message: issue.message || \"Semantic issue detected\",\n ruleId: \"uilint/semantic\",\n severity: 1 as const,\n }));\n\n if (issues.length > 0) {\n console.error(`[uilint] Found ${issues.length} issue(s) (${elapsed}ms)`);\n } else {\n console.error(`[uilint] No issues found (${elapsed}ms)`);\n }\n\n return issues;\n } catch (e) {\n console.error(\n `[uilint] Semantic analysis failed to parse response after ${elapsed}ms: ${\n e instanceof Error ? e.message : String(e)\n }`\n );\n return [];\n }\n}\n","/**\n * File-hash based caching for LLM semantic rule\n *\n * Uses xxhash for fast hashing of file contents.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\n// Lazy-loaded xxhash\nlet xxhashInstance: Awaited<\n ReturnType<typeof import(\"xxhash-wasm\")[\"default\"]>\n> | null = null;\n\nasync function getXxhash() {\n if (!xxhashInstance) {\n const xxhash = await import(\"xxhash-wasm\");\n xxhashInstance = await xxhash.default();\n }\n return xxhashInstance;\n}\n\n/**\n * Synchronous hash using a simple djb2 algorithm (fallback when xxhash not available)\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash * 33) ^ str.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n}\n\n/**\n * Hash content using xxhash (async) or djb2 (sync fallback)\n */\nexport async function hashContent(content: string): Promise<string> {\n try {\n const xxhash = await getXxhash();\n return xxhash.h64ToString(content);\n } catch {\n return djb2Hash(content);\n }\n}\n\n/**\n * Synchronous hash for when async is not possible\n */\nexport function hashContentSync(content: string): string {\n return djb2Hash(content);\n}\n\nexport interface CacheEntry {\n fileHash: string;\n styleguideHash: string;\n issues: CachedIssue[];\n timestamp: number;\n}\n\nexport interface CachedIssue {\n line: number;\n column?: number;\n message: string;\n ruleId: string;\n severity: 1 | 2; // 1 = warn, 2 = error\n}\n\nexport interface CacheStore {\n version: number;\n entries: Record<string, CacheEntry>;\n}\n\nconst CACHE_VERSION = 1;\nconst CACHE_FILE = \".uilint/.cache/eslint-semantic.json\";\n\n/**\n * Get the cache file path for a project\n */\nexport function getCachePath(projectRoot: string): string {\n return join(projectRoot, CACHE_FILE);\n}\n\n/**\n * Load the cache store\n */\nexport function loadCache(projectRoot: string): CacheStore {\n const cachePath = getCachePath(projectRoot);\n\n if (!existsSync(cachePath)) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n try {\n const content = readFileSync(cachePath, \"utf-8\");\n const cache = JSON.parse(content) as CacheStore;\n\n // Invalidate if version mismatch\n if (cache.version !== CACHE_VERSION) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n return cache;\n } catch {\n return { version: CACHE_VERSION, entries: {} };\n }\n}\n\n/**\n * Save the cache store\n */\nexport function saveCache(projectRoot: string, cache: CacheStore): void {\n const cachePath = getCachePath(projectRoot);\n\n try {\n const cacheDir = dirname(cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n }\n\n writeFileSync(cachePath, JSON.stringify(cache, null, 2), \"utf-8\");\n } catch {\n // Silently fail - caching is optional\n }\n}\n\n/**\n * Get cached entry for a file\n */\nexport function getCacheEntry(\n projectRoot: string,\n filePath: string,\n fileHash: string,\n styleguideHash: string\n): CacheEntry | null {\n const cache = loadCache(projectRoot);\n const entry = cache.entries[filePath];\n\n if (!entry) return null;\n\n // Check if hashes match\n if (entry.fileHash !== fileHash || entry.styleguideHash !== styleguideHash) {\n return null;\n }\n\n return entry;\n}\n\n/**\n * Set cached entry for a file\n */\nexport function setCacheEntry(\n projectRoot: string,\n filePath: string,\n entry: CacheEntry\n): void {\n const cache = loadCache(projectRoot);\n cache.entries[filePath] = entry;\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear cache for a specific file\n */\nexport function clearCacheEntry(projectRoot: string, filePath: string): void {\n const cache = loadCache(projectRoot);\n delete cache.entries[filePath];\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear entire cache\n */\nexport function clearCache(projectRoot: string): void {\n saveCache(projectRoot, { version: CACHE_VERSION, entries: {} });\n}\n","/**\n * Styleguide loader for the LLM semantic rule\n *\n * Only the semantic rule reads the styleguide - static rules use ESLint options.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { dirname, isAbsolute, join, resolve } from \"path\";\n\nconst DEFAULT_STYLEGUIDE_PATHS = [\n \".uilint/styleguide.md\",\n \".uilint/styleguide.yaml\",\n \".uilint/styleguide.yml\",\n];\n\n/**\n * Find workspace root by walking up looking for pnpm-workspace.yaml, package.json, or .git\n */\nfunction findWorkspaceRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (\n existsSync(join(dir, \"pnpm-workspace.yaml\")) ||\n existsSync(join(dir, \".git\"))\n ) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Find the nearest package root (directory containing package.json),\n * stopping at the workspace root.\n */\nfunction findNearestPackageRoot(\n startDir: string,\n workspaceRoot: string\n): string {\n let dir = startDir;\n for (let i = 0; i < 30; i++) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n if (dir === workspaceRoot) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Find the styleguide file path\n */\nexport function findStyleguidePath(\n startDir: string,\n explicitPath?: string\n): string | null {\n // Explicit path takes precedence\n if (explicitPath) {\n if (isAbsolute(explicitPath)) {\n return existsSync(explicitPath) ? explicitPath : null;\n }\n\n // For relative explicit paths, try:\n // 1) relative to the file dir (back-compat)\n // 2) relative to the nearest package root (typical \"project root\")\n // 3) relative to workspace root (monorepo root)\n const workspaceRoot = findWorkspaceRoot(startDir);\n const packageRoot = findNearestPackageRoot(startDir, workspaceRoot);\n\n const candidates = [\n resolve(startDir, explicitPath),\n resolve(packageRoot, explicitPath),\n resolve(workspaceRoot, explicitPath),\n ];\n\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n\n return null;\n }\n\n // Check from start dir up to workspace root\n const workspaceRoot = findWorkspaceRoot(startDir);\n let dir = startDir;\n\n while (true) {\n for (const relativePath of DEFAULT_STYLEGUIDE_PATHS) {\n const fullPath = join(dir, relativePath);\n if (existsSync(fullPath)) {\n return fullPath;\n }\n }\n\n // Stop at workspace root\n if (dir === workspaceRoot) break;\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n return null;\n}\n\n/**\n * Load styleguide content from file\n */\nexport function loadStyleguide(\n startDir: string,\n explicitPath?: string\n): string | null {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return null;\n\n try {\n return readFileSync(path, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Get styleguide path and content\n */\nexport function getStyleguide(\n startDir: string,\n explicitPath?: string\n): { path: string | null; content: string | null } {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return { path: null, content: null };\n\n try {\n const content = readFileSync(path, \"utf-8\");\n return { path, content };\n } catch {\n return { path, content: null };\n }\n}\n","/**\n * Rule: semantic-vision\n *\n * ESLint rule that reports cached vision analysis results for UI elements.\n * Vision analysis is performed by the UILint browser overlay and results are\n * cached in .uilint/screenshots/{timestamp}-{route}.json files.\n *\n * This rule:\n * 1. Finds cached vision analysis results for the current file\n * 2. Reports any issues that match elements in this file (by data-loc)\n * 3. If no cached results exist, silently passes (analysis is triggered by browser)\n */\n\nimport { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { dirname, join, relative } from \"path\";\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"visionIssue\" | \"analysisStale\";\n\ntype Options = [\n {\n /** Maximum age of cached results in milliseconds (default: 1 hour) */\n maxAgeMs?: number;\n /** Path to screenshots directory (default: .uilint/screenshots) */\n screenshotsPath?: string;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"semantic-vision\",\n version: \"1.0.0\",\n name: \"Vision Analysis\",\n description: \"Report cached vision analysis results from UILint browser overlay\",\n defaultSeverity: \"warn\",\n category: \"semantic\",\n icon: \"👁️\",\n hint: \"Vision AI for rendered UI\",\n defaultEnabled: false,\n requiresStyleguide: false,\n plugin: \"vision\",\n customInspector: \"vision-issue\",\n heatmapColor: \"#8B5CF6\",\n postInstallInstructions: \"Add the UILint browser overlay to your app and run analysis from the browser to generate cached results.\",\n defaultOptions: [{ maxAgeMs: 3600000, screenshotsPath: \".uilint/screenshots\" }],\n optionSchema: {\n fields: [\n {\n key: \"maxAgeMs\",\n label: \"Max cache age (milliseconds)\",\n type: \"number\",\n defaultValue: 3600000,\n placeholder: \"3600000\",\n description: \"Maximum age of cached results in milliseconds (default: 1 hour)\",\n },\n {\n key: \"screenshotsPath\",\n label: \"Screenshots directory path\",\n type: \"text\",\n defaultValue: \".uilint/screenshots\",\n placeholder: \".uilint/screenshots\",\n description: \"Relative path to the screenshots directory containing analysis results\",\n },\n ],\n },\n docs: `\n## What it does\n\nReports UI issues found by the UILint browser overlay's vision analysis. The overlay\ncaptures screenshots and analyzes them using vision AI, then caches the results.\nThis ESLint rule reads those cached results and reports them as linting errors.\n\n## How it works\n\n1. **Browser overlay**: When running your dev server with the UILint overlay, it captures\n screenshots and analyzes them using vision AI\n2. **Results cached**: Analysis results are saved to \\`.uilint/screenshots/*.json\\`\n3. **ESLint reports**: This rule reads cached results and reports issues at the correct\n source locations using \\`data-loc\\` attributes\n\n## Why it's useful\n\n- **Visual issues**: Catches problems that can only be seen in rendered UI\n- **Continuous feedback**: Issues appear in your editor as you develop\n- **No manual review**: AI spots spacing, alignment, and consistency issues automatically\n\n## Prerequisites\n\n1. **UILint overlay installed**: Add the overlay component to your app\n2. **Run analysis**: Load pages in the browser with the overlay active\n3. **Results cached**: Wait for analysis to complete and cache results\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/semantic-vision\": [\"warn\", {\n maxAgeMs: 3600000, // Ignore results older than 1 hour\n screenshotsPath: \".uilint/screenshots\" // Where cached results are stored\n}]\n\\`\\`\\`\n\n## Notes\n\n- If no cached results exist, the rule passes silently\n- Results are matched to source files using \\`data-loc\\` attributes\n- Stale results (older than \\`maxAgeMs\\`) are reported as warnings\n- Run the browser overlay to refresh cached analysis\n`,\n});\n\n/**\n * Vision analysis result structure stored in JSON files\n */\ninterface VisionAnalysisResult {\n /** Timestamp when analysis was performed */\n timestamp: number;\n /** Route that was analyzed (e.g., \"/\", \"/profile\") */\n route: string;\n /** Screenshot filename (for reference) */\n screenshotFile?: string;\n /** Issues found by vision analysis */\n issues: VisionIssue[];\n}\n\n/**\n * Individual issue from vision analysis\n */\ninterface VisionIssue {\n /** Element text that the LLM referenced */\n elementText?: string;\n /** data-loc reference (format: \"path:line:column\") */\n dataLoc?: string;\n /** Human-readable description of the issue */\n message: string;\n /** Issue category */\n category?: \"spacing\" | \"color\" | \"typography\" | \"alignment\" | \"accessibility\" | \"layout\" | \"other\";\n /** Severity level */\n severity?: \"error\" | \"warning\" | \"info\";\n}\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Get all vision analysis result files from screenshots directory\n */\nfunction getVisionResultFiles(screenshotsDir: string): string[] {\n if (!existsSync(screenshotsDir)) {\n return [];\n }\n\n try {\n const files = readdirSync(screenshotsDir);\n return files\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => join(screenshotsDir, f))\n .sort()\n .reverse(); // Most recent first\n } catch {\n return [];\n }\n}\n\n/**\n * Load and parse a vision analysis result file\n */\nfunction loadVisionResult(filePath: string): VisionAnalysisResult | null {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as VisionAnalysisResult;\n } catch {\n return null;\n }\n}\n\n/**\n * Parse a data-loc string into file path and location\n * Format: \"path/to/file.tsx:line:column\"\n */\nfunction parseDataLoc(dataLoc: string): { filePath: string; line: number; column: number } | null {\n // Match pattern: path:line:column (line and column are numbers)\n const match = dataLoc.match(/^(.+):(\\d+):(\\d+)$/);\n if (!match) return null;\n\n return {\n filePath: match[1]!,\n line: parseInt(match[2]!, 10),\n column: parseInt(match[3]!, 10),\n };\n}\n\n/**\n * Normalize file path for comparison (handle relative vs absolute paths)\n */\nfunction normalizeFilePath(filePath: string, projectRoot: string): string {\n // If it's already a relative path, return as-is\n if (!filePath.startsWith(\"/\")) {\n return filePath;\n }\n // Convert absolute to relative\n return relative(projectRoot, filePath);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"semantic-vision\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Report cached vision analysis results from UILint browser overlay\",\n },\n messages: {\n visionIssue: \"[Vision] {{message}}\",\n analysisStale:\n \"Vision analysis results are stale (older than {{age}}). Re-run analysis in browser.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxAgeMs: {\n type: \"number\",\n description:\n \"Maximum age of cached results in milliseconds (default: 1 hour)\",\n },\n screenshotsPath: {\n type: \"string\",\n description:\n \"Path to screenshots directory (default: .uilint/screenshots)\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ maxAgeMs: 60 * 60 * 1000 }], // 1 hour default\n create(context) {\n const options = context.options[0] || {};\n const maxAgeMs = options.maxAgeMs ?? 60 * 60 * 1000;\n const filePath = context.filename;\n const fileDir = dirname(filePath);\n\n // Find project root and screenshots directory\n const projectRoot = findProjectRoot(fileDir);\n const screenshotsDir = options.screenshotsPath\n ? join(projectRoot, options.screenshotsPath)\n : join(projectRoot, \".uilint\", \"screenshots\");\n\n // Get the relative path of the current file for matching against data-loc\n const relativeFilePath = normalizeFilePath(filePath, projectRoot);\n\n // Find all vision result files\n const resultFiles = getVisionResultFiles(screenshotsDir);\n if (resultFiles.length === 0) {\n // No cached results - silently pass (analysis happens in browser)\n return {};\n }\n\n // Collect issues that match this file from all recent results\n const matchingIssues: Array<{\n issue: VisionIssue;\n line: number;\n column: number;\n isStale: boolean;\n }> = [];\n\n const now = Date.now();\n\n for (const resultFile of resultFiles) {\n const result = loadVisionResult(resultFile);\n if (!result || !result.issues) continue;\n\n const isStale = now - result.timestamp > maxAgeMs;\n\n for (const issue of result.issues) {\n if (!issue.dataLoc) continue;\n\n const parsed = parseDataLoc(issue.dataLoc);\n if (!parsed) continue;\n\n // Check if this issue is for the current file\n const issueFilePath = normalizeFilePath(parsed.filePath, projectRoot);\n if (issueFilePath === relativeFilePath) {\n matchingIssues.push({\n issue,\n line: parsed.line,\n column: parsed.column,\n isStale,\n });\n }\n }\n }\n\n // De-duplicate issues by line:column:message\n const seenIssues = new Set<string>();\n const uniqueIssues = matchingIssues.filter((item) => {\n const key = `${item.line}:${item.column}:${item.issue.message}`;\n if (seenIssues.has(key)) return false;\n seenIssues.add(key);\n return true;\n });\n\n return {\n Program(node) {\n for (const { issue, line, column, isStale } of uniqueIssues) {\n // Build message with category prefix if available\n const categoryPrefix = issue.category\n ? `[${issue.category}] `\n : \"\";\n const message = `${categoryPrefix}${issue.message}`;\n\n // Report stale warning separately if enabled\n if (isStale) {\n const ageHours = Math.round(maxAgeMs / (60 * 60 * 1000));\n context.report({\n node,\n loc: { line, column },\n messageId: \"analysisStale\",\n data: { age: `${ageHours}h` },\n });\n }\n\n context.report({\n node,\n loc: { line, column },\n messageId: \"visionIssue\",\n data: { message },\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: enforce-absolute-imports\n *\n * Requires alias imports (e.g., @/) for imports that traverse more than a\n * configurable number of directory levels. Prevents fragile relative import\n * paths like ../../../utils/helper.\n *\n * Examples:\n * - Bad: import { x } from '../../utils/helper'\n * - Good: import { x } from '@/utils/helper'\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferAbsoluteImport\";\ntype Options = [\n {\n /** Maximum allowed parent directory traversals (default: 1, allows ../ but not ../../) */\n maxRelativeDepth?: number;\n /** The alias prefix to suggest (default: \"@/\") */\n aliasPrefix?: string;\n /** Patterns to ignore (e.g., [\"node_modules\", \".css\"]) */\n ignorePaths?: string[];\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"enforce-absolute-imports\",\n version: \"1.0.0\",\n name: \"Enforce Absolute Imports\",\n description:\n \"Require alias imports for paths beyond a configurable directory depth\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"📦\",\n hint: \"Prevents deep relative imports\",\n defaultEnabled: true,\n defaultOptions: [{ maxRelativeDepth: 1, aliasPrefix: \"@/\" }],\n optionSchema: {\n fields: [\n {\n key: \"maxRelativeDepth\",\n label: \"Maximum relative depth\",\n type: \"number\",\n defaultValue: 1,\n description:\n \"Maximum number of parent directory traversals allowed (../ counts as 1)\",\n },\n {\n key: \"aliasPrefix\",\n label: \"Alias prefix\",\n type: \"text\",\n defaultValue: \"@/\",\n description: \"The path alias prefix to use (e.g., @/, ~/)\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnforces the use of path aliases (like \\`@/\\`) for imports that traverse multiple\nparent directories. This prevents fragile relative imports that are hard to\nmaintain and refactor.\n\n## Why it's useful\n\n- **Maintainability**: Absolute imports don't break when files move\n- **Readability**: Clear indication of where imports come from\n- **Consistency**: Standardizes import style across the codebase\n- **Refactoring**: Easier to move files without updating import paths\n\n## Examples\n\n### ❌ Incorrect (with maxRelativeDepth: 1)\n\n\\`\\`\\`tsx\n// Too many parent traversals\nimport { Button } from '../../components/Button';\nimport { utils } from '../../../lib/utils';\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using alias imports\nimport { Button } from '@/components/Button';\nimport { utils } from '@/lib/utils';\n\n// Single parent traversal (within threshold)\nimport { sibling } from '../sibling';\nimport { local } from './local';\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/enforce-absolute-imports\": [\"warn\", {\n maxRelativeDepth: 1, // Allow ../ but not ../../\n aliasPrefix: \"@/\", // Suggested alias prefix\n ignorePaths: [\".css\", \".scss\", \"node_modules\"]\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Count the number of parent directory traversals in an import path\n */\nfunction countParentTraversals(importSource: string): number {\n // Match all occurrences of ../ or ..\\\\ (Windows)\n const matches = importSource.match(/\\.\\.\\//g);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check if an import is a relative path\n */\nfunction isRelativeImport(importSource: string): boolean {\n return importSource.startsWith(\"./\") || importSource.startsWith(\"../\");\n}\n\n/**\n * Check if the import should be ignored\n */\nfunction shouldIgnore(importSource: string, ignorePaths: string[]): boolean {\n return ignorePaths.some((pattern) => importSource.includes(pattern));\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"enforce-absolute-imports\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Require alias imports for paths beyond a configurable directory depth\",\n },\n messages: {\n preferAbsoluteImport:\n \"Import traverses {{depth}} parent director{{plural}}. Use an alias like '{{aliasPrefix}}...' instead of '{{importSource}}'.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxRelativeDepth: {\n type: \"number\",\n minimum: 0,\n description:\n \"Maximum number of parent directory traversals allowed\",\n },\n aliasPrefix: {\n type: \"string\",\n description: \"The path alias prefix to suggest\",\n },\n ignorePaths: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Patterns to ignore\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n maxRelativeDepth: 1,\n aliasPrefix: \"@/\",\n ignorePaths: [],\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const maxRelativeDepth = options.maxRelativeDepth ?? 1;\n const aliasPrefix = options.aliasPrefix ?? \"@/\";\n const ignorePaths = options.ignorePaths ?? [];\n\n /**\n * Check an import source and report if it exceeds the depth threshold\n */\n function checkImportSource(\n source: string,\n node: TSESTree.StringLiteral\n ): void {\n // Skip non-relative imports (node_modules, aliases, etc.)\n if (!isRelativeImport(source)) {\n return;\n }\n\n // Skip ignored paths\n if (shouldIgnore(source, ignorePaths)) {\n return;\n }\n\n const depth = countParentTraversals(source);\n\n if (depth > maxRelativeDepth) {\n context.report({\n node,\n messageId: \"preferAbsoluteImport\",\n data: {\n depth: String(depth),\n plural: depth === 1 ? \"y\" : \"ies\",\n aliasPrefix,\n importSource: source,\n },\n });\n }\n }\n\n return {\n // Standard import declarations: import { x } from '../../utils'\n ImportDeclaration(node) {\n const source = node.source.value as string;\n checkImportSource(source, node.source);\n },\n\n // Re-exports with source: export { x } from '../../utils'\n ExportNamedDeclaration(node) {\n if (node.source) {\n const source = node.source.value as string;\n checkImportSource(source, node.source);\n }\n },\n\n // Export all: export * from '../../utils'\n ExportAllDeclaration(node) {\n const source = node.source.value as string;\n checkImportSource(source, node.source);\n },\n };\n },\n});\n","/**\n * Rule: no-any-in-props\n *\n * Prevents React components from using `any` type in their props, ensuring\n * type safety at component boundaries.\n *\n * Examples:\n * - Bad: function Component(props: any) {}\n * - Bad: function Component({ x }: { x: any }) {}\n * - Bad: const Component: FC<any> = () => {}\n * - Good: function Component(props: { name: string }) {}\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"anyInProps\" | \"anyInPropsProperty\";\ntype Options = [\n {\n /** Also check FC<any> and React.FC<any> patterns */\n checkFCGenerics?: boolean;\n /** Allow any in generic defaults (e.g., <T = any>) */\n allowInGenericDefaults?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-any-in-props\",\n version: \"1.0.0\",\n name: \"No Any in Props\",\n description: \"Disallow 'any' type in React component props\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🔒\",\n hint: \"Ensures type safety in component props\",\n defaultEnabled: true,\n defaultOptions: [{ checkFCGenerics: true, allowInGenericDefaults: false }],\n optionSchema: {\n fields: [\n {\n key: \"checkFCGenerics\",\n label: \"Check FC generics\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Check FC<any> and React.FC<any> patterns\",\n },\n {\n key: \"allowInGenericDefaults\",\n label: \"Allow in generic defaults\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Allow any in generic type parameter defaults\",\n },\n ],\n },\n docs: `\n## What it does\n\nPrevents the use of \\`any\\` type in React component props. This ensures type\nsafety at component boundaries, catching type errors at compile time rather\nthan runtime.\n\n## Why it's useful\n\n- **Type Safety**: Catches prop type errors at compile time\n- **Documentation**: Props serve as self-documenting API\n- **Refactoring**: IDE can track prop usage across codebase\n- **Code Quality**: Encourages thoughtful API design\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Direct any annotation\nfunction Component(props: any) {}\n\n// Any in destructured props\nfunction Component({ data }: { data: any }) {}\n\n// FC with any generic\nconst Component: FC<any> = () => {};\n\n// Any in props interface\ninterface Props { value: any }\nfunction Component(props: Props) {}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Properly typed props\nfunction Component(props: { name: string }) {}\n\n// Using unknown for truly unknown types\nfunction Component({ data }: { data: unknown }) {}\n\n// Typed FC\nconst Component: FC<{ count: number }> = () => {};\n\n// Generic component with constraint\nfunction List<T extends object>(props: { items: T[] }) {}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-any-in-props\": [\"error\", {\n checkFCGenerics: true, // Check FC<any> patterns\n allowInGenericDefaults: false // Disallow <T = any>\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Check if a name is likely a React component (PascalCase, not a hook)\n */\nfunction isComponentName(name: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(name) && !name.startsWith(\"Use\");\n}\n\n/**\n * Check if a type node contains 'any'\n */\nfunction containsAnyType(\n node: TSESTree.TypeNode,\n allowInGenericDefaults: boolean\n): { hasAny: boolean; location: string | null } {\n if (!node) {\n return { hasAny: false, location: null };\n }\n\n switch (node.type) {\n case \"TSAnyKeyword\":\n return { hasAny: true, location: null };\n\n case \"TSTypeLiteral\":\n // Check each property in { prop: any }\n for (const member of node.members) {\n if (\n member.type === \"TSPropertySignature\" &&\n member.typeAnnotation?.typeAnnotation\n ) {\n const result = containsAnyType(\n member.typeAnnotation.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n const propName =\n member.key.type === \"Identifier\" ? member.key.name : \"property\";\n return { hasAny: true, location: `property '${propName}'` };\n }\n }\n // Index signature [key: string]: any\n if (\n member.type === \"TSIndexSignature\" &&\n member.typeAnnotation?.typeAnnotation\n ) {\n const result = containsAnyType(\n member.typeAnnotation.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n return { hasAny: true, location: \"index signature\" };\n }\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSUnionType\":\n case \"TSIntersectionType\":\n for (const typeNode of node.types) {\n const result = containsAnyType(typeNode, allowInGenericDefaults);\n if (result.hasAny) {\n return result;\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSArrayType\":\n return containsAnyType(node.elementType, allowInGenericDefaults);\n\n case \"TSTypeReference\":\n // Check generic arguments like Array<any>, Record<string, any>\n if (node.typeArguments) {\n for (const param of node.typeArguments.params) {\n const result = containsAnyType(param, allowInGenericDefaults);\n if (result.hasAny) {\n return { hasAny: true, location: \"generic argument\" };\n }\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSFunctionType\":\n // Check return type and parameters\n if (node.returnType?.typeAnnotation) {\n const result = containsAnyType(\n node.returnType.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n return { hasAny: true, location: \"function return type\" };\n }\n }\n for (const param of node.params) {\n // Skip TSParameterProperty (doesn't have typeAnnotation) and RestElement\n if (\n param.type !== \"RestElement\" &&\n param.type !== \"TSParameterProperty\" &&\n \"typeAnnotation\" in param &&\n param.typeAnnotation?.typeAnnotation\n ) {\n const result = containsAnyType(\n param.typeAnnotation.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n return { hasAny: true, location: \"function parameter\" };\n }\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSTupleType\":\n for (const elementType of node.elementTypes) {\n // Handle both TSNamedTupleMember and regular type nodes\n const typeToCheck =\n elementType.type === \"TSNamedTupleMember\"\n ? elementType.elementType\n : elementType;\n const result = containsAnyType(typeToCheck, allowInGenericDefaults);\n if (result.hasAny) {\n return { hasAny: true, location: \"tuple element\" };\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSConditionalType\":\n // Check all parts of conditional type\n const checkResult = containsAnyType(\n node.checkType,\n allowInGenericDefaults\n );\n if (checkResult.hasAny) return checkResult;\n const extendsResult = containsAnyType(\n node.extendsType,\n allowInGenericDefaults\n );\n if (extendsResult.hasAny) return extendsResult;\n const trueResult = containsAnyType(\n node.trueType,\n allowInGenericDefaults\n );\n if (trueResult.hasAny) return trueResult;\n const falseResult = containsAnyType(\n node.falseType,\n allowInGenericDefaults\n );\n if (falseResult.hasAny) return falseResult;\n return { hasAny: false, location: null };\n\n case \"TSMappedType\":\n if (node.typeAnnotation) {\n return containsAnyType(node.typeAnnotation, allowInGenericDefaults);\n }\n return { hasAny: false, location: null };\n\n default:\n return { hasAny: false, location: null };\n }\n}\n\n/**\n * Get the name of a function or component\n */\nfunction getComponentName(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression\n): string | null {\n // Function declaration: function Foo() {}\n if (node.type === \"FunctionDeclaration\" && node.id) {\n return node.id.name;\n }\n\n // Variable declarator: const Foo = () => {}\n const parent = node.parent;\n if (\n parent?.type === \"VariableDeclarator\" &&\n parent.id.type === \"Identifier\"\n ) {\n return parent.id.name;\n }\n\n // forwardRef/memo wrapper: const Foo = forwardRef(() => {})\n if (parent?.type === \"CallExpression\") {\n const callParent = parent.parent;\n if (\n callParent?.type === \"VariableDeclarator\" &&\n callParent.id.type === \"Identifier\"\n ) {\n return callParent.id.name;\n }\n }\n\n // Named function expression: const x = function Foo() {}\n if (node.type === \"FunctionExpression\" && node.id) {\n return node.id.name;\n }\n\n return null;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-any-in-props\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Disallow 'any' type in React component props\",\n },\n messages: {\n anyInProps:\n \"Component '{{componentName}}' has 'any' type in props. Use a specific type or 'unknown' instead.\",\n anyInPropsProperty:\n \"Component '{{componentName}}' has 'any' type in {{location}}. Use a specific type or 'unknown' instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n checkFCGenerics: {\n type: \"boolean\",\n description: \"Check FC<any> and React.FC<any> patterns\",\n },\n allowInGenericDefaults: {\n type: \"boolean\",\n description: \"Allow any in generic type parameter defaults\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n checkFCGenerics: true,\n allowInGenericDefaults: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const checkFCGenerics = options.checkFCGenerics ?? true;\n const allowInGenericDefaults = options.allowInGenericDefaults ?? false;\n\n /**\n * Check a function's first parameter for any type\n */\n function checkFunctionProps(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression\n ): void {\n const componentName = getComponentName(node);\n\n // Skip if not a component (not PascalCase)\n if (!componentName || !isComponentName(componentName)) {\n return;\n }\n\n // Check first parameter (props)\n const firstParam = node.params[0];\n if (!firstParam) {\n return;\n }\n\n // Get type annotation\n let typeAnnotation: TSESTree.TypeNode | null = null;\n\n if (firstParam.type === \"Identifier\" && firstParam.typeAnnotation) {\n typeAnnotation = firstParam.typeAnnotation.typeAnnotation;\n } else if (\n firstParam.type === \"ObjectPattern\" &&\n firstParam.typeAnnotation\n ) {\n typeAnnotation = firstParam.typeAnnotation.typeAnnotation;\n }\n\n if (typeAnnotation) {\n const result = containsAnyType(typeAnnotation, allowInGenericDefaults);\n if (result.hasAny) {\n context.report({\n node: firstParam,\n messageId: result.location ? \"anyInPropsProperty\" : \"anyInProps\",\n data: {\n componentName,\n location: result.location || \"props\",\n },\n });\n }\n }\n }\n\n /**\n * Check FC<any> or React.FC<any> patterns\n */\n function checkFCGeneric(node: TSESTree.VariableDeclarator): void {\n if (!checkFCGenerics) {\n return;\n }\n\n // Get variable name\n if (node.id.type !== \"Identifier\") {\n return;\n }\n const componentName = node.id.name;\n\n // Skip if not a component name\n if (!isComponentName(componentName)) {\n return;\n }\n\n // Check type annotation\n const typeAnnotation = node.id.typeAnnotation?.typeAnnotation;\n if (!typeAnnotation || typeAnnotation.type !== \"TSTypeReference\") {\n return;\n }\n\n // Check if it's FC or React.FC\n let isFCType = false;\n if (\n typeAnnotation.typeName.type === \"Identifier\" &&\n [\"FC\", \"FunctionComponent\", \"VFC\"].includes(typeAnnotation.typeName.name)\n ) {\n isFCType = true;\n } else if (\n typeAnnotation.typeName.type === \"TSQualifiedName\" &&\n typeAnnotation.typeName.left.type === \"Identifier\" &&\n typeAnnotation.typeName.left.name === \"React\" &&\n [\"FC\", \"FunctionComponent\", \"VFC\"].includes(\n typeAnnotation.typeName.right.name\n )\n ) {\n isFCType = true;\n }\n\n if (!isFCType || !typeAnnotation.typeArguments) {\n return;\n }\n\n // Check the type argument\n const firstTypeArg = typeAnnotation.typeArguments.params[0];\n if (firstTypeArg) {\n const result = containsAnyType(firstTypeArg, allowInGenericDefaults);\n if (result.hasAny) {\n context.report({\n node: firstTypeArg,\n messageId: result.location ? \"anyInPropsProperty\" : \"anyInProps\",\n data: {\n componentName,\n location: result.location || \"FC type parameter\",\n },\n });\n }\n }\n }\n\n return {\n FunctionDeclaration(node) {\n checkFunctionProps(node);\n },\n\n ArrowFunctionExpression(node) {\n checkFunctionProps(node);\n },\n\n FunctionExpression(node) {\n checkFunctionProps(node);\n },\n\n VariableDeclarator(node) {\n checkFCGeneric(node);\n },\n };\n },\n});\n","/**\n * Rule: zustand-use-selectors\n *\n * Requires selector functions when accessing Zustand store state to prevent\n * unnecessary re-renders.\n *\n * Examples:\n * - Bad: const state = useStore()\n * - Bad: const { count } = useStore()\n * - Good: const count = useStore((s) => s.count)\n * - Good: const count = useStore(selectCount)\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"missingSelector\" | \"useSelectorFunction\";\ntype Options = [\n {\n /** Regex pattern for store hook names (default: \"^use\\\\w*Store$\") */\n storePattern?: string;\n /** Allow useShallow() wrapper without selector */\n allowShallow?: boolean;\n /** Require named selector functions instead of inline arrows */\n requireNamedSelectors?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"zustand-use-selectors\",\n version: \"1.0.0\",\n name: \"Zustand Use Selectors\",\n description: \"Require selector functions when accessing Zustand store state\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"⚡\",\n hint: \"Prevents unnecessary re-renders\",\n defaultEnabled: true,\n defaultOptions: [\n { storePattern: \"^use\\\\w*Store$\", allowShallow: true, requireNamedSelectors: false },\n ],\n optionSchema: {\n fields: [\n {\n key: \"storePattern\",\n label: \"Store hook pattern\",\n type: \"text\",\n defaultValue: \"^use\\\\w*Store$\",\n description: \"Regex pattern for identifying Zustand store hooks\",\n },\n {\n key: \"allowShallow\",\n label: \"Allow useShallow\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Allow useShallow() wrapper without explicit selector\",\n },\n {\n key: \"requireNamedSelectors\",\n label: \"Require named selectors\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Require named selector functions instead of inline arrows\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnforces the use of selector functions when accessing Zustand store state.\nWhen you call a Zustand store without a selector, your component subscribes\nto the entire store and re-renders on any state change.\n\n## Why it's useful\n\n- **Performance**: Prevents unnecessary re-renders\n- **Optimization**: Components only update when selected state changes\n- **Best Practice**: Follows Zustand's recommended patterns\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Subscribes to entire store - re-renders on any change\nconst state = useStore();\nconst { count, user } = useStore();\n\n// Component re-renders when anything changes, not just count\nfunction Counter() {\n const { count } = useStore();\n return <span>{count}</span>;\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Only re-renders when count changes\nconst count = useStore((state) => state.count);\n\n// Named selector\nconst selectCount = (state) => state.count;\nconst count = useStore(selectCount);\n\n// Multiple values with shallow\nimport { useShallow } from 'zustand/shallow';\nconst { count, user } = useStore(\n useShallow((state) => ({ count: state.count, user: state.user }))\n);\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/zustand-use-selectors\": [\"warn\", {\n storePattern: \"^use\\\\\\\\w*Store$\", // Match useXxxStore pattern\n allowShallow: true, // Allow useShallow without inline selector\n requireNamedSelectors: false // Allow inline arrow selectors\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Check if a node is a Zustand store call based on the pattern\n */\nfunction isZustandStoreCall(\n callee: TSESTree.Node,\n storePattern: RegExp\n): boolean {\n if (callee.type === \"Identifier\") {\n return storePattern.test(callee.name);\n }\n return false;\n}\n\n/**\n * Check if the first argument is a selector function or reference\n */\nfunction hasSelector(args: TSESTree.CallExpressionArgument[]): boolean {\n if (args.length === 0) {\n return false;\n }\n\n const firstArg = args[0];\n\n // Arrow function: (s) => s.count\n if (firstArg.type === \"ArrowFunctionExpression\") {\n return true;\n }\n\n // Function expression: function(s) { return s.count; }\n if (firstArg.type === \"FunctionExpression\") {\n return true;\n }\n\n // Named selector reference: selectCount\n if (firstArg.type === \"Identifier\") {\n return true;\n }\n\n // Member expression: selectors.count or module.selectCount\n if (firstArg.type === \"MemberExpression\") {\n return true;\n }\n\n // Call expression (might be useShallow or similar)\n if (firstArg.type === \"CallExpression\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if the selector is wrapped in useShallow\n */\nfunction isShallowWrapped(args: TSESTree.CallExpressionArgument[]): boolean {\n if (args.length === 0) {\n return false;\n }\n\n const firstArg = args[0];\n\n if (firstArg.type === \"CallExpression\") {\n if (\n firstArg.callee.type === \"Identifier\" &&\n firstArg.callee.name === \"useShallow\"\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if the selector is an inline arrow function\n */\nfunction isInlineSelector(args: TSESTree.CallExpressionArgument[]): boolean {\n if (args.length === 0) {\n return false;\n }\n\n const firstArg = args[0];\n return (\n firstArg.type === \"ArrowFunctionExpression\" ||\n firstArg.type === \"FunctionExpression\"\n );\n}\n\n/**\n * Get the store name from the call expression\n */\nfunction getStoreName(callee: TSESTree.Node): string {\n if (callee.type === \"Identifier\") {\n return callee.name;\n }\n return \"useStore\";\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"zustand-use-selectors\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require selector functions when accessing Zustand store state\",\n },\n messages: {\n missingSelector:\n \"Call to '{{storeName}}' is missing a selector. Use '{{storeName}}((state) => state.property)' to prevent unnecessary re-renders.\",\n useSelectorFunction:\n \"Consider using a named selector function instead of an inline arrow for '{{storeName}}'. Example: '{{storeName}}(selectProperty)'\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n storePattern: {\n type: \"string\",\n description: \"Regex pattern for store hook names\",\n },\n allowShallow: {\n type: \"boolean\",\n description: \"Allow useShallow() wrapper\",\n },\n requireNamedSelectors: {\n type: \"boolean\",\n description: \"Require named selector functions\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n storePattern: \"^use\\\\w*Store$\",\n allowShallow: true,\n requireNamedSelectors: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const storePatternStr = options.storePattern ?? \"^use\\\\w*Store$\";\n const allowShallow = options.allowShallow ?? true;\n const requireNamedSelectors = options.requireNamedSelectors ?? false;\n\n let storePattern: RegExp;\n try {\n storePattern = new RegExp(storePatternStr);\n } catch {\n // If invalid regex, use default\n storePattern = /^use\\w*Store$/;\n }\n\n return {\n CallExpression(node) {\n // Check if this is a Zustand store call\n if (!isZustandStoreCall(node.callee, storePattern)) {\n return;\n }\n\n const storeName = getStoreName(node.callee);\n\n // Check for selector\n if (!hasSelector(node.arguments)) {\n context.report({\n node,\n messageId: \"missingSelector\",\n data: { storeName },\n });\n return;\n }\n\n // If useShallow is used and allowed, that's fine\n if (allowShallow && isShallowWrapped(node.arguments)) {\n return;\n }\n\n // Check for named selectors if required\n if (requireNamedSelectors && isInlineSelector(node.arguments)) {\n context.report({\n node,\n messageId: \"useSelectorFunction\",\n data: { storeName },\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: no-prop-drilling-depth\n *\n * Warns when a prop is passed through multiple intermediate components\n * without being used, indicating prop drilling that should be refactored\n * to context or state management.\n *\n * Examples:\n * - Bad: Prop passed through 3+ components without use\n * - Good: Prop used directly in receiving component\n * - Good: Using Context or Zustand instead of drilling\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"propDrilling\";\ntype Options = [\n {\n /** Maximum depth before warning (default: 2) */\n maxDepth?: number;\n /** Props to ignore (e.g., className, style, children) */\n ignoredProps?: string[];\n /** Component patterns to skip (regex strings) */\n ignoreComponents?: string[];\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-prop-drilling-depth\",\n version: \"1.0.0\",\n name: \"No Prop Drilling Depth\",\n description: \"Warn when props are drilled through too many components\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🔗\",\n hint: \"Detects excessive prop passing\",\n defaultEnabled: true,\n defaultOptions: [\n {\n maxDepth: 2,\n ignoredProps: [\"className\", \"style\", \"children\", \"key\", \"ref\", \"id\"],\n ignoreComponents: [],\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"maxDepth\",\n label: \"Maximum drilling depth\",\n type: \"number\",\n defaultValue: 2,\n description:\n \"Maximum number of components a prop can pass through without use\",\n },\n {\n key: \"ignoredProps\",\n label: \"Ignored props\",\n type: \"text\",\n defaultValue: \"className, style, children, key, ref, id\",\n description: \"Comma-separated prop names to ignore (common pass-through props)\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects when props are passed through multiple intermediate components without\nbeing used (prop drilling). This is often a sign that you should use React\nContext, Zustand, or another state management solution.\n\n## Why it's useful\n\n- **Maintainability**: Deep prop drilling creates tight coupling\n- **Refactoring**: Changes require updates in many files\n- **Readability**: Hard to trace where props come from\n- **Performance**: Unnecessary re-renders in intermediate components\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Grandparent passes user through Parent to Child\nfunction Grandparent({ user }) {\n return <Parent user={user} />;\n}\n\nfunction Parent({ user }) {\n // Parent doesn't use 'user', just passes it along\n return <Child user={user} />;\n}\n\nfunction Child({ user }) {\n return <div>{user.name}</div>;\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Use Context instead\nconst UserContext = createContext();\n\nfunction Grandparent({ user }) {\n return (\n <UserContext.Provider value={user}>\n <Parent />\n </UserContext.Provider>\n );\n}\n\nfunction Child() {\n const user = useContext(UserContext);\n return <div>{user.name}</div>;\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-prop-drilling-depth\": [\"warn\", {\n maxDepth: 2, // Allow passing through 2 components\n ignoredProps: [\"className\", \"style\", \"children\"], // Common pass-through props\n ignoreComponents: [\"^Layout\", \"^Wrapper\"] // Skip wrapper components\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Information about a component's prop usage\n */\ninterface ComponentPropInfo {\n /** Props received by the component */\n receivedProps: Set<string>;\n /** Props passed to child components: propName -> childComponentNames[] */\n passedProps: Map<string, string[]>;\n /** Props actually used in the component (not just passed) */\n usedProps: Set<string>;\n /** Child components that receive props from this component */\n childComponents: string[];\n}\n\n/**\n * Cache for analyzed component prop information\n */\nconst componentPropCache = new Map<string, ComponentPropInfo>();\n\n/**\n * Clear the prop analysis cache\n */\nexport function clearPropCache(): void {\n componentPropCache.clear();\n}\n\n/**\n * Check if a name is a React component (PascalCase)\n */\nfunction isComponentName(name: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(name);\n}\n\n/**\n * Extract props from a function parameter\n */\nfunction extractPropsFromParam(\n param: TSESTree.Parameter\n): { propNames: Set<string>; isSpread: boolean } {\n const propNames = new Set<string>();\n let isSpread = false;\n\n if (param.type === \"ObjectPattern\") {\n for (const prop of param.properties) {\n if (prop.type === \"RestElement\") {\n isSpread = true;\n } else if (\n prop.type === \"Property\" &&\n prop.key.type === \"Identifier\"\n ) {\n propNames.add(prop.key.name);\n }\n }\n } else if (param.type === \"Identifier\") {\n // Single props parameter - assume all props accessed via props.x\n isSpread = true;\n }\n\n return { propNames, isSpread };\n}\n\n/**\n * Find all JSX elements in a function body and extract prop passing info\n */\nfunction analyzeJSXPropPassing(\n body: TSESTree.Node,\n receivedProps: Set<string>\n): { passedProps: Map<string, string[]>; usedProps: Set<string> } {\n const passedProps = new Map<string, string[]>();\n const usedProps = new Set<string>();\n\n function visit(node: TSESTree.Node): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check JSX elements for prop passing\n if (node.type === \"JSXOpeningElement\") {\n const elementName = getJSXElementName(node.name);\n\n // Only care about component elements (PascalCase)\n if (elementName && isComponentName(elementName)) {\n for (const attr of node.attributes) {\n if (attr.type === \"JSXAttribute\" && attr.name.type === \"JSXIdentifier\") {\n const attrName = attr.name.name;\n const propValue = attr.value;\n\n // Check if the attribute value is a received prop\n if (propValue?.type === \"JSXExpressionContainer\") {\n const expr = propValue.expression;\n if (expr.type === \"Identifier\" && receivedProps.has(expr.name)) {\n // This prop is being passed to a child\n const existing = passedProps.get(expr.name) || [];\n existing.push(elementName);\n passedProps.set(expr.name, existing);\n } else if (\n expr.type === \"MemberExpression\" &&\n expr.object.type === \"Identifier\" &&\n expr.object.name === \"props\" &&\n expr.property.type === \"Identifier\"\n ) {\n // props.x pattern\n const propName = expr.property.name;\n if (receivedProps.has(propName) || receivedProps.size === 0) {\n const existing = passedProps.get(propName) || [];\n existing.push(elementName);\n passedProps.set(propName, existing);\n }\n }\n }\n }\n\n // Check for spread props: {...props} or {...rest}\n if (attr.type === \"JSXSpreadAttribute\") {\n if (attr.argument.type === \"Identifier\") {\n const spreadName = attr.argument.name;\n if (spreadName === \"props\" || receivedProps.has(spreadName)) {\n // All props are being spread\n for (const prop of receivedProps) {\n const existing = passedProps.get(prop) || [];\n existing.push(elementName);\n passedProps.set(prop, existing);\n }\n }\n }\n }\n }\n }\n }\n\n // Check for prop usage (not just passing)\n // e.g., {user.name} or {props.user.name} or just {user}\n if (\n node.type === \"MemberExpression\" &&\n node.object.type === \"Identifier\" &&\n receivedProps.has(node.object.name)\n ) {\n usedProps.add(node.object.name);\n }\n\n if (\n node.type === \"Identifier\" &&\n receivedProps.has(node.name) &&\n node.parent?.type !== \"JSXExpressionContainer\"\n ) {\n // Prop used in expression (but not directly passed to child)\n usedProps.add(node.name);\n }\n\n // Check for props.x.something usage\n if (\n node.type === \"MemberExpression\" &&\n node.object.type === \"MemberExpression\" &&\n node.object.object.type === \"Identifier\" &&\n node.object.object.name === \"props\" &&\n node.object.property.type === \"Identifier\"\n ) {\n usedProps.add(node.object.property.name);\n }\n\n // Recurse into children\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n const child = (node as unknown as Record<string, unknown>)[key];\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\") {\n visit(item as TSESTree.Node);\n }\n }\n } else if (child && typeof child === \"object\") {\n visit(child as TSESTree.Node);\n }\n }\n }\n\n visit(body);\n return { passedProps, usedProps };\n}\n\n/**\n * Get the name of a JSX element\n */\nfunction getJSXElementName(node: TSESTree.JSXTagNameExpression): string | null {\n if (node.type === \"JSXIdentifier\") {\n return node.name;\n }\n if (node.type === \"JSXMemberExpression\") {\n // Get the root object for namespace components\n let current = node.object;\n while (current.type === \"JSXMemberExpression\") {\n current = current.object;\n }\n return current.type === \"JSXIdentifier\" ? current.name : null;\n }\n return null;\n}\n\n/**\n * Track prop drilling within a single file\n */\ninterface PropDrillingInfo {\n propName: string;\n component: string;\n passedTo: string[];\n usedDirectly: boolean;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-prop-drilling-depth\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Warn when props are drilled through too many components\",\n },\n messages: {\n propDrilling:\n \"Prop '{{propName}}' is passed through {{depth}} component(s) without being used. Consider using Context or state management. Path: {{path}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxDepth: {\n type: \"number\",\n minimum: 1,\n description: \"Maximum drilling depth before warning\",\n },\n ignoredProps: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Props to ignore\",\n },\n ignoreComponents: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Component patterns to skip (regex)\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n maxDepth: 2,\n ignoredProps: [\"className\", \"style\", \"children\", \"key\", \"ref\", \"id\"],\n ignoreComponents: [],\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const maxDepth = options.maxDepth ?? 2;\n const ignoredProps = new Set(\n options.ignoredProps ?? [\n \"className\",\n \"style\",\n \"children\",\n \"key\",\n \"ref\",\n \"id\",\n ]\n );\n const ignoreComponentPatterns = (options.ignoreComponents ?? []).map(\n (p) => new RegExp(p)\n );\n\n // Track components and their prop flows within the file\n const componentProps = new Map<string, ComponentPropInfo>();\n const imports = new Map<string, string>(); // localName -> importSource\n const componentNodes = new Map<string, TSESTree.Node>(); // componentName -> node\n\n function shouldIgnoreComponent(name: string): boolean {\n return ignoreComponentPatterns.some((pattern) => pattern.test(name));\n }\n\n function shouldIgnoreProp(name: string): boolean {\n return ignoredProps.has(name);\n }\n\n /**\n * Analyze a component function for prop drilling\n */\n function analyzeComponent(\n name: string,\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n reportNode: TSESTree.Node\n ): void {\n if (shouldIgnoreComponent(name)) return;\n\n const firstParam = node.params[0];\n if (!firstParam) return;\n\n const { propNames, isSpread } = extractPropsFromParam(firstParam);\n\n // If using spread without destructuring, we can't easily track props\n if (isSpread && propNames.size === 0) return;\n\n const body = node.body;\n if (!body) return;\n\n const { passedProps, usedProps } = analyzeJSXPropPassing(body, propNames);\n\n componentProps.set(name, {\n receivedProps: propNames,\n passedProps,\n usedProps,\n childComponents: [...new Set([...passedProps.values()].flat())],\n });\n\n componentNodes.set(name, reportNode);\n }\n\n return {\n // Track imports for cross-file analysis\n ImportDeclaration(node) {\n const source = node.source.value as string;\n for (const spec of node.specifiers) {\n if (spec.type === \"ImportSpecifier\" || spec.type === \"ImportDefaultSpecifier\") {\n imports.set(spec.local.name, source);\n }\n }\n },\n\n // Analyze function declarations\n FunctionDeclaration(node) {\n if (node.id && isComponentName(node.id.name)) {\n analyzeComponent(node.id.name, node, node);\n }\n },\n\n // Analyze arrow functions\n VariableDeclarator(node) {\n if (\n node.id.type === \"Identifier\" &&\n isComponentName(node.id.name) &&\n node.init?.type === \"ArrowFunctionExpression\"\n ) {\n analyzeComponent(node.id.name, node.init, node);\n }\n },\n\n // Analyze at the end of the file\n \"Program:exit\"() {\n // Find drilling chains within the file\n for (const [componentName, info] of componentProps) {\n for (const [propName, children] of info.passedProps) {\n if (shouldIgnoreProp(propName)) continue;\n\n // Check if prop is used directly\n if (info.usedProps.has(propName)) continue;\n\n // Track the drilling chain\n const chain: string[] = [componentName];\n let depth = 0;\n let current = children;\n\n while (current.length > 0 && depth < maxDepth + 1) {\n depth++;\n const nextChildren: string[] = [];\n\n for (const child of current) {\n chain.push(child);\n const childInfo = componentProps.get(child);\n\n if (childInfo) {\n // Check if child uses the prop\n if (childInfo.usedProps.has(propName)) {\n // Prop is used here, drilling stops\n break;\n }\n\n // Check if child passes the prop further\n const childPasses = childInfo.passedProps.get(propName);\n if (childPasses) {\n nextChildren.push(...childPasses);\n }\n }\n }\n\n current = nextChildren;\n }\n\n // Report if depth exceeds threshold\n if (depth > maxDepth) {\n const reportNode = componentNodes.get(componentName);\n if (reportNode) {\n context.report({\n node: reportNode,\n messageId: \"propDrilling\",\n data: {\n propName,\n depth: String(depth),\n path: chain.slice(0, maxDepth + 2).join(\" → \"),\n },\n });\n }\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: no-secrets-in-code\n *\n * Detects hardcoded secrets, API keys, passwords, and tokens in source code.\n * Prevents accidental exposure of sensitive credentials.\n *\n * Examples:\n * - Bad: const apiKey = 'AKIA1234567890ABCDEF'\n * - Bad: const password = 'mySecretPassword123'\n * - Good: const apiKey = process.env.API_KEY\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"secretDetected\" | \"suspiciousVariable\";\ntype Options = [\n {\n /** Additional regex patterns to detect (as strings) */\n additionalPatterns?: Array<{ name: string; pattern: string }>;\n /** Check variable names for suspicious patterns */\n checkVariableNames?: boolean;\n /** Minimum length for generic secret detection */\n minSecretLength?: number;\n /** Relax rules in test files */\n allowInTestFiles?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-secrets-in-code\",\n version: \"1.0.0\",\n name: \"No Secrets in Code\",\n description: \"Detect hardcoded secrets, API keys, and tokens\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🔐\",\n hint: \"Prevents credential leaks\",\n defaultEnabled: true,\n defaultOptions: [\n {\n checkVariableNames: true,\n minSecretLength: 16,\n allowInTestFiles: false,\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"checkVariableNames\",\n label: \"Check variable names\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Check for suspicious variable names with high-entropy values\",\n },\n {\n key: \"minSecretLength\",\n label: \"Minimum secret length\",\n type: \"number\",\n defaultValue: 16,\n description: \"Minimum string length for generic secret detection\",\n },\n {\n key: \"allowInTestFiles\",\n label: \"Allow in test files\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Skip detection in test files (*.test.*, *.spec.*)\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects hardcoded secrets, API keys, passwords, and tokens in source code.\nThese should be stored in environment variables or secure vaults instead.\n\n## Why it's useful\n\n- **Security**: Prevents credential leaks in version control\n- **Compliance**: Helps meet security audit requirements\n- **Best Practice**: Enforces proper secrets management\n\n## Detected Patterns\n\n- AWS Access Keys and Secret Keys\n- GitHub Personal Access Tokens (ghp_*)\n- Stripe API Keys (sk_live_*, sk_test_*)\n- Google API Keys\n- Firebase Keys\n- Slack Tokens\n- npm Tokens\n- JWT Tokens\n- Private Keys (PEM format)\n- Generic API keys, passwords, and secrets in suspicious variables\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Hardcoded AWS credentials\nconst accessKey = 'AKIA1234567890ABCDEF';\nconst secretKey = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY';\n\n// Hardcoded passwords\nconst dbPassword = 'supersecretpassword123';\n\n// Hardcoded tokens\nconst token = 'ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Use environment variables\nconst accessKey = process.env.AWS_ACCESS_KEY_ID;\nconst secretKey = process.env.AWS_SECRET_ACCESS_KEY;\n\n// Reference from config\nconst dbPassword = config.database.password;\n\n// Use a secrets manager\nconst token = await secretsManager.getSecret('github-token');\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-secrets-in-code\": [\"error\", {\n checkVariableNames: true, // Check suspicious variable names\n minSecretLength: 16, // Minimum length for generic detection\n allowInTestFiles: false, // Don't skip test files\n additionalPatterns: [ // Add custom patterns\n { name: \"Custom API\", pattern: \"^myapi_[a-z0-9]{32}$\" }\n ]\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Known secret patterns with names and regex\n */\nconst SECRET_PATTERNS: Array<{ name: string; pattern: RegExp }> = [\n // AWS\n { name: \"AWS Access Key ID\", pattern: /\\bAKIA[0-9A-Z]{16}\\b/ },\n { name: \"AWS Secret Access Key\", pattern: /\\b[A-Za-z0-9/+=]{40}\\b/ },\n\n // GitHub\n { name: \"GitHub Personal Access Token\", pattern: /\\bghp_[A-Za-z0-9]{36}\\b/ },\n { name: \"GitHub OAuth Token\", pattern: /\\bgho_[A-Za-z0-9]{36}\\b/ },\n { name: \"GitHub App Token\", pattern: /\\bghu_[A-Za-z0-9]{36}\\b/ },\n { name: \"GitHub Refresh Token\", pattern: /\\bghr_[A-Za-z0-9]{36}\\b/ },\n\n // Stripe\n { name: \"Stripe Live Secret Key\", pattern: /\\bsk_live_[A-Za-z0-9]{24,}\\b/ },\n { name: \"Stripe Test Secret Key\", pattern: /\\bsk_test_[A-Za-z0-9]{24,}\\b/ },\n { name: \"Stripe Restricted Key\", pattern: /\\brk_live_[A-Za-z0-9]{24,}\\b/ },\n\n // Google\n { name: \"Google API Key\", pattern: /\\bAIza[A-Za-z0-9_-]{35}\\b/ },\n\n // Slack\n { name: \"Slack Token\", pattern: /\\bxox[baprs]-[A-Za-z0-9-]{10,48}\\b/ },\n { name: \"Slack Webhook\", pattern: /\\bhooks\\.slack\\.com\\/services\\/T[A-Za-z0-9]+\\/B[A-Za-z0-9]+\\/[A-Za-z0-9]+\\b/ },\n\n // npm\n { name: \"npm Token\", pattern: /\\bnpm_[A-Za-z0-9]{36}\\b/ },\n\n // SendGrid\n { name: \"SendGrid API Key\", pattern: /\\bSG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}\\b/ },\n\n // Twilio\n { name: \"Twilio API Key\", pattern: /\\bSK[a-z0-9]{32}\\b/ },\n\n // Firebase\n { name: \"Firebase Key\", pattern: /\\bAAAA[A-Za-z0-9_-]{7}:[A-Za-z0-9_-]{140}\\b/ },\n\n // Generic patterns\n { name: \"Private Key\", pattern: /-----BEGIN\\s+(RSA\\s+|EC\\s+|DSA\\s+|OPENSSH\\s+)?PRIVATE\\s+KEY-----/ },\n { name: \"JWT Token\", pattern: /\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/ },\n\n // Anthropic\n { name: \"Anthropic API Key\", pattern: /\\bsk-ant-api[A-Za-z0-9_-]{20,}\\b/ },\n\n // OpenAI\n { name: \"OpenAI API Key\", pattern: /\\bsk-proj-[A-Za-z0-9_-]{20,}\\b/ },\n { name: \"OpenAI API Key (old)\", pattern: /\\bsk-[A-Za-z0-9]{48}\\b/ },\n];\n\n/**\n * Variable name patterns that suggest secrets\n */\nconst SUSPICIOUS_VARIABLE_PATTERNS: RegExp[] = [\n /^api[_-]?key$/i,\n /^secret[_-]?key$/i,\n /^private[_-]?key$/i,\n /^access[_-]?key$/i,\n /^auth[_-]?key$/i,\n /^access[_-]?token$/i,\n /^auth[_-]?token$/i,\n /^api[_-]?token$/i,\n /^bearer[_-]?token$/i,\n /^jwt[_-]?token$/i,\n /^refresh[_-]?token$/i,\n /^password$/i,\n /^passwd$/i,\n /^pwd$/i,\n /^db[_-]?password$/i,\n /^database[_-]?password$/i,\n /^secret$/i,\n /^client[_-]?secret$/i,\n /^app[_-]?secret$/i,\n];\n\n/**\n * Patterns that indicate safe/placeholder values\n */\nconst PLACEHOLDER_PATTERNS: RegExp[] = [\n /^your[_-]?/i,\n /^xxx+$/i,\n /^placeholder/i,\n /^example/i,\n /^test[_-]?/i,\n /^fake[_-]?/i,\n /^dummy/i,\n /^sample/i,\n /<[^>]+>/, // <your-key-here>\n /\\${[^}]+}/, // ${API_KEY}\n /^\\*+$/, // ****\n];\n\n/**\n * Calculate Shannon entropy of a string\n */\nfunction calculateEntropy(str: string): number {\n if (str.length === 0) return 0;\n\n const freq: Record<string, number> = {};\n for (const char of str) {\n freq[char] = (freq[char] || 0) + 1;\n }\n\n let entropy = 0;\n const len = str.length;\n for (const count of Object.values(freq)) {\n const p = count / len;\n entropy -= p * Math.log2(p);\n }\n\n return entropy;\n}\n\n/**\n * Check if a value looks like a placeholder\n */\nfunction isPlaceholder(value: string): boolean {\n return PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(value));\n}\n\n/**\n * Check if a value is likely an environment variable reference\n */\nfunction isEnvReference(value: string): boolean {\n return value.includes(\"process.env\") || value.includes(\"import.meta.env\");\n}\n\n/**\n * Get a preview of the secret (first and last few chars)\n */\nfunction getPreview(value: string, maxLength: number = 20): string {\n if (value.length <= maxLength) {\n return value.substring(0, 8) + \"...\";\n }\n return value.substring(0, 8) + \"...\" + value.substring(value.length - 4);\n}\n\n/**\n * Check if file is a test file\n */\nfunction isTestFile(filename: string): boolean {\n return /\\.(test|spec)\\.[jt]sx?$/.test(filename) ||\n /\\/__tests__\\//.test(filename) ||\n /\\/test\\//.test(filename);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-secrets-in-code\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Detect hardcoded secrets, API keys, and tokens\",\n },\n messages: {\n secretDetected:\n \"Potential {{secretType}} detected: '{{preview}}'. Use environment variables instead of hardcoding secrets.\",\n suspiciousVariable:\n \"Variable '{{variableName}}' appears to contain a secret. Use environment variables instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n additionalPatterns: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n pattern: { type: \"string\" },\n },\n required: [\"name\", \"pattern\"],\n },\n description: \"Additional patterns to detect\",\n },\n checkVariableNames: {\n type: \"boolean\",\n description: \"Check variable names for suspicious patterns\",\n },\n minSecretLength: {\n type: \"number\",\n description: \"Minimum length for generic secret detection\",\n },\n allowInTestFiles: {\n type: \"boolean\",\n description: \"Skip detection in test files\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n checkVariableNames: true,\n minSecretLength: 16,\n allowInTestFiles: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const checkVariableNames = options.checkVariableNames ?? true;\n const minSecretLength = options.minSecretLength ?? 16;\n const allowInTestFiles = options.allowInTestFiles ?? false;\n const additionalPatterns = options.additionalPatterns ?? [];\n\n const filename = context.filename || context.getFilename?.() || \"\";\n\n // Skip test files if configured\n if (allowInTestFiles && isTestFile(filename)) {\n return {};\n }\n\n // Build full pattern list\n const allPatterns = [...SECRET_PATTERNS];\n for (const custom of additionalPatterns) {\n try {\n allPatterns.push({\n name: custom.name,\n pattern: new RegExp(custom.pattern),\n });\n } catch {\n // Invalid regex, skip\n }\n }\n\n /**\n * Check a string value for secrets\n */\n function checkStringForSecrets(\n value: string,\n node: TSESTree.Node,\n variableName?: string\n ): void {\n // Skip empty strings and short strings\n if (!value || value.length < 8) {\n return;\n }\n\n // Skip placeholders\n if (isPlaceholder(value)) {\n return;\n }\n\n // Check against known patterns\n for (const { name, pattern } of allPatterns) {\n if (pattern.test(value)) {\n context.report({\n node,\n messageId: \"secretDetected\",\n data: {\n secretType: name,\n preview: getPreview(value),\n },\n });\n return;\n }\n }\n\n // Check for suspicious variable names with high-entropy values\n if (checkVariableNames && variableName) {\n const isSuspiciousName = SUSPICIOUS_VARIABLE_PATTERNS.some((pattern) =>\n pattern.test(variableName)\n );\n\n if (isSuspiciousName && value.length >= minSecretLength) {\n const entropy = calculateEntropy(value);\n // High entropy (> 3.5) suggests random/secret data\n if (entropy > 3.5) {\n context.report({\n node,\n messageId: \"suspiciousVariable\",\n data: {\n variableName,\n },\n });\n }\n }\n }\n }\n\n /**\n * Get variable name from declarator\n */\n function getVariableName(node: TSESTree.Node): string | undefined {\n if (node.parent?.type === \"VariableDeclarator\") {\n const declarator = node.parent;\n if (declarator.id.type === \"Identifier\") {\n return declarator.id.name;\n }\n }\n if (node.parent?.type === \"Property\") {\n const prop = node.parent;\n if (prop.key.type === \"Identifier\") {\n return prop.key.name;\n }\n }\n return undefined;\n }\n\n return {\n // Check string literals\n Literal(node) {\n if (typeof node.value === \"string\") {\n const variableName = getVariableName(node);\n checkStringForSecrets(node.value, node, variableName);\n }\n },\n\n // Check template literals\n TemplateLiteral(node) {\n // Only check if no expressions (pure string)\n if (node.expressions.length === 0 && node.quasis.length === 1) {\n const value = node.quasis[0].value.raw;\n const variableName = getVariableName(node);\n checkStringForSecrets(value, node, variableName);\n }\n },\n };\n },\n});\n","/**\n * Rule: require-input-validation\n *\n * Requires API route handlers to validate request body using schema validation\n * libraries like Zod, Yup, or Joi before accessing request data.\n *\n * Examples:\n * - Bad: const { name } = await req.json()\n * - Good: const data = schema.parse(await req.json())\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"missingValidation\" | \"unvalidatedBodyAccess\";\ntype Options = [\n {\n /** HTTP methods that require validation (default: POST, PUT, PATCH, DELETE) */\n httpMethods?: string[];\n /** File patterns that indicate API routes */\n routePatterns?: string[];\n /** Allow manual type guards/if-checks as validation */\n allowManualValidation?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"require-input-validation\",\n version: \"1.0.0\",\n name: \"Require Input Validation\",\n description: \"Require schema validation in API route handlers\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"✅\",\n hint: \"Enforces input validation in APIs\",\n defaultEnabled: true,\n defaultOptions: [\n {\n httpMethods: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n routePatterns: [\"route.ts\", \"route.tsx\", \"/api/\", \"/app/api/\"],\n allowManualValidation: false,\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"httpMethods\",\n label: \"HTTP methods requiring validation\",\n type: \"multiselect\",\n defaultValue: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n options: [\n { value: \"GET\", label: \"GET\" },\n { value: \"POST\", label: \"POST\" },\n { value: \"PUT\", label: \"PUT\" },\n { value: \"PATCH\", label: \"PATCH\" },\n { value: \"DELETE\", label: \"DELETE\" },\n ],\n description: \"HTTP methods that require request body validation\",\n },\n {\n key: \"allowManualValidation\",\n label: \"Allow manual validation\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Allow if-checks and type guards instead of schema validation\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnsures that API route handlers validate request body data using a schema\nvalidation library (Zod, Yup, Joi, etc.) before accessing it.\n\n## Why it's useful\n\n- **Security**: Prevents injection attacks and malformed data\n- **Type Safety**: Ensures runtime data matches expected types\n- **Error Handling**: Provides clear validation error messages\n- **Best Practice**: Follows defense-in-depth principles\n\n## Supported Validation Libraries\n\n- Zod: \\`parse()\\`, \\`safeParse()\\`, \\`parseAsync()\\`\n- Yup: \\`validate()\\`, \\`validateSync()\\`\n- Joi: \\`validate()\\`\n- Superstruct: \\`create()\\`, \\`assert()\\`\n- io-ts: \\`decode()\\`\n- Valibot: \\`parse()\\`, \\`safeParse()\\`\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Next.js App Router\nexport async function POST(request: Request) {\n const body = await request.json();\n // Body accessed without validation\n await db.users.create({ name: body.name });\n}\n\n// Next.js Pages API\nexport default function handler(req, res) {\n const { email } = req.body; // Unvalidated\n sendEmail(email);\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\nimport { z } from 'zod';\n\nconst CreateUserSchema = z.object({\n name: z.string().min(1),\n email: z.string().email(),\n});\n\nexport async function POST(request: Request) {\n const body = await request.json();\n const data = CreateUserSchema.parse(body); // Validated!\n await db.users.create(data);\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/require-input-validation\": [\"warn\", {\n httpMethods: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n routePatterns: [\"route.ts\", \"/api/\"],\n allowManualValidation: false\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * HTTP method names (Next.js App Router style)\n */\nconst HTTP_METHODS = [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\", \"OPTIONS\"];\n\n/**\n * Validation method names from common libraries\n */\nconst VALIDATION_METHODS = [\n // Zod\n \"parse\",\n \"safeParse\",\n \"parseAsync\",\n \"safeParseAsync\",\n // Yup\n \"validate\",\n \"validateSync\",\n \"validateAt\",\n \"validateSyncAt\",\n // Joi\n \"validate\",\n \"validateAsync\",\n // Superstruct\n \"create\",\n \"assert\",\n // io-ts\n \"decode\",\n // Valibot\n \"parse\",\n \"safeParse\",\n // Generic\n \"validateBody\",\n \"validateRequest\",\n \"validateInput\",\n];\n\n/**\n * Check if file matches route patterns\n */\nfunction isApiRouteFile(filename: string, patterns: string[]): boolean {\n return patterns.some((pattern) => filename.includes(pattern));\n}\n\n/**\n * Check if a function is an HTTP method handler\n */\nfunction isHttpMethodHandler(\n node: TSESTree.Node,\n methods: string[]\n): { isHandler: boolean; method: string | null } {\n // Check export function GET/POST/etc\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n const name = node.declaration.id.name.toUpperCase();\n if (methods.includes(name)) {\n return { isHandler: true, method: name };\n }\n }\n\n // Check export const GET = async () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (decl.id.type === \"Identifier\") {\n const name = decl.id.name.toUpperCase();\n if (methods.includes(name)) {\n return { isHandler: true, method: name };\n }\n }\n }\n }\n\n return { isHandler: false, method: null };\n}\n\n/**\n * Check if a call expression is a validation call\n */\nfunction isValidationCall(node: TSESTree.CallExpression): boolean {\n // Check method calls: schema.parse(), schema.validate()\n if (\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\"\n ) {\n const methodName = node.callee.property.name;\n\n // Exclude JSON.parse as it's not schema validation\n if (\n node.callee.object.type === \"Identifier\" &&\n node.callee.object.name === \"JSON\" &&\n methodName === \"parse\"\n ) {\n return false;\n }\n\n return VALIDATION_METHODS.includes(methodName);\n }\n\n // Check direct calls: validate(schema, data)\n if (node.callee.type === \"Identifier\") {\n const funcName = node.callee.name;\n return VALIDATION_METHODS.includes(funcName);\n }\n\n return false;\n}\n\n/**\n * Check if a node is a body access pattern\n */\nfunction isBodyAccess(node: TSESTree.Node): {\n isAccess: boolean;\n accessType: string | null;\n} {\n // req.body\n if (\n node.type === \"MemberExpression\" &&\n node.property.type === \"Identifier\" &&\n node.property.name === \"body\"\n ) {\n return { isAccess: true, accessType: \"req.body\" };\n }\n\n // request.json() or req.json()\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n node.callee.property.name === \"json\"\n ) {\n return { isAccess: true, accessType: \"request.json()\" };\n }\n\n // request.formData()\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n node.callee.property.name === \"formData\"\n ) {\n return { isAccess: true, accessType: \"request.formData()\" };\n }\n\n // request.text()\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n node.callee.property.name === \"text\"\n ) {\n return { isAccess: true, accessType: \"request.text()\" };\n }\n\n return { isAccess: false, accessType: null };\n}\n\n/**\n * Track if we're inside a validation context\n */\ninterface ValidationContext {\n hasValidation: boolean;\n bodyAccessNodes: Array<{ node: TSESTree.Node; accessType: string }>;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"require-input-validation\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Require schema validation in API route handlers\",\n },\n messages: {\n missingValidation:\n \"API route handler '{{method}}' accesses request body without validation. Use a schema validation library like Zod.\",\n unvalidatedBodyAccess:\n \"Accessing '{{accessType}}' without prior validation. Validate the data first using a schema.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n httpMethods: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"HTTP methods that require validation\",\n },\n routePatterns: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"File patterns that indicate API routes\",\n },\n allowManualValidation: {\n type: \"boolean\",\n description: \"Allow manual type guards as validation\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n httpMethods: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n routePatterns: [\"route.ts\", \"route.tsx\", \"/api/\", \"/app/api/\"],\n allowManualValidation: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const httpMethods = (options.httpMethods ?? [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"]).map(\n (m) => m.toUpperCase()\n );\n const routePatterns = options.routePatterns ?? [\n \"route.ts\",\n \"route.tsx\",\n \"/api/\",\n \"/app/api/\",\n ];\n\n const filename = context.filename || context.getFilename?.() || \"\";\n\n // Only check API route files\n if (!isApiRouteFile(filename, routePatterns)) {\n return {};\n }\n\n // Track handlers and their validation status\n const handlerContexts = new Map<TSESTree.Node, ValidationContext>();\n let currentHandler: TSESTree.Node | null = null;\n let currentMethod: string | null = null;\n\n return {\n // Detect HTTP method handlers\n ExportNamedDeclaration(node) {\n const { isHandler, method } = isHttpMethodHandler(node, httpMethods);\n if (isHandler) {\n currentHandler = node;\n currentMethod = method;\n handlerContexts.set(node, {\n hasValidation: false,\n bodyAccessNodes: [],\n });\n }\n },\n\n // Track body access within handlers\n MemberExpression(node) {\n if (!currentHandler) return;\n\n const ctx = handlerContexts.get(currentHandler);\n if (!ctx) return;\n\n const { isAccess, accessType } = isBodyAccess(node);\n if (isAccess && accessType) {\n ctx.bodyAccessNodes.push({ node, accessType });\n }\n },\n\n CallExpression(node) {\n if (!currentHandler) return;\n\n const ctx = handlerContexts.get(currentHandler);\n if (!ctx) return;\n\n // Check for body access\n const { isAccess, accessType } = isBodyAccess(node);\n if (isAccess && accessType) {\n // Check if this is inside a validation call\n // e.g., schema.parse(await request.json())\n if (\n node.parent?.type === \"AwaitExpression\" &&\n node.parent.parent?.type === \"CallExpression\" &&\n isValidationCall(node.parent.parent)\n ) {\n ctx.hasValidation = true;\n return;\n }\n\n // Check if this is directly wrapped in validation\n if (\n node.parent?.type === \"CallExpression\" &&\n isValidationCall(node.parent)\n ) {\n ctx.hasValidation = true;\n return;\n }\n\n ctx.bodyAccessNodes.push({ node, accessType });\n }\n\n // Check for validation calls\n if (isValidationCall(node)) {\n ctx.hasValidation = true;\n }\n },\n\n \"ExportNamedDeclaration:exit\"(node: TSESTree.ExportNamedDeclaration) {\n const ctx = handlerContexts.get(node);\n if (!ctx) return;\n\n // If we have body access but no validation, report\n if (ctx.bodyAccessNodes.length > 0 && !ctx.hasValidation) {\n // Report on the first body access\n const firstAccess = ctx.bodyAccessNodes[0];\n context.report({\n node: firstAccess.node,\n messageId: \"unvalidatedBodyAccess\",\n data: {\n accessType: firstAccess.accessType,\n },\n });\n }\n\n // Clean up\n if (currentHandler === node) {\n currentHandler = null;\n currentMethod = null;\n }\n handlerContexts.delete(node);\n },\n };\n },\n});\n","/**\n * Rule: no-semantic-duplicates\n *\n * Warns when code is semantically similar to existing indexed code.\n * This rule queries a pre-built semantic index (from uilint duplicates index)\n * rather than calling the LLM during linting - making it fast.\n *\n * Prerequisites:\n * - Run `uilint duplicates index` to build the semantic index first\n * - The index is stored at .uilint/.duplicates-index/\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { existsSync, readFileSync, appendFileSync, writeFileSync } from \"fs\";\nimport { dirname, join, relative } from \"path\";\n\n// Debug logging - writes to .uilint/no-semantic-duplicates.log in the project root\nlet logFile: string | null = null;\nlet logInitialized = false;\n\nfunction initLog(projectRoot: string): void {\n if (logFile) return;\n const uilintDir = join(projectRoot, \".uilint\");\n if (existsSync(uilintDir)) {\n logFile = join(uilintDir, \"no-semantic-duplicates.log\");\n }\n}\n\nfunction log(message: string): void {\n if (!logFile) return;\n try {\n const timestamp = new Date().toISOString();\n const line = `[${timestamp}] ${message}\\n`;\n if (!logInitialized) {\n writeFileSync(logFile, line);\n logInitialized = true;\n } else {\n appendFileSync(logFile, line);\n }\n } catch {\n // Ignore logging errors\n }\n}\n\ntype MessageIds = \"semanticDuplicate\" | \"noIndex\";\ntype Options = [\n {\n /** Similarity threshold (0-1). Default: 0.85 */\n threshold?: number;\n /** Path to the index directory */\n indexPath?: string;\n /** Minimum number of lines for a chunk to be reported (default: 3) */\n minLines?: number;\n }\n];\n\n/**\n * Rule metadata\n */\nexport const meta = defineRuleMeta({\n id: \"no-semantic-duplicates\",\n version: \"1.0.0\",\n name: \"No Semantic Duplicates\",\n description: \"Warn when code is semantically similar to existing code\",\n defaultSeverity: \"warn\",\n category: \"semantic\",\n icon: \"🔍\",\n hint: \"Finds similar code via embeddings\",\n defaultEnabled: false,\n plugin: \"semantic\",\n customInspector: \"duplicates\",\n requirements: [\n {\n type: \"semantic-index\",\n description: \"Requires semantic index for duplicate detection\",\n setupHint: \"Run: uilint duplicates index\",\n },\n ],\n postInstallInstructions: \"Run 'uilint duplicates index' to build the semantic index before using this rule.\",\n defaultOptions: [{ threshold: 0.85, indexPath: \".uilint/.duplicates-index\", minLines: 3 }],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Similarity threshold\",\n type: \"number\",\n defaultValue: 0.85,\n description:\n \"Minimum similarity score (0-1) to report as duplicate. Higher = stricter.\",\n },\n {\n key: \"indexPath\",\n label: \"Index path\",\n type: \"text\",\n defaultValue: \".uilint/.duplicates-index\",\n description: \"Path to the semantic duplicates index directory\",\n },\n {\n key: \"minLines\",\n label: \"Minimum lines\",\n type: \"number\",\n defaultValue: 3,\n description:\n \"Minimum number of lines for a chunk to be reported as a potential duplicate.\",\n },\n ],\n },\n docs: `\n## What it does\n\nWarns when code (components, hooks, functions) is semantically similar to other\ncode in the codebase. Unlike syntactic duplicate detection, this finds code that\nimplements similar functionality even if written differently.\n\n## Prerequisites\n\nBefore using this rule, you must build the semantic index:\n\n\\`\\`\\`bash\nuilint duplicates index\n\\`\\`\\`\n\nThis creates an embedding-based index at \\`.uilint/.duplicates-index/\\`.\n\n## Why it's useful\n\n- **Reduce Duplication**: Find components/hooks that could be consolidated\n- **Discover Patterns**: Identify similar code that could be abstracted\n- **Code Quality**: Encourage reuse over reimplementation\n- **Fast**: Queries pre-built index, no LLM calls during linting\n\n## How it works\n\n1. The rule checks if the current file is in the semantic index\n2. For each indexed code chunk, it looks up similar chunks\n3. If similar chunks exist above the threshold, it reports a warning\n\n## Examples\n\n### Semantic duplicates detected:\n\n\\`\\`\\`tsx\n// UserCard.tsx - Original component\nexport function UserCard({ user }) {\n return (\n <div className=\"card\">\n <img src={user.avatar} />\n <h3>{user.name}</h3>\n </div>\n );\n}\n\n// ProfileCard.tsx - Semantically similar (warning!)\nexport function ProfileCard({ profile }) {\n return (\n <article className=\"profile\">\n <img src={profile.avatarUrl} />\n <h2>{profile.displayName}</h2>\n </article>\n );\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-semantic-duplicates\": [\"warn\", {\n threshold: 0.85, // Similarity threshold (0-1)\n indexPath: \".uilint/.duplicates-index\",\n minLines: 3 // Minimum lines to report (default: 3)\n}]\n\\`\\`\\`\n\n## Notes\n\n- Run \\`uilint duplicates index\\` after significant code changes\n- Use \\`uilint duplicates find\\` to explore all duplicate groups\n- The rule only reports if the file is in the index\n`,\n});\n\n// Cache for loaded index data across files in a single ESLint run\nlet indexCache: {\n projectRoot: string;\n vectorStore: Map<string, number[]>;\n metadataStore: Map<\n string,\n {\n filePath: string;\n startLine: number;\n endLine: number;\n startColumn: number;\n endColumn: number;\n name: string | null;\n kind: string;\n }\n >;\n fileToChunks: Map<string, string[]>;\n} | null = null;\n\n/**\n * Clear the index cache (useful for testing)\n */\nexport function clearIndexCache(): void {\n indexCache = null;\n}\n\n/**\n * Find project root by looking for the .uilint directory (preferred)\n * or falling back to the root package.json (monorepo root)\n */\nfunction findProjectRoot(startPath: string, indexPath: string): string {\n let current = startPath;\n let lastPackageJson: string | null = null;\n\n // Walk up the directory tree\n while (current !== dirname(current)) {\n // Check for .uilint directory with index (highest priority)\n const uilintDir = join(current, indexPath);\n if (existsSync(join(uilintDir, \"manifest.json\"))) {\n return current;\n }\n\n // Track package.json locations\n if (existsSync(join(current, \"package.json\"))) {\n lastPackageJson = current;\n }\n\n current = dirname(current);\n }\n\n // Return the topmost package.json location (monorepo root) or start path\n return lastPackageJson || startPath;\n}\n\n/**\n * Load the index into memory (cached across files)\n */\nfunction loadIndex(\n projectRoot: string,\n indexPath: string\n): typeof indexCache | null {\n const fullIndexPath = join(projectRoot, indexPath);\n log(`loadIndex called: projectRoot=${projectRoot}, indexPath=${indexPath}`);\n log(`fullIndexPath=${fullIndexPath}`);\n\n // Check if we already have a cached index for this project\n if (indexCache && indexCache.projectRoot === projectRoot) {\n log(`Using cached index (${indexCache.vectorStore.size} vectors, ${indexCache.fileToChunks.size} files)`);\n return indexCache;\n }\n\n // Check if index exists\n const manifestPath = join(fullIndexPath, \"manifest.json\");\n if (!existsSync(manifestPath)) {\n log(`Index not found: manifest.json missing at ${manifestPath}`);\n return null;\n }\n\n try {\n // Load metadata\n const metadataPath = join(fullIndexPath, \"metadata.json\");\n if (!existsSync(metadataPath)) {\n log(`Index not found: metadata.json missing at ${metadataPath}`);\n return null;\n }\n\n const metadataContent = readFileSync(metadataPath, \"utf-8\");\n const metadataJson = JSON.parse(metadataContent);\n\n // Support both formats: { entries: {...} } and direct { chunkId: {...} }\n const entries = metadataJson.entries || metadataJson;\n log(`Loaded metadata.json: ${Object.keys(entries).length} entries`);\n\n const metadataStore = new Map<\n string,\n {\n filePath: string;\n startLine: number;\n endLine: number;\n startColumn: number;\n endColumn: number;\n name: string | null;\n kind: string;\n }\n >();\n const fileToChunks = new Map<string, string[]>();\n\n for (const [id, meta] of Object.entries(entries)) {\n const m = meta as {\n filePath: string;\n startLine: number;\n endLine: number;\n startColumn: number;\n endColumn: number;\n name: string | null;\n kind: string;\n };\n metadataStore.set(id, {\n filePath: m.filePath,\n startLine: m.startLine,\n endLine: m.endLine,\n startColumn: m.startColumn ?? 0,\n endColumn: m.endColumn ?? 0,\n name: m.name,\n kind: m.kind,\n });\n\n // Build file -> chunks mapping\n const chunks = fileToChunks.get(m.filePath) || [];\n chunks.push(id);\n fileToChunks.set(m.filePath, chunks);\n }\n\n log(`File to chunks mapping:`);\n for (const [filePath, chunks] of fileToChunks.entries()) {\n log(` ${filePath}: ${chunks.length} chunks (${chunks.join(\", \")})`);\n }\n\n // Load vectors (binary format)\n const vectorsPath = join(fullIndexPath, \"embeddings.bin\");\n const idsPath = join(fullIndexPath, \"ids.json\");\n const vectorStore = new Map<string, number[]>();\n\n if (existsSync(vectorsPath) && existsSync(idsPath)) {\n const idsContent = readFileSync(idsPath, \"utf-8\");\n const ids = JSON.parse(idsContent) as string[];\n log(`Loaded ids.json: ${ids.length} IDs`);\n\n const buffer = readFileSync(vectorsPath);\n // Must use byteOffset and byteLength because Node's Buffer uses pooling\n // and buffer.buffer may contain data from other buffers at different offsets\n const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // Read header\n const dimension = view.getUint32(0, true);\n const count = view.getUint32(4, true);\n log(`Embeddings binary: dimension=${dimension}, count=${count}`);\n\n // Read vectors\n let offset = 8;\n for (let i = 0; i < count && i < ids.length; i++) {\n const vector: number[] = [];\n for (let j = 0; j < dimension; j++) {\n vector.push(view.getFloat32(offset, true));\n offset += 4;\n }\n vectorStore.set(ids[i], vector);\n }\n log(`Loaded ${vectorStore.size} vectors into store`);\n } else {\n log(`Missing vectors or ids files: vectorsPath=${existsSync(vectorsPath)}, idsPath=${existsSync(idsPath)}`);\n }\n\n indexCache = {\n projectRoot,\n vectorStore,\n metadataStore,\n fileToChunks,\n };\n\n log(`Index loaded successfully: ${vectorStore.size} vectors, ${metadataStore.size} metadata entries, ${fileToChunks.size} files`);\n return indexCache;\n } catch (err) {\n log(`Error loading index: ${err}`);\n return null;\n }\n}\n\n/**\n * Calculate cosine similarity between two vectors\n */\nfunction cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) return 0;\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n const denominator = Math.sqrt(normA) * Math.sqrt(normB);\n return denominator === 0 ? 0 : dotProduct / denominator;\n}\n\n/**\n * Find similar chunks to a given chunk\n */\nfunction findSimilarChunks(\n index: NonNullable<typeof indexCache>,\n chunkId: string,\n threshold: number\n): Array<{ id: string; score: number }> {\n log(`findSimilarChunks: chunkId=${chunkId}, threshold=${threshold}`);\n\n const vector = index.vectorStore.get(chunkId);\n if (!vector) {\n log(` No vector found for chunk ${chunkId}`);\n return [];\n }\n log(` Vector found: dimension=${vector.length}`);\n\n const results: Array<{ id: string; score: number }> = [];\n const allScores: Array<{ id: string; score: number }> = [];\n\n for (const [id, vec] of index.vectorStore.entries()) {\n if (id === chunkId) continue;\n\n const score = cosineSimilarity(vector, vec);\n allScores.push({ id, score });\n if (score >= threshold) {\n results.push({ id, score });\n }\n }\n\n // Log top 10 scores regardless of threshold\n const sortedAll = allScores.sort((a, b) => b.score - a.score).slice(0, 10);\n log(` Top 10 similarity scores (threshold=${threshold}):`);\n for (const { id, score } of sortedAll) {\n const meta = index.metadataStore.get(id);\n const meetsThreshold = score >= threshold ? \"✓\" : \"✗\";\n log(` ${meetsThreshold} ${(score * 100).toFixed(1)}% - ${id} (${meta?.name || \"anonymous\"} in ${meta?.filePath})`);\n }\n\n log(` Found ${results.length} chunks above threshold`);\n return results.sort((a, b) => b.score - a.score);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-semantic-duplicates\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Warn when code is semantically similar to existing code\",\n },\n messages: {\n semanticDuplicate:\n \"This {{kind}} '{{name}}' is {{similarity}}% similar to '{{otherName}}' at {{otherLocation}}. Consider consolidating.\",\n noIndex:\n \"Semantic duplicates index not found. Run 'uilint duplicates index' first.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n threshold: {\n type: \"number\",\n minimum: 0,\n maximum: 1,\n description: \"Similarity threshold (0-1)\",\n },\n indexPath: {\n type: \"string\",\n description: \"Path to the index directory\",\n },\n minLines: {\n type: \"integer\",\n minimum: 1,\n description: \"Minimum number of lines for a chunk to be reported\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n threshold: 0.85,\n indexPath: \".uilint/.duplicates-index\",\n minLines: 3,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const threshold = options.threshold ?? 0.85;\n const indexPath = options.indexPath ?? \".uilint/.duplicates-index\";\n const minLines = options.minLines ?? 3;\n\n const filename = context.filename || context.getFilename();\n const projectRoot = findProjectRoot(dirname(filename), indexPath);\n\n // Initialize logging to .uilint folder\n initLog(projectRoot);\n\n log(`\\n========== Rule create() ==========`);\n log(`Filename: ${filename}`);\n log(`Threshold: ${threshold}`);\n log(`Index path: ${indexPath}`);\n log(`Min lines: ${minLines}`);\n log(`Project root: ${projectRoot}`);\n\n const index = loadIndex(projectRoot, indexPath);\n\n // Track which chunks we've already reported to avoid duplicates\n const reportedChunks = new Set<string>();\n\n /**\n * Check if a node location corresponds to an indexed chunk\n * and if so, check for similar chunks\n */\n function checkForDuplicates(\n node: TSESTree.Node,\n name: string | null\n ): void {\n log(`checkForDuplicates: name=${name}, file=${filename}`);\n\n if (!index) {\n log(` No index loaded`);\n return;\n }\n\n // Get chunks for this file\n const fileChunks = index.fileToChunks.get(filename);\n log(` Looking for chunks for file: ${filename}`);\n log(` Files in index: ${Array.from(index.fileToChunks.keys()).join(\", \")}`);\n\n if (!fileChunks || fileChunks.length === 0) {\n log(` No chunks found for this file`);\n return;\n }\n log(` Found ${fileChunks.length} chunks: ${fileChunks.join(\", \")}`);\n\n // Find the chunk that contains this node's location\n const nodeLine = node.loc?.start.line;\n if (!nodeLine) {\n log(` No node line number`);\n return;\n }\n log(` Node starts at line ${nodeLine}`);\n\n for (const chunkId of fileChunks) {\n if (reportedChunks.has(chunkId)) {\n log(` Chunk ${chunkId} already reported, skipping`);\n continue;\n }\n\n const meta = index.metadataStore.get(chunkId);\n if (!meta) {\n log(` No metadata for chunk ${chunkId}`);\n continue;\n }\n\n log(` Checking chunk ${chunkId}: lines ${meta.startLine}-${meta.endLine} (node at line ${nodeLine})`);\n\n // Check if this node is within the chunk's line range\n if (nodeLine >= meta.startLine && nodeLine <= meta.endLine) {\n log(` Node is within chunk range, searching for similar chunks...`);\n\n // Find similar chunks\n const similar = findSimilarChunks(index, chunkId, threshold);\n\n if (similar.length > 0) {\n const best = similar[0];\n const bestMeta = index.metadataStore.get(best.id);\n\n if (bestMeta) {\n // Check minimum lines threshold\n const chunkLines = meta.endLine - meta.startLine + 1;\n if (chunkLines < minLines) {\n log(` Skipping: chunk has ${chunkLines} lines, below minLines=${minLines}`);\n continue;\n }\n\n reportedChunks.add(chunkId);\n\n const relPath = relative(projectRoot, bestMeta.filePath);\n const similarity = Math.round(best.score * 100);\n\n log(` REPORTING: ${meta.kind} '${name || meta.name}' is ${similarity}% similar to '${bestMeta.name}' at ${relPath}:${bestMeta.startLine}`);\n\n context.report({\n node,\n loc: {\n start: { line: meta.startLine, column: meta.startColumn },\n end: { line: meta.endLine, column: meta.endColumn },\n },\n messageId: \"semanticDuplicate\",\n data: {\n kind: meta.kind,\n name: name || meta.name || \"(anonymous)\",\n similarity: String(similarity),\n otherName: bestMeta.name || \"(anonymous)\",\n otherLocation: `${relPath}:${bestMeta.startLine}`,\n },\n });\n }\n } else {\n log(` No similar chunks found above threshold`);\n }\n } else {\n log(` Node line ${nodeLine} not in chunk range ${meta.startLine}-${meta.endLine}`);\n }\n }\n }\n\n return {\n // Check function declarations\n FunctionDeclaration(node) {\n const name = node.id?.name || null;\n checkForDuplicates(node, name);\n },\n\n // Check arrow functions assigned to variables\n \"VariableDeclarator[init.type='ArrowFunctionExpression']\"(\n node: TSESTree.VariableDeclarator\n ) {\n const name =\n node.id.type === \"Identifier\" ? node.id.name : null;\n if (node.init) {\n checkForDuplicates(node.init, name);\n }\n },\n\n // Check function expressions\n \"VariableDeclarator[init.type='FunctionExpression']\"(\n node: TSESTree.VariableDeclarator\n ) {\n const name =\n node.id.type === \"Identifier\" ? node.id.name : null;\n if (node.init) {\n checkForDuplicates(node.init, name);\n }\n },\n };\n },\n});\n","/**\n * Rule: require-test-coverage\n *\n * Enforces that source files have test coverage above a configurable threshold.\n * Checks for:\n * - Existence of test files\n * - Coverage data in Istanbul JSON format\n * - Statement coverage percentage\n */\n\nimport { createRule, defineRuleMeta } from \"../../utils/create-rule.js\";\nimport { existsSync, readFileSync, statSync } from \"fs\";\nimport { dirname, join, basename, relative } from \"path\";\nimport { execSync } from \"child_process\";\nimport {\n aggregateCoverage,\n type IstanbulCoverage as AggregatorIstanbulCoverage,\n} from \"./lib/coverage-aggregator.js\";\nimport {\n analyzeJSXElementCoverage,\n type IstanbulCoverage as JSXAnalyzerIstanbulCoverage,\n} from \"./lib/jsx-coverage-analyzer.js\";\nimport { analyzeChunks, getChunkThreshold } from \"./lib/chunk-analyzer.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\n/**\n * Simple glob pattern matching function\n * Supports: *, **, ?\n */\nfunction simpleGlobMatch(pattern: string, path: string): boolean {\n // Normalize path separators\n const normalizedPath = path.replace(/\\\\/g, \"/\");\n const normalizedPattern = pattern.replace(/\\\\/g, \"/\");\n\n // Escape regex special chars except our glob patterns\n let regexStr = normalizedPattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\") // Escape regex special chars\n .replace(/\\*\\*/g, \"{{GLOBSTAR}}\") // Placeholder for **\n .replace(/\\*/g, \"[^/]*\") // * matches anything except /\n .replace(/\\?/g, \"[^/]\") // ? matches single char except /\n .replace(/{{GLOBSTAR}}/g, \".*\"); // ** matches anything including /\n\n // Add anchors\n const regex = new RegExp(`^${regexStr}$`);\n return regex.test(normalizedPath);\n}\n\ntype MessageIds =\n | \"noCoverage\"\n | \"belowThreshold\"\n | \"noCoverageData\"\n | \"belowAggregateThreshold\"\n | \"jsxBelowThreshold\"\n | \"chunkBelowThreshold\"\n | \"untestedFunction\";\n\ntype SeverityLevel = \"error\" | \"warn\" | \"off\";\n\ntype Options = [\n {\n /** Path to coverage JSON file. Default: \"coverage/coverage-final.json\" */\n coveragePath?: string;\n /** Coverage threshold percentage. Default: 80 */\n threshold?: number;\n /** Pattern-specific thresholds */\n thresholdsByPattern?: Array<{ pattern: string; threshold: number }>;\n /** Severity levels for different issue types */\n severity?: {\n noCoverage?: SeverityLevel;\n belowThreshold?: SeverityLevel;\n };\n /** Patterns to detect test files. Default: [\".test.ts\", \".test.tsx\", \".spec.ts\", \".spec.tsx\", \"__tests__/\"] */\n testPatterns?: string[];\n /** Glob patterns for files to ignore. Default: [\"**\\/*.d.ts\", \"**\\/index.ts\"] */\n ignorePatterns?: string[];\n /** Mode: \"all\" checks all code, \"changed\" only checks git-changed lines. Default: \"all\" */\n mode?: \"all\" | \"changed\";\n /** Base branch for \"changed\" mode. Default: \"main\" */\n baseBranch?: string;\n /** Aggregate coverage threshold for components. Default: 70 */\n aggregateThreshold?: number;\n /** Severity for aggregate coverage check. Default: \"warn\" */\n aggregateSeverity?: SeverityLevel;\n /** JSX element coverage threshold percentage. Default: 50 */\n jsxThreshold?: number;\n /** Severity for JSX element coverage check. Default: \"warn\" */\n jsxSeverity?: SeverityLevel;\n /** Enable chunk-level coverage reporting (replaces file-level). Default: false */\n chunkCoverage?: boolean;\n /** Threshold for strict categories (utility/hook/store). Default: 80 */\n chunkThreshold?: number;\n /** Focus on non-React code with relaxed thresholds for components. Default: false */\n focusNonReact?: boolean;\n /** Threshold for relaxed categories (component/handler). Default: 50 */\n relaxedThreshold?: number;\n /** Severity for chunk coverage. Default: \"warn\" */\n chunkSeverity?: SeverityLevel;\n /** Minimum statements in file to require coverage. Default: 5 */\n minStatements?: number;\n }\n];\n\n/**\n * Istanbul coverage JSON format\n */\ninterface IstanbulCoverage {\n [filePath: string]: {\n path: string;\n statementMap: {\n [key: string]: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n fnMap: {\n [key: string]: {\n name: string;\n decl: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n };\n branchMap: {\n [key: string]: {\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n type: string;\n locations: Array<{\n start: { line: number; column: number };\n end: { line: number; column: number };\n }>;\n };\n };\n s: { [key: string]: number }; // Statement hit counts\n f: { [key: string]: number }; // Function hit counts\n b: { [key: string]: number[] }; // Branch hit counts\n };\n}\n\n/**\n * Rule metadata\n */\nexport const meta = defineRuleMeta({\n id: \"require-test-coverage\",\n version: \"1.0.0\",\n name: \"Require Test Coverage\",\n description: \"Enforce that source files have adequate test coverage\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🧪\",\n hint: \"Ensures code has tests\",\n defaultEnabled: true,\n isDirectoryBased: true,\n requirements: [\n {\n type: \"coverage\",\n description: \"Requires test coverage data\",\n setupHint: \"Run tests with coverage: npm test -- --coverage\",\n },\n ],\n defaultOptions: [\n {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\",\n ],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\",\n baseBranch: \"main\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description: \"Minimum coverage percentage required (0-100)\",\n },\n {\n key: \"coveragePath\",\n label: \"Coverage file path\",\n type: \"text\",\n defaultValue: \"coverage/coverage-final.json\",\n description: \"Path to Istanbul coverage JSON file\",\n },\n {\n key: \"mode\",\n label: \"Mode\",\n type: \"select\",\n defaultValue: \"all\",\n options: [\n { value: \"all\", label: \"Check all code\" },\n { value: \"changed\", label: \"Only check changed lines\" },\n ],\n description: \"Whether to check all code or only git-changed lines\",\n },\n {\n key: \"chunkCoverage\",\n label: \"Enable chunk-level coverage\",\n type: \"boolean\",\n defaultValue: true,\n description:\n \"Report coverage for individual functions instead of file level\",\n },\n {\n key: \"focusNonReact\",\n label: \"Focus on non-React code\",\n type: \"boolean\",\n defaultValue: false,\n description:\n \"Apply strict thresholds to utilities/stores/hooks, relaxed to components\",\n },\n {\n key: \"chunkThreshold\",\n label: \"Chunk coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description:\n \"Minimum coverage for utility/hook/store chunks (0-100)\",\n },\n {\n key: \"relaxedThreshold\",\n label: \"Relaxed threshold for React code\",\n type: \"number\",\n defaultValue: 50,\n description:\n \"Threshold for components/handlers when focusNonReact is enabled\",\n },\n {\n key: \"minStatements\",\n label: \"Minimum statements for coverage\",\n type: \"number\",\n defaultValue: 5,\n description:\n \"Files with fewer statements are exempt from coverage requirements\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnforces that source files have test coverage above a configurable threshold.\nIt checks for:\n- Existence of corresponding test files\n- Coverage data in Istanbul JSON format\n- Statement coverage percentage meeting the threshold\n\n## Why it's useful\n\n- **Quality Assurance**: Ensures critical code is tested\n- **Catch Regressions**: Prevents merging untested changes\n- **Configurable**: Different thresholds for different file patterns\n- **Git Integration**: Can focus only on changed lines\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/require-test-coverage\": [\"warn\", {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [\n { pattern: \"**/utils/*.ts\", threshold: 90 },\n { pattern: \"**/generated/**\", threshold: 0 },\n ],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\".test.ts\", \".test.tsx\", \".spec.ts\", \".spec.tsx\", \"__tests__/\"],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\", // or \"changed\"\n baseBranch: \"main\" // for \"changed\" mode\n}]\n\\`\\`\\`\n\n## Examples\n\n### Below threshold:\n\\`\\`\\`ts\n// src/api.ts - 40% coverage (threshold: 80%)\nexport function fetchData() { ... } // Warning: Coverage below threshold\n\\`\\`\\`\n`,\n});\n\n// Cache for loaded coverage data\nlet coverageCache: {\n projectRoot: string;\n coveragePath: string;\n mtime: number;\n data: IstanbulCoverage;\n} | null = null;\n\n/**\n * Clear the coverage cache (useful for testing)\n */\nexport function clearCoverageCache(): void {\n coverageCache = null;\n}\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startPath: string): string {\n let current = startPath;\n let lastPackageJson: string | null = null;\n\n while (current !== dirname(current)) {\n if (existsSync(join(current, \"package.json\"))) {\n lastPackageJson = current;\n }\n // If we find a coverage directory, use this as project root\n if (existsSync(join(current, \"coverage\"))) {\n return current;\n }\n current = dirname(current);\n }\n\n return lastPackageJson || startPath;\n}\n\n/**\n * Load coverage data from JSON file\n */\nfunction loadCoverage(\n projectRoot: string,\n coveragePath: string\n): IstanbulCoverage | null {\n const fullPath = join(projectRoot, coveragePath);\n\n if (!existsSync(fullPath)) {\n return null;\n }\n\n try {\n const stat = statSync(fullPath);\n const mtime = stat.mtimeMs;\n\n // Check cache\n if (\n coverageCache &&\n coverageCache.projectRoot === projectRoot &&\n coverageCache.coveragePath === coveragePath &&\n coverageCache.mtime === mtime\n ) {\n return coverageCache.data;\n }\n\n const content = readFileSync(fullPath, \"utf-8\");\n const data = JSON.parse(content) as IstanbulCoverage;\n\n // Update cache\n coverageCache = {\n projectRoot,\n coveragePath,\n mtime,\n data,\n };\n\n return data;\n } catch {\n return null;\n }\n}\n\n/**\n * Calculate statement coverage percentage for a file\n */\nfunction calculateCoverage(fileCoverage: IstanbulCoverage[string]): number {\n const statements = fileCoverage.s;\n const keys = Object.keys(statements);\n\n if (keys.length === 0) {\n return 100; // No statements = 100% covered\n }\n\n const covered = keys.filter((key) => statements[key] > 0).length;\n return Math.round((covered / keys.length) * 100);\n}\n\n/**\n * Check if a file matches any of the ignore patterns\n */\nfunction shouldIgnore(filePath: string, ignorePatterns: string[]): boolean {\n for (const pattern of ignorePatterns) {\n if (simpleGlobMatch(pattern, filePath)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Get threshold for a file, checking pattern-specific thresholds first\n */\nfunction getThreshold(\n filePath: string,\n globalThreshold: number,\n thresholdsByPattern: Array<{ pattern: string; threshold: number }>\n): number {\n for (const { pattern, threshold } of thresholdsByPattern) {\n if (simpleGlobMatch(pattern, filePath)) {\n return threshold;\n }\n }\n return globalThreshold;\n}\n\n/**\n * Get changed line numbers from git diff\n */\nfunction getChangedLines(\n projectRoot: string,\n filePath: string,\n baseBranch: string\n): Set<number> | null {\n try {\n const relPath = relative(projectRoot, filePath);\n const diff = execSync(`git diff ${baseBranch}...HEAD -- \"${relPath}\"`, {\n cwd: projectRoot,\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n const changedLines = new Set<number>();\n const lines = diff.split(\"\\n\");\n\n let currentLine = 0;\n for (const line of lines) {\n // Parse hunk header: @@ -start,count +start,count @@\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n changedLines.add(currentLine);\n currentLine++;\n } else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) {\n // Deleted line, don't increment\n } else if (!line.startsWith(\"\\\\\")) {\n currentLine++;\n }\n }\n\n return changedLines;\n } catch {\n // Git command failed, return null to fall back to \"all\" mode\n return null;\n }\n}\n\n/**\n * Calculate coverage for only changed lines\n */\nfunction calculateChangedLinesCoverage(\n fileCoverage: IstanbulCoverage[string],\n changedLines: Set<number>\n): number {\n const statementMap = fileCoverage.statementMap;\n const statements = fileCoverage.s;\n\n let relevantStatements = 0;\n let coveredStatements = 0;\n\n for (const [key, location] of Object.entries(statementMap)) {\n // Check if any line of this statement was changed\n let isRelevant = false;\n for (let line = location.start.line; line <= location.end.line; line++) {\n if (changedLines.has(line)) {\n isRelevant = true;\n break;\n }\n }\n\n if (isRelevant) {\n relevantStatements++;\n if (statements[key] > 0) {\n coveredStatements++;\n }\n }\n }\n\n if (relevantStatements === 0) {\n return 100; // No changed statements = 100% covered\n }\n\n return Math.round((coveredStatements / relevantStatements) * 100);\n}\n\n/**\n * Normalize file path for coverage lookup\n * Coverage JSON may store paths in different formats\n */\nfunction findCoverageForFile(\n coverage: IstanbulCoverage,\n filePath: string,\n projectRoot: string\n): IstanbulCoverage[string] | null {\n // Try exact match first\n if (coverage[filePath]) {\n return coverage[filePath];\n }\n\n // Try relative path from project root\n const relPath = relative(projectRoot, filePath);\n if (coverage[relPath]) {\n return coverage[relPath];\n }\n\n // Try with leading slash (common in Istanbul output)\n const withSlash = \"/\" + relPath;\n if (coverage[withSlash]) {\n return coverage[withSlash];\n }\n\n // Try just the src-relative path\n const srcMatch = relPath.match(/src\\/.+$/);\n if (srcMatch) {\n const srcPath = \"/\" + srcMatch[0];\n if (coverage[srcPath]) {\n return coverage[srcPath];\n }\n }\n\n return null;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"require-test-coverage\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Enforce that source files have adequate test coverage\",\n },\n messages: {\n noCoverage:\n \"No coverage data found for '{{fileName}}' in coverage report\",\n belowThreshold:\n \"Coverage for '{{fileName}}' is {{coverage}}%, below threshold of {{threshold}}%\",\n noCoverageData:\n \"Coverage data not found at '{{coveragePath}}'. Run tests with coverage first.\",\n belowAggregateThreshold:\n \"Aggregate coverage ({{coverage}}%) is below threshold ({{threshold}}%). \" +\n \"Includes {{fileCount}} files. Lowest: {{lowestFile}} ({{lowestCoverage}}%)\",\n jsxBelowThreshold:\n \"<{{tagName}}> element coverage is {{coverage}}%, below threshold of {{threshold}}%\",\n chunkBelowThreshold:\n \"{{category}} '{{name}}' has {{coverage}}% coverage, below {{threshold}}% threshold\",\n untestedFunction:\n \"Function '{{name}}' ({{category}}) is not covered by tests\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n coveragePath: {\n type: \"string\",\n description: \"Path to coverage JSON file\",\n },\n threshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description: \"Coverage threshold percentage\",\n },\n thresholdsByPattern: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n pattern: { type: \"string\" },\n threshold: { type: \"number\", minimum: 0, maximum: 100 },\n },\n required: [\"pattern\", \"threshold\"],\n additionalProperties: false,\n },\n description: \"Pattern-specific thresholds\",\n },\n severity: {\n type: \"object\",\n properties: {\n noCoverage: { type: \"string\", enum: [\"error\", \"warn\", \"off\"] },\n belowThreshold: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n },\n },\n additionalProperties: false,\n },\n testPatterns: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Patterns to detect test files\",\n },\n ignorePatterns: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Glob patterns for files to ignore\",\n },\n mode: {\n type: \"string\",\n enum: [\"all\", \"changed\"],\n description: \"Check all code or only changed lines\",\n },\n baseBranch: {\n type: \"string\",\n description: \"Base branch for changed mode\",\n },\n aggregateThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description:\n \"Aggregate coverage threshold for components (includes dependencies)\",\n },\n aggregateSeverity: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n description: \"Severity for aggregate coverage check\",\n },\n jsxThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description:\n \"JSX element coverage threshold percentage (includes event handlers)\",\n },\n jsxSeverity: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n description: \"Severity for JSX element coverage check\",\n },\n chunkCoverage: {\n type: \"boolean\",\n description:\n \"Enable chunk-level coverage reporting (replaces file-level)\",\n },\n chunkThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description:\n \"Threshold for strict categories (utility/hook/store)\",\n },\n focusNonReact: {\n type: \"boolean\",\n description:\n \"Focus on non-React code with relaxed thresholds for components\",\n },\n relaxedThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description: \"Threshold for relaxed categories (component/handler)\",\n },\n chunkSeverity: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n description: \"Severity for chunk coverage check\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\",\n ],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\",\n baseBranch: \"main\",\n aggregateThreshold: 70,\n aggregateSeverity: \"warn\",\n jsxThreshold: 50,\n jsxSeverity: \"warn\",\n chunkCoverage: true,\n chunkThreshold: 80,\n focusNonReact: false,\n relaxedThreshold: 50,\n chunkSeverity: \"warn\",\n minStatements: 5,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const coveragePath = options.coveragePath ?? \"coverage/coverage-final.json\";\n const threshold = options.threshold ?? 80;\n const thresholdsByPattern = options.thresholdsByPattern ?? [];\n const severity = {\n noCoverage: options.severity?.noCoverage ?? \"error\",\n belowThreshold: options.severity?.belowThreshold ?? \"warn\",\n };\n const aggregateThreshold = options.aggregateThreshold ?? 70;\n const aggregateSeverity = options.aggregateSeverity ?? \"warn\";\n const testPatterns = options.testPatterns ?? [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\",\n ];\n const ignorePatterns = options.ignorePatterns ?? [\n \"**/*.d.ts\",\n \"**/index.ts\",\n ];\n const mode = options.mode ?? \"all\";\n const baseBranch = options.baseBranch ?? \"main\";\n const jsxThreshold = options.jsxThreshold ?? 50;\n const jsxSeverity = options.jsxSeverity ?? \"warn\";\n const chunkCoverage = options.chunkCoverage ?? true;\n const chunkThreshold = options.chunkThreshold ?? 80;\n const focusNonReact = options.focusNonReact ?? false;\n const relaxedThreshold = options.relaxedThreshold ?? 50;\n const chunkSeverity = options.chunkSeverity ?? \"warn\";\n const minStatements = options.minStatements ?? 5;\n\n const filename = context.filename || context.getFilename();\n const projectRoot = findProjectRoot(dirname(filename));\n\n // Check if file should be ignored\n const relPath = relative(projectRoot, filename);\n if (shouldIgnore(relPath, ignorePatterns)) {\n return {};\n }\n\n // Skip test files themselves\n if (\n testPatterns.some((p) =>\n filename.includes(p.replace(\"__tests__/\", \"__tests__\"))\n )\n ) {\n return {};\n }\n\n // Track if we've already reported for this file\n let reported = false;\n\n // Collect JSX elements with their ancestors for element-level coverage\n const jsxElements: Array<{\n node: TSESTree.JSXElement;\n ancestors: TSESTree.Node[];\n }> = [];\n\n return {\n // Collect JSX elements for element-level coverage analysis\n JSXElement(node: TSESTree.JSXElement) {\n // Get ancestors using context.sourceCode (ESLint v9) or context.getAncestors (legacy)\n const ancestors = context.sourceCode?.getAncestors?.(node) ?? [];\n jsxElements.push({ node, ancestors });\n },\n\n \"Program:exit\"(node: TSESTree.Program) {\n if (reported) return;\n reported = true;\n\n // Load coverage data\n const coverage = loadCoverage(projectRoot, coveragePath);\n\n // Check if coverage data exists\n if (!coverage) {\n if (severity.noCoverage !== \"off\") {\n context.report({\n node,\n messageId: \"noCoverageData\",\n data: {\n coveragePath,\n },\n });\n }\n return;\n }\n\n // Find coverage for this file\n const fileCoverage = findCoverageForFile(\n coverage,\n filename,\n projectRoot\n );\n\n if (!fileCoverage) {\n // File is not in coverage report - this is OK if coverage data exists\n // but this specific file wasn't covered (different from no coverage data at all)\n return;\n }\n\n // Skip small files (fewer statements than minStatements threshold)\n const statementCount = Object.keys(fileCoverage.s).length;\n if (statementCount < minStatements) {\n return;\n }\n\n // Calculate coverage\n let coveragePercent: number;\n\n if (mode === \"changed\") {\n const changedLines = getChangedLines(\n projectRoot,\n filename,\n baseBranch\n );\n if (changedLines && changedLines.size > 0) {\n coveragePercent = calculateChangedLinesCoverage(\n fileCoverage,\n changedLines\n );\n } else {\n // No changed lines or git failed - use full coverage\n coveragePercent = calculateCoverage(fileCoverage);\n }\n } else {\n coveragePercent = calculateCoverage(fileCoverage);\n }\n\n // Get threshold for this file\n const fileThreshold = getThreshold(\n relPath,\n threshold,\n thresholdsByPattern\n );\n\n // Check if below threshold (file-level) - skipped when chunkCoverage is enabled\n if (\n !chunkCoverage &&\n severity.belowThreshold !== \"off\" &&\n coveragePercent < fileThreshold\n ) {\n context.report({\n node,\n messageId: \"belowThreshold\",\n data: {\n fileName: basename(filename),\n coverage: String(coveragePercent),\n threshold: String(fileThreshold),\n },\n });\n }\n\n // Check chunk-level coverage (replaces file-level when enabled)\n if (chunkCoverage && chunkSeverity !== \"off\" && fileCoverage) {\n const chunks = analyzeChunks(\n context.sourceCode.ast,\n filename,\n fileCoverage\n );\n\n // Report one message per chunk below threshold, highlighting just the declaration\n for (const chunk of chunks) {\n const chunkThresholdValue = getChunkThreshold(chunk, {\n focusNonReact,\n chunkThreshold,\n relaxedThreshold,\n });\n\n if (chunk.coverage.percentage < chunkThresholdValue) {\n const messageId =\n chunk.coverage.functionCalled\n ? \"chunkBelowThreshold\"\n : \"untestedFunction\";\n\n context.report({\n loc: chunk.declarationLoc,\n messageId,\n data: {\n name: chunk.name,\n category: chunk.category,\n coverage: String(chunk.coverage.percentage),\n threshold: String(chunkThresholdValue),\n },\n });\n }\n }\n }\n\n // Check aggregate coverage for component files (JSX)\n if (\n aggregateSeverity !== \"off\" &&\n (filename.endsWith(\".tsx\") || filename.endsWith(\".jsx\"))\n ) {\n // Check if file actually contains JSX by looking at the AST\n const hasJSX = checkForJSX(context.sourceCode.ast);\n\n if (hasJSX) {\n const aggregateResult = aggregateCoverage(\n filename,\n projectRoot,\n coverage as AggregatorIstanbulCoverage\n );\n\n if (aggregateResult.aggregateCoverage < aggregateThreshold) {\n const lowestFile = aggregateResult.lowestCoverageFile;\n context.report({\n node,\n messageId: \"belowAggregateThreshold\",\n data: {\n coverage: String(\n Math.round(aggregateResult.aggregateCoverage)\n ),\n threshold: String(aggregateThreshold),\n fileCount: String(aggregateResult.totalFiles),\n lowestFile: lowestFile\n ? basename(lowestFile.path)\n : \"N/A\",\n lowestCoverage: lowestFile\n ? String(Math.round(lowestFile.percentage))\n : \"N/A\",\n },\n });\n }\n }\n }\n\n // Check JSX element-level coverage\n if (\n jsxSeverity !== \"off\" &&\n jsxElements.length > 0 &&\n coverage\n ) {\n // Compute relative path for dataLoc (consistent with overlay matching)\n const fileRelPath = relPath.startsWith(\"/\") ? relPath : `/${relPath}`;\n\n for (const { node: jsxNode, ancestors } of jsxElements) {\n // Only check elements with event handlers (interactive elements)\n const hasEventHandlers = jsxNode.openingElement.attributes.some(\n (attr) =>\n attr.type === \"JSXAttribute\" &&\n attr.name.type === \"JSXIdentifier\" &&\n /^on[A-Z]/.test(attr.name.name)\n );\n\n // Skip non-interactive elements to reduce noise\n if (!hasEventHandlers) {\n continue;\n }\n\n const result = analyzeJSXElementCoverage(\n jsxNode,\n fileRelPath,\n coverage as JSXAnalyzerIstanbulCoverage,\n ancestors,\n projectRoot\n );\n\n if (result.coverage.percentage < jsxThreshold) {\n // Get the tag name for the error message\n const openingElement = jsxNode.openingElement;\n let tagName = \"unknown\";\n if (openingElement.name.type === \"JSXIdentifier\") {\n tagName = openingElement.name.name;\n } else if (openingElement.name.type === \"JSXMemberExpression\") {\n // For Foo.Bar, use \"Foo.Bar\"\n let current: TSESTree.JSXTagNameExpression = openingElement.name;\n const parts: string[] = [];\n while (current.type === \"JSXMemberExpression\") {\n if (current.property.type === \"JSXIdentifier\") {\n parts.unshift(current.property.name);\n }\n current = current.object;\n }\n if (current.type === \"JSXIdentifier\") {\n parts.unshift(current.name);\n }\n tagName = parts.join(\".\");\n }\n\n context.report({\n node: jsxNode,\n messageId: \"jsxBelowThreshold\",\n data: {\n tagName,\n coverage: String(result.coverage.percentage),\n threshold: String(jsxThreshold),\n dataLoc: result.dataLoc,\n },\n });\n }\n }\n }\n },\n };\n },\n});\n\n/**\n * Check if an AST contains JSX elements\n * Uses a visited set to avoid infinite recursion from circular references (e.g., parent pointers)\n */\nfunction checkForJSX(ast: unknown, visited: WeakSet<object> = new WeakSet()): boolean {\n if (!ast || typeof ast !== \"object\") return false;\n\n // Avoid circular references\n if (visited.has(ast as object)) return false;\n visited.add(ast as object);\n\n const node = ast as Record<string, unknown>;\n\n // Check if this node is JSX\n if (\n node.type === \"JSXElement\" ||\n node.type === \"JSXFragment\" ||\n node.type === \"JSXText\"\n ) {\n return true;\n }\n\n // Only traverse known AST child properties to avoid parent/token references\n const childKeys = [\"body\", \"declarations\", \"declaration\", \"expression\", \"expressions\",\n \"argument\", \"arguments\", \"callee\", \"elements\", \"properties\", \"value\", \"init\",\n \"consequent\", \"alternate\", \"test\", \"left\", \"right\", \"object\", \"property\",\n \"children\", \"openingElement\", \"closingElement\", \"attributes\"];\n\n for (const key of childKeys) {\n const child = node[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (checkForJSX(item, visited)) return true;\n }\n } else {\n if (checkForJSX(child, visited)) return true;\n }\n }\n }\n\n return false;\n}\n","/**\n * File Categorizer\n *\n * Categorizes TypeScript/React files by their role in the codebase.\n * Used for smart weighting in coverage aggregation.\n *\n * Categories:\n * - core (1.0): hooks, components, services, stores - critical logic\n * - utility (0.5): formatters, validators, helpers - supporting code\n * - constant (0.25): config, constants, enums - static data\n * - type (0): .d.ts files, type-only exports - no runtime impact\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { basename } from \"path\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\nexport type FileCategory = \"core\" | \"utility\" | \"constant\" | \"type\";\n\nexport interface FileCategoryResult {\n category: FileCategory;\n weight: number;\n reason: string;\n}\n\nconst CATEGORY_WEIGHTS: Record<FileCategory, number> = {\n core: 1.0,\n utility: 0.5,\n constant: 0.25,\n type: 0,\n};\n\n/**\n * Categorize a TypeScript/React file by its role\n */\nexport function categorizeFile(\n filePath: string,\n _projectRoot: string\n): FileCategoryResult {\n const fileName = basename(filePath);\n\n // 1. Type definition files are always \"type\"\n if (filePath.endsWith(\".d.ts\")) {\n return {\n category: \"type\",\n weight: 0,\n reason: \"TypeScript declaration file (.d.ts)\",\n };\n }\n\n // 2. Check file name patterns for core files\n // Hooks: use*.ts or use*.tsx\n if (/^use[A-Z]/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"React hook (use* pattern)\",\n };\n }\n\n // Services: *.service.ts\n if (/\\.service\\.(ts|tsx)$/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"Service file (*.service.ts pattern)\",\n };\n }\n\n // Stores: *.store.ts\n if (/\\.store\\.(ts|tsx)$/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"Store file (*.store.ts pattern)\",\n };\n }\n\n // API files: *.api.ts\n if (/\\.api\\.(ts|tsx)$/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"API file (*.api.ts pattern)\",\n };\n }\n\n // 3. Parse AST to analyze exports\n if (!existsSync(filePath)) {\n return {\n category: \"utility\",\n weight: 0.5,\n reason: \"File not found, defaulting to utility\",\n };\n }\n\n let ast: TSESTree.Program;\n try {\n const content = readFileSync(filePath, \"utf-8\");\n ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n });\n } catch {\n return {\n category: \"utility\",\n weight: 0.5,\n reason: \"Failed to parse file, defaulting to utility\",\n };\n }\n\n // Analyze the file's exports\n const analysis = analyzeExports(ast);\n\n // 4. Type-only files (only type/interface exports, no runtime code)\n if (analysis.hasOnlyTypeExports) {\n return {\n category: \"type\",\n weight: 0,\n reason: \"File contains only type/interface exports\",\n };\n }\n\n // 5. Check for JSX (React component)\n if (analysis.hasJSX) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"React component (contains JSX)\",\n };\n }\n\n // 6. Constant files (only const/enum exports, no functions)\n if (analysis.hasOnlyConstantExports) {\n return {\n category: \"constant\",\n weight: 0.25,\n reason: \"File contains only constant/enum exports\",\n };\n }\n\n // 7. Default to utility\n return {\n category: \"utility\",\n weight: 0.5,\n reason: \"General utility file with function exports\",\n };\n}\n\ninterface ExportAnalysis {\n hasOnlyTypeExports: boolean;\n hasOnlyConstantExports: boolean;\n hasJSX: boolean;\n hasFunctionExports: boolean;\n hasConstExports: boolean;\n hasTypeExports: boolean;\n}\n\n/**\n * Analyze exports in an AST to determine file category\n */\nfunction analyzeExports(ast: TSESTree.Program): ExportAnalysis {\n let hasFunctionExports = false;\n let hasConstExports = false;\n let hasTypeExports = false;\n let hasJSX = false;\n\n // Walk the AST to find exports and JSX\n function visit(node: TSESTree.Node): void {\n // Check for JSX\n if (\n node.type === \"JSXElement\" ||\n node.type === \"JSXFragment\" ||\n node.type === \"JSXText\"\n ) {\n hasJSX = true;\n }\n\n // Export named declaration\n if (node.type === \"ExportNamedDeclaration\") {\n const decl = node.declaration;\n\n // Type/interface exports\n if (\n node.exportKind === \"type\" ||\n decl?.type === \"TSTypeAliasDeclaration\" ||\n decl?.type === \"TSInterfaceDeclaration\"\n ) {\n hasTypeExports = true;\n }\n // Function exports\n else if (\n decl?.type === \"FunctionDeclaration\" ||\n (decl?.type === \"VariableDeclaration\" &&\n decl.declarations.some(\n (d) =>\n d.init?.type === \"ArrowFunctionExpression\" ||\n d.init?.type === \"FunctionExpression\"\n ))\n ) {\n hasFunctionExports = true;\n }\n // Const/enum exports\n else if (\n decl?.type === \"VariableDeclaration\" ||\n decl?.type === \"TSEnumDeclaration\"\n ) {\n // Check if it's a const with non-function value\n if (decl.type === \"VariableDeclaration\") {\n const hasNonFunctionInit = decl.declarations.some(\n (d) =>\n d.init &&\n d.init.type !== \"ArrowFunctionExpression\" &&\n d.init.type !== \"FunctionExpression\"\n );\n if (hasNonFunctionInit) {\n hasConstExports = true;\n }\n } else {\n hasConstExports = true;\n }\n }\n // Re-exports without declaration - check specifiers\n else if (!decl && node.specifiers.length > 0) {\n // For re-exports, we can't easily determine the type without resolving\n // Treat as potential function exports to be safe\n // Note: if exportKind was \"type\", we would have matched the first branch\n hasFunctionExports = true;\n }\n }\n\n // Export default\n if (node.type === \"ExportDefaultDeclaration\") {\n const decl = node.declaration;\n if (\n decl.type === \"FunctionDeclaration\" ||\n decl.type === \"ArrowFunctionExpression\" ||\n decl.type === \"FunctionExpression\"\n ) {\n hasFunctionExports = true;\n } else if (decl.type === \"ClassDeclaration\") {\n // Classes are typically core logic\n hasFunctionExports = true;\n } else {\n hasConstExports = true;\n }\n }\n\n // Recurse into children\n for (const key of Object.keys(node)) {\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n visit(item as TSESTree.Node);\n }\n }\n } else if (\"type\" in child) {\n visit(child as TSESTree.Node);\n }\n }\n }\n }\n\n for (const node of ast.body) {\n visit(node);\n }\n\n // Determine derived properties\n const hasOnlyTypeExports =\n hasTypeExports && !hasFunctionExports && !hasConstExports;\n const hasOnlyConstantExports =\n hasConstExports && !hasFunctionExports && !hasTypeExports;\n\n return {\n hasOnlyTypeExports,\n hasOnlyConstantExports,\n hasJSX,\n hasFunctionExports,\n hasConstExports,\n hasTypeExports,\n };\n}\n\n/**\n * Get the weight for a category\n */\nexport function getCategoryWeight(category: FileCategory): number {\n return CATEGORY_WEIGHTS[category];\n}\n","/**\n * Dependency Graph Builder\n *\n * Builds a dependency graph by tracing all imports from an entry file.\n * Used for calculating aggregate test coverage across a component and its dependencies.\n *\n * Key behaviors:\n * - Traces transitive dependencies (full depth)\n * - Excludes node_modules (external packages)\n * - Handles circular dependencies via visited set\n * - Follows re-exports to actual source files\n * - Caches results for performance\n */\n\nimport { existsSync, readFileSync, statSync } from \"fs\";\nimport { dirname, resolve } from \"path\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { resolveImportPath, parseFile } from \"./export-resolver.js\";\n\nexport interface DependencyGraph {\n /** The entry file that was analyzed */\n root: string;\n /** All transitive dependencies (absolute paths, project files only) */\n allDependencies: Set<string>;\n}\n\ninterface CacheEntry {\n graph: DependencyGraph;\n mtime: number;\n}\n\n/**\n * Cache for dependency graphs (per entry file)\n */\nconst dependencyCache = new Map<string, CacheEntry>();\n\n/**\n * Build a dependency graph starting from an entry file\n *\n * @param entryFile - Absolute path to the entry file\n * @param projectRoot - Project root directory (used for determining project boundaries)\n * @returns DependencyGraph with all transitive dependencies\n */\nexport function buildDependencyGraph(\n entryFile: string,\n projectRoot: string\n): DependencyGraph {\n // Check cache\n const cached = dependencyCache.get(entryFile);\n if (cached) {\n // Validate cache by checking entry file mtime\n try {\n const currentMtime = statSync(entryFile).mtimeMs;\n if (currentMtime === cached.mtime) {\n return cached.graph;\n }\n } catch {\n // File doesn't exist or can't be read, invalidate cache\n }\n }\n\n const allDependencies = new Set<string>();\n const visited = new Set<string>();\n\n // Recursively collect dependencies\n collectDependencies(entryFile, projectRoot, allDependencies, visited);\n\n const graph: DependencyGraph = {\n root: entryFile,\n allDependencies,\n };\n\n // Cache the result\n try {\n const mtime = statSync(entryFile).mtimeMs;\n dependencyCache.set(entryFile, { graph, mtime });\n } catch {\n // If we can't get mtime, don't cache\n }\n\n return graph;\n}\n\n/**\n * Recursively collect dependencies from a file\n */\nfunction collectDependencies(\n filePath: string,\n projectRoot: string,\n allDependencies: Set<string>,\n visited: Set<string>\n): void {\n // Prevent infinite loops from circular dependencies\n if (visited.has(filePath)) {\n return;\n }\n visited.add(filePath);\n\n // Parse the file to extract imports\n const imports = extractImports(filePath);\n\n for (const importSource of imports) {\n // Resolve the import to an absolute path\n const resolvedPath = resolveImportPath(importSource, filePath);\n\n if (!resolvedPath) {\n // Could not resolve (external package or unresolvable)\n continue;\n }\n\n // Skip node_modules\n if (resolvedPath.includes(\"node_modules\")) {\n continue;\n }\n\n // Skip files outside the project\n if (!resolvedPath.startsWith(projectRoot)) {\n continue;\n }\n\n // Skip already visited files (handles circular dependencies)\n // This prevents adding the root file back as a dependency\n if (visited.has(resolvedPath)) {\n continue;\n }\n\n // Add to dependencies\n allDependencies.add(resolvedPath);\n\n // Recurse into this dependency\n collectDependencies(resolvedPath, projectRoot, allDependencies, visited);\n }\n}\n\n/**\n * Extract all import sources from a file\n */\nfunction extractImports(filePath: string): string[] {\n if (!existsSync(filePath)) {\n return [];\n }\n\n const ast = parseFile(filePath);\n if (!ast) {\n return [];\n }\n\n const imports: string[] = [];\n\n for (const node of ast.body) {\n // import ... from \"source\"\n if (node.type === \"ImportDeclaration\" && node.source.value) {\n imports.push(node.source.value as string);\n }\n\n // export ... from \"source\" (re-exports)\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.source?.value\n ) {\n imports.push(node.source.value as string);\n }\n\n // export * from \"source\"\n if (node.type === \"ExportAllDeclaration\" && node.source.value) {\n imports.push(node.source.value as string);\n }\n }\n\n // Also check for dynamic imports in the AST\n const dynamicImports = extractDynamicImports(ast);\n imports.push(...dynamicImports);\n\n return imports;\n}\n\n/**\n * Extract dynamic import() calls from the AST\n */\nfunction extractDynamicImports(ast: TSESTree.Program): string[] {\n const imports: string[] = [];\n\n function visit(node: TSESTree.Node): void {\n // import(\"source\")\n if (\n node.type === \"ImportExpression\" &&\n node.source.type === \"Literal\" &&\n typeof node.source.value === \"string\"\n ) {\n imports.push(node.source.value);\n }\n\n // Recurse into children\n for (const key of Object.keys(node)) {\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n visit(item as TSESTree.Node);\n }\n }\n } else if (\"type\" in child) {\n visit(child as TSESTree.Node);\n }\n }\n }\n }\n\n for (const node of ast.body) {\n visit(node);\n }\n\n return imports;\n}\n\n/**\n * Invalidate the cache for a specific file\n *\n * Call this when a file changes to ensure fresh data\n */\nexport function invalidateDependencyCache(filePath: string): void {\n dependencyCache.delete(filePath);\n\n // Also invalidate any graphs that include this file as a dependency\n for (const [entryFile, entry] of dependencyCache) {\n if (entry.graph.allDependencies.has(filePath)) {\n dependencyCache.delete(entryFile);\n }\n }\n}\n\n/**\n * Clear the entire dependency cache\n */\nexport function clearDependencyCache(): void {\n dependencyCache.clear();\n}\n\n/**\n * Get cache statistics (for debugging/monitoring)\n */\nexport function getDependencyCacheStats(): {\n size: number;\n entries: string[];\n} {\n return {\n size: dependencyCache.size,\n entries: Array.from(dependencyCache.keys()),\n };\n}\n","/**\n * Export Resolver\n *\n * Resolves import paths and finds export definitions, following re-exports\n * to their original source files.\n */\n\nimport { ResolverFactory } from \"oxc-resolver\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport { readFileSync, existsSync } from \"fs\";\nimport { dirname, join, extname } from \"path\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\n// Module-level resolver instance (reused across calls)\nlet resolverInstance: ReturnType<typeof ResolverFactory.prototype.sync> | null =\n null;\nlet resolverFactory: ResolverFactory | null = null;\n\n/**\n * Information about a resolved export\n */\nexport interface ResolvedExport {\n /** The name of the export (e.g., \"Button\") */\n name: string;\n /** Absolute path to the file containing the actual definition */\n filePath: string;\n /** The local name in the source file (may differ from export name) */\n localName: string;\n /** Whether this is a re-export (export { X } from './other') */\n isReexport: boolean;\n}\n\n/**\n * Cache for file exports to avoid re-parsing\n */\nconst exportCache = new Map<\n string,\n Map<string, { localName: string; reexportSource?: string }>\n>();\n\n/**\n * Cache for parsed ASTs\n */\nconst astCache = new Map<string, TSESTree.Program>();\n\n/**\n * Cache for resolved paths\n */\nconst resolvedPathCache = new Map<string, string | null>();\n\n/**\n * Get or create the resolver factory\n */\nfunction getResolverFactory(): ResolverFactory {\n if (!resolverFactory) {\n resolverFactory = new ResolverFactory({\n extensions: [\".tsx\", \".ts\", \".jsx\", \".js\"],\n mainFields: [\"module\", \"main\"],\n conditionNames: [\"import\", \"require\", \"node\", \"default\"],\n // Enable TypeScript path resolution\n tsconfig: {\n configFile: \"tsconfig.json\",\n references: \"auto\",\n },\n });\n }\n return resolverFactory;\n}\n\n/**\n * Resolve an import path to an absolute file path\n */\nexport function resolveImportPath(\n importSource: string,\n fromFile: string\n): string | null {\n const cacheKey = `${fromFile}::${importSource}`;\n\n if (resolvedPathCache.has(cacheKey)) {\n return resolvedPathCache.get(cacheKey) ?? null;\n }\n\n // Skip node_modules\n if (\n importSource.startsWith(\"react\") ||\n importSource.startsWith(\"next\") ||\n (!importSource.startsWith(\".\") &&\n !importSource.startsWith(\"@/\") &&\n !importSource.startsWith(\"~/\"))\n ) {\n // Check if it's a known external package\n if (\n importSource.includes(\"@mui/\") ||\n importSource.includes(\"@chakra-ui/\") ||\n importSource.includes(\"antd\") ||\n importSource.includes(\"@radix-ui/\")\n ) {\n // Return a marker for external packages - we don't resolve them but track them\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n\n try {\n const factory = getResolverFactory();\n const fromDir = dirname(fromFile);\n const result = factory.sync(fromDir, importSource);\n\n if (result.path) {\n resolvedPathCache.set(cacheKey, result.path);\n return result.path;\n }\n } catch {\n // Fallback: try manual resolution for common patterns\n const resolved = manualResolve(importSource, fromFile);\n resolvedPathCache.set(cacheKey, resolved);\n return resolved;\n }\n\n resolvedPathCache.set(cacheKey, null);\n return null;\n}\n\n/**\n * Manual fallback resolution for common patterns\n */\nfunction manualResolve(importSource: string, fromFile: string): string | null {\n const fromDir = dirname(fromFile);\n const extensions = [\".tsx\", \".ts\", \".jsx\", \".js\"];\n\n // Handle @/ alias - find tsconfig and resolve\n if (importSource.startsWith(\"@/\")) {\n const projectRoot = findProjectRoot(fromFile);\n if (projectRoot) {\n const relativePath = importSource.slice(2); // Remove @/\n for (const ext of extensions) {\n const candidate = join(projectRoot, relativePath + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(projectRoot, relativePath, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n }\n\n // Handle relative imports\n if (importSource.startsWith(\".\")) {\n for (const ext of extensions) {\n const candidate = join(fromDir, importSource + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(fromDir, importSource, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Find the project root by looking for tsconfig.json or package.json\n */\nfunction findProjectRoot(fromFile: string): string | null {\n let dir = dirname(fromFile);\n const root = \"/\";\n\n while (dir !== root) {\n if (existsSync(join(dir, \"tsconfig.json\"))) {\n return dir;\n }\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n\n return null;\n}\n\n/**\n * Parse a file and cache the AST\n */\nexport function parseFile(filePath: string): TSESTree.Program | null {\n if (astCache.has(filePath)) {\n return astCache.get(filePath)!;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n });\n astCache.set(filePath, ast);\n return ast;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract export information from a file\n */\nfunction extractExports(\n filePath: string\n): Map<string, { localName: string; reexportSource?: string }> {\n if (exportCache.has(filePath)) {\n return exportCache.get(filePath)!;\n }\n\n const exports = new Map<\n string,\n { localName: string; reexportSource?: string }\n >();\n const ast = parseFile(filePath);\n\n if (!ast) {\n exportCache.set(filePath, exports);\n return exports;\n }\n\n for (const node of ast.body) {\n // Handle: export function Button() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(node.declaration.id.name, {\n localName: node.declaration.id.name,\n });\n }\n\n // Handle: export const Button = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (decl.id.type === \"Identifier\") {\n exports.set(decl.id.name, { localName: decl.id.name });\n }\n }\n }\n\n // Handle: export { Button } or export { Button as Btn }\n if (node.type === \"ExportNamedDeclaration\" && node.specifiers.length > 0) {\n const source = node.source?.value as string | undefined;\n for (const spec of node.specifiers) {\n if (spec.type === \"ExportSpecifier\") {\n const exportedName =\n spec.exported.type === \"Identifier\"\n ? spec.exported.name\n : spec.exported.value;\n const localName =\n spec.local.type === \"Identifier\"\n ? spec.local.name\n : spec.local.value;\n\n exports.set(exportedName, {\n localName,\n reexportSource: source,\n });\n }\n }\n }\n\n // Handle: export default function Button() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(\"default\", { localName: node.declaration.id.name });\n }\n\n // Handle: export default Button\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"Identifier\"\n ) {\n exports.set(\"default\", { localName: node.declaration.name });\n }\n }\n\n exportCache.set(filePath, exports);\n return exports;\n}\n\n/**\n * Resolve an export to its original definition, following re-exports\n */\nexport function resolveExport(\n exportName: string,\n filePath: string,\n visited = new Set<string>()\n): ResolvedExport | null {\n // Cycle detection\n const key = `${filePath}::${exportName}`;\n if (visited.has(key)) {\n return null;\n }\n visited.add(key);\n\n const exports = extractExports(filePath);\n const exportInfo = exports.get(exportName);\n\n if (!exportInfo) {\n return null;\n }\n\n // If it's a re-export, follow the chain\n if (exportInfo.reexportSource) {\n const resolvedPath = resolveImportPath(exportInfo.reexportSource, filePath);\n if (resolvedPath) {\n return resolveExport(exportInfo.localName, resolvedPath, visited);\n }\n return null;\n }\n\n // This is the actual definition\n return {\n name: exportName,\n filePath,\n localName: exportInfo.localName,\n isReexport: false,\n };\n}\n\n/**\n * Clear all caches (useful for testing or watch mode)\n */\nexport function clearResolverCaches(): void {\n exportCache.clear();\n astCache.clear();\n resolvedPathCache.clear();\n}\n","/**\n * Coverage Aggregator\n *\n * Calculates weighted aggregate coverage for a component by tracing its\n * dependencies and combining their coverage using smart weighting.\n *\n * Weighting strategy:\n * - core (1.0): hooks, components, services - critical logic\n * - utility (0.5): formatters, validators - supporting code\n * - constant (0.25): config, constants - static data\n * - type (0): .d.ts, type-only - no runtime impact\n */\n\nimport { categorizeFile, type FileCategory } from \"./file-categorizer.js\";\nimport { buildDependencyGraph } from \"./dependency-graph.js\";\n\n/**\n * Istanbul coverage JSON format (matching require-test-coverage.ts)\n */\nexport interface IstanbulCoverage {\n [filePath: string]: {\n path: string;\n statementMap: {\n [key: string]: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n fnMap: {\n [key: string]: {\n name: string;\n decl: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n };\n branchMap: {\n [key: string]: {\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n type: string;\n locations: Array<{\n start: { line: number; column: number };\n end: { line: number; column: number };\n }>;\n };\n };\n s: { [key: string]: number }; // Statement hit counts\n f: { [key: string]: number }; // Function hit counts\n b: { [key: string]: number[] }; // Branch hit counts\n };\n}\n\n/**\n * Coverage information for a single file\n */\nexport interface FileCoverageInfo {\n filePath: string;\n category: FileCategory;\n weight: number;\n statements: { covered: number; total: number };\n percentage: number;\n}\n\n/**\n * Aggregated coverage result for a component\n */\nexport interface AggregatedCoverage {\n /** The component file that was analyzed */\n componentFile: string;\n /** Coverage percentage for just the component file */\n componentCoverage: number;\n /** Weighted aggregate coverage across component + all dependencies */\n aggregateCoverage: number;\n /** Total number of files analyzed (component + dependencies) */\n totalFiles: number;\n /** Detailed coverage info for each file */\n filesAnalyzed: FileCoverageInfo[];\n /** Files with 0% coverage */\n uncoveredFiles: string[];\n /** The file with lowest coverage (excluding 0% files) */\n lowestCoverageFile: { path: string; percentage: number } | null;\n}\n\n/**\n * Calculate aggregate coverage for a component and its dependencies\n *\n * @param componentFile - Absolute path to the component file\n * @param projectRoot - Project root directory\n * @param coverageData - Istanbul coverage data\n * @returns Aggregated coverage information\n */\nexport function aggregateCoverage(\n componentFile: string,\n projectRoot: string,\n coverageData: IstanbulCoverage\n): AggregatedCoverage {\n // Build dependency graph\n const graph = buildDependencyGraph(componentFile, projectRoot);\n\n // Collect all files to analyze (component + dependencies)\n const allFiles = new Set<string>([componentFile, ...graph.allDependencies]);\n\n // Analyze each file\n const filesAnalyzed: FileCoverageInfo[] = [];\n const uncoveredFiles: string[] = [];\n let lowestCoverageFile: { path: string; percentage: number } | null = null;\n let componentCoverageInfo: FileCoverageInfo | null = null;\n\n for (const filePath of allFiles) {\n const coverageInfo = getFileCoverage(filePath, projectRoot, coverageData);\n filesAnalyzed.push(coverageInfo);\n\n // Track component coverage separately\n if (filePath === componentFile) {\n componentCoverageInfo = coverageInfo;\n }\n\n // Track uncovered files (0%)\n if (coverageInfo.percentage === 0 && coverageInfo.statements.total > 0) {\n uncoveredFiles.push(filePath);\n }\n\n // Track lowest coverage (excluding 0% and type files with weight 0)\n if (\n coverageInfo.percentage > 0 &&\n coverageInfo.weight > 0 &&\n coverageInfo.statements.total > 0\n ) {\n if (\n !lowestCoverageFile ||\n coverageInfo.percentage < lowestCoverageFile.percentage\n ) {\n lowestCoverageFile = {\n path: filePath,\n percentage: coverageInfo.percentage,\n };\n }\n }\n }\n\n // Calculate weighted aggregate coverage\n const aggregateCoverageValue = calculateWeightedCoverage(filesAnalyzed);\n\n return {\n componentFile,\n componentCoverage: componentCoverageInfo?.percentage ?? 0,\n aggregateCoverage: aggregateCoverageValue,\n totalFiles: filesAnalyzed.length,\n filesAnalyzed,\n uncoveredFiles,\n lowestCoverageFile,\n };\n}\n\n/**\n * Get coverage information for a single file\n */\nfunction getFileCoverage(\n filePath: string,\n projectRoot: string,\n coverageData: IstanbulCoverage\n): FileCoverageInfo {\n // Categorize the file\n const categoryResult = categorizeFile(filePath, projectRoot);\n\n // Find coverage data for this file\n const fileCoverage = findCoverageForFile(filePath, coverageData, projectRoot);\n\n if (!fileCoverage) {\n // No coverage data - could mean not tested or file not found\n return {\n filePath,\n category: categoryResult.category,\n weight: categoryResult.weight,\n statements: { covered: 0, total: 0 },\n percentage: 0,\n };\n }\n\n // Calculate statement coverage\n const statementHits = fileCoverage.s;\n const totalStatements = Object.keys(statementHits).length;\n const coveredStatements = Object.values(statementHits).filter(\n (hits) => hits > 0\n ).length;\n\n const percentage =\n totalStatements > 0 ? (coveredStatements / totalStatements) * 100 : 0;\n\n return {\n filePath,\n category: categoryResult.category,\n weight: categoryResult.weight,\n statements: { covered: coveredStatements, total: totalStatements },\n percentage: Math.round(percentage * 100) / 100, // Round to 2 decimal places\n };\n}\n\n/**\n * Find coverage data for a file, handling path normalization\n */\nfunction findCoverageForFile(\n filePath: string,\n coverageData: IstanbulCoverage,\n projectRoot: string\n): IstanbulCoverage[string] | null {\n // Try exact match first\n if (coverageData[filePath]) {\n return coverageData[filePath];\n }\n\n // Try relative path from project root\n const relativePath = filePath.startsWith(projectRoot)\n ? filePath.slice(projectRoot.length)\n : filePath;\n\n // Try with and without leading slash\n const pathVariants = [\n relativePath,\n relativePath.startsWith(\"/\") ? relativePath.slice(1) : `/${relativePath}`,\n relativePath.startsWith(\"/\") ? relativePath : `/${relativePath}`,\n ];\n\n for (const variant of pathVariants) {\n if (coverageData[variant]) {\n return coverageData[variant];\n }\n }\n\n // Try matching by checking if coverage path ends with relative path\n for (const [coveragePath, coverage] of Object.entries(coverageData)) {\n if (\n coveragePath.endsWith(relativePath) ||\n coveragePath.endsWith(relativePath.slice(1))\n ) {\n return coverage;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate weighted average coverage across files\n *\n * Uses statement count * weight for each file to determine contribution.\n * Files with weight 0 (type files) are excluded from calculation.\n */\nfunction calculateWeightedCoverage(files: FileCoverageInfo[]): number {\n let totalWeightedStatements = 0;\n let totalWeightedCovered = 0;\n\n for (const file of files) {\n // Skip files with weight 0 (type files)\n if (file.weight === 0) {\n continue;\n }\n\n // Skip files with no statements\n if (file.statements.total === 0) {\n continue;\n }\n\n const weightedTotal = file.statements.total * file.weight;\n const weightedCovered = file.statements.covered * file.weight;\n\n totalWeightedStatements += weightedTotal;\n totalWeightedCovered += weightedCovered;\n }\n\n if (totalWeightedStatements === 0) {\n return 0;\n }\n\n const percentage = (totalWeightedCovered / totalWeightedStatements) * 100;\n return Math.round(percentage * 100) / 100; // Round to 2 decimal places\n}\n","/**\n * JSX Coverage Analyzer\n *\n * Analyzes JSX elements to determine test coverage for interactive elements\n * like event handlers. Uses Istanbul coverage data to check if the code\n * associated with JSX elements has been executed during tests.\n *\n * Phase 1: Core functions for statement-level coverage analysis\n * Phase 2: Event handler extraction and analysis\n * Phase 3: Conditional parent analysis + Component-level aggregation (partial TODO)\n * Phase 4: Import dependency coverage + ESLint rule reporting (partial TODO)\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport type { IstanbulCoverage } from \"./coverage-aggregator.js\";\n\n/**\n * Re-export IstanbulCoverage for consumers of this module\n */\nexport type { IstanbulCoverage } from \"./coverage-aggregator.js\";\n\n/**\n * Istanbul coverage data for a single file\n */\nexport type IstanbulFileCoverage = IstanbulCoverage[string];\n\n/**\n * Source location with start and end positions\n */\nexport interface SourceLocation {\n start: { line: number; column: number };\n end: { line: number; column: number };\n}\n\n/**\n * Coverage statistics for a code region\n */\nexport interface CoverageStats {\n /** Number of statements that were executed at least once */\n covered: number;\n /** Total number of statements in the region */\n total: number;\n /** Coverage percentage (0-100) */\n percentage: number;\n}\n\n/**\n * Coverage result for a single JSX element\n */\nexport interface JSXCoverageResult {\n /** The data-loc attribute value for this element */\n dataLoc: string;\n /** Whether this element has any event handlers */\n hasEventHandlers: boolean;\n /** Names of event handlers found (e.g., [\"onClick\", \"onSubmit\"]) */\n eventHandlerNames: string[];\n /** Coverage statistics for statements within this element */\n coverage: CoverageStats;\n /** Whether the element is considered \"covered\" (percentage > 0) */\n isCovered: boolean;\n}\n\n// =============================================================================\n// Phase 1: Core Functions\n// =============================================================================\n\n/**\n * Creates a \"file:line:column\" format string for data-loc attribute\n *\n * @param filePath - Absolute or relative path to the file\n * @param loc - Source location with start position\n * @returns Formatted string like \"src/Button.tsx:15:4\"\n */\nexport function buildDataLoc(filePath: string, loc: SourceLocation): string {\n return `${filePath}:${loc.start.line}:${loc.start.column}`;\n}\n\n/**\n * Find statement IDs that overlap with the given source location\n *\n * A statement overlaps if its line range intersects with the location's\n * line range. Column-level precision is not used for overlap detection.\n *\n * @param loc - The source location to check\n * @param fileCoverage - Istanbul coverage data for the file\n * @returns Set of statement IDs (keys from statementMap) that overlap\n */\nexport function findStatementsInRange(\n loc: SourceLocation,\n fileCoverage: IstanbulFileCoverage\n): Set<string> {\n const overlappingStatements = new Set<string>();\n\n for (const [statementId, statementLoc] of Object.entries(\n fileCoverage.statementMap\n )) {\n // Check if statement's line range overlaps with location's line range\n const statementStart = statementLoc.start.line;\n const statementEnd = statementLoc.end.line;\n const locStart = loc.start.line;\n const locEnd = loc.end.line;\n\n // Two ranges overlap if: start1 <= end2 AND start2 <= end1\n if (statementStart <= locEnd && locStart <= statementEnd) {\n overlappingStatements.add(statementId);\n }\n }\n\n return overlappingStatements;\n}\n\n/**\n * Calculate coverage statistics from a set of statement IDs\n *\n * @param statementIds - Set of statement IDs to check\n * @param fileCoverage - Istanbul coverage data for the file\n * @returns Coverage statistics with covered count, total, and percentage\n */\nexport function calculateCoverageFromStatements(\n statementIds: Set<string>,\n fileCoverage: IstanbulFileCoverage\n): CoverageStats {\n if (statementIds.size === 0) {\n return { covered: 0, total: 0, percentage: 0 };\n }\n\n let covered = 0;\n const total = statementIds.size;\n\n for (const statementId of statementIds) {\n const hitCount = fileCoverage.s[statementId];\n if (hitCount !== undefined && hitCount > 0) {\n covered++;\n }\n }\n\n const percentage = total > 0 ? Math.round((covered / total) * 100) : 0;\n\n return { covered, total, percentage };\n}\n\n/**\n * Find coverage data for a file with path normalization\n *\n * Handles various path formats:\n * - Absolute paths\n * - Relative paths with or without leading slash\n * - Paths that may differ in their base directory\n *\n * @param coverage - Full Istanbul coverage data\n * @param filePath - The file path to find coverage for\n * @returns File coverage data if found, undefined otherwise\n */\nexport function findCoverageForFile(\n coverage: IstanbulCoverage,\n filePath: string\n): IstanbulFileCoverage | undefined {\n // Try exact match first\n if (coverage[filePath]) {\n return coverage[filePath];\n }\n\n // Normalize the path for comparison (remove leading slashes, standardize)\n const normalizedPath = filePath.replace(/^\\/+/, \"\");\n\n // Try with and without leading slash\n const pathVariants = [\n normalizedPath,\n `/${normalizedPath}`,\n filePath,\n ];\n\n for (const variant of pathVariants) {\n if (coverage[variant]) {\n return coverage[variant];\n }\n }\n\n // Try matching by checking if coverage path ends with our path\n for (const [coveragePath, fileCoverage] of Object.entries(coverage)) {\n const normalizedCoveragePath = coveragePath.replace(/^\\/+/, \"\");\n\n if (\n normalizedCoveragePath.endsWith(normalizedPath) ||\n normalizedPath.endsWith(normalizedCoveragePath)\n ) {\n return fileCoverage;\n }\n }\n\n return undefined;\n}\n\n/**\n * Check if a JSX attribute is an event handler (starts with \"on\" followed by uppercase)\n *\n * Event handlers follow the pattern: onClick, onSubmit, onChange, etc.\n * This excludes spread attributes and non-event props like \"only\" or \"once\".\n *\n * @param attr - JSX attribute or spread attribute\n * @returns true if the attribute is an event handler\n */\nexport function isEventHandlerAttribute(\n attr: TSESTree.JSXAttribute | TSESTree.JSXSpreadAttribute\n): boolean {\n // Spread attributes are not event handlers by themselves\n if (attr.type === \"JSXSpreadAttribute\") {\n return false;\n }\n\n // Only handle JSXIdentifier names (not namespaced like xml:lang)\n if (attr.name.type !== \"JSXIdentifier\") {\n return false;\n }\n\n const name = attr.name.name;\n\n // Match pattern: on[A-Z]...\n return /^on[A-Z]/.test(name);\n}\n\n/**\n * Analyze a JSX element for test coverage\n *\n * Main entry point that combines all the above functions to produce\n * a complete coverage analysis for a single JSX element.\n *\n * @param jsxNode - The JSX element node from the AST\n * @param filePath - Path to the file containing this element\n * @param coverage - Istanbul coverage data\n * @param ancestors - Optional ancestor nodes for resolving handler references\n * @param projectRoot - Optional project root for resolving import paths\n * @returns Coverage result for the JSX element\n */\nexport function analyzeJSXElementCoverage(\n jsxNode: TSESTree.JSXElement,\n filePath: string,\n coverage: IstanbulCoverage,\n ancestors: TSESTree.Node[] = [],\n projectRoot?: string\n): JSXCoverageResult {\n // Build the data-loc identifier\n const loc = jsxNode.loc;\n const dataLoc = buildDataLoc(filePath, loc);\n\n // Find event handlers on this element\n const eventHandlerNames: string[] = [];\n for (const attr of jsxNode.openingElement.attributes) {\n if (isEventHandlerAttribute(attr) && attr.type === \"JSXAttribute\") {\n if (attr.name.type === \"JSXIdentifier\") {\n eventHandlerNames.push(attr.name.name);\n }\n }\n }\n const hasEventHandlers = eventHandlerNames.length > 0;\n\n // Find coverage data for this file\n const fileCoverage = findCoverageForFile(coverage, filePath);\n\n if (!fileCoverage) {\n // No coverage data available for this file\n return {\n dataLoc,\n hasEventHandlers,\n eventHandlerNames,\n coverage: { covered: 0, total: 0, percentage: 0 },\n isCovered: false,\n };\n }\n\n // Find statements that overlap with this JSX element\n const statementIds = findStatementsInRange(loc, fileCoverage);\n\n // Also include statements from event handler bodies (Phase 2)\n if (hasEventHandlers) {\n const handlerStatementIds = getHandlerStatements(\n jsxNode,\n fileCoverage,\n ancestors\n );\n for (const stmtId of handlerStatementIds) {\n statementIds.add(stmtId);\n }\n }\n\n // Include statements from conditional ancestors (Phase 3)\n // This ensures conditionally rendered elements include the condition's coverage\n const conditionalAncestor = findConditionalAncestor(jsxNode, ancestors);\n if (conditionalAncestor) {\n const conditionalStatementIds = getConditionalStatements(\n conditionalAncestor,\n fileCoverage\n );\n for (const stmtId of conditionalStatementIds) {\n statementIds.add(stmtId);\n }\n }\n\n // Calculate local coverage statistics (statements in this file)\n const localCoverage = calculateCoverageFromStatements(\n statementIds,\n fileCoverage\n );\n\n // Phase 4: Include import dependency coverage\n // Find imports used in this JSX element and aggregate their coverage\n let importCoverage = { covered: 0, total: 0 };\n if (projectRoot && ancestors.length > 0) {\n const importPaths = findImportsUsedInJSX(jsxNode, ancestors);\n if (importPaths.size > 0) {\n importCoverage = aggregateImportCoverage(\n importPaths,\n coverage,\n projectRoot,\n filePath\n );\n }\n }\n\n // Combine local and import coverage (weighted by statement count)\n const totalCovered = localCoverage.covered + importCoverage.covered;\n const totalStatements = localCoverage.total + importCoverage.total;\n const combinedPercentage =\n totalStatements > 0 ? Math.round((totalCovered / totalStatements) * 100) : 0;\n\n const coverageStats: CoverageStats = {\n covered: totalCovered,\n total: totalStatements,\n percentage: combinedPercentage,\n };\n\n return {\n dataLoc,\n hasEventHandlers,\n eventHandlerNames,\n coverage: coverageStats,\n isCovered: coverageStats.percentage > 0,\n };\n}\n\n// =============================================================================\n// Phase 2: Event Handler Analysis\n// =============================================================================\n\n/**\n * Extract the expression from an event handler attribute value\n *\n * Handles various forms of event handler values:\n * - {handleClick} - identifier reference\n * - {() => doSomething()} - inline arrow function\n * - {fn.bind(this)} - call expression (like bind)\n * - {obj.method} - member expression\n *\n * @param attr - The JSX attribute to extract from\n * @returns The expression if found, null for string literals or empty values\n */\nexport function extractEventHandlerExpression(\n attr: TSESTree.JSXAttribute\n): TSESTree.Expression | null {\n // No value means no expression (e.g., <input disabled />)\n if (!attr.value) {\n return null;\n }\n\n // String literals are not expressions we can analyze\n // e.g., onClick=\"someGlobalFunction()\"\n if (attr.value.type === \"Literal\") {\n return null;\n }\n\n // JSX expression container: {expression}\n if (attr.value.type === \"JSXExpressionContainer\") {\n const expression = attr.value.expression;\n\n // Empty expression container {} or JSXEmptyExpression\n if (expression.type === \"JSXEmptyExpression\") {\n return null;\n }\n\n // Return the actual expression (Identifier, ArrowFunctionExpression, CallExpression, etc.)\n return expression;\n }\n\n // JSXElement as value (rare, but possible)\n // e.g., onClick={<SomeComponent />} - not a valid handler expression\n return null;\n}\n\n/**\n * Find the function declaration for an identifier used as an event handler\n *\n * Searches through the ancestor chain to find where an identifier is declared.\n * Handles:\n * - Variable declarations with function expressions\n * - Variable declarations with arrow functions\n * - Function declarations\n * - Function parameters (destructured or direct)\n *\n * @param identifier - The identifier node (e.g., the \"handleClick\" in onClick={handleClick})\n * @param ancestors - The ancestor nodes from the AST traversal (innermost first or any order)\n * @returns The function body node if found, null otherwise\n */\nexport function findHandlerFunctionDeclaration(\n identifier: TSESTree.Identifier,\n ancestors: TSESTree.Node[]\n): TSESTree.Node | null {\n const targetName = identifier.name;\n\n for (const ancestor of ancestors) {\n // Check FunctionDeclaration\n if (\n ancestor.type === \"FunctionDeclaration\" &&\n ancestor.id?.name === targetName\n ) {\n return ancestor.body;\n }\n\n // Check VariableDeclaration\n if (ancestor.type === \"VariableDeclaration\") {\n for (const declarator of ancestor.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n // Check if the init is a function\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n\n // Check BlockStatement and Program for contained declarations\n if (ancestor.type === \"BlockStatement\" || ancestor.type === \"Program\") {\n const body =\n ancestor.type === \"Program\" ? ancestor.body : ancestor.body;\n\n for (const statement of body) {\n // Function declarations in block\n if (\n statement.type === \"FunctionDeclaration\" &&\n statement.id?.name === targetName\n ) {\n return statement.body;\n }\n\n // Variable declarations in block\n if (statement.type === \"VariableDeclaration\") {\n for (const declarator of statement.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n\n // Export declarations\n if (statement.type === \"ExportNamedDeclaration\" && statement.declaration) {\n if (\n statement.declaration.type === \"FunctionDeclaration\" &&\n statement.declaration.id?.name === targetName\n ) {\n return statement.declaration.body;\n }\n\n if (statement.declaration.type === \"VariableDeclaration\") {\n for (const declarator of statement.declaration.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n }\n }\n }\n\n // Check function body for nested declarations (component functions)\n if (\n ancestor.type === \"ArrowFunctionExpression\" ||\n ancestor.type === \"FunctionExpression\" ||\n ancestor.type === \"FunctionDeclaration\"\n ) {\n const funcBody = ancestor.body;\n\n // Only check BlockStatement bodies (not expression bodies)\n if (funcBody.type === \"BlockStatement\") {\n for (const statement of funcBody.body) {\n if (\n statement.type === \"FunctionDeclaration\" &&\n statement.id?.name === targetName\n ) {\n return statement.body;\n }\n\n if (statement.type === \"VariableDeclaration\") {\n for (const declarator of statement.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Get statement IDs for all event handlers on a JSX element\n *\n * For each event handler attribute on the element:\n * - Extract the handler expression\n * - For inline arrows: find statements within the arrow body range\n * - For identifier references: find the handler declaration and its body range\n *\n * @param jsxNode - The JSX element to analyze\n * @param fileCoverage - Istanbul coverage data for the file\n * @param ancestors - Optional ancestor nodes for identifier resolution\n * @returns Set of statement IDs that are part of event handler bodies\n */\nexport function getHandlerStatements(\n jsxNode: TSESTree.JSXElement,\n fileCoverage: IstanbulFileCoverage,\n ancestors: TSESTree.Node[] = []\n): Set<string> {\n const handlerStatements = new Set<string>();\n\n for (const attr of jsxNode.openingElement.attributes) {\n // Skip non-event-handler attributes\n if (!isEventHandlerAttribute(attr) || attr.type !== \"JSXAttribute\") {\n continue;\n }\n\n const expression = extractEventHandlerExpression(attr);\n if (!expression) {\n continue;\n }\n\n // Handle inline arrow functions and function expressions\n if (\n expression.type === \"ArrowFunctionExpression\" ||\n expression.type === \"FunctionExpression\"\n ) {\n const body = expression.body;\n if (body.loc) {\n const bodyStatements = findStatementsInRange(body.loc, fileCoverage);\n for (const stmtId of bodyStatements) {\n handlerStatements.add(stmtId);\n }\n }\n continue;\n }\n\n // Handle identifier references (e.g., onClick={handleClick})\n if (expression.type === \"Identifier\") {\n const functionBody = findHandlerFunctionDeclaration(expression, ancestors);\n if (functionBody && functionBody.loc) {\n const bodyStatements = findStatementsInRange(functionBody.loc, fileCoverage);\n for (const stmtId of bodyStatements) {\n handlerStatements.add(stmtId);\n }\n }\n continue;\n }\n\n // Handle call expressions (e.g., onClick={fn.bind(this)})\n // We analyze the entire call expression range\n if (expression.type === \"CallExpression\" && expression.loc) {\n const callStatements = findStatementsInRange(expression.loc, fileCoverage);\n for (const stmtId of callStatements) {\n handlerStatements.add(stmtId);\n }\n continue;\n }\n\n // Handle member expressions (e.g., onClick={obj.method})\n // These typically point to methods that we can't easily resolve\n // without more complex analysis, so we just note the expression location\n if (expression.type === \"MemberExpression\" && expression.loc) {\n const memberStatements = findStatementsInRange(expression.loc, fileCoverage);\n for (const stmtId of memberStatements) {\n handlerStatements.add(stmtId);\n }\n }\n }\n\n return handlerStatements;\n}\n\n// =============================================================================\n// Phase 3: Conditional Parent Analysis\n// =============================================================================\n\n/**\n * Find a conditional ancestor that controls this element's rendering\n *\n * Walks up the ancestor chain to find the first conditional expression\n * that determines whether this JSX element is rendered:\n * - LogicalExpression with `&&`: {condition && <Element />}\n * - ConditionalExpression (ternary): {condition ? <A /> : <B />}\n *\n * @param node - The current JSX element node\n * @param ancestors - The ancestor nodes from the AST traversal\n * @returns The conditional expression if found, null otherwise\n */\nexport function findConditionalAncestor(\n node: TSESTree.Node,\n ancestors: TSESTree.Node[]\n): TSESTree.LogicalExpression | TSESTree.ConditionalExpression | null {\n for (const ancestor of ancestors) {\n // Check for logical expression with && operator\n // Pattern: {condition && <Element />}\n if (\n ancestor.type === \"LogicalExpression\" &&\n ancestor.operator === \"&&\"\n ) {\n return ancestor;\n }\n\n // Check for conditional (ternary) expression\n // Pattern: {condition ? <A /> : <B />}\n if (ancestor.type === \"ConditionalExpression\") {\n return ancestor;\n }\n\n // Stop searching when we hit a JSX element boundary\n // (we don't want to cross into parent JSX elements)\n if (ancestor.type === \"JSXElement\" && ancestor !== node) {\n break;\n }\n\n // Stop at function boundaries\n if (\n ancestor.type === \"ArrowFunctionExpression\" ||\n ancestor.type === \"FunctionExpression\" ||\n ancestor.type === \"FunctionDeclaration\"\n ) {\n break;\n }\n }\n\n return null;\n}\n\n/**\n * Get statement IDs for the condition/test part of a conditional expression\n *\n * For LogicalExpression (&&): gets statements in the left operand (the condition)\n * For ConditionalExpression (ternary): gets statements in the test expression\n *\n * @param conditional - The conditional expression node\n * @param fileCoverage - Istanbul coverage data for the file\n * @returns Set of statement IDs that are part of the condition\n */\nexport function getConditionalStatements(\n conditional: TSESTree.LogicalExpression | TSESTree.ConditionalExpression,\n fileCoverage: IstanbulFileCoverage\n): Set<string> {\n const conditionStatements = new Set<string>();\n\n if (conditional.type === \"LogicalExpression\") {\n // For &&, the left side is the condition\n const condition = conditional.left;\n if (condition.loc) {\n const statements = findStatementsInRange(condition.loc, fileCoverage);\n for (const stmtId of statements) {\n conditionStatements.add(stmtId);\n }\n }\n } else if (conditional.type === \"ConditionalExpression\") {\n // For ternary, the test is the condition\n const condition = conditional.test;\n if (condition.loc) {\n const statements = findStatementsInRange(condition.loc, fileCoverage);\n for (const stmtId of statements) {\n conditionStatements.add(stmtId);\n }\n }\n }\n\n return conditionStatements;\n}\n\n// =============================================================================\n// Phase 4: Import Dependency Coverage\n// =============================================================================\n\n/**\n * Recursively collect all identifiers used within a node\n *\n * @param node - AST node to traverse\n * @param identifiers - Set to accumulate identifier names\n */\nfunction collectIdentifiersFromNode(\n node: TSESTree.Node,\n identifiers: Set<string>\n): void {\n switch (node.type) {\n case \"Identifier\":\n identifiers.add(node.name);\n break;\n\n case \"JSXIdentifier\":\n // JSX element names (e.g., <Component />) - these are components from imports\n identifiers.add(node.name);\n break;\n\n case \"JSXExpressionContainer\":\n if (node.expression.type !== \"JSXEmptyExpression\") {\n collectIdentifiersFromNode(node.expression, identifiers);\n }\n break;\n\n case \"JSXElement\":\n // Collect from opening element (tag name and attributes)\n collectIdentifiersFromNode(node.openingElement, identifiers);\n // Collect from children\n for (const child of node.children) {\n collectIdentifiersFromNode(child, identifiers);\n }\n break;\n\n case \"JSXOpeningElement\":\n // Collect from element name\n collectIdentifiersFromNode(node.name, identifiers);\n // Collect from attributes\n for (const attr of node.attributes) {\n collectIdentifiersFromNode(attr, identifiers);\n }\n break;\n\n case \"JSXAttribute\":\n // Collect from attribute value if it exists\n if (node.value) {\n collectIdentifiersFromNode(node.value, identifiers);\n }\n break;\n\n case \"JSXSpreadAttribute\":\n collectIdentifiersFromNode(node.argument, identifiers);\n break;\n\n case \"JSXMemberExpression\":\n // e.g., <Foo.Bar /> - collect the object\n collectIdentifiersFromNode(node.object, identifiers);\n break;\n\n case \"CallExpression\":\n collectIdentifiersFromNode(node.callee, identifiers);\n for (const arg of node.arguments) {\n collectIdentifiersFromNode(arg, identifiers);\n }\n break;\n\n case \"MemberExpression\":\n collectIdentifiersFromNode(node.object, identifiers);\n break;\n\n case \"ArrowFunctionExpression\":\n case \"FunctionExpression\":\n collectIdentifiersFromNode(node.body, identifiers);\n break;\n\n case \"BlockStatement\":\n for (const statement of node.body) {\n collectIdentifiersFromNode(statement, identifiers);\n }\n break;\n\n case \"ExpressionStatement\":\n collectIdentifiersFromNode(node.expression, identifiers);\n break;\n\n case \"ReturnStatement\":\n if (node.argument) {\n collectIdentifiersFromNode(node.argument, identifiers);\n }\n break;\n\n case \"BinaryExpression\":\n case \"LogicalExpression\":\n collectIdentifiersFromNode(node.left, identifiers);\n collectIdentifiersFromNode(node.right, identifiers);\n break;\n\n case \"ConditionalExpression\":\n collectIdentifiersFromNode(node.test, identifiers);\n collectIdentifiersFromNode(node.consequent, identifiers);\n collectIdentifiersFromNode(node.alternate, identifiers);\n break;\n\n case \"UnaryExpression\":\n collectIdentifiersFromNode(node.argument, identifiers);\n break;\n\n case \"TemplateLiteral\":\n for (const expr of node.expressions) {\n collectIdentifiersFromNode(expr, identifiers);\n }\n break;\n\n case \"ArrayExpression\":\n for (const element of node.elements) {\n if (element) {\n collectIdentifiersFromNode(element, identifiers);\n }\n }\n break;\n\n case \"ObjectExpression\":\n for (const prop of node.properties) {\n collectIdentifiersFromNode(prop, identifiers);\n }\n break;\n\n case \"Property\":\n collectIdentifiersFromNode(node.value, identifiers);\n break;\n\n case \"SpreadElement\":\n collectIdentifiersFromNode(node.argument, identifiers);\n break;\n\n case \"JSXText\":\n case \"JSXFragment\":\n case \"Literal\":\n // No identifiers in these\n break;\n\n default:\n // For other node types, we don't recurse to avoid complexity\n break;\n }\n}\n\n/**\n * Find imports used within a JSX element\n *\n * Identifies which imported modules are used within the JSX element by:\n * 1. Collecting all identifiers used in the JSX (props, children expressions, etc.)\n * 2. Walking up to the Program node to find ImportDeclaration nodes\n * 3. Matching used identifiers to their import sources\n *\n * @param jsxNode - The JSX element to analyze\n * @param ancestors - Ancestor nodes from AST traversal (should include Program)\n * @returns Set of import module specifiers (the 'from' paths) used in this JSX\n */\nexport function findImportsUsedInJSX(\n jsxNode: TSESTree.JSXElement,\n ancestors: TSESTree.Node[]\n): Set<string> {\n const importPaths = new Set<string>();\n\n // Step 1: Collect all identifiers used in this JSX element\n const usedIdentifiers = new Set<string>();\n collectIdentifiersFromNode(jsxNode, usedIdentifiers);\n\n // Step 2: Find the Program node in ancestors to access imports\n let programNode: TSESTree.Program | null = null;\n for (const ancestor of ancestors) {\n if (ancestor.type === \"Program\") {\n programNode = ancestor;\n break;\n }\n }\n\n if (!programNode) {\n return importPaths;\n }\n\n // Step 3: Build a map of imported identifiers to their module sources\n const importedIdentifiers = new Map<string, string>();\n\n for (const statement of programNode.body) {\n if (statement.type === \"ImportDeclaration\") {\n const source = statement.source.value;\n if (typeof source !== \"string\") {\n continue;\n }\n\n for (const specifier of statement.specifiers) {\n switch (specifier.type) {\n case \"ImportDefaultSpecifier\":\n // import Foo from 'module' -> Foo maps to 'module'\n importedIdentifiers.set(specifier.local.name, source);\n break;\n\n case \"ImportSpecifier\":\n // import { Foo } from 'module' -> Foo maps to 'module'\n // import { Foo as Bar } from 'module' -> Bar maps to 'module'\n importedIdentifiers.set(specifier.local.name, source);\n break;\n\n case \"ImportNamespaceSpecifier\":\n // import * as Foo from 'module' -> Foo maps to 'module'\n importedIdentifiers.set(specifier.local.name, source);\n break;\n }\n }\n }\n }\n\n // Step 4: Match used identifiers to their import sources\n for (const identifier of usedIdentifiers) {\n const importSource = importedIdentifiers.get(identifier);\n if (importSource) {\n importPaths.add(importSource);\n }\n }\n\n return importPaths;\n}\n\n/**\n * Resolve an import path to a file path\n *\n * Handles relative imports by resolving them against the current file's directory.\n * For non-relative imports (node_modules), returns null as we don't analyze those.\n *\n * @param importPath - The import specifier (e.g., './utils' or 'react')\n * @param currentFilePath - Path of the file containing the import\n * @param projectRoot - Project root directory\n * @returns Resolved file path or null if can't be resolved\n */\nfunction resolveImportPath(\n importPath: string,\n currentFilePath: string,\n projectRoot: string\n): string | null {\n // Skip non-relative imports (node_modules packages)\n if (!importPath.startsWith(\".\") && !importPath.startsWith(\"/\")) {\n return null;\n }\n\n // Get the directory of the current file\n const lastSlashIndex = currentFilePath.lastIndexOf(\"/\");\n const currentDir =\n lastSlashIndex >= 0 ? currentFilePath.slice(0, lastSlashIndex) : projectRoot;\n\n // Resolve the relative path\n let resolvedPath: string;\n if (importPath.startsWith(\"/\")) {\n // Absolute from project root\n resolvedPath = projectRoot + importPath;\n } else {\n // Relative path - need to resolve . and ..\n const parts = currentDir.split(\"/\").filter(Boolean);\n const importParts = importPath.split(\"/\");\n\n for (const part of importParts) {\n if (part === \".\") {\n continue;\n } else if (part === \"..\") {\n parts.pop();\n } else {\n parts.push(part);\n }\n }\n\n resolvedPath = \"/\" + parts.join(\"/\");\n }\n\n // Common extensions to try\n const extensions = [\"\", \".ts\", \".tsx\", \".js\", \".jsx\", \"/index.ts\", \"/index.tsx\", \"/index.js\", \"/index.jsx\"];\n\n for (const ext of extensions) {\n const fullPath = resolvedPath + ext;\n // We just return the resolved path - the caller will check if coverage exists\n // This is a simplified resolution that doesn't check file existence\n if (ext === \"\" && (resolvedPath.endsWith(\".ts\") || resolvedPath.endsWith(\".tsx\") ||\n resolvedPath.endsWith(\".js\") || resolvedPath.endsWith(\".jsx\"))) {\n return resolvedPath;\n }\n if (ext !== \"\") {\n return fullPath;\n }\n }\n\n return resolvedPath;\n}\n\n/**\n * Aggregate coverage from imported files\n *\n * For each import path, attempts to find coverage data for that file\n * and aggregates the statement coverage across all imported files.\n *\n * Note: When an import is used, the entire imported file's coverage is included\n * in the calculation (full file coverage when any part of a dependency is used).\n *\n * @param importPaths - Set of import module specifiers\n * @param coverage - Istanbul coverage data\n * @param projectRoot - Project root directory\n * @param currentFilePath - Path of the file containing the imports (for resolving relative paths)\n * @returns Aggregated coverage stats: { covered: number, total: number }\n */\nexport function aggregateImportCoverage(\n importPaths: Set<string>,\n coverage: IstanbulCoverage,\n projectRoot: string,\n currentFilePath: string = \"\"\n): { covered: number; total: number } {\n let totalCovered = 0;\n let totalStatements = 0;\n\n for (const importPath of importPaths) {\n // Try to resolve the import path to a file path\n const resolvedPath = resolveImportPath(importPath, currentFilePath, projectRoot);\n\n if (!resolvedPath) {\n // Non-relative import (node_modules) - skip\n continue;\n }\n\n // Try to find coverage for this file\n const fileCoverage = findCoverageForFile(coverage, resolvedPath);\n\n if (!fileCoverage) {\n // Also try with the raw import path in case coverage uses that format\n const rawCoverage = findCoverageForFile(coverage, importPath);\n if (!rawCoverage) {\n continue;\n }\n // Use the raw coverage\n const statementCount = Object.keys(rawCoverage.s).length;\n const coveredCount = Object.values(rawCoverage.s).filter((hits) => hits > 0).length;\n totalStatements += statementCount;\n totalCovered += coveredCount;\n continue;\n }\n\n // Aggregate full file coverage (all statements in the imported file)\n const statementCount = Object.keys(fileCoverage.s).length;\n const coveredCount = Object.values(fileCoverage.s).filter((hits) => hits > 0).length;\n\n totalStatements += statementCount;\n totalCovered += coveredCount;\n }\n\n return { covered: totalCovered, total: totalStatements };\n}\n","/**\n * Chunk Analyzer\n *\n * Analyzes individual \"chunks\" (exported functions, classes, hooks, stores)\n * for test coverage. Used for granular coverage reporting at the function level\n * instead of file level.\n *\n * Categories:\n * - utility: formatters, validators, helpers (strict threshold)\n * - hook: React hooks (use* pattern) (strict threshold)\n * - store: Zustand/Redux stores (strict threshold)\n * - handler: event handler functions (relaxed threshold)\n * - component: JSX-returning functions (relaxed threshold)\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport {\n findStatementsInRange,\n calculateCoverageFromStatements,\n type IstanbulFileCoverage,\n type SourceLocation,\n type CoverageStats,\n} from \"./jsx-coverage-analyzer.js\";\n\nexport type ChunkCategory =\n | \"utility\"\n | \"hook\"\n | \"store\"\n | \"handler\"\n | \"component\";\n\nexport interface ChunkInfo {\n /** Function/export name */\n name: string;\n /** Category of this chunk */\n category: ChunkCategory;\n /** Whether this is React-related code */\n isReactRelated: boolean;\n /** Location in source (full function body) */\n loc: SourceLocation;\n /** Location of just the declaration line (for error highlighting) */\n declarationLoc: SourceLocation;\n /** Function ID in fnMap (if found) */\n fnId: string | null;\n /** Is this an export? */\n isExport: boolean;\n}\n\nexport interface ChunkCoverageResult extends ChunkInfo {\n /** Coverage stats for this chunk */\n coverage: {\n /** Was the function ever called during tests? */\n functionCalled: boolean;\n /** Number of statements covered */\n statementsCovered: number;\n /** Total statements in the function */\n statementsTotal: number;\n /** Coverage percentage (0-100) */\n percentage: number;\n };\n}\n\n/**\n * Check if an AST node contains JSX elements\n */\nfunction containsJSX(\n node: TSESTree.Node,\n visited: WeakSet<object> = new WeakSet()\n): boolean {\n if (!node || typeof node !== \"object\") return false;\n if (visited.has(node)) return false;\n visited.add(node);\n\n if (\n node.type === \"JSXElement\" ||\n node.type === \"JSXFragment\" ||\n node.type === \"JSXText\"\n ) {\n return true;\n }\n\n // Only traverse known child properties to avoid parent references\n const childKeys = [\n \"body\",\n \"declarations\",\n \"declaration\",\n \"expression\",\n \"expressions\",\n \"argument\",\n \"arguments\",\n \"callee\",\n \"elements\",\n \"properties\",\n \"value\",\n \"init\",\n \"consequent\",\n \"alternate\",\n \"test\",\n \"left\",\n \"right\",\n \"object\",\n \"property\",\n \"children\",\n \"openingElement\",\n \"closingElement\",\n ];\n\n for (const key of childKeys) {\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n if (containsJSX(item as TSESTree.Node, visited)) return true;\n }\n }\n } else if (\"type\" in child) {\n if (containsJSX(child as TSESTree.Node, visited)) return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Categorize a function based on its name and content\n */\nexport function categorizeChunk(\n name: string,\n functionBody: TSESTree.Node | null,\n isInStoreFile: boolean\n): { category: ChunkCategory; isReactRelated: boolean } {\n // Hooks: starts with \"use\" followed by uppercase\n if (/^use[A-Z]/.test(name)) {\n return { category: \"hook\", isReactRelated: true };\n }\n\n // Store: in a .store.ts file or name ends with Store\n if (isInStoreFile || /Store$/.test(name)) {\n return { category: \"store\", isReactRelated: false };\n }\n\n // Handler: starts with \"handle\" or \"on\" followed by uppercase\n if (/^handle[A-Z]/.test(name) || /^on[A-Z]/.test(name)) {\n return { category: \"handler\", isReactRelated: true };\n }\n\n // Component: contains JSX (check the function body)\n if (functionBody && containsJSX(functionBody)) {\n return { category: \"component\", isReactRelated: true };\n }\n\n // Default: utility\n return { category: \"utility\", isReactRelated: false };\n}\n\n/**\n * Extract function name from various AST patterns\n */\nfunction getFunctionName(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression,\n parent: TSESTree.Node | undefined\n): string | null {\n // Named function declaration\n if (node.type === \"FunctionDeclaration\" && node.id) {\n return node.id.name;\n }\n\n // Variable declarator: const foo = () => {}\n if (parent?.type === \"VariableDeclarator\" && parent.id.type === \"Identifier\") {\n return parent.id.name;\n }\n\n // Property: { foo: () => {} }\n if (parent?.type === \"Property\" && parent.key.type === \"Identifier\") {\n return parent.key.name;\n }\n\n return null;\n}\n\n/**\n * Find function ID in fnMap by matching name and location\n */\nfunction findFnId(\n name: string,\n loc: SourceLocation,\n fileCoverage: IstanbulFileCoverage | null\n): string | null {\n if (!fileCoverage) return null;\n\n for (const [fnId, fnInfo] of Object.entries(fileCoverage.fnMap)) {\n // Match by name first\n if (fnInfo.name === name) {\n return fnId;\n }\n\n // If name doesn't match (anonymous or different), match by location\n // Function declaration location should be close to our AST location\n if (\n fnInfo.decl.start.line === loc.start.line ||\n fnInfo.loc.start.line === loc.start.line\n ) {\n return fnId;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate coverage for a specific function\n */\nfunction calculateChunkCoverage(\n fnId: string | null,\n loc: SourceLocation,\n fileCoverage: IstanbulFileCoverage | null\n): ChunkCoverageResult[\"coverage\"] {\n if (!fileCoverage) {\n return {\n functionCalled: false,\n statementsCovered: 0,\n statementsTotal: 0,\n percentage: 0,\n };\n }\n\n // Check if function was called\n const functionCalled = fnId !== null && (fileCoverage.f[fnId] ?? 0) > 0;\n\n // Find statements within function body\n const statementIds = findStatementsInRange(loc, fileCoverage);\n const stats = calculateCoverageFromStatements(statementIds, fileCoverage);\n\n return {\n functionCalled,\n statementsCovered: stats.covered,\n statementsTotal: stats.total,\n percentage: stats.percentage,\n };\n}\n\n/**\n * Collect all exported functions/classes from an AST\n */\ninterface ExportedFunction {\n name: string;\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression;\n loc: SourceLocation;\n /** Location of just the declaration line (for highlighting) */\n declarationLoc: SourceLocation;\n body: TSESTree.Node | null;\n}\n\n/**\n * Get declaration location - just the first line of the function\n * This is used for error highlighting to avoid highlighting the entire function body\n */\nfunction getDeclarationLoc(loc: SourceLocation): SourceLocation {\n return {\n start: loc.start,\n end: { line: loc.start.line, column: 999 },\n };\n}\n\nfunction collectExportedFunctions(ast: TSESTree.Program): ExportedFunction[] {\n const exports: ExportedFunction[] = [];\n\n for (const node of ast.body) {\n // export function foo() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n const loc = node.declaration.loc;\n exports.push({\n name: node.declaration.id.name,\n node: node.declaration,\n loc,\n declarationLoc: getDeclarationLoc(loc),\n body: node.declaration.body,\n });\n }\n\n // export const foo = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (\n decl.id.type === \"Identifier\" &&\n decl.init &&\n (decl.init.type === \"ArrowFunctionExpression\" ||\n decl.init.type === \"FunctionExpression\")\n ) {\n // For arrow functions, use the variable declaration line, not the function body\n const loc = decl.init.loc;\n const declarationLoc = getDeclarationLoc(decl.loc);\n exports.push({\n name: decl.id.name,\n node: decl.init,\n loc,\n declarationLoc,\n body: decl.init.body,\n });\n }\n }\n }\n\n // export default function foo() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\"\n ) {\n const name = node.declaration.id?.name ?? \"default\";\n const loc = node.declaration.loc;\n exports.push({\n name,\n node: node.declaration,\n loc,\n declarationLoc: getDeclarationLoc(loc),\n body: node.declaration.body,\n });\n }\n\n // export default () => {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n (node.declaration.type === \"ArrowFunctionExpression\" ||\n node.declaration.type === \"FunctionExpression\")\n ) {\n const loc = node.declaration.loc;\n exports.push({\n name: \"default\",\n node: node.declaration,\n loc,\n declarationLoc: getDeclarationLoc(loc),\n body: node.declaration.body,\n });\n }\n }\n\n return exports;\n}\n\n/**\n * Analyze all exported chunks in a file for coverage\n *\n * @param ast - The parsed AST of the file\n * @param filePath - Path to the file (used for store detection)\n * @param fileCoverage - Istanbul coverage data for the file (or null)\n * @returns Array of chunks with their coverage information\n */\nexport function analyzeChunks(\n ast: TSESTree.Program,\n filePath: string,\n fileCoverage: IstanbulFileCoverage | null\n): ChunkCoverageResult[] {\n const isInStoreFile = /\\.store\\.(ts|tsx)$/.test(filePath);\n const exportedFunctions = collectExportedFunctions(ast);\n const results: ChunkCoverageResult[] = [];\n\n for (const exported of exportedFunctions) {\n const { category, isReactRelated } = categorizeChunk(\n exported.name,\n exported.body,\n isInStoreFile\n );\n\n const fnId = findFnId(exported.name, exported.loc, fileCoverage);\n const coverage = calculateChunkCoverage(fnId, exported.loc, fileCoverage);\n\n results.push({\n name: exported.name,\n category,\n isReactRelated,\n loc: exported.loc,\n declarationLoc: exported.declarationLoc,\n fnId,\n isExport: true,\n coverage,\n });\n }\n\n return results;\n}\n\n/**\n * Get the appropriate threshold for a chunk based on options\n */\nexport function getChunkThreshold(\n chunk: ChunkCoverageResult,\n options: {\n focusNonReact?: boolean;\n chunkThreshold?: number;\n relaxedThreshold?: number;\n }\n): number {\n const strictThreshold = options.chunkThreshold ?? 80;\n const relaxedThreshold = options.relaxedThreshold ?? 50;\n\n if (!options.focusNonReact) {\n // Uniform threshold for all chunks\n return strictThreshold;\n }\n\n // focusNonReact mode: relaxed threshold for React-related code\n if (chunk.category === \"component\" || chunk.category === \"handler\") {\n return relaxedThreshold;\n }\n\n // Strict threshold for utility, hook, store\n return strictThreshold;\n}\n","/**\n * Rule: prefer-tailwind\n *\n * Encourages using Tailwind className over inline style attributes.\n * - Detects files with a high ratio of inline `style` vs `className` usage\n * - Warns at each element using style without className when ratio exceeds threshold\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferTailwind\" | \"preferSemanticColors\";\ntype Options = [\n {\n /** Minimum ratio of style-only elements before warnings trigger (0-1). Default: 0.3 */\n styleRatioThreshold?: number;\n /** Don't warn if file has fewer than N JSX elements with styling. Default: 3 */\n minElementsForAnalysis?: number;\n /** Style properties to ignore (e.g., [\"transform\", \"animation\"] for dynamic values). Default: [] */\n allowedStyleProperties?: string[];\n /** Component names to skip (e.g., [\"motion.div\", \"animated.View\"]). Default: [] */\n ignoreComponents?: string[];\n /** Prefer semantic colors (bg-destructive) over hard-coded (bg-red-500). Default: false */\n preferSemanticColors?: boolean;\n /** Hard-coded color names to allow when preferSemanticColors is enabled. Default: [] */\n allowedHardCodedColors?: string[];\n }?\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"prefer-tailwind\",\n version: \"1.0.0\",\n name: \"Prefer Tailwind\",\n description: \"Encourage Tailwind className over inline style attributes\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🎨\",\n hint: \"Prefers className over inline styles\",\n defaultEnabled: true,\n defaultOptions: [\n {\n styleRatioThreshold: 0.3,\n minElementsForAnalysis: 3,\n allowedStyleProperties: [],\n ignoreComponents: [],\n preferSemanticColors: true,\n allowedHardCodedColors: [],\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"styleRatioThreshold\",\n label: \"Style ratio threshold\",\n type: \"number\",\n defaultValue: 0.3,\n description:\n \"Minimum ratio (0-1) of style-only elements before warnings trigger\",\n },\n {\n key: \"minElementsForAnalysis\",\n label: \"Minimum elements\",\n type: \"number\",\n defaultValue: 3,\n description: \"Don't warn if file has fewer styled elements than this\",\n },\n {\n key: \"allowedStyleProperties\",\n label: \"Allowed style properties\",\n type: \"text\",\n defaultValue: \"\",\n description:\n \"Comma-separated list of style properties to allow (e.g., transform,animation)\",\n },\n {\n key: \"ignoreComponents\",\n label: \"Ignored components\",\n type: \"text\",\n defaultValue: \"\",\n description:\n \"Comma-separated component names to skip (e.g., motion.div,animated.View)\",\n },\n {\n key: \"preferSemanticColors\",\n label: \"Prefer semantic colors\",\n type: \"boolean\",\n defaultValue: true,\n description:\n \"Warn against hard-coded colors (bg-red-500) in favor of semantic theme colors (bg-destructive)\",\n },\n {\n key: \"allowedHardCodedColors\",\n label: \"Allowed hard-coded colors\",\n type: \"text\",\n defaultValue: \"\",\n description:\n \"Comma-separated color names to allow when preferSemanticColors is enabled (e.g., gray,slate)\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects files with a high ratio of inline \\`style\\` attributes versus \\`className\\` usage\nin JSX elements. Reports warnings on elements that use \\`style\\` without \\`className\\`,\nbut only when the file exceeds a configurable threshold ratio.\n\n## Why it's useful\n\n- **Consistency**: Encourages using Tailwind's utility classes for styling\n- **Maintainability**: Tailwind classes are easier to read and maintain than inline styles\n- **Performance**: Tailwind generates optimized CSS; inline styles can't be deduplicated\n- **Theming**: Tailwind classes work with dark mode and responsive variants\n\n## Examples\n\n### ❌ Incorrect (when file exceeds threshold)\n\n\\`\\`\\`tsx\n// Many elements using style without className\n<div style={{ color: 'red' }}>Red text</div>\n<span style={{ marginTop: '10px' }}>Spaced</span>\n<p style={{ fontSize: '16px' }}>Paragraph</p>\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using Tailwind className\n<div className=\"text-red-500\">Red text</div>\n<span className=\"mt-2\">Spaced</span>\n<p className=\"text-base\">Paragraph</p>\n\n// Both style and className (acceptable for dynamic values)\n<div className=\"p-4\" style={{ backgroundColor: dynamicColor }}>Mixed</div>\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/prefer-tailwind\": [\"warn\", {\n styleRatioThreshold: 0.3, // Warn when >30% of elements are style-only\n minElementsForAnalysis: 3, // Need at least 3 styled elements to analyze\n allowedStyleProperties: [\"transform\", \"animation\"], // Skip these properties\n ignoreComponents: [\"motion.div\", \"animated.View\"], // Skip animation libraries\n preferSemanticColors: true, // Warn on hard-coded colors like bg-red-500\n allowedHardCodedColors: [\"gray\", \"slate\"] // Allow specific color palettes\n}]\n\\`\\`\\`\n\n## Semantic Colors\n\nWhen \\`preferSemanticColors\\` is enabled, the rule warns against hard-coded Tailwind color classes\nin favor of semantic theme colors:\n\n### ❌ Hard-coded colors (when enabled)\n\n\\`\\`\\`tsx\n<div className=\"bg-red-500 text-white\">Error</div>\n<button className=\"hover:bg-blue-600\">Click</button>\n\\`\\`\\`\n\n### ✅ Semantic colors (preferred)\n\n\\`\\`\\`tsx\n<div className=\"bg-destructive text-destructive-foreground\">Error</div>\n<button className=\"hover:bg-primary\">Click</button>\n\\`\\`\\`\n\nSemantic colors like \\`bg-background\\`, \\`text-foreground\\`, \\`bg-primary\\`, \\`bg-destructive\\`,\n\\`bg-muted\\`, etc. work better with theming and dark mode.\n\nColors that are always allowed: \\`white\\`, \\`black\\`, \\`transparent\\`, \\`inherit\\`, \\`current\\`.\n\n## Notes\n\n- Elements with BOTH \\`style\\` and \\`className\\` are considered acceptable\n- Files with few styled elements are not analyzed (prevents false positives)\n- The rule uses a ratio-based approach to catch systematic patterns, not isolated cases\n- Use \\`allowedStyleProperties\\` for dynamic values that can't use Tailwind\n- Use \\`ignoreComponents\\` for animation libraries that require inline styles\n`,\n});\n\n/**\n * Get the component name from a JSX opening element\n */\nfunction getComponentName(node: TSESTree.JSXOpeningElement): string {\n const name = node.name;\n\n if (name.type === \"JSXIdentifier\") {\n return name.name;\n }\n\n if (name.type === \"JSXMemberExpression\") {\n // Handle motion.div, animated.View, etc.\n const parts: string[] = [];\n let current: TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier = name;\n\n while (current.type === \"JSXMemberExpression\") {\n if (current.property.type === \"JSXIdentifier\") {\n parts.unshift(current.property.name);\n }\n current = current.object as\n | TSESTree.JSXMemberExpression\n | TSESTree.JSXIdentifier;\n }\n\n if (current.type === \"JSXIdentifier\") {\n parts.unshift(current.name);\n }\n\n return parts.join(\".\");\n }\n\n return \"\";\n}\n\n/**\n * Extract property names from a style object expression\n */\nfunction getStylePropertyNames(\n value: TSESTree.JSXExpressionContainer\n): string[] {\n const expr = value.expression;\n\n // Handle style={{ prop: value }}\n if (expr.type === \"ObjectExpression\") {\n return expr.properties\n .filter((prop): prop is TSESTree.Property => prop.type === \"Property\")\n .map((prop) => {\n if (prop.key.type === \"Identifier\") {\n return prop.key.name;\n }\n if (prop.key.type === \"Literal\" && typeof prop.key.value === \"string\") {\n return prop.key.value;\n }\n return \"\";\n })\n .filter(Boolean);\n }\n\n // For style={variable} or style={{...spread}}, we can't determine properties\n return [];\n}\n\n/**\n * Check if all style properties are in the allowed list\n */\nfunction hasOnlyAllowedProperties(\n styleProperties: string[],\n allowedProperties: string[]\n): boolean {\n if (allowedProperties.length === 0 || styleProperties.length === 0) {\n return false;\n }\n\n return styleProperties.every((prop) => allowedProperties.includes(prop));\n}\n\ninterface ElementInfo {\n node: TSESTree.JSXOpeningElement;\n hasStyle: boolean;\n hasClassName: boolean;\n styleProperties: string[];\n}\n\n/**\n * Tailwind color names that should use semantic alternatives\n * Excludes neutral colors that are often acceptable\n */\nconst HARD_CODED_COLOR_NAMES = [\n \"red\",\n \"orange\",\n \"amber\",\n \"yellow\",\n \"lime\",\n \"green\",\n \"emerald\",\n \"teal\",\n \"cyan\",\n \"sky\",\n \"blue\",\n \"indigo\",\n \"violet\",\n \"purple\",\n \"fuchsia\",\n \"pink\",\n \"rose\",\n \"slate\",\n \"gray\",\n \"zinc\",\n \"neutral\",\n \"stone\",\n];\n\n/**\n * Colors that are always allowed (not theme-dependent)\n */\nconst ALWAYS_ALLOWED_COLORS = [\n \"white\",\n \"black\",\n \"transparent\",\n \"inherit\",\n \"current\",\n];\n\n/**\n * Regex to match hard-coded Tailwind color classes\n * Matches patterns like: bg-red-500, text-blue-600/50, hover:bg-green-400, dark:text-slate-100\n * Color utilities: bg, text, border, ring, outline, decoration, accent, fill, stroke,\n * from, via, to (gradients), divide, placeholder, caret, shadow\n */\nfunction createHardCodedColorRegex(colorNames: string[]): RegExp {\n const colorPattern = colorNames.join(\"|\");\n // Match color utilities with color-shade pattern, optional opacity, with optional variant prefixes\n return new RegExp(\n `(?:^|\\\\s)(?:[a-z-]+:)*(?:bg|text|border|ring|outline|decoration|accent|fill|stroke|from|via|to|divide|placeholder|caret|shadow)-(${colorPattern})-\\\\d{1,3}(?:/\\\\d{1,3})?(?=\\\\s|$)`,\n \"g\"\n );\n}\n\n/**\n * Extract className value from a JSX attribute\n */\nfunction getClassNameValue(attr: TSESTree.JSXAttribute): string | null {\n if (!attr.value) return null;\n\n // className=\"...\"\n if (attr.value.type === \"Literal\" && typeof attr.value.value === \"string\") {\n return attr.value.value;\n }\n\n // className={\"...\"}\n if (\n attr.value.type === \"JSXExpressionContainer\" &&\n attr.value.expression.type === \"Literal\" &&\n typeof attr.value.expression.value === \"string\"\n ) {\n return attr.value.expression.value;\n }\n\n // className={`...`}\n if (\n attr.value.type === \"JSXExpressionContainer\" &&\n attr.value.expression.type === \"TemplateLiteral\"\n ) {\n // Extract static parts of template literal\n return attr.value.expression.quasis.map((q) => q.value.raw).join(\" \");\n }\n\n return null;\n}\n\n/**\n * Check if a className string contains hard-coded color classes\n */\nfunction findHardCodedColors(\n className: string,\n allowedColors: string[]\n): string[] {\n const disallowedColorNames = HARD_CODED_COLOR_NAMES.filter(\n (c) => !allowedColors.includes(c)\n );\n\n if (disallowedColorNames.length === 0) return [];\n\n const regex = createHardCodedColorRegex(disallowedColorNames);\n const matches: string[] = [];\n let match;\n\n while ((match = regex.exec(className)) !== null) {\n matches.push(match[0].trim());\n }\n\n return matches;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"prefer-tailwind\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Encourage Tailwind className over inline style attributes\",\n },\n messages: {\n preferTailwind:\n \"Prefer Tailwind className over inline style. This element uses style attribute without className.\",\n preferSemanticColors:\n \"Prefer semantic color classes (e.g., bg-destructive, text-primary) over hard-coded colors (e.g., bg-red-500).\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n styleRatioThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 1,\n description:\n \"Minimum ratio of style-only elements to trigger warnings\",\n },\n minElementsForAnalysis: {\n type: \"number\",\n minimum: 1,\n description: \"Minimum styled elements required for analysis\",\n },\n allowedStyleProperties: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Style properties to ignore\",\n },\n ignoreComponents: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Component names to skip\",\n },\n preferSemanticColors: {\n type: \"boolean\",\n description:\n \"Warn against hard-coded colors in favor of semantic theme colors\",\n },\n allowedHardCodedColors: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Hard-coded color names to allow when preferSemanticColors is enabled\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n styleRatioThreshold: 0.3,\n minElementsForAnalysis: 3,\n allowedStyleProperties: [],\n ignoreComponents: [],\n preferSemanticColors: false,\n allowedHardCodedColors: [],\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const styleRatioThreshold = options.styleRatioThreshold ?? 0.3;\n const minElementsForAnalysis = options.minElementsForAnalysis ?? 3;\n const allowedStyleProperties = options.allowedStyleProperties ?? [];\n const ignoreComponents = options.ignoreComponents ?? [];\n const preferSemanticColors = options.preferSemanticColors ?? false;\n const allowedHardCodedColors = options.allowedHardCodedColors ?? [];\n\n // Tracking state for file-level analysis\n const styledElements: ElementInfo[] = [];\n\n /**\n * Check if a JSXAttribute is a style attribute with an expression\n */\n function isStyleAttribute(attr: TSESTree.JSXAttribute): boolean {\n return (\n attr.name.type === \"JSXIdentifier\" &&\n attr.name.name === \"style\" &&\n attr.value?.type === \"JSXExpressionContainer\"\n );\n }\n\n /**\n * Check if a JSXAttribute is a className attribute\n */\n function isClassNameAttribute(attr: TSESTree.JSXAttribute): boolean {\n return (\n attr.name.type === \"JSXIdentifier\" &&\n (attr.name.name === \"className\" || attr.name.name === \"class\")\n );\n }\n\n return {\n JSXOpeningElement(node) {\n // Check if component should be ignored\n const componentName = getComponentName(node);\n if (ignoreComponents.includes(componentName)) {\n return;\n }\n\n let hasStyle = false;\n let hasClassName = false;\n let styleProperties: string[] = [];\n\n for (const attr of node.attributes) {\n if (attr.type === \"JSXAttribute\") {\n if (isStyleAttribute(attr)) {\n hasStyle = true;\n styleProperties = getStylePropertyNames(\n attr.value as TSESTree.JSXExpressionContainer\n );\n }\n if (isClassNameAttribute(attr)) {\n hasClassName = true;\n\n // Check for hard-coded colors if preferSemanticColors is enabled\n if (preferSemanticColors) {\n const classNameValue = getClassNameValue(attr);\n if (classNameValue) {\n const hardCodedColors = findHardCodedColors(\n classNameValue,\n allowedHardCodedColors\n );\n if (hardCodedColors.length > 0) {\n context.report({\n node,\n messageId: \"preferSemanticColors\",\n });\n }\n }\n }\n }\n }\n }\n\n // Only track elements that have style OR className (or both)\n if (hasStyle || hasClassName) {\n styledElements.push({\n node,\n hasStyle,\n hasClassName,\n styleProperties,\n });\n }\n },\n\n \"Program:exit\"() {\n // Don't analyze if not enough styled elements\n if (styledElements.length < minElementsForAnalysis) {\n return;\n }\n\n // Filter out elements where all style properties are allowed\n const styleOnlyElements = styledElements.filter((el) => {\n if (!el.hasStyle || el.hasClassName) {\n return false;\n }\n\n // If all style properties are in the allowed list, don't count this element\n if (\n hasOnlyAllowedProperties(el.styleProperties, allowedStyleProperties)\n ) {\n return false;\n }\n\n return true;\n });\n\n const ratio = styleOnlyElements.length / styledElements.length;\n\n // Only report if ratio exceeds threshold\n if (ratio > styleRatioThreshold) {\n for (const element of styleOnlyElements) {\n context.report({\n node: element.node,\n messageId: \"preferTailwind\",\n });\n }\n }\n },\n };\n },\n});\n","/**\n * Category Registry\n *\n * Centralized metadata for rule categories.\n * Used by CLI installers and UI components to display category information\n * without hardcoding assumptions.\n */\n\n/**\n * Metadata for a rule category\n */\nexport interface CategoryMeta {\n /** Category identifier */\n id: \"static\" | \"semantic\";\n /** Display name */\n name: string;\n /** Short description */\n description: string;\n /** Icon for display (emoji) */\n icon: string;\n /** Whether rules in this category are enabled by default during install */\n defaultEnabled: boolean;\n}\n\n/**\n * Registry of all rule categories\n */\nexport const categoryRegistry: CategoryMeta[] = [\n {\n id: \"static\",\n name: \"Static Rules\",\n description: \"Pattern-based, fast analysis\",\n icon: \"\\u{1F4CB}\",\n defaultEnabled: true,\n },\n {\n id: \"semantic\",\n name: \"Semantic Rules\",\n description: \"LLM-powered analysis\",\n icon: \"\\u{1F9E0}\",\n defaultEnabled: false,\n },\n];\n\n/**\n * Get metadata for a specific category\n */\nexport function getCategoryMeta(id: string): CategoryMeta | undefined {\n return categoryRegistry.find((cat) => cat.id === id);\n}\n","/**\n * Rule Registry\n *\n * Central registry of all UILint ESLint rules with metadata for CLI tooling.\n * Metadata is now colocated with each rule file - this module re-exports\n * the collected metadata for use by installers and other tools.\n */\n\n// Re-export types from create-rule for consumers\nexport type {\n RuleMeta,\n RuleOptionSchema,\n OptionFieldSchema,\n RuleRequirement,\n RuleMigration,\n} from \"./utils/create-rule.js\";\n\n// Backward compatibility alias\nexport type { RuleMeta as RuleMetadata } from \"./utils/create-rule.js\";\n\n// Re-export category registry\nexport {\n categoryRegistry,\n getCategoryMeta,\n type CategoryMeta,\n} from \"./category-registry.js\";\n\n// Import colocated metadata from each rule file\n// Single-file rules\nimport { meta as consistentDarkMode } from \"./rules/consistent-dark-mode.js\";\nimport { meta as noDirectStoreImport } from \"./rules/no-direct-store-import.js\";\nimport { meta as preferZustandStateManagement } from \"./rules/prefer-zustand-state-management.js\";\nimport { meta as semanticVision } from \"./rules/semantic-vision.js\";\nimport { meta as enforceAbsoluteImports } from \"./rules/enforce-absolute-imports.js\";\nimport { meta as noAnyInProps } from \"./rules/no-any-in-props.js\";\nimport { meta as zustandUseSelectors } from \"./rules/zustand-use-selectors.js\";\nimport { meta as noSecretsInCode } from \"./rules/no-secrets-in-code.js\";\nimport { meta as requireInputValidation } from \"./rules/require-input-validation.js\";\nimport { meta as noPropDrillingDepth } from \"./rules/no-prop-drilling-depth.js\";\nimport { meta as noSemanticDuplicates } from \"./rules/no-semantic-duplicates.js\";\nimport { meta as preferTailwind } from \"./rules/prefer-tailwind.js\";\n\n// Directory-based rules (complex rules with colocated utilities)\nimport { meta as noMixedComponentLibraries } from \"./rules/no-mixed-component-libraries/index.js\";\nimport { meta as semantic } from \"./rules/semantic/index.js\";\nimport { meta as requireTestCoverage } from \"./rules/require-test-coverage/index.js\";\n\nimport type { RuleMeta } from \"./utils/create-rule.js\";\n\n/**\n * Registry of all available UILint ESLint rules\n *\n * When adding a new rule:\n * 1. Create the rule file in src/rules/\n * 2. Export a `meta` object using `defineRuleMeta()`\n * 3. Import and add the meta to this array\n * 4. Run `pnpm generate:index` to regenerate exports\n */\nexport const ruleRegistry: RuleMeta[] = [\n // Existing rules\n consistentDarkMode,\n noDirectStoreImport,\n preferZustandStateManagement,\n noMixedComponentLibraries,\n semantic,\n semanticVision,\n // New UI rules\n enforceAbsoluteImports,\n noAnyInProps,\n zustandUseSelectors,\n noPropDrillingDepth,\n // New security rules\n noSecretsInCode,\n requireInputValidation,\n // Semantic duplicate detection\n noSemanticDuplicates,\n // Test coverage enforcement\n requireTestCoverage,\n // Style preferences\n preferTailwind,\n];\n\n/**\n * Get rule metadata by ID\n */\nexport function getRuleMetadata(id: string): RuleMeta | undefined {\n return ruleRegistry.find((rule) => rule.id === id);\n}\n\n/**\n * Get all rules in a category\n */\nexport function getRulesByCategory(\n category: \"static\" | \"semantic\"\n): RuleMeta[] {\n return ruleRegistry.filter((rule) => rule.category === category);\n}\n\n/**\n * Get documentation for a rule (useful for CLI help commands)\n */\nexport function getRuleDocs(id: string): string | undefined {\n const rule = getRuleMetadata(id);\n return rule?.docs;\n}\n\n/**\n * Get all rule IDs\n */\nexport function getAllRuleIds(): string[] {\n return ruleRegistry.map((rule) => rule.id);\n}\n","/**\n * UILint ESLint Plugin\n *\n * THIS FILE IS AUTO-GENERATED from src/rule-registry.ts.\n * Do not edit by hand. Run: pnpm -C packages/uilint-eslint generate:index\n */\n\nimport type { Linter } from \"eslint\";\nimport consistentDarkMode from \"./rules/consistent-dark-mode.js\";\nimport noDirectStoreImport from \"./rules/no-direct-store-import.js\";\nimport preferZustandStateManagement from \"./rules/prefer-zustand-state-management.js\";\nimport noMixedComponentLibraries from \"./rules/no-mixed-component-libraries/index.js\";\nimport semantic from \"./rules/semantic/index.js\";\nimport semanticVision from \"./rules/semantic-vision.js\";\nimport enforceAbsoluteImports from \"./rules/enforce-absolute-imports.js\";\nimport noAnyInProps from \"./rules/no-any-in-props.js\";\nimport zustandUseSelectors from \"./rules/zustand-use-selectors.js\";\nimport noPropDrillingDepth from \"./rules/no-prop-drilling-depth.js\";\nimport noSecretsInCode from \"./rules/no-secrets-in-code.js\";\nimport requireInputValidation from \"./rules/require-input-validation.js\";\nimport noSemanticDuplicates from \"./rules/no-semantic-duplicates.js\";\nimport requireTestCoverage from \"./rules/require-test-coverage/index.js\";\nimport preferTailwind from \"./rules/prefer-tailwind.js\";\n\n/**\n * All available rules\n */\nconst rules = {\n \"consistent-dark-mode\": consistentDarkMode,\n \"no-direct-store-import\": noDirectStoreImport,\n \"prefer-zustand-state-management\": preferZustandStateManagement,\n \"no-mixed-component-libraries\": noMixedComponentLibraries,\n \"semantic\": semantic,\n \"semantic-vision\": semanticVision,\n \"enforce-absolute-imports\": enforceAbsoluteImports,\n \"no-any-in-props\": noAnyInProps,\n \"zustand-use-selectors\": zustandUseSelectors,\n \"no-prop-drilling-depth\": noPropDrillingDepth,\n \"no-secrets-in-code\": noSecretsInCode,\n \"require-input-validation\": requireInputValidation,\n \"no-semantic-duplicates\": noSemanticDuplicates,\n \"require-test-coverage\": requireTestCoverage,\n \"prefer-tailwind\": preferTailwind,\n};\n\n// Package version (injected at build time or fallback)\nconst version = \"0.1.0\";\n\n/**\n * Plugin metadata\n */\nconst meta = {\n name: \"uilint\",\n version,\n};\n\n/**\n * The ESLint plugin object\n */\nconst plugin = {\n meta,\n rules,\n};\n\n/**\n * Shared language options for all configs\n */\nconst jsxLanguageOptions: Linter.Config[\"languageOptions\"] = {\n parserOptions: {\n ecmaFeatures: {\n jsx: true,\n },\n },\n};\n\n/**\n * Recommended config - static rules only\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.recommended];\n * ```\n */\nconst recommendedConfig: Linter.Config = {\n name: \"uilint/recommended\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/consistent-dark-mode\": [\"error\", ...[\n {\n \"warnOnMissingDarkMode\": true\n }\n ]],\n \"uilint/no-direct-store-import\": [\"warn\", ...[\n {\n \"storePattern\": \"use*Store\"\n }\n ]],\n \"uilint/prefer-zustand-state-management\": [\"warn\", ...[\n {\n \"maxStateHooks\": 3,\n \"countUseState\": true,\n \"countUseReducer\": true,\n \"countUseContext\": true\n }\n ]],\n \"uilint/no-mixed-component-libraries\": [\"error\", ...[\n {\n \"preferred\": \"shadcn\",\n \"libraries\": [\n \"shadcn\",\n \"mui\"\n ]\n }\n ]],\n \"uilint/enforce-absolute-imports\": [\"warn\", ...[\n {\n \"maxRelativeDepth\": 1,\n \"aliasPrefix\": \"@/\"\n }\n ]],\n \"uilint/no-any-in-props\": [\"error\", ...[\n {\n \"checkFCGenerics\": true,\n \"allowInGenericDefaults\": false\n }\n ]],\n \"uilint/zustand-use-selectors\": [\"warn\", ...[\n {\n \"storePattern\": \"^use\\\\w*Store$\",\n \"allowShallow\": true,\n \"requireNamedSelectors\": false\n }\n ]],\n \"uilint/no-prop-drilling-depth\": [\"warn\", ...[\n {\n \"maxDepth\": 2,\n \"ignoredProps\": [\n \"className\",\n \"style\",\n \"children\",\n \"key\",\n \"ref\",\n \"id\"\n ],\n \"ignoreComponents\": []\n }\n ]],\n \"uilint/no-secrets-in-code\": [\"error\", ...[\n {\n \"checkVariableNames\": true,\n \"minSecretLength\": 16,\n \"allowInTestFiles\": false\n }\n ]],\n \"uilint/require-input-validation\": [\"warn\", ...[\n {\n \"httpMethods\": [\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\"\n ],\n \"routePatterns\": [\n \"route.ts\",\n \"route.tsx\",\n \"/api/\",\n \"/app/api/\"\n ],\n \"allowManualValidation\": false\n }\n ]],\n \"uilint/require-test-coverage\": [\"warn\", ...[\n {\n \"coveragePath\": \"coverage/coverage-final.json\",\n \"threshold\": 80,\n \"thresholdsByPattern\": [],\n \"severity\": {\n \"noCoverage\": \"error\",\n \"belowThreshold\": \"warn\"\n },\n \"testPatterns\": [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\"\n ],\n \"ignorePatterns\": [\n \"**/*.d.ts\",\n \"**/index.ts\"\n ],\n \"mode\": \"all\",\n \"baseBranch\": \"main\"\n }\n ]],\n \"uilint/prefer-tailwind\": [\"warn\", ...[\n {\n \"styleRatioThreshold\": 0.3,\n \"minElementsForAnalysis\": 3,\n \"allowedStyleProperties\": [],\n \"ignoreComponents\": [],\n \"preferSemanticColors\": true,\n \"allowedHardCodedColors\": []\n }\n ]],\n },\n};\n\n/**\n * Strict config - static rules + semantic rules\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.strict];\n * ```\n */\nconst strictConfig: Linter.Config = {\n name: \"uilint/strict\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/consistent-dark-mode\": [\"error\", ...[\n {\n \"warnOnMissingDarkMode\": true\n }\n ]],\n \"uilint/no-direct-store-import\": [\"warn\", ...[\n {\n \"storePattern\": \"use*Store\"\n }\n ]],\n \"uilint/prefer-zustand-state-management\": [\"warn\", ...[\n {\n \"maxStateHooks\": 3,\n \"countUseState\": true,\n \"countUseReducer\": true,\n \"countUseContext\": true\n }\n ]],\n \"uilint/no-mixed-component-libraries\": [\"error\", ...[\n {\n \"preferred\": \"shadcn\",\n \"libraries\": [\n \"shadcn\",\n \"mui\"\n ]\n }\n ]],\n \"uilint/semantic\": [\"warn\", ...[\n {\n \"model\": \"qwen3-coder:30b\",\n \"styleguidePath\": \".uilint/styleguide.md\"\n }\n ]],\n \"uilint/semantic-vision\": [\"warn\", ...[\n {\n \"maxAgeMs\": 3600000,\n \"screenshotsPath\": \".uilint/screenshots\"\n }\n ]],\n \"uilint/enforce-absolute-imports\": [\"warn\", ...[\n {\n \"maxRelativeDepth\": 1,\n \"aliasPrefix\": \"@/\"\n }\n ]],\n \"uilint/no-any-in-props\": [\"error\", ...[\n {\n \"checkFCGenerics\": true,\n \"allowInGenericDefaults\": false\n }\n ]],\n \"uilint/zustand-use-selectors\": [\"warn\", ...[\n {\n \"storePattern\": \"^use\\\\w*Store$\",\n \"allowShallow\": true,\n \"requireNamedSelectors\": false\n }\n ]],\n \"uilint/no-prop-drilling-depth\": [\"warn\", ...[\n {\n \"maxDepth\": 2,\n \"ignoredProps\": [\n \"className\",\n \"style\",\n \"children\",\n \"key\",\n \"ref\",\n \"id\"\n ],\n \"ignoreComponents\": []\n }\n ]],\n \"uilint/no-secrets-in-code\": [\"error\", ...[\n {\n \"checkVariableNames\": true,\n \"minSecretLength\": 16,\n \"allowInTestFiles\": false\n }\n ]],\n \"uilint/require-input-validation\": [\"warn\", ...[\n {\n \"httpMethods\": [\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\"\n ],\n \"routePatterns\": [\n \"route.ts\",\n \"route.tsx\",\n \"/api/\",\n \"/app/api/\"\n ],\n \"allowManualValidation\": false\n }\n ]],\n \"uilint/no-semantic-duplicates\": [\"warn\", ...[\n {\n \"threshold\": 0.85,\n \"indexPath\": \".uilint/.duplicates-index\",\n \"minLines\": 3\n }\n ]],\n \"uilint/require-test-coverage\": [\"warn\", ...[\n {\n \"coveragePath\": \"coverage/coverage-final.json\",\n \"threshold\": 80,\n \"thresholdsByPattern\": [],\n \"severity\": {\n \"noCoverage\": \"error\",\n \"belowThreshold\": \"warn\"\n },\n \"testPatterns\": [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\"\n ],\n \"ignorePatterns\": [\n \"**/*.d.ts\",\n \"**/index.ts\"\n ],\n \"mode\": \"all\",\n \"baseBranch\": \"main\"\n }\n ]],\n \"uilint/prefer-tailwind\": [\"warn\", ...[\n {\n \"styleRatioThreshold\": 0.3,\n \"minElementsForAnalysis\": 3,\n \"allowedStyleProperties\": [],\n \"ignoreComponents\": [],\n \"preferSemanticColors\": true,\n \"allowedHardCodedColors\": []\n }\n ]],\n },\n};\n\n/**\n * Pre-configured configs\n */\nconst configs: Record<string, Linter.Config> = {\n recommended: recommendedConfig,\n strict: strictConfig,\n};\n\n/**\n * UILint ESLint export interface\n */\nexport interface UILintESLint {\n meta: typeof meta;\n plugin: typeof plugin;\n rules: typeof rules;\n configs: Record<string, Linter.Config>;\n}\n\n/**\n * Default export for ESLint flat config\n */\nconst uilintEslint: UILintESLint = {\n meta,\n plugin,\n rules,\n configs,\n};\n\nexport default uilintEslint;\n\n// Named exports for convenience\nexport { plugin, rules, configs, meta };\n\n// Re-export utilities for custom rule creation\nexport { createRule } from \"./utils/create-rule.js\";\n\n// Re-export styleguide utilities (from semantic rule)\nexport {\n loadStyleguide,\n findStyleguidePath,\n getStyleguide,\n} from \"./rules/semantic/lib/styleguide-loader.js\";\n\n// Re-export cache utilities (from semantic rule)\nexport {\n hashContent,\n hashContentSync,\n getCacheEntry,\n setCacheEntry,\n clearCache,\n clearCacheEntry,\n loadCache,\n saveCache,\n type CacheEntry,\n type CachedIssue,\n type CacheStore,\n} from \"./rules/semantic/lib/cache.js\";\n\n// Re-export import graph utilities (from no-mixed-component-libraries rule)\nexport {\n getComponentLibrary,\n clearCache as clearImportGraphCache,\n type LibraryName,\n} from \"./rules/no-mixed-component-libraries/lib/import-graph.js\";\n\n// Re-export rule registry for CLI tooling\nexport {\n ruleRegistry,\n getRuleMetadata,\n getRulesByCategory,\n getRuleDocs,\n getAllRuleIds,\n categoryRegistry,\n getCategoryMeta,\n type RuleMeta,\n type RuleMetadata, // Backward compatibility alias\n type OptionFieldSchema,\n type RuleOptionSchema,\n type RuleRequirement,\n type RuleMigration,\n type CategoryMeta,\n} from \"./rule-registry.js\";\n\n// Re-export defineRuleMeta for rule authors\nexport { defineRuleMeta } from \"./utils/create-rule.js\";\n\n// Re-export coverage utilities (from require-test-coverage rule)\nexport {\n aggregateCoverage,\n type IstanbulCoverage,\n type FileCoverageInfo,\n type AggregatedCoverage,\n} from \"./rules/require-test-coverage/lib/coverage-aggregator.js\";\n\nexport {\n buildDependencyGraph,\n type DependencyGraph,\n} from \"./rules/require-test-coverage/lib/dependency-graph.js\";\n\nexport {\n categorizeFile,\n type FileCategory,\n type FileCategoryResult,\n} from \"./rules/require-test-coverage/lib/file-categorizer.js\";\n\n// Re-export JSX coverage analyzer utilities (from require-test-coverage rule)\nexport {\n analyzeJSXElementCoverage,\n buildDataLoc,\n findStatementsInRange,\n calculateCoverageFromStatements,\n findCoverageForFile,\n isEventHandlerAttribute,\n type IstanbulFileCoverage,\n type SourceLocation,\n type CoverageStats,\n type JSXCoverageResult,\n} from \"./rules/require-test-coverage/lib/jsx-coverage-analyzer.js\";\n\n// Re-export oxc-resolver for custom rules that need import resolution\nexport { ResolverFactory } from \"oxc-resolver\";\n"],"mappings":"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","names":["meta","meta","meta","isComponentName","meta","existsSync","readFileSync","dirname","join","existsSync","readFileSync","dirname","join","clearCache","existsSync","readFileSync","dirname","join","workspaceRoot","meta","dirname","readFileSync","findProjectRoot","existsSync","join","existsSync","readFileSync","dirname","join","relative","meta","findProjectRoot","existsSync","join","dirname","readFileSync","relative","meta","meta","meta","meta","isComponentName","meta","meta","existsSync","readFileSync","writeFileSync","dirname","join","relative","meta","findProjectRoot","dirname","join","existsSync","readFileSync","meta","relative","existsSync","readFileSync","statSync","dirname","join","basename","relative","existsSync","readFileSync","parse","existsSync","readFileSync","parse","existsSync","ResolverFactory","parse","readFileSync","existsSync","dirname","join","resolverFactory","astCache","resolvedPathCache","getResolverFactory","resolverFactory","ResolverFactory","resolveImportPath","dirname","manualResolve","findProjectRoot","join","existsSync","parseFile","readFileSync","parse","extractImports","resolveImportPath","existsSync","parseFile","findCoverageForFile","resolveImportPath","statementCount","coveredCount","meta","findProjectRoot","dirname","existsSync","join","statSync","readFileSync","shouldIgnore","relative","findCoverageForFile","basename","meta","getComponentName","getComponentName","meta","ResolverFactory","meta"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/create-rule.ts","../src/rules/consistent-dark-mode.ts","../src/rules/no-direct-store-import.ts","../src/rules/prefer-zustand-state-management.ts","../src/rules/no-mixed-component-libraries/lib/export-resolver.ts","../src/rules/no-mixed-component-libraries/lib/component-parser.ts","../src/rules/no-mixed-component-libraries/lib/import-graph.ts","../src/rules/no-mixed-component-libraries/index.ts","../src/rules/semantic/index.ts","../src/rules/semantic/lib/cache.ts","../src/rules/semantic/lib/styleguide-loader.ts","../src/rules/semantic-vision.ts","../src/rules/enforce-absolute-imports.ts","../src/rules/no-any-in-props.ts","../src/rules/zustand-use-selectors.ts","../src/rules/no-prop-drilling-depth.ts","../src/rules/no-secrets-in-code.ts","../src/rules/require-input-validation.ts","../src/rules/no-semantic-duplicates.ts","../src/rules/require-test-coverage/index.ts","../src/rules/require-test-coverage/lib/file-categorizer.ts","../src/rules/require-test-coverage/lib/dependency-graph.ts","../src/rules/require-test-coverage/lib/export-resolver.ts","../src/rules/require-test-coverage/lib/coverage-aggregator.ts","../src/rules/require-test-coverage/lib/jsx-coverage-analyzer.ts","../src/rules/require-test-coverage/lib/chunk-analyzer.ts","../src/rules/prefer-tailwind.ts","../src/category-registry.ts","../src/rule-registry.ts","../src/index.ts"],"sourcesContent":["/**\n * Rule creation helper using @typescript-eslint/utils\n */\n\nimport { ESLintUtils } from \"@typescript-eslint/utils\";\n\nexport const createRule = ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/peter-suggate/uilint/blob/main/packages/uilint-eslint/docs/rules/${name}.md`\n);\n\n/**\n * Schema for prompting user to configure a rule option in the CLI\n */\nexport interface OptionFieldSchema {\n /** Field name in the options object */\n key: string;\n /** Display label for the prompt */\n label: string;\n /** Prompt type */\n type: \"text\" | \"number\" | \"boolean\" | \"select\" | \"multiselect\";\n /** Default value */\n defaultValue: unknown;\n /** Placeholder text (for text/number inputs) */\n placeholder?: string;\n /** Options for select/multiselect */\n options?: Array<{ value: string | number; label: string }>;\n /** Description/hint for the field */\n description?: string;\n}\n\n/**\n * Schema describing how to prompt for rule options during installation\n */\nexport interface RuleOptionSchema {\n /** Fields that can be configured for this rule */\n fields: OptionFieldSchema[];\n}\n\n/**\n * External requirement that a rule needs to function\n */\nexport interface RuleRequirement {\n /** Requirement type for programmatic checks */\n type: \"ollama\" | \"git\" | \"coverage\" | \"semantic-index\" | \"styleguide\";\n /** Human-readable description */\n description: string;\n /** Optional: how to satisfy the requirement */\n setupHint?: string;\n}\n\n/**\n * Rule migration definition for updating rule options between versions\n */\nexport interface RuleMigration {\n /** Source version (semver) */\n from: string;\n /** Target version (semver) */\n to: string;\n /** Human-readable description of what changed */\n description: string;\n /** Function to migrate options from old format to new format */\n migrate: (oldOptions: unknown[]) => unknown[];\n /** Whether this migration contains breaking changes */\n breaking?: boolean;\n}\n\n/**\n * Colocated rule metadata - exported alongside each rule\n *\n * This structure keeps all rule metadata in the same file as the rule implementation,\n * making it easy to maintain and extend as new rules are added.\n */\nexport interface RuleMeta {\n /** Rule identifier (e.g., \"consistent-dark-mode\") - must match filename */\n id: string;\n\n /** Semantic version of the rule (e.g., \"1.0.0\") */\n version: string;\n\n /** Display name for CLI (e.g., \"No Arbitrary Tailwind\") */\n name: string;\n\n /** Short description for CLI selection prompts (one line) */\n description: string;\n\n /** Default severity level */\n defaultSeverity: \"error\" | \"warn\" | \"off\";\n\n /** Category for grouping in CLI */\n category: \"static\" | \"semantic\";\n\n /** Icon for display in CLI/UI (emoji or icon name) */\n icon?: string;\n\n /** Short hint about the rule type/requirements */\n hint?: string;\n\n /** Whether rule is enabled by default during install */\n defaultEnabled?: boolean;\n\n /** External requirements the rule needs */\n requirements?: RuleRequirement[];\n\n /**\n * NPM packages that must be installed for this rule to work.\n * These will be added to the target project's dependencies during installation.\n *\n * Example: [\"xxhash-wasm\"] for rules using the xxhash library\n */\n npmDependencies?: string[];\n\n /** Instructions to show after installation */\n postInstallInstructions?: string;\n\n /** Framework compatibility */\n frameworks?: (\"next\" | \"vite\" | \"cra\" | \"remix\")[];\n\n /** Whether this rule requires a styleguide file */\n requiresStyleguide?: boolean;\n\n /** Default options for the rule (passed as second element in ESLint config) */\n defaultOptions?: unknown[];\n\n /** Schema for prompting user to configure options during install */\n optionSchema?: RuleOptionSchema;\n\n /**\n * Detailed documentation in markdown format.\n * Should include:\n * - What the rule does\n * - Why it's useful\n * - Examples of incorrect and correct code\n * - Configuration options explained\n */\n docs: string;\n\n /**\n * Internal utility dependencies that this rule requires.\n * When the rule is copied to a target project, these utilities\n * will be transformed to import from \"uilint-eslint\" instead\n * of relative paths.\n *\n * Example: [\"coverage-aggregator\", \"dependency-graph\"]\n */\n internalDependencies?: string[];\n\n /**\n * Whether this rule is directory-based (has lib/ folder with utilities).\n * Directory-based rules are installed as folders with index.ts and lib/ subdirectory.\n * Single-file rules are installed as single .ts files.\n *\n * When true, ESLint config imports will use:\n * ./.uilint/rules/rule-id/index.js\n * When false (default):\n * ./.uilint/rules/rule-id.js\n */\n isDirectoryBased?: boolean;\n\n /**\n * Migrations for updating rule options between versions.\n * Migrations are applied in order to transform options from older versions.\n */\n migrations?: RuleMigration[];\n\n /**\n * Which UI plugin should handle this rule.\n * Defaults based on category:\n * - \"static\" category → \"eslint\" plugin\n * - \"semantic\" category → \"semantic\" plugin\n *\n * Special cases:\n * - \"vision\" for semantic-vision rule\n */\n plugin?: \"eslint\" | \"vision\" | \"semantic\";\n\n /**\n * Custom inspector panel ID to use for this rule's issues.\n * If not specified, uses the plugin's default issue inspector.\n *\n * Examples:\n * - \"vision-issue\" for VisionIssueInspector\n * - \"duplicates\" for DuplicatesInspector\n * - \"semantic-issue\" for SemanticIssueInspector\n */\n customInspector?: string;\n\n /**\n * Custom heatmap color for this rule's issues.\n * CSS color value (hex, rgb, hsl, or named color).\n * If not specified, uses severity-based coloring.\n */\n heatmapColor?: string;\n}\n\n/**\n * Helper to define rule metadata with type safety\n */\nexport function defineRuleMeta(meta: RuleMeta): RuleMeta {\n return meta;\n}\n","/**\n * Rule: consistent-dark-mode\n *\n * Ensures consistent dark mode theming in Tailwind CSS classes.\n * - Error: When some color classes have dark: variants but others don't within the same element\n * - Warning: When Tailwind color classes are used in a file but no dark: theming exists\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"inconsistentDarkMode\" | \"missingDarkMode\";\ntype Options = [\n {\n /** Whether to warn when no dark mode classes are found in a file that uses Tailwind colors. Default: true */\n warnOnMissingDarkMode?: boolean;\n }?\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"consistent-dark-mode\",\n version: \"1.0.0\",\n name: \"Consistent Dark Mode\",\n description: \"Ensure consistent dark: theming (error on mix, warn on missing)\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🌓\",\n hint: \"Ensures dark mode consistency\",\n defaultEnabled: true,\n defaultOptions: [{ warnOnMissingDarkMode: true }],\n optionSchema: {\n fields: [\n {\n key: \"warnOnMissingDarkMode\",\n label: \"Warn when elements lack dark: variant\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Enable warnings for elements missing dark mode variants\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects inconsistent dark mode theming in Tailwind CSS classes. Reports errors when\nsome color classes in an element have \\`dark:\\` variants but others don't, and optionally\nwarns when a file uses color classes without any dark mode theming.\n\n## Why it's useful\n\n- **Prevents broken dark mode**: Catches cases where some colors change in dark mode but others don't\n- **Encourages completeness**: Prompts you to add dark mode support where it's missing\n- **No false positives**: Only flags explicit Tailwind colors, not custom/CSS variable colors\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Some colors have dark variants, others don't\n<div className=\"bg-white dark:bg-slate-900 text-black\">\n// ^^^^^^^^^ missing dark: variant\n\n// Mix of themed and unthemed\n<button className=\"bg-blue-500 dark:bg-blue-600 border-gray-300\">\n// ^^^^^^^^^^^^^^^ missing dark: variant\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// All color classes have dark variants\n<div className=\"bg-white dark:bg-slate-900 text-black dark:text-white\">\n\n// Using semantic/custom colors (automatically themed via CSS variables)\n<div className=\"bg-background text-foreground\">\n<div className=\"bg-brand text-brand-foreground\">\n<div className=\"bg-primary text-primary-foreground\">\n\n// Consistent theming\n<button className=\"bg-blue-500 dark:bg-blue-600 border-gray-300 dark:border-gray-600\">\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/consistent-dark-mode\": [\"error\", {\n warnOnMissingDarkMode: true // Warn if file uses colors without any dark mode\n}]\n\\`\\`\\`\n\n## Notes\n\n- Only explicit Tailwind colors (like \\`blue-500\\`, \\`white\\`, \\`slate-900\\`) require dark variants\n- Custom/semantic colors (\\`background\\`, \\`foreground\\`, \\`brand\\`, \\`primary\\`, etc.) are exempt\n- These are assumed to be CSS variables that handle dark mode automatically\n- Transparent, inherit, and current values are exempt\n- Non-color utilities (like \\`text-lg\\`, \\`border-2\\`) are correctly ignored\n`,\n});\n\n// Color-related class prefixes that should have dark mode variants\nconst COLOR_PREFIXES = [\n \"bg-\",\n \"text-\",\n \"border-\",\n \"border-t-\",\n \"border-r-\",\n \"border-b-\",\n \"border-l-\",\n \"border-x-\",\n \"border-y-\",\n \"ring-\",\n \"ring-offset-\",\n \"divide-\",\n \"outline-\",\n \"shadow-\",\n \"accent-\",\n \"caret-\",\n \"fill-\",\n \"stroke-\",\n \"decoration-\",\n \"placeholder-\",\n \"from-\",\n \"via-\",\n \"to-\",\n];\n\n// Values that don't need dark variants (colorless or inherited)\nconst EXEMPT_SUFFIXES = [\"transparent\", \"inherit\", \"current\", \"auto\", \"none\"];\n\n// Built-in Tailwind CSS color palette names\n// These are the ONLY colors that should trigger dark mode warnings.\n// Custom colors (like 'brand', 'company-primary') are assumed to be\n// CSS variables that handle dark mode automatically.\nconst TAILWIND_COLOR_NAMES = new Set([\n // Special colors\n \"white\",\n \"black\",\n // Gray scale palettes\n \"slate\",\n \"gray\",\n \"zinc\",\n \"neutral\",\n \"stone\",\n // Warm colors\n \"red\",\n \"orange\",\n \"amber\",\n \"yellow\",\n // Green colors\n \"lime\",\n \"green\",\n \"emerald\",\n \"teal\",\n // Blue colors\n \"cyan\",\n \"sky\",\n \"blue\",\n \"indigo\",\n // Purple/Pink colors\n \"violet\",\n \"purple\",\n \"fuchsia\",\n \"pink\",\n \"rose\",\n]);\n\n/**\n * Check if a class has 'dark' in its variant chain\n */\nfunction hasDarkVariant(className: string): boolean {\n const parts = className.split(\":\");\n // All parts except the last are variants\n const variants = parts.slice(0, -1);\n return variants.includes(\"dark\");\n}\n\n/**\n * Get the base class (without any variants like hover:, dark:, md:, etc.)\n */\nfunction getBaseClass(className: string): string {\n const parts = className.split(\":\");\n return parts[parts.length - 1] || \"\";\n}\n\n/**\n * Find the color prefix this class uses, if any\n */\nfunction getColorPrefix(baseClass: string): string | null {\n // Sort by length descending to match more specific prefixes first\n // (e.g., \"border-t-\" before \"border-\")\n const sortedPrefixes = [...COLOR_PREFIXES].sort(\n (a, b) => b.length - a.length\n );\n return sortedPrefixes.find((p) => baseClass.startsWith(p)) || null;\n}\n\n/**\n * Check if the value is an explicit Tailwind color.\n * Uses an allowlist approach: only built-in Tailwind color names trigger warnings.\n * Custom colors (like 'brand', 'primary', 'company-blue') are assumed to be\n * CSS variables that handle dark mode automatically and should NOT trigger.\n *\n * Matches patterns like:\n * - white, black (standalone colors)\n * - blue-500, slate-900 (color-scale)\n * - blue-500/50, gray-900/80 (with opacity modifier)\n */\nfunction isTailwindColor(value: string): boolean {\n // Remove opacity modifier if present (e.g., \"blue-500/50\" -> \"blue-500\")\n const valueWithoutOpacity = value.split(\"/\")[0] || value;\n\n // Check for standalone colors (white, black)\n if (TAILWIND_COLOR_NAMES.has(valueWithoutOpacity)) {\n return true;\n }\n\n // Check for color-scale pattern (e.g., \"blue-500\", \"slate-900\")\n // Pattern: colorName-number where number is 50, 100, 200, ..., 950\n const match = valueWithoutOpacity.match(/^([a-z]+)-(\\d+)$/);\n if (match) {\n const colorName = match[1];\n const scale = match[2];\n // Valid Tailwind scales are: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950\n const validScales = [\n \"50\",\n \"100\",\n \"200\",\n \"300\",\n \"400\",\n \"500\",\n \"600\",\n \"700\",\n \"800\",\n \"900\",\n \"950\",\n ];\n if (colorName && TAILWIND_COLOR_NAMES.has(colorName) && validScales.includes(scale || \"\")) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if the value after the prefix looks like an explicit Tailwind color.\n * Uses allowlist approach: only built-in Tailwind colors should trigger dark mode warnings.\n * Custom/semantic colors (brand, primary, foreground, etc.) are NOT flagged.\n */\nfunction isColorValue(baseClass: string, prefix: string): boolean {\n const value = baseClass.slice(prefix.length);\n\n // Empty value is not a color\n if (!value) {\n return false;\n }\n\n // Only flag explicit Tailwind colors\n // Custom colors, CSS variable colors, and semantic colors are exempt\n return isTailwindColor(value);\n}\n\n/**\n * Check if a class is exempt from dark mode requirements\n */\nfunction isExempt(baseClass: string): boolean {\n return EXEMPT_SUFFIXES.some((suffix) => baseClass.endsWith(suffix));\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"consistent-dark-mode\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Ensure consistent dark mode theming in Tailwind classes\",\n },\n messages: {\n inconsistentDarkMode:\n \"Inconsistent dark mode: '{{unthemed}}' lack dark: variants while other color classes have them.\",\n missingDarkMode:\n \"No dark mode theming detected. Consider adding dark: variants for color classes.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n warnOnMissingDarkMode: {\n type: \"boolean\",\n description:\n \"Whether to warn when no dark mode classes are found in a file that uses Tailwind colors\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ warnOnMissingDarkMode: true }],\n create(context) {\n const options = context.options[0] || {};\n const warnOnMissingDarkMode = options.warnOnMissingDarkMode ?? true;\n\n let fileHasColorClasses = false;\n let fileHasDarkMode = false;\n const reportedNodes = new Set<TSESTree.Node>();\n\n function checkClassString(node: TSESTree.Node, classString: string) {\n const classes = classString.split(/\\s+/).filter(Boolean);\n if (classes.length === 0) return;\n\n // Track usage per color prefix: { hasLight, hasDark, lightClasses }\n const prefixUsage = new Map<\n string,\n { hasLight: boolean; hasDark: boolean; lightClasses: string[] }\n >();\n\n for (const cls of classes) {\n const baseClass = getBaseClass(cls);\n const prefix = getColorPrefix(baseClass);\n\n if (!prefix) continue;\n if (isExempt(baseClass)) continue;\n\n // Verify this is actually a color class, not something like text-lg\n if (!isColorValue(baseClass, prefix)) continue;\n\n if (!prefixUsage.has(prefix)) {\n prefixUsage.set(prefix, {\n hasLight: false,\n hasDark: false,\n lightClasses: [],\n });\n }\n\n const usage = prefixUsage.get(prefix)!;\n\n if (hasDarkVariant(cls)) {\n usage.hasDark = true;\n fileHasDarkMode = true;\n } else {\n usage.hasLight = true;\n usage.lightClasses.push(cls);\n }\n }\n\n // Track if file uses color classes\n if (prefixUsage.size > 0) {\n fileHasColorClasses = true;\n }\n\n // Check for inconsistency: some prefixes have dark variants, others don't\n const entries = Array.from(prefixUsage.entries());\n const hasSomeDark = entries.some(([_, u]) => u.hasDark);\n\n if (hasSomeDark) {\n const unthemedEntries = entries.filter(\n ([_, usage]) => usage.hasLight && !usage.hasDark\n );\n\n if (unthemedEntries.length > 0 && !reportedNodes.has(node)) {\n reportedNodes.add(node);\n // Collect the actual class names that lack dark variants\n const unthemedClasses = unthemedEntries.flatMap(\n ([_, u]) => u.lightClasses\n );\n\n context.report({\n node,\n messageId: \"inconsistentDarkMode\",\n data: { unthemed: unthemedClasses.join(\", \") },\n });\n }\n }\n }\n\n function processStringValue(node: TSESTree.Node, value: string) {\n checkClassString(node, value);\n }\n\n function processTemplateLiteral(node: TSESTree.TemplateLiteral) {\n for (const quasi of node.quasis) {\n checkClassString(quasi, quasi.value.raw);\n }\n }\n\n return {\n // Check className attributes in JSX\n JSXAttribute(node) {\n if (\n node.name.type === \"JSXIdentifier\" &&\n (node.name.name === \"className\" || node.name.name === \"class\")\n ) {\n const value = node.value;\n\n // Handle string literal: className=\"...\"\n if (value?.type === \"Literal\" && typeof value.value === \"string\") {\n processStringValue(value, value.value);\n }\n\n // Handle JSX expression: className={...}\n if (value?.type === \"JSXExpressionContainer\") {\n const expr = value.expression;\n\n // Direct string: className={\"...\"}\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n processStringValue(expr, expr.value);\n }\n\n // Template literal: className={`...`}\n if (expr.type === \"TemplateLiteral\") {\n processTemplateLiteral(expr);\n }\n }\n }\n },\n\n // Check cn(), clsx(), classnames(), cva() calls\n CallExpression(node) {\n if (node.callee.type !== \"Identifier\") return;\n const name = node.callee.name;\n\n if (\n name === \"cn\" ||\n name === \"clsx\" ||\n name === \"classnames\" ||\n name === \"cva\" ||\n name === \"twMerge\"\n ) {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n processStringValue(arg, arg.value);\n }\n if (arg.type === \"TemplateLiteral\") {\n processTemplateLiteral(arg);\n }\n // Handle arrays of class strings\n if (arg.type === \"ArrayExpression\") {\n for (const element of arg.elements) {\n if (\n element?.type === \"Literal\" &&\n typeof element.value === \"string\"\n ) {\n processStringValue(element, element.value);\n }\n if (element?.type === \"TemplateLiteral\") {\n processTemplateLiteral(element);\n }\n }\n }\n }\n }\n },\n\n // At the end of the file, check if Tailwind colors are used without any dark mode\n \"Program:exit\"(node) {\n if (warnOnMissingDarkMode && fileHasColorClasses && !fileHasDarkMode) {\n context.report({\n node,\n messageId: \"missingDarkMode\",\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: no-direct-store-import\n *\n * Forbids direct Zustand store imports - prefer using hooks via context.\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"noDirectImport\";\ntype Options = [\n {\n storePattern?: string;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-direct-store-import\",\n version: \"1.0.0\",\n name: \"No Direct Store Import\",\n description: \"Forbid direct Zustand store imports (use context hooks)\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🏪\",\n hint: \"Encourages testable store access\",\n defaultEnabled: true,\n defaultOptions: [{ storePattern: \"use*Store\" }],\n optionSchema: {\n fields: [\n {\n key: \"storePattern\",\n label: \"Glob pattern for store files\",\n type: \"text\",\n defaultValue: \"use*Store\",\n placeholder: \"use*Store\",\n description: \"Pattern to match store file names\",\n },\n ],\n },\n docs: `\n## What it does\n\nPrevents direct imports of Zustand stores, encouraging the use of context-based hooks\nfor better dependency injection and testability.\n\n## Why it's useful\n\n- **Testability**: Context-based access allows easy mocking in tests\n- **Flexibility**: Store implementation can change without updating all consumers\n- **Dependency Injection**: Stores can be provided at different levels of the component tree\n- **Server Components**: Helps avoid accidentally importing stores in server components\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Directly importing the store\nimport { useAuthStore } from '../stores/auth-store';\nimport { useCartStore } from '@/stores/useCartStore';\n\nfunction MyComponent() {\n const user = useAuthStore((s) => s.user);\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using context-provided hooks\nimport { useAuth } from '../contexts/auth-context';\nimport { useCart } from '@/hooks/useCart';\n\nfunction MyComponent() {\n const { user } = useAuth();\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-direct-store-import\": [\"warn\", {\n storePattern: \"use*Store\" // Pattern to match store names\n}]\n\\`\\`\\`\n\n## Notes\n\n- The pattern uses glob syntax (\\`*\\` matches any characters)\n- Only triggers for imports from paths containing \"store\"\n- Works with both named and default imports\n`,\n});\n\n// Convert glob pattern to regex\nfunction patternToRegex(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\");\n return new RegExp(`^${escaped}$`);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-direct-store-import\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Forbid direct Zustand store imports (use hooks via context)\",\n },\n messages: {\n noDirectImport:\n \"Avoid importing store '{{name}}' directly. Use the store via a context hook instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n storePattern: {\n type: \"string\",\n description: \"Glob pattern for store names\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ storePattern: \"use*Store\" }],\n create(context) {\n const options = context.options[0] || {};\n const pattern = options.storePattern || \"use*Store\";\n const regex = patternToRegex(pattern);\n\n return {\n ImportDeclaration(node) {\n // Check if importing from a store file\n const source = node.source.value as string;\n if (!source.includes(\"store\")) return;\n\n // Check imported specifiers\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportSpecifier\") {\n const importedName =\n specifier.imported.type === \"Identifier\"\n ? specifier.imported.name\n : specifier.imported.value;\n\n if (regex.test(importedName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: importedName },\n });\n }\n }\n\n if (specifier.type === \"ImportDefaultSpecifier\") {\n const localName = specifier.local.name;\n if (regex.test(localName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: localName },\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: prefer-zustand-state-management\n *\n * Detects excessive use of React state hooks (useState, useReducer, useContext)\n * in components and suggests using Zustand stores for better state management.\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"excessiveStateHooks\";\ntype Options = [\n {\n /** Maximum number of state hooks before warning. Default: 3 */\n maxStateHooks?: number;\n /** Whether to count useState calls. Default: true */\n countUseState?: boolean;\n /** Whether to count useReducer calls. Default: true */\n countUseReducer?: boolean;\n /** Whether to count useContext calls. Default: true */\n countUseContext?: boolean;\n }?\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"prefer-zustand-state-management\",\n version: \"1.0.0\",\n name: \"Prefer Zustand State Management\",\n description: \"Detect excessive useState/useReducer/useContext; suggest Zustand\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🐻\",\n hint: \"Suggests centralized state management\",\n defaultEnabled: true,\n defaultOptions: [\n {\n maxStateHooks: 3,\n countUseState: true,\n countUseReducer: true,\n countUseContext: true,\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"maxStateHooks\",\n label: \"Max state hooks before warning\",\n type: \"number\",\n defaultValue: 3,\n placeholder: \"3\",\n description: \"Maximum number of state hooks allowed before warning\",\n },\n {\n key: \"countUseState\",\n label: \"Count useState hooks\",\n type: \"boolean\",\n defaultValue: true,\n },\n {\n key: \"countUseReducer\",\n label: \"Count useReducer hooks\",\n type: \"boolean\",\n defaultValue: true,\n },\n {\n key: \"countUseContext\",\n label: \"Count useContext hooks\",\n type: \"boolean\",\n defaultValue: true,\n },\n ],\n },\n docs: `\n## What it does\n\nDetects components that use many React state hooks (\\`useState\\`, \\`useReducer\\`, \\`useContext\\`)\nand suggests consolidating state into a Zustand store for better maintainability.\n\n## Why it's useful\n\n- **Simplifies components**: Fewer hooks means less cognitive overhead\n- **Centralizes state**: Related state lives together in a store\n- **Better performance**: Zustand's selector pattern prevents unnecessary re-renders\n- **Easier testing**: Store logic can be tested independently of components\n\n## Examples\n\n### ❌ Incorrect (with default maxStateHooks: 3)\n\n\\`\\`\\`tsx\nfunction UserProfile() {\n const [name, setName] = useState('');\n const [email, setEmail] = useState('');\n const [avatar, setAvatar] = useState(null);\n const [isLoading, setIsLoading] = useState(false); // 4 hooks = warning\n // ...\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using a Zustand store\nconst useUserStore = create((set) => ({\n name: '',\n email: '',\n avatar: null,\n isLoading: false,\n setName: (name) => set({ name }),\n // ...\n}));\n\nfunction UserProfile() {\n const { name, email, avatar, isLoading } = useUserStore();\n // Much cleaner!\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/prefer-zustand-state-management\": [\"warn\", {\n maxStateHooks: 3, // Warn when exceeding this count\n countUseState: true, // Include useState in count\n countUseReducer: true, // Include useReducer in count\n countUseContext: true // Include useContext in count\n}]\n\\`\\`\\`\n\n## Notes\n\n- Custom hooks (starting with \\`use\\` lowercase) are exempt from this rule\n- Only counts hooks at the top level of the component, not in nested functions\n- Adjust \\`maxStateHooks\\` based on your team's preferences\n`,\n});\n\ninterface ComponentInfo {\n name: string;\n node: TSESTree.Node;\n hookCount: number;\n functionNode:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression;\n}\n\nconst STATE_HOOKS = new Set([\"useState\", \"useReducer\", \"useContext\"]);\n\nexport default createRule<Options, MessageIds>({\n name: \"prefer-zustand-state-management\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Detect excessive use of React state hooks and suggest Zustand stores\",\n },\n messages: {\n excessiveStateHooks:\n \"Component '{{component}}' has {{count}} state hooks (max: {{max}}). Consider using a Zustand store for state management.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxStateHooks: {\n type: \"number\",\n minimum: 1,\n description: \"Maximum number of state hooks before warning\",\n },\n countUseState: {\n type: \"boolean\",\n description: \"Whether to count useState calls\",\n },\n countUseReducer: {\n type: \"boolean\",\n description: \"Whether to count useReducer calls\",\n },\n countUseContext: {\n type: \"boolean\",\n description: \"Whether to count useContext calls\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n maxStateHooks: 3,\n countUseState: true,\n countUseReducer: true,\n countUseContext: true,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const maxStateHooks = options.maxStateHooks ?? 3;\n const countUseState = options.countUseState ?? true;\n const countUseReducer = options.countUseReducer ?? true;\n const countUseContext = options.countUseContext ?? true;\n\n // Stack to track current component context\n const componentStack: ComponentInfo[] = [];\n\n // Set of function nodes we've identified as components to check\n const componentFunctions = new Map<TSESTree.Node, ComponentInfo>();\n\n /**\n * Check if a function name indicates a React component (PascalCase)\n */\n function isComponentName(name: string | null | undefined): boolean {\n if (!name) return false;\n // Components start with uppercase, hooks start with lowercase \"use\"\n return /^[A-Z]/.test(name);\n }\n\n /**\n * Check if a function name indicates a custom hook (starts with \"use\")\n */\n function isCustomHookName(name: string | null | undefined): boolean {\n if (!name) return false;\n return /^use[A-Z]/.test(name);\n }\n\n /**\n * Get the name of a function from various declaration patterns\n */\n function getFunctionName(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression\n ): string | null {\n // Function declaration: function MyComponent() {}\n if (node.type === \"FunctionDeclaration\" && node.id) {\n return node.id.name;\n }\n\n // Check parent for variable declaration: const MyComponent = () => {}\n const parent = node.parent;\n\n if (\n parent?.type === \"VariableDeclarator\" &&\n parent.id.type === \"Identifier\"\n ) {\n return parent.id.name;\n }\n\n // Check for forwardRef/memo: const MyComponent = forwardRef(function MyComponent() {})\n // or const MyComponent = forwardRef(() => {})\n if (parent?.type === \"CallExpression\") {\n const callParent = parent.parent;\n if (\n callParent?.type === \"VariableDeclarator\" &&\n callParent.id.type === \"Identifier\"\n ) {\n return callParent.id.name;\n }\n }\n\n // Named function expression: const x = function MyComponent() {}\n if (node.type === \"FunctionExpression\" && node.id) {\n return node.id.name;\n }\n\n return null;\n }\n\n /**\n * Check if a hook call should be counted based on options\n */\n function shouldCountHook(hookName: string): boolean {\n switch (hookName) {\n case \"useState\":\n return countUseState;\n case \"useReducer\":\n return countUseReducer;\n case \"useContext\":\n return countUseContext;\n default:\n return false;\n }\n }\n\n /**\n * Get hook name from a call expression (handles both useState and React.useState)\n */\n function getHookName(callee: TSESTree.Expression): string | null {\n // Direct call: useState()\n if (callee.type === \"Identifier\" && STATE_HOOKS.has(callee.name)) {\n return callee.name;\n }\n\n // Member expression: React.useState()\n if (\n callee.type === \"MemberExpression\" &&\n callee.object.type === \"Identifier\" &&\n callee.object.name === \"React\" &&\n callee.property.type === \"Identifier\" &&\n STATE_HOOKS.has(callee.property.name)\n ) {\n return callee.property.name;\n }\n\n return null;\n }\n\n /**\n * Check if we're directly inside a component function (not in a nested function)\n */\n function isDirectChildOfComponent(\n node: TSESTree.Node,\n componentNode: TSESTree.Node\n ): boolean {\n let current: TSESTree.Node | undefined = node.parent;\n\n while (current) {\n // If we hit the component node, we're a direct child\n if (current === componentNode) {\n return true;\n }\n\n // If we hit another function first, we're nested\n if (\n current.type === \"FunctionDeclaration\" ||\n current.type === \"FunctionExpression\" ||\n current.type === \"ArrowFunctionExpression\"\n ) {\n return false;\n }\n\n current = current.parent;\n }\n\n return false;\n }\n\n /**\n * Enter a function that might be a component\n */\n function enterFunction(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression\n ) {\n const name = getFunctionName(node);\n\n // Skip custom hooks - they're allowed to have many state hooks\n if (isCustomHookName(name)) {\n return;\n }\n\n // Skip non-component functions (lowercase names that aren't anonymous)\n if (name && !isComponentName(name)) {\n return;\n }\n\n // Track this as a potential component\n const componentInfo: ComponentInfo = {\n name: name || \"AnonymousComponent\",\n node,\n hookCount: 0,\n functionNode: node,\n };\n\n componentStack.push(componentInfo);\n componentFunctions.set(node, componentInfo);\n }\n\n /**\n * Exit a function and report if it had too many hooks\n */\n function exitFunction(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression\n ) {\n const componentInfo = componentFunctions.get(node);\n\n if (!componentInfo) {\n return;\n }\n\n // Remove from stack\n const index = componentStack.findIndex((c) => c.functionNode === node);\n if (index !== -1) {\n componentStack.splice(index, 1);\n }\n\n // Check if exceeded threshold\n if (componentInfo.hookCount > maxStateHooks) {\n context.report({\n node: componentInfo.node,\n messageId: \"excessiveStateHooks\",\n data: {\n component: componentInfo.name,\n count: componentInfo.hookCount,\n max: maxStateHooks,\n },\n });\n }\n\n componentFunctions.delete(node);\n }\n\n return {\n FunctionDeclaration: enterFunction,\n FunctionExpression: enterFunction,\n ArrowFunctionExpression: enterFunction,\n \"FunctionDeclaration:exit\": exitFunction,\n \"FunctionExpression:exit\": exitFunction,\n \"ArrowFunctionExpression:exit\": exitFunction,\n\n CallExpression(node) {\n const hookName = getHookName(node.callee);\n\n if (!hookName || !shouldCountHook(hookName)) {\n return;\n }\n\n // Find the innermost component this hook belongs to\n // We iterate from the end to find the most recent (innermost) component\n for (let i = componentStack.length - 1; i >= 0; i--) {\n const component = componentStack[i];\n\n if (isDirectChildOfComponent(node, component.functionNode)) {\n component.hookCount++;\n break;\n }\n }\n },\n };\n },\n});\n","/**\n * Export Resolver\n *\n * Resolves import paths and finds export definitions, following re-exports\n * to their original source files.\n */\n\nimport { ResolverFactory } from \"oxc-resolver\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport { readFileSync, existsSync } from \"fs\";\nimport { dirname, join, extname } from \"path\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\n// Module-level resolver instance (reused across calls)\nlet resolverInstance: ReturnType<typeof ResolverFactory.prototype.sync> | null =\n null;\nlet resolverFactory: ResolverFactory | null = null;\n\n/**\n * Information about a resolved export\n */\nexport interface ResolvedExport {\n /** The name of the export (e.g., \"Button\") */\n name: string;\n /** Absolute path to the file containing the actual definition */\n filePath: string;\n /** The local name in the source file (may differ from export name) */\n localName: string;\n /** Whether this is a re-export (export { X } from './other') */\n isReexport: boolean;\n}\n\n/**\n * Cache for file exports to avoid re-parsing\n */\nconst exportCache = new Map<\n string,\n Map<string, { localName: string; reexportSource?: string }>\n>();\n\n/**\n * Cache for parsed ASTs\n */\nconst astCache = new Map<string, TSESTree.Program>();\n\n/**\n * Cache for resolved paths\n */\nconst resolvedPathCache = new Map<string, string | null>();\n\n/**\n * Get or create the resolver factory\n */\nfunction getResolverFactory(): ResolverFactory {\n if (!resolverFactory) {\n resolverFactory = new ResolverFactory({\n extensions: [\".tsx\", \".ts\", \".jsx\", \".js\"],\n mainFields: [\"module\", \"main\"],\n conditionNames: [\"import\", \"require\", \"node\", \"default\"],\n // Enable TypeScript path resolution\n tsconfig: {\n configFile: \"tsconfig.json\",\n references: \"auto\",\n },\n });\n }\n return resolverFactory;\n}\n\n/**\n * Resolve an import path to an absolute file path\n */\nexport function resolveImportPath(\n importSource: string,\n fromFile: string\n): string | null {\n const cacheKey = `${fromFile}::${importSource}`;\n\n if (resolvedPathCache.has(cacheKey)) {\n return resolvedPathCache.get(cacheKey) ?? null;\n }\n\n // Skip node_modules\n if (\n importSource.startsWith(\"react\") ||\n importSource.startsWith(\"next\") ||\n (!importSource.startsWith(\".\") &&\n !importSource.startsWith(\"@/\") &&\n !importSource.startsWith(\"~/\"))\n ) {\n // Check if it's a known external package\n if (\n importSource.includes(\"@mui/\") ||\n importSource.includes(\"@chakra-ui/\") ||\n importSource.includes(\"antd\") ||\n importSource.includes(\"@radix-ui/\")\n ) {\n // Return a marker for external packages - we don't resolve them but track them\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n\n try {\n const factory = getResolverFactory();\n const fromDir = dirname(fromFile);\n const result = factory.sync(fromDir, importSource);\n\n if (result.path) {\n resolvedPathCache.set(cacheKey, result.path);\n return result.path;\n }\n } catch {\n // Fallback: try manual resolution for common patterns\n const resolved = manualResolve(importSource, fromFile);\n resolvedPathCache.set(cacheKey, resolved);\n return resolved;\n }\n\n resolvedPathCache.set(cacheKey, null);\n return null;\n}\n\n/**\n * Manual fallback resolution for common patterns\n */\nfunction manualResolve(importSource: string, fromFile: string): string | null {\n const fromDir = dirname(fromFile);\n const extensions = [\".tsx\", \".ts\", \".jsx\", \".js\"];\n\n // Handle @/ alias - find tsconfig and resolve\n if (importSource.startsWith(\"@/\")) {\n const projectRoot = findProjectRoot(fromFile);\n if (projectRoot) {\n const relativePath = importSource.slice(2); // Remove @/\n for (const ext of extensions) {\n const candidate = join(projectRoot, relativePath + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(projectRoot, relativePath, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n }\n\n // Handle relative imports\n if (importSource.startsWith(\".\")) {\n for (const ext of extensions) {\n const candidate = join(fromDir, importSource + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(fromDir, importSource, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Find the project root by looking for tsconfig.json or package.json\n */\nfunction findProjectRoot(fromFile: string): string | null {\n let dir = dirname(fromFile);\n const root = \"/\";\n\n while (dir !== root) {\n if (existsSync(join(dir, \"tsconfig.json\"))) {\n return dir;\n }\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n\n return null;\n}\n\n/**\n * Parse a file and cache the AST\n */\nexport function parseFile(filePath: string): TSESTree.Program | null {\n if (astCache.has(filePath)) {\n return astCache.get(filePath)!;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n });\n astCache.set(filePath, ast);\n return ast;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract export information from a file\n */\nfunction extractExports(\n filePath: string\n): Map<string, { localName: string; reexportSource?: string }> {\n if (exportCache.has(filePath)) {\n return exportCache.get(filePath)!;\n }\n\n const exports = new Map<\n string,\n { localName: string; reexportSource?: string }\n >();\n const ast = parseFile(filePath);\n\n if (!ast) {\n exportCache.set(filePath, exports);\n return exports;\n }\n\n for (const node of ast.body) {\n // Handle: export function Button() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(node.declaration.id.name, {\n localName: node.declaration.id.name,\n });\n }\n\n // Handle: export const Button = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (decl.id.type === \"Identifier\") {\n exports.set(decl.id.name, { localName: decl.id.name });\n }\n }\n }\n\n // Handle: export { Button } or export { Button as Btn }\n if (node.type === \"ExportNamedDeclaration\" && node.specifiers.length > 0) {\n const source = node.source?.value as string | undefined;\n for (const spec of node.specifiers) {\n if (spec.type === \"ExportSpecifier\") {\n const exportedName =\n spec.exported.type === \"Identifier\"\n ? spec.exported.name\n : spec.exported.value;\n const localName =\n spec.local.type === \"Identifier\"\n ? spec.local.name\n : spec.local.value;\n\n exports.set(exportedName, {\n localName,\n reexportSource: source,\n });\n }\n }\n }\n\n // Handle: export default function Button() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(\"default\", { localName: node.declaration.id.name });\n }\n\n // Handle: export default Button\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"Identifier\"\n ) {\n exports.set(\"default\", { localName: node.declaration.name });\n }\n }\n\n exportCache.set(filePath, exports);\n return exports;\n}\n\n/**\n * Resolve an export to its original definition, following re-exports\n */\nexport function resolveExport(\n exportName: string,\n filePath: string,\n visited = new Set<string>()\n): ResolvedExport | null {\n // Cycle detection\n const key = `${filePath}::${exportName}`;\n if (visited.has(key)) {\n return null;\n }\n visited.add(key);\n\n const exports = extractExports(filePath);\n const exportInfo = exports.get(exportName);\n\n if (!exportInfo) {\n return null;\n }\n\n // If it's a re-export, follow the chain\n if (exportInfo.reexportSource) {\n const resolvedPath = resolveImportPath(exportInfo.reexportSource, filePath);\n if (resolvedPath) {\n return resolveExport(exportInfo.localName, resolvedPath, visited);\n }\n return null;\n }\n\n // This is the actual definition\n return {\n name: exportName,\n filePath,\n localName: exportInfo.localName,\n isReexport: false,\n };\n}\n\n/**\n * Clear all caches (useful for testing or watch mode)\n */\nexport function clearResolverCaches(): void {\n exportCache.clear();\n astCache.clear();\n resolvedPathCache.clear();\n}\n","/**\n * Component Parser\n *\n * Parses a single component's body to extract styling information\n * and identify nested component usage.\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { parseFile } from \"./export-resolver.js\";\n\n/**\n * Known UI library import patterns\n */\nexport type LibraryName = \"shadcn\" | \"mui\" | \"chakra\" | \"antd\";\n\nexport const LIBRARY_PATTERNS: Record<LibraryName, string[]> = {\n shadcn: [\"@/components/ui\", \"@radix-ui/\", \"components/ui/\"],\n mui: [\"@mui/material\", \"@mui/icons-material\", \"@emotion/\"],\n chakra: [\"@chakra-ui/\"],\n antd: [\"antd\", \"@ant-design/\"],\n};\n\n/**\n * Information about a component used within another component\n */\nexport interface UsedComponent {\n /** Component name (e.g., \"Button\", \"Card\") */\n name: string;\n /** Import source path (e.g., \"@mui/material\", \"./button\") */\n importSource: string;\n /** Line number where the component is used */\n line: number;\n /** Column number where the component is used */\n column: number;\n}\n\n/**\n * Styling information extracted from a component\n */\nexport interface ComponentStyleInfo {\n /** Tailwind classes used in the component */\n tailwindClasses: string[];\n /** Inline style objects (as string representations) */\n inlineStyles: string[];\n /** Other components used within this component */\n usedComponents: UsedComponent[];\n /** Directly detected library (from import source) */\n directLibrary: LibraryName | null;\n}\n\n/**\n * Import map for a file: localName -> importSource\n */\nexport type ImportMap = Map<string, string>;\n\n/**\n * Extract imports from a file's AST\n */\nexport function extractImports(ast: TSESTree.Program): ImportMap {\n const imports = new Map<string, string>();\n\n for (const node of ast.body) {\n if (node.type === \"ImportDeclaration\") {\n const source = node.source.value as string;\n for (const spec of node.specifiers) {\n if (spec.type === \"ImportSpecifier\") {\n imports.set(spec.local.name, source);\n } else if (spec.type === \"ImportDefaultSpecifier\") {\n imports.set(spec.local.name, source);\n } else if (spec.type === \"ImportNamespaceSpecifier\") {\n imports.set(spec.local.name, source);\n }\n }\n }\n }\n\n return imports;\n}\n\n/**\n * Detect which UI library an import source belongs to\n */\nexport function detectLibraryFromSource(\n importSource: string\n): LibraryName | null {\n for (const [library, patterns] of Object.entries(LIBRARY_PATTERNS)) {\n if (patterns.some((p) => importSource.includes(p))) {\n return library as LibraryName;\n }\n }\n return null;\n}\n\n/**\n * Find a function/arrow function component definition by name in an AST\n */\nexport function findComponentDefinition(\n ast: TSESTree.Program,\n componentName: string\n): TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | null {\n for (const node of ast.body) {\n // export function ComponentName() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id?.name === componentName\n ) {\n return node.declaration;\n }\n\n // export const ComponentName = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (\n decl.id.type === \"Identifier\" &&\n decl.id.name === componentName &&\n decl.init?.type === \"ArrowFunctionExpression\"\n ) {\n return decl.init;\n }\n }\n }\n\n // function ComponentName() {} (not exported directly)\n if (\n node.type === \"FunctionDeclaration\" &&\n node.id?.name === componentName\n ) {\n return node;\n }\n\n // const ComponentName = () => {}\n if (node.type === \"VariableDeclaration\") {\n for (const decl of node.declarations) {\n if (\n decl.id.type === \"Identifier\" &&\n decl.id.name === componentName &&\n decl.init?.type === \"ArrowFunctionExpression\"\n ) {\n return decl.init;\n }\n }\n }\n\n // export default function ComponentName() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\" &&\n node.declaration.id?.name === componentName\n ) {\n return node.declaration;\n }\n }\n\n return null;\n}\n\n/**\n * Extract Tailwind classes from a className string\n */\nfunction extractTailwindClasses(classString: string): string[] {\n return classString.split(/\\s+/).filter(Boolean);\n}\n\n/**\n * Recursively traverse a node and extract styling info\n */\nfunction traverseForStyling(\n node: TSESTree.Node,\n imports: ImportMap,\n result: ComponentStyleInfo\n): void {\n if (!node || typeof node !== \"object\") return;\n\n // Handle JSX elements\n if (node.type === \"JSXElement\" && node.openingElement) {\n const opening = node.openingElement;\n\n // Check if this is a component (PascalCase) or HTML element\n if (\n opening.name.type === \"JSXIdentifier\" &&\n /^[A-Z]/.test(opening.name.name)\n ) {\n const componentName = opening.name.name;\n const importSource = imports.get(componentName);\n\n if (importSource) {\n result.usedComponents.push({\n name: componentName,\n importSource,\n line: opening.loc.start.line,\n column: opening.loc.start.column,\n });\n\n // Check if this import is from a known UI library\n const library = detectLibraryFromSource(importSource);\n if (library && !result.directLibrary) {\n result.directLibrary = library;\n }\n }\n }\n\n // Handle JSX member expressions like Modal.Header\n if (opening.name.type === \"JSXMemberExpression\") {\n let objectName: string | null = null;\n let current = opening.name.object;\n while (current.type === \"JSXMemberExpression\") {\n current = current.object;\n }\n if (current.type === \"JSXIdentifier\") {\n objectName = current.name;\n }\n\n if (objectName) {\n const importSource = imports.get(objectName);\n if (importSource) {\n const library = detectLibraryFromSource(importSource);\n if (library && !result.directLibrary) {\n result.directLibrary = library;\n }\n }\n }\n }\n\n // Extract className/class attributes\n for (const attr of opening.attributes) {\n if (\n attr.type === \"JSXAttribute\" &&\n attr.name.type === \"JSXIdentifier\" &&\n (attr.name.name === \"className\" || attr.name.name === \"class\")\n ) {\n if (\n attr.value?.type === \"Literal\" &&\n typeof attr.value.value === \"string\"\n ) {\n result.tailwindClasses.push(\n ...extractTailwindClasses(attr.value.value)\n );\n }\n if (attr.value?.type === \"JSXExpressionContainer\") {\n const expr = attr.value.expression;\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n result.tailwindClasses.push(...extractTailwindClasses(expr.value));\n }\n if (expr.type === \"TemplateLiteral\") {\n for (const quasi of expr.quasis) {\n result.tailwindClasses.push(\n ...extractTailwindClasses(quasi.value.raw)\n );\n }\n }\n }\n }\n\n // Extract inline styles\n if (\n attr.type === \"JSXAttribute\" &&\n attr.name.type === \"JSXIdentifier\" &&\n attr.name.name === \"style\"\n ) {\n if (attr.value?.type === \"JSXExpressionContainer\") {\n // Just note that there's an inline style - we don't parse the object\n result.inlineStyles.push(\"[inline style]\");\n }\n }\n }\n }\n\n // Handle cn(), clsx(), twMerge() calls\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"Identifier\" &&\n [\"cn\", \"clsx\", \"classnames\", \"twMerge\"].includes(node.callee.name)\n ) {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n result.tailwindClasses.push(...extractTailwindClasses(arg.value));\n }\n if (arg.type === \"TemplateLiteral\") {\n for (const quasi of arg.quasis) {\n result.tailwindClasses.push(\n ...extractTailwindClasses(quasi.value.raw)\n );\n }\n }\n }\n }\n\n // Recursively traverse all properties\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n\n const child = (node as unknown as Record<string, unknown>)[key];\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\") {\n traverseForStyling(item as TSESTree.Node, imports, result);\n }\n }\n } else if (child && typeof child === \"object\") {\n traverseForStyling(child as TSESTree.Node, imports, result);\n }\n }\n}\n\n/**\n * Parse a component's body and extract styling information\n */\nexport function parseComponentBody(\n filePath: string,\n componentName: string\n): ComponentStyleInfo | null {\n const ast = parseFile(filePath);\n if (!ast) return null;\n\n const imports = extractImports(ast);\n const componentDef = findComponentDefinition(ast, componentName);\n\n if (!componentDef) {\n return null;\n }\n\n const result: ComponentStyleInfo = {\n tailwindClasses: [],\n inlineStyles: [],\n usedComponents: [],\n directLibrary: null,\n };\n\n // Traverse the component body\n if (componentDef.body) {\n traverseForStyling(componentDef.body, imports, result);\n }\n\n // Deduplicate classes\n result.tailwindClasses = [...new Set(result.tailwindClasses)];\n\n return result;\n}\n\n/**\n * Analyze a file and extract all component usages with their libraries\n * (used for the entry file analysis)\n */\nexport function analyzeFileImports(\n filePath: string\n): Map<string, { importSource: string; library: LibraryName | null }> {\n const ast = parseFile(filePath);\n if (!ast) return new Map();\n\n const result = new Map<\n string,\n { importSource: string; library: LibraryName | null }\n >();\n const imports = extractImports(ast);\n\n for (const [name, source] of imports) {\n result.set(name, {\n importSource: source,\n library: detectLibraryFromSource(source),\n });\n }\n\n return result;\n}\n","/**\n * Import Graph Service\n *\n * Provides demand-driven cross-file analysis to detect UI library usage\n * across component trees. Uses in-memory caching for performance.\n */\n\nimport {\n resolveImportPath,\n resolveExport,\n clearResolverCaches,\n} from \"./export-resolver.js\";\nimport {\n parseComponentBody,\n detectLibraryFromSource,\n type LibraryName,\n type ComponentStyleInfo,\n} from \"./component-parser.js\";\n\n/**\n * Information about a component's UI library usage\n */\nexport interface ComponentLibraryInfo {\n /** Direct library (from import source, e.g., \"@mui/material\" -> \"mui\") */\n library: LibraryName | null;\n /** Libraries used internally by this component (for local components) */\n internalLibraries: Set<LibraryName>;\n /** Evidence of which internal components caused the library detection */\n libraryEvidence: Array<{\n componentName: string;\n library: LibraryName;\n }>;\n /** Whether this is a local component (resolved from project files) */\n isLocalComponent: boolean;\n}\n\n/**\n * Cache for analyzed components: \"filePath::componentName\" -> ComponentLibraryInfo\n */\nconst componentLibraryCache = new Map<string, ComponentLibraryInfo>();\n\n/**\n * Get a singleton instance of the import graph service\n */\nexport function getImportGraphService() {\n return {\n getComponentLibrary,\n clearCache,\n };\n}\n\n/**\n * Analyze a component's library usage, including transitive dependencies\n *\n * @param contextFilePath - The file where the component is used (for resolving relative imports)\n * @param componentName - The name of the component (e.g., \"Button\", \"MyCard\")\n * @param importSource - The import source (e.g., \"@mui/material\", \"./components/cards\")\n * @returns Library information including direct and transitive library usage\n */\nexport function getComponentLibrary(\n contextFilePath: string,\n componentName: string,\n importSource: string\n): ComponentLibraryInfo {\n // Check if import source directly indicates a known library\n const directLibrary = detectLibraryFromSource(importSource);\n\n if (directLibrary) {\n // It's a direct import from a known library (e.g., @mui/material)\n return {\n library: directLibrary,\n internalLibraries: new Set(),\n libraryEvidence: [],\n isLocalComponent: false,\n };\n }\n\n // It's a local component - resolve and analyze it\n const resolvedPath = resolveImportPath(importSource, contextFilePath);\n\n if (!resolvedPath) {\n // Could not resolve - might be external or invalid\n return {\n library: null,\n internalLibraries: new Set(),\n libraryEvidence: [],\n isLocalComponent: false,\n };\n }\n\n // Check cache\n const cacheKey = `${resolvedPath}::${componentName}`;\n if (componentLibraryCache.has(cacheKey)) {\n return componentLibraryCache.get(cacheKey)!;\n }\n\n // Resolve re-exports to find the actual component definition\n const resolvedExport = resolveExport(componentName, resolvedPath);\n const actualFilePath = resolvedExport?.filePath ?? resolvedPath;\n const actualComponentName = resolvedExport?.localName ?? componentName;\n\n // Analyze the component body\n const result = analyzeComponentLibraries(\n actualFilePath,\n actualComponentName,\n new Set([cacheKey]) // Track visited to prevent cycles\n );\n\n componentLibraryCache.set(cacheKey, result);\n return result;\n}\n\n/**\n * Recursively analyze a component's library usage\n */\nfunction analyzeComponentLibraries(\n filePath: string,\n componentName: string,\n visited: Set<string>\n): ComponentLibraryInfo {\n const styleInfo = parseComponentBody(filePath, componentName);\n\n if (!styleInfo) {\n return {\n library: null,\n internalLibraries: new Set(),\n libraryEvidence: [],\n isLocalComponent: true,\n };\n }\n\n const internalLibraries = new Set<LibraryName>();\n const libraryEvidence: Array<{\n componentName: string;\n library: LibraryName;\n }> = [];\n\n // Check direct library usage within this component\n if (styleInfo.directLibrary) {\n internalLibraries.add(styleInfo.directLibrary);\n }\n\n // Analyze each used component\n for (const usedComponent of styleInfo.usedComponents) {\n const usedLibrary = detectLibraryFromSource(usedComponent.importSource);\n\n if (usedLibrary) {\n // Direct import from a known library\n internalLibraries.add(usedLibrary);\n libraryEvidence.push({\n componentName: usedComponent.name,\n library: usedLibrary,\n });\n } else {\n // It's a local component - recurse into it\n const resolvedPath = resolveImportPath(\n usedComponent.importSource,\n filePath\n );\n\n if (resolvedPath) {\n const cacheKey = `${resolvedPath}::${usedComponent.name}`;\n\n // Skip if already visited (cycle detection)\n if (!visited.has(cacheKey)) {\n visited.add(cacheKey);\n\n // Check cache first\n let nestedInfo: ComponentLibraryInfo;\n if (componentLibraryCache.has(cacheKey)) {\n nestedInfo = componentLibraryCache.get(cacheKey)!;\n } else {\n // Resolve re-exports\n const resolvedExport = resolveExport(\n usedComponent.name,\n resolvedPath\n );\n const actualFilePath = resolvedExport?.filePath ?? resolvedPath;\n const actualComponentName =\n resolvedExport?.localName ?? usedComponent.name;\n\n nestedInfo = analyzeComponentLibraries(\n actualFilePath,\n actualComponentName,\n visited\n );\n componentLibraryCache.set(cacheKey, nestedInfo);\n }\n\n // Aggregate the nested component's libraries\n if (nestedInfo.library) {\n internalLibraries.add(nestedInfo.library);\n libraryEvidence.push({\n componentName: usedComponent.name,\n library: nestedInfo.library,\n });\n }\n\n for (const lib of nestedInfo.internalLibraries) {\n internalLibraries.add(lib);\n }\n\n // Add evidence from nested components\n for (const evidence of nestedInfo.libraryEvidence) {\n libraryEvidence.push({\n componentName: `${usedComponent.name} → ${evidence.componentName}`,\n library: evidence.library,\n });\n }\n }\n }\n }\n }\n\n return {\n library: styleInfo.directLibrary,\n internalLibraries,\n libraryEvidence,\n isLocalComponent: true,\n };\n}\n\n/**\n * Clear all caches (useful for testing or between ESLint runs)\n */\nexport function clearCache(): void {\n componentLibraryCache.clear();\n clearResolverCaches();\n}\n\n// Re-export types for convenience\nexport type { LibraryName };\n","/**\n * Rule: no-mixed-component-libraries\n *\n * Forbids using non-preferred UI component libraries. Reports errors at\n * the JSX usage site, including transitive usage through local components.\n *\n * Examples:\n * - <MuiButton> from @mui/material -> error at <MuiButton> usage\n * - <MyCard> that internally uses MUI -> error at <MyCard> usage\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { createRule, defineRuleMeta } from \"../../utils/create-rule.js\";\nimport {\n getComponentLibrary,\n type LibraryName,\n} from \"./lib/import-graph.js\";\n\ntype MessageIds = \"nonPreferredLibrary\" | \"transitiveNonPreferred\";\ntype Options = [\n {\n /** The preferred UI library. Components from other libraries will be flagged. */\n preferred: LibraryName;\n /** Additional libraries to detect (defaults to common ones) */\n libraries?: LibraryName[];\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-mixed-component-libraries\",\n version: \"1.0.0\",\n name: \"No Mixed Component Libraries\",\n description: \"Forbid mixing component libraries (e.g., shadcn + MUI)\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🧩\",\n hint: \"Ensures consistent UI library usage\",\n defaultEnabled: true,\n isDirectoryBased: true,\n defaultOptions: [{ preferred: \"shadcn\", libraries: [\"shadcn\", \"mui\"] }],\n optionSchema: {\n fields: [\n {\n key: \"preferred\",\n label: \"Preferred component library\",\n type: \"select\",\n defaultValue: \"shadcn\",\n options: [\n { value: \"shadcn\", label: \"shadcn/ui\" },\n { value: \"mui\", label: \"MUI (Material-UI)\" },\n { value: \"chakra\", label: \"Chakra UI\" },\n { value: \"antd\", label: \"Ant Design\" },\n ],\n description: \"The preferred UI library. Components from other libraries will be flagged.\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects and reports when components from non-preferred UI libraries are used in your codebase.\nThis includes both direct imports and transitive usage through your own components that wrap\nnon-preferred libraries internally.\n\n## Why it's useful\n\n- **Consistency**: Ensures a uniform look and feel across your application\n- **Bundle size**: Prevents accidentally including multiple UI frameworks\n- **Maintenance**: Reduces the number of styling systems to maintain\n- **Migration support**: Helps identify what needs to change when migrating UI libraries\n\n## Examples\n\n### ❌ Incorrect (with preferred: \"shadcn\")\n\n\\`\\`\\`tsx\n// Direct MUI usage\nimport { Button } from '@mui/material';\n<Button>Click me</Button> // Error: Component <Button> is from mui\n\n// Transitive usage through local component\nimport { MyCard } from './components/MyCard'; // MyCard uses MUI internally\n<MyCard /> // Error: Component <MyCard> internally uses mui components\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using the preferred library\nimport { Button } from '@/components/ui/button';\nimport { Card } from '@/components/ui/card';\n\n<Button>Click me</Button>\n<Card>Content</Card>\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-mixed-component-libraries\": [\"error\", {\n preferred: \"shadcn\", // Your preferred library\n libraries: [\"shadcn\", \"mui\", \"chakra\", \"antd\"] // Libraries to detect\n}]\n\\`\\`\\`\n\n## Supported Libraries\n\n- **shadcn**: shadcn/ui components (imports from \\`@/components/ui/\\`)\n- **mui**: Material-UI (\\`@mui/material\\`, \\`@mui/joy\\`)\n- **chakra**: Chakra UI (\\`@chakra-ui/react\\`)\n- **antd**: Ant Design (\\`antd\\`)\n`,\n\n});\n\n/**\n * Information about a component usage in the file\n */\ninterface ComponentUsage {\n /** The JSX element node (for error reporting) */\n node: TSESTree.JSXOpeningElement;\n /** Component name (e.g., \"Button\", \"MuiCard\") */\n componentName: string;\n /** Import source (e.g., \"@mui/material\", \"./components/cards\") */\n importSource: string;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-mixed-component-libraries\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Forbid using non-preferred UI component libraries. Reports at JSX usage sites, including transitive usage.\",\n },\n messages: {\n nonPreferredLibrary:\n \"Component <{{component}}> is from {{library}}, but {{preferred}} is the preferred library.\",\n transitiveNonPreferred:\n \"Component <{{component}}> internally uses {{libraries}} components ({{internalComponents}}). The preferred library is {{preferred}}.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n preferred: {\n type: \"string\",\n enum: [\"shadcn\", \"mui\", \"chakra\", \"antd\"],\n description: \"The preferred UI library\",\n },\n libraries: {\n type: \"array\",\n items: {\n type: \"string\",\n enum: [\"shadcn\", \"mui\", \"chakra\", \"antd\"],\n },\n description: \"Libraries to detect (defaults to all)\",\n },\n },\n required: [\"preferred\"],\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n { preferred: \"shadcn\", libraries: [\"shadcn\", \"mui\", \"chakra\", \"antd\"] },\n ],\n create(context) {\n const options = context.options[0];\n const preferred = options.preferred;\n\n // Track imports: localName -> importSource\n const importMap = new Map<string, string>();\n\n // Track all component usages for analysis at Program:exit\n const componentUsages: ComponentUsage[] = [];\n\n return {\n ImportDeclaration(node) {\n const source = node.source.value as string;\n\n for (const spec of node.specifiers) {\n if (spec.type === \"ImportSpecifier\") {\n importMap.set(spec.local.name, source);\n } else if (spec.type === \"ImportDefaultSpecifier\") {\n importMap.set(spec.local.name, source);\n } else if (spec.type === \"ImportNamespaceSpecifier\") {\n importMap.set(spec.local.name, source);\n }\n }\n },\n\n JSXOpeningElement(node) {\n // Get the component name\n let componentName: string | null = null;\n\n if (node.name.type === \"JSXIdentifier\") {\n componentName = node.name.name;\n } else if (node.name.type === \"JSXMemberExpression\") {\n // Handle Namespace.Component (e.g., Modal.Header)\n let current = node.name.object;\n while (current.type === \"JSXMemberExpression\") {\n current = current.object;\n }\n if (current.type === \"JSXIdentifier\") {\n componentName = current.name;\n }\n }\n\n // Skip HTML elements (lowercase) and missing names\n if (!componentName || !/^[A-Z]/.test(componentName)) {\n return;\n }\n\n // Skip components that aren't imported (might be defined in same file)\n const importSource = importMap.get(componentName);\n if (!importSource) {\n return;\n }\n\n componentUsages.push({\n node,\n componentName,\n importSource,\n });\n },\n\n \"Program:exit\"() {\n const filename = context.filename || context.getFilename();\n\n for (const usage of componentUsages) {\n const libraryInfo = getComponentLibrary(\n filename,\n usage.componentName,\n usage.importSource\n );\n\n // Case 1: Direct import from non-preferred library\n if (libraryInfo.library && libraryInfo.library !== preferred) {\n context.report({\n node: usage.node,\n messageId: \"nonPreferredLibrary\",\n data: {\n component: usage.componentName,\n library: libraryInfo.library,\n preferred,\n },\n });\n continue;\n }\n\n // Case 2: Local component that uses non-preferred library internally\n if (\n libraryInfo.isLocalComponent &&\n libraryInfo.internalLibraries.size > 0\n ) {\n const nonPreferredLibs = [...libraryInfo.internalLibraries].filter(\n (lib) => lib !== preferred\n );\n\n if (nonPreferredLibs.length > 0) {\n // Get evidence of which internal components caused the violation\n const internalComponents = libraryInfo.libraryEvidence\n .filter((e) => e.library !== preferred)\n .map((e) => e.componentName)\n .slice(0, 3) // Limit to first 3 for readability\n .join(\", \");\n\n context.report({\n node: usage.node,\n messageId: \"transitiveNonPreferred\",\n data: {\n component: usage.componentName,\n libraries: nonPreferredLibs.join(\", \"),\n internalComponents: internalComponents || \"unknown\",\n preferred,\n },\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: semantic\n *\n * LLM-powered semantic UI analysis using the project's styleguide.\n * This is the only rule that reads .uilint/styleguide.md.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { spawnSync } from \"child_process\";\nimport { dirname, join, relative } from \"path\";\nimport { createRule, defineRuleMeta } from \"../../utils/create-rule.js\";\nimport {\n getCacheEntry,\n hashContentSync,\n setCacheEntry,\n type CachedIssue,\n} from \"./lib/cache.js\";\nimport { getStyleguide } from \"./lib/styleguide-loader.js\";\nimport { UILINT_DEFAULT_OLLAMA_MODEL } from \"uilint-core\";\nimport { buildSourceScanPrompt } from \"uilint-core\";\n\ntype MessageIds = \"semanticIssue\" | \"styleguideNotFound\" | \"analysisError\";\ntype Options = [\n {\n model?: string;\n styleguidePath?: string;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"semantic\",\n version: \"1.0.0\",\n name: \"Semantic Analysis\",\n description: \"LLM-powered semantic UI analysis using your styleguide\",\n defaultSeverity: \"warn\",\n category: \"semantic\",\n icon: \"🧠\",\n hint: \"LLM-powered UI analysis\",\n defaultEnabled: false,\n requiresStyleguide: true,\n plugin: \"semantic\",\n customInspector: \"semantic-issue\",\n requirements: [\n {\n type: \"ollama\",\n description: \"Requires Ollama running locally\",\n setupHint: \"Run: ollama serve && ollama pull qwen3-coder:30b\",\n },\n {\n type: \"styleguide\",\n description: \"Requires a styleguide file\",\n setupHint: \"Run: uilint genstyleguide\",\n },\n ],\n npmDependencies: [\"xxhash-wasm\"],\n defaultOptions: [{ model: \"qwen3-coder:30b\", styleguidePath: \".uilint/styleguide.md\" }],\n optionSchema: {\n fields: [\n {\n key: \"model\",\n label: \"Ollama model to use\",\n type: \"text\",\n defaultValue: \"qwen3-coder:30b\",\n placeholder: \"qwen3-coder:30b\",\n description: \"The Ollama model name for semantic analysis\",\n },\n {\n key: \"styleguidePath\",\n label: \"Path to styleguide file\",\n type: \"text\",\n defaultValue: \".uilint/styleguide.md\",\n placeholder: \".uilint/styleguide.md\",\n description: \"Relative path to the styleguide markdown file\",\n },\n ],\n },\n docs: `\n## What it does\n\nUses a local LLM (via Ollama) to analyze your React components against your project's\nstyleguide. It catches semantic issues that pattern-based rules can't detect, like:\n- Using incorrect spacing that doesn't match your design system conventions\n- Inconsistent button styles across similar contexts\n- Missing accessibility patterns defined in your styleguide\n\n## Why it's useful\n\n- **Custom rules**: Enforces your project's unique conventions without writing custom ESLint rules\n- **Context-aware**: Understands component intent, not just syntax\n- **Evolving standards**: Update your styleguide, and the rule adapts automatically\n- **Local & private**: Runs entirely on your machine using Ollama\n\n## Prerequisites\n\n1. **Ollama installed**: \\`brew install ollama\\` or from ollama.ai\n2. **Model pulled**: \\`ollama pull qwen3-coder:30b\\` (or your preferred model)\n3. **Styleguide created**: Create \\`.uilint/styleguide.md\\` describing your conventions\n\n## Example Styleguide\n\n\\`\\`\\`markdown\n# UI Style Guide\n\n## Spacing\n- Use gap-4 for spacing between card elements\n- Use py-2 px-4 for button padding\n\n## Colors\n- Primary actions: bg-primary text-primary-foreground\n- Destructive actions: bg-destructive text-destructive-foreground\n\n## Components\n- All forms must include a Cancel button\n- Modal headers should use text-lg font-semibold\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/semantic\": [\"warn\", {\n model: \"qwen3-coder:30b\", // Ollama model name\n styleguidePath: \".uilint/styleguide.md\" // Path to styleguide\n}]\n\\`\\`\\`\n\n## Notes\n\n- Results are cached based on file content and styleguide hash\n- First run may be slow as the model loads; subsequent runs use cache\n- Works best with detailed, specific styleguide documentation\n- Set to \"off\" in CI to avoid slow builds (use pre-commit hooks locally)\n`,\n isDirectoryBased: true,\n});\n\nexport default createRule<Options, MessageIds>({\n name: \"semantic\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"LLM-powered semantic UI analysis using styleguide\",\n },\n messages: {\n semanticIssue: \"{{message}}\",\n styleguideNotFound:\n \"No styleguide found. Create .uilint/styleguide.md or specify styleguidePath.\",\n analysisError: \"Semantic analysis failed: {{error}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n model: {\n type: \"string\",\n description: \"Ollama model to use\",\n },\n styleguidePath: {\n type: \"string\",\n description: \"Path to styleguide file\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ model: UILINT_DEFAULT_OLLAMA_MODEL }],\n create(context) {\n const options = context.options[0] || {};\n const filePath = context.filename;\n const fileDir = dirname(filePath);\n\n // Get styleguide\n const { path: styleguidePath, content: styleguide } = getStyleguide(\n fileDir,\n options.styleguidePath\n );\n\n // Skip if no styleguide\n if (!styleguide) {\n console.error(\n `[uilint] Styleguide not found (styleguidePath=${String(\n options.styleguidePath ?? \"\"\n )}, startDir=${fileDir})`\n );\n\n return {\n Program(node) {\n context.report({\n node,\n messageId: \"styleguideNotFound\",\n });\n },\n };\n }\n\n // Read and hash file contents\n let fileContent: string;\n try {\n fileContent = readFileSync(filePath, \"utf-8\");\n } catch {\n console.error(`[uilint] Failed to read file ${filePath}`);\n return {\n Program(node) {\n context.report({\n node,\n messageId: \"analysisError\",\n data: { error: `Failed to read source file ${filePath}` },\n });\n },\n };\n }\n\n const fileHash = hashContentSync(fileContent);\n const styleguideHash = hashContentSync(styleguide);\n\n // Check cache\n const projectRoot = findProjectRoot(fileDir);\n const relativeFilePath = relative(projectRoot, filePath);\n const cached = getCacheEntry(\n projectRoot,\n relativeFilePath,\n fileHash,\n styleguideHash\n );\n\n const ENABLE_CACHE = false;\n if (ENABLE_CACHE && cached) {\n console.error(`[uilint] Cache hit for ${filePath}`);\n\n // Report cached issues\n return {\n Program(node) {\n for (const issue of cached.issues) {\n context.report({\n node,\n loc: { line: issue.line, column: issue.column || 0 },\n messageId: \"semanticIssue\",\n data: { message: issue.message },\n });\n }\n },\n };\n }\n\n // Cache miss: run sync analysis now (slow), cache, then report.\n ENABLE_CACHE &&\n console.error(\n `[uilint] Cache miss for ${filePath}, running semantic analysis`\n );\n\n return {\n Program(node) {\n const issues = runSemanticAnalysisSync(\n fileContent,\n styleguide,\n options.model || UILINT_DEFAULT_OLLAMA_MODEL,\n filePath\n );\n\n setCacheEntry(projectRoot, relativeFilePath, {\n fileHash,\n styleguideHash,\n issues,\n timestamp: Date.now(),\n });\n\n for (const issue of issues) {\n context.report({\n node,\n loc: { line: issue.line, column: issue.column || 0 },\n messageId: \"semanticIssue\",\n data: { message: issue.message },\n });\n }\n },\n };\n },\n});\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Run semantic analysis using Ollama (synchronously).\n *\n * Implementation detail:\n * - ESLint rules are synchronous.\n * - Blocking on a Promise (sleep-loop/Atomics) would also block Node's event loop,\n * preventing the HTTP request to Ollama from ever completing.\n * - To keep this simple & debuggable, we run the async LLM call in a child Node\n * process and synchronously wait for it to exit.\n */\nfunction runSemanticAnalysisSync(\n sourceCode: string,\n styleguide: string,\n model: string,\n filePath?: string\n): CachedIssue[] {\n const startTime = Date.now();\n const fileDisplay = filePath ? ` ${filePath}` : \"\";\n\n console.error(`[uilint] Starting semantic analysis (sync)${fileDisplay}`);\n console.error(`[uilint] Model: ${model}`);\n\n // Build prompt in-process (pure string building).\n const prompt = buildSourceScanPrompt(sourceCode, styleguide, {});\n\n // Avoid `uilint-core/node` exports *and* CJS resolution:\n // resolve the installed dependency by file URL relative to this plugin bundle.\n // When built, `import.meta.url` points at `.../uilint-eslint/dist/index.js`,\n // and the dependency lives at `.../uilint-eslint/node_modules/uilint-core/dist/node.js`.\n const coreNodeUrl = new URL(\n \"../node_modules/uilint-core/dist/node.js\",\n import.meta.url\n ).href;\n\n const childScript = `\n import * as coreNode from ${JSON.stringify(coreNodeUrl)};\n const { OllamaClient, logInfo, logWarning, createProgress, pc } = coreNode;\n const chunks = [];\n for await (const c of process.stdin) chunks.push(c);\n const input = JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n const model = input.model;\n const prompt = input.prompt;\n\n const client = new OllamaClient({ model });\n const ok = await client.isAvailable();\n if (!ok) {\n logWarning(\"Ollama not available, skipping semantic analysis\");\n process.stdout.write(JSON.stringify({ issues: [] }));\n process.exit(0);\n }\n\n logInfo(\\`Ollama connected \\${pc.dim(\\`(model: \\${model})\\`)}\\`);\n const progress = createProgress(\"Analyzing with LLM...\");\n try {\n const response = await client.complete(prompt, {\n json: true,\n stream: true,\n onProgress: (latestLine) => {\n const maxLen = 60;\n const display =\n latestLine.length > maxLen\n ? latestLine.slice(0, maxLen) + \"…\"\n : latestLine;\n progress.update(\\`LLM: \\${pc.dim(display || \"...\")}\\`);\n },\n });\n progress.succeed(\"LLM complete\");\n process.stdout.write(response);\n } catch (e) {\n progress.fail(\\`LLM failed: \\${e instanceof Error ? e.message : String(e)}\\`);\n process.exit(1);\n }\n `;\n\n const child = spawnSync(\n process.execPath,\n [\"--input-type=module\", \"-e\", childScript],\n {\n input: JSON.stringify({ model, prompt }),\n encoding: \"utf8\",\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n maxBuffer: 20 * 1024 * 1024,\n }\n );\n\n const elapsed = Date.now() - startTime;\n\n if (child.error) {\n console.error(\n `[uilint] Semantic analysis failed after ${elapsed}ms: ${child.error.message}`\n );\n return [];\n }\n\n if (typeof child.status === \"number\" && child.status !== 0) {\n console.error(\n `[uilint] Semantic analysis failed after ${elapsed}ms: child exited ${child.status}`\n );\n return [];\n }\n\n const responseText = (child.stdout || \"\").trim();\n if (!responseText) {\n console.error(\n `[uilint] Semantic analysis returned empty response (${elapsed}ms)`\n );\n return [];\n }\n\n try {\n const parsed = JSON.parse(responseText) as {\n issues?: Array<{ line?: number; column?: number; message?: string }>;\n };\n\n const issues = (parsed.issues || []).map((issue) => ({\n line: issue.line || 1,\n column: issue.column,\n message: issue.message || \"Semantic issue detected\",\n ruleId: \"uilint/semantic\",\n severity: 1 as const,\n }));\n\n if (issues.length > 0) {\n console.error(`[uilint] Found ${issues.length} issue(s) (${elapsed}ms)`);\n } else {\n console.error(`[uilint] No issues found (${elapsed}ms)`);\n }\n\n return issues;\n } catch (e) {\n console.error(\n `[uilint] Semantic analysis failed to parse response after ${elapsed}ms: ${\n e instanceof Error ? e.message : String(e)\n }`\n );\n return [];\n }\n}\n","/**\n * File-hash based caching for LLM semantic rule\n *\n * Uses xxhash for fast hashing of file contents.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\n// Lazy-loaded xxhash\nlet xxhashInstance: Awaited<\n ReturnType<typeof import(\"xxhash-wasm\")[\"default\"]>\n> | null = null;\n\nasync function getXxhash() {\n if (!xxhashInstance) {\n const xxhash = await import(\"xxhash-wasm\");\n xxhashInstance = await xxhash.default();\n }\n return xxhashInstance;\n}\n\n/**\n * Synchronous hash using a simple djb2 algorithm (fallback when xxhash not available)\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash * 33) ^ str.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n}\n\n/**\n * Hash content using xxhash (async) or djb2 (sync fallback)\n */\nexport async function hashContent(content: string): Promise<string> {\n try {\n const xxhash = await getXxhash();\n return xxhash.h64ToString(content);\n } catch {\n return djb2Hash(content);\n }\n}\n\n/**\n * Synchronous hash for when async is not possible\n */\nexport function hashContentSync(content: string): string {\n return djb2Hash(content);\n}\n\nexport interface CacheEntry {\n fileHash: string;\n styleguideHash: string;\n issues: CachedIssue[];\n timestamp: number;\n}\n\nexport interface CachedIssue {\n line: number;\n column?: number;\n message: string;\n ruleId: string;\n severity: 1 | 2; // 1 = warn, 2 = error\n}\n\nexport interface CacheStore {\n version: number;\n entries: Record<string, CacheEntry>;\n}\n\nconst CACHE_VERSION = 1;\nconst CACHE_FILE = \".uilint/.cache/eslint-semantic.json\";\n\n/**\n * Get the cache file path for a project\n */\nexport function getCachePath(projectRoot: string): string {\n return join(projectRoot, CACHE_FILE);\n}\n\n/**\n * Load the cache store\n */\nexport function loadCache(projectRoot: string): CacheStore {\n const cachePath = getCachePath(projectRoot);\n\n if (!existsSync(cachePath)) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n try {\n const content = readFileSync(cachePath, \"utf-8\");\n const cache = JSON.parse(content) as CacheStore;\n\n // Invalidate if version mismatch\n if (cache.version !== CACHE_VERSION) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n return cache;\n } catch {\n return { version: CACHE_VERSION, entries: {} };\n }\n}\n\n/**\n * Save the cache store\n */\nexport function saveCache(projectRoot: string, cache: CacheStore): void {\n const cachePath = getCachePath(projectRoot);\n\n try {\n const cacheDir = dirname(cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n }\n\n writeFileSync(cachePath, JSON.stringify(cache, null, 2), \"utf-8\");\n } catch {\n // Silently fail - caching is optional\n }\n}\n\n/**\n * Get cached entry for a file\n */\nexport function getCacheEntry(\n projectRoot: string,\n filePath: string,\n fileHash: string,\n styleguideHash: string\n): CacheEntry | null {\n const cache = loadCache(projectRoot);\n const entry = cache.entries[filePath];\n\n if (!entry) return null;\n\n // Check if hashes match\n if (entry.fileHash !== fileHash || entry.styleguideHash !== styleguideHash) {\n return null;\n }\n\n return entry;\n}\n\n/**\n * Set cached entry for a file\n */\nexport function setCacheEntry(\n projectRoot: string,\n filePath: string,\n entry: CacheEntry\n): void {\n const cache = loadCache(projectRoot);\n cache.entries[filePath] = entry;\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear cache for a specific file\n */\nexport function clearCacheEntry(projectRoot: string, filePath: string): void {\n const cache = loadCache(projectRoot);\n delete cache.entries[filePath];\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear entire cache\n */\nexport function clearCache(projectRoot: string): void {\n saveCache(projectRoot, { version: CACHE_VERSION, entries: {} });\n}\n","/**\n * Styleguide loader for the LLM semantic rule\n *\n * Only the semantic rule reads the styleguide - static rules use ESLint options.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { dirname, isAbsolute, join, resolve } from \"path\";\n\nconst DEFAULT_STYLEGUIDE_PATHS = [\n \".uilint/styleguide.md\",\n \".uilint/styleguide.yaml\",\n \".uilint/styleguide.yml\",\n];\n\n/**\n * Find workspace root by walking up looking for pnpm-workspace.yaml, package.json, or .git\n */\nfunction findWorkspaceRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (\n existsSync(join(dir, \"pnpm-workspace.yaml\")) ||\n existsSync(join(dir, \".git\"))\n ) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Find the nearest package root (directory containing package.json),\n * stopping at the workspace root.\n */\nfunction findNearestPackageRoot(\n startDir: string,\n workspaceRoot: string\n): string {\n let dir = startDir;\n for (let i = 0; i < 30; i++) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n if (dir === workspaceRoot) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Find the styleguide file path\n */\nexport function findStyleguidePath(\n startDir: string,\n explicitPath?: string\n): string | null {\n // Explicit path takes precedence\n if (explicitPath) {\n if (isAbsolute(explicitPath)) {\n return existsSync(explicitPath) ? explicitPath : null;\n }\n\n // For relative explicit paths, try:\n // 1) relative to the file dir (back-compat)\n // 2) relative to the nearest package root (typical \"project root\")\n // 3) relative to workspace root (monorepo root)\n const workspaceRoot = findWorkspaceRoot(startDir);\n const packageRoot = findNearestPackageRoot(startDir, workspaceRoot);\n\n const candidates = [\n resolve(startDir, explicitPath),\n resolve(packageRoot, explicitPath),\n resolve(workspaceRoot, explicitPath),\n ];\n\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n\n return null;\n }\n\n // Check from start dir up to workspace root\n const workspaceRoot = findWorkspaceRoot(startDir);\n let dir = startDir;\n\n while (true) {\n for (const relativePath of DEFAULT_STYLEGUIDE_PATHS) {\n const fullPath = join(dir, relativePath);\n if (existsSync(fullPath)) {\n return fullPath;\n }\n }\n\n // Stop at workspace root\n if (dir === workspaceRoot) break;\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n return null;\n}\n\n/**\n * Load styleguide content from file\n */\nexport function loadStyleguide(\n startDir: string,\n explicitPath?: string\n): string | null {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return null;\n\n try {\n return readFileSync(path, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Get styleguide path and content\n */\nexport function getStyleguide(\n startDir: string,\n explicitPath?: string\n): { path: string | null; content: string | null } {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return { path: null, content: null };\n\n try {\n const content = readFileSync(path, \"utf-8\");\n return { path, content };\n } catch {\n return { path, content: null };\n }\n}\n","/**\n * Rule: semantic-vision\n *\n * ESLint rule that reports cached vision analysis results for UI elements.\n * Vision analysis is performed by the UILint browser overlay and results are\n * cached in .uilint/screenshots/{timestamp}-{route}.json files.\n *\n * This rule:\n * 1. Finds cached vision analysis results for the current file\n * 2. Reports any issues that match elements in this file (by data-loc)\n * 3. If no cached results exist, silently passes (analysis is triggered by browser)\n */\n\nimport { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { dirname, join, relative } from \"path\";\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"visionIssue\" | \"analysisStale\";\n\ntype Options = [\n {\n /** Maximum age of cached results in milliseconds (default: 1 hour) */\n maxAgeMs?: number;\n /** Path to screenshots directory (default: .uilint/screenshots) */\n screenshotsPath?: string;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"semantic-vision\",\n version: \"1.0.0\",\n name: \"Vision Analysis\",\n description: \"Report cached vision analysis results from UILint browser overlay\",\n defaultSeverity: \"warn\",\n category: \"semantic\",\n icon: \"👁️\",\n hint: \"Vision AI for rendered UI\",\n defaultEnabled: false,\n requiresStyleguide: false,\n plugin: \"vision\",\n customInspector: \"vision-issue\",\n heatmapColor: \"#8B5CF6\",\n postInstallInstructions: \"Add the UILint browser overlay to your app and run analysis from the browser to generate cached results.\",\n defaultOptions: [{ maxAgeMs: 3600000, screenshotsPath: \".uilint/screenshots\" }],\n optionSchema: {\n fields: [\n {\n key: \"maxAgeMs\",\n label: \"Max cache age (milliseconds)\",\n type: \"number\",\n defaultValue: 3600000,\n placeholder: \"3600000\",\n description: \"Maximum age of cached results in milliseconds (default: 1 hour)\",\n },\n {\n key: \"screenshotsPath\",\n label: \"Screenshots directory path\",\n type: \"text\",\n defaultValue: \".uilint/screenshots\",\n placeholder: \".uilint/screenshots\",\n description: \"Relative path to the screenshots directory containing analysis results\",\n },\n ],\n },\n docs: `\n## What it does\n\nReports UI issues found by the UILint browser overlay's vision analysis. The overlay\ncaptures screenshots and analyzes them using vision AI, then caches the results.\nThis ESLint rule reads those cached results and reports them as linting errors.\n\n## How it works\n\n1. **Browser overlay**: When running your dev server with the UILint overlay, it captures\n screenshots and analyzes them using vision AI\n2. **Results cached**: Analysis results are saved to \\`.uilint/screenshots/*.json\\`\n3. **ESLint reports**: This rule reads cached results and reports issues at the correct\n source locations using \\`data-loc\\` attributes\n\n## Why it's useful\n\n- **Visual issues**: Catches problems that can only be seen in rendered UI\n- **Continuous feedback**: Issues appear in your editor as you develop\n- **No manual review**: AI spots spacing, alignment, and consistency issues automatically\n\n## Prerequisites\n\n1. **UILint overlay installed**: Add the overlay component to your app\n2. **Run analysis**: Load pages in the browser with the overlay active\n3. **Results cached**: Wait for analysis to complete and cache results\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/semantic-vision\": [\"warn\", {\n maxAgeMs: 3600000, // Ignore results older than 1 hour\n screenshotsPath: \".uilint/screenshots\" // Where cached results are stored\n}]\n\\`\\`\\`\n\n## Notes\n\n- If no cached results exist, the rule passes silently\n- Results are matched to source files using \\`data-loc\\` attributes\n- Stale results (older than \\`maxAgeMs\\`) are reported as warnings\n- Run the browser overlay to refresh cached analysis\n`,\n});\n\n/**\n * Vision analysis result structure stored in JSON files\n */\ninterface VisionAnalysisResult {\n /** Timestamp when analysis was performed */\n timestamp: number;\n /** Route that was analyzed (e.g., \"/\", \"/profile\") */\n route: string;\n /** Screenshot filename (for reference) */\n screenshotFile?: string;\n /** Issues found by vision analysis */\n issues: VisionIssue[];\n}\n\n/**\n * Individual issue from vision analysis\n */\ninterface VisionIssue {\n /** Element text that the LLM referenced */\n elementText?: string;\n /** data-loc reference (format: \"path:line:column\") */\n dataLoc?: string;\n /** Human-readable description of the issue */\n message: string;\n /** Issue category */\n category?: \"spacing\" | \"color\" | \"typography\" | \"alignment\" | \"accessibility\" | \"layout\" | \"other\";\n /** Severity level */\n severity?: \"error\" | \"warning\" | \"info\";\n}\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Get all vision analysis result files from screenshots directory\n */\nfunction getVisionResultFiles(screenshotsDir: string): string[] {\n if (!existsSync(screenshotsDir)) {\n return [];\n }\n\n try {\n const files = readdirSync(screenshotsDir);\n return files\n .filter((f) => f.endsWith(\".json\"))\n .map((f) => join(screenshotsDir, f))\n .sort()\n .reverse(); // Most recent first\n } catch {\n return [];\n }\n}\n\n/**\n * Load and parse a vision analysis result file\n */\nfunction loadVisionResult(filePath: string): VisionAnalysisResult | null {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n return JSON.parse(content) as VisionAnalysisResult;\n } catch {\n return null;\n }\n}\n\n/**\n * Parse a data-loc string into file path and location\n * Format: \"path/to/file.tsx:line:column\"\n */\nfunction parseDataLoc(dataLoc: string): { filePath: string; line: number; column: number } | null {\n // Match pattern: path:line:column (line and column are numbers)\n const match = dataLoc.match(/^(.+):(\\d+):(\\d+)$/);\n if (!match) return null;\n\n return {\n filePath: match[1]!,\n line: parseInt(match[2]!, 10),\n column: parseInt(match[3]!, 10),\n };\n}\n\n/**\n * Normalize file path for comparison (handle relative vs absolute paths)\n */\nfunction normalizeFilePath(filePath: string, projectRoot: string): string {\n // If it's already a relative path, return as-is\n if (!filePath.startsWith(\"/\")) {\n return filePath;\n }\n // Convert absolute to relative\n return relative(projectRoot, filePath);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"semantic-vision\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Report cached vision analysis results from UILint browser overlay\",\n },\n messages: {\n visionIssue: \"[Vision] {{message}}\",\n analysisStale:\n \"Vision analysis results are stale (older than {{age}}). Re-run analysis in browser.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxAgeMs: {\n type: \"number\",\n description:\n \"Maximum age of cached results in milliseconds (default: 1 hour)\",\n },\n screenshotsPath: {\n type: \"string\",\n description:\n \"Path to screenshots directory (default: .uilint/screenshots)\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ maxAgeMs: 60 * 60 * 1000 }], // 1 hour default\n create(context) {\n const options = context.options[0] || {};\n const maxAgeMs = options.maxAgeMs ?? 60 * 60 * 1000;\n const filePath = context.filename;\n const fileDir = dirname(filePath);\n\n // Find project root and screenshots directory\n const projectRoot = findProjectRoot(fileDir);\n const screenshotsDir = options.screenshotsPath\n ? join(projectRoot, options.screenshotsPath)\n : join(projectRoot, \".uilint\", \"screenshots\");\n\n // Get the relative path of the current file for matching against data-loc\n const relativeFilePath = normalizeFilePath(filePath, projectRoot);\n\n // Find all vision result files\n const resultFiles = getVisionResultFiles(screenshotsDir);\n if (resultFiles.length === 0) {\n // No cached results - silently pass (analysis happens in browser)\n return {};\n }\n\n // Collect issues that match this file from all recent results\n const matchingIssues: Array<{\n issue: VisionIssue;\n line: number;\n column: number;\n isStale: boolean;\n }> = [];\n\n const now = Date.now();\n\n for (const resultFile of resultFiles) {\n const result = loadVisionResult(resultFile);\n if (!result || !result.issues) continue;\n\n const isStale = now - result.timestamp > maxAgeMs;\n\n for (const issue of result.issues) {\n if (!issue.dataLoc) continue;\n\n const parsed = parseDataLoc(issue.dataLoc);\n if (!parsed) continue;\n\n // Check if this issue is for the current file\n const issueFilePath = normalizeFilePath(parsed.filePath, projectRoot);\n if (issueFilePath === relativeFilePath) {\n matchingIssues.push({\n issue,\n line: parsed.line,\n column: parsed.column,\n isStale,\n });\n }\n }\n }\n\n // De-duplicate issues by line:column:message\n const seenIssues = new Set<string>();\n const uniqueIssues = matchingIssues.filter((item) => {\n const key = `${item.line}:${item.column}:${item.issue.message}`;\n if (seenIssues.has(key)) return false;\n seenIssues.add(key);\n return true;\n });\n\n return {\n Program(node) {\n for (const { issue, line, column, isStale } of uniqueIssues) {\n // Build message with category prefix if available\n const categoryPrefix = issue.category\n ? `[${issue.category}] `\n : \"\";\n const message = `${categoryPrefix}${issue.message}`;\n\n // Report stale warning separately if enabled\n if (isStale) {\n const ageHours = Math.round(maxAgeMs / (60 * 60 * 1000));\n context.report({\n node,\n loc: { line, column },\n messageId: \"analysisStale\",\n data: { age: `${ageHours}h` },\n });\n }\n\n context.report({\n node,\n loc: { line, column },\n messageId: \"visionIssue\",\n data: { message },\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: enforce-absolute-imports\n *\n * Requires alias imports (e.g., @/) for imports that traverse more than a\n * configurable number of directory levels. Prevents fragile relative import\n * paths like ../../../utils/helper.\n *\n * Examples:\n * - Bad: import { x } from '../../utils/helper'\n * - Good: import { x } from '@/utils/helper'\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferAbsoluteImport\";\ntype Options = [\n {\n /** Maximum allowed parent directory traversals (default: 1, allows ../ but not ../../) */\n maxRelativeDepth?: number;\n /** The alias prefix to suggest (default: \"@/\") */\n aliasPrefix?: string;\n /** Patterns to ignore (e.g., [\"node_modules\", \".css\"]) */\n ignorePaths?: string[];\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"enforce-absolute-imports\",\n version: \"1.0.0\",\n name: \"Enforce Absolute Imports\",\n description:\n \"Require alias imports for paths beyond a configurable directory depth\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"📦\",\n hint: \"Prevents deep relative imports\",\n defaultEnabled: true,\n defaultOptions: [{ maxRelativeDepth: 1, aliasPrefix: \"@/\" }],\n optionSchema: {\n fields: [\n {\n key: \"maxRelativeDepth\",\n label: \"Maximum relative depth\",\n type: \"number\",\n defaultValue: 1,\n description:\n \"Maximum number of parent directory traversals allowed (../ counts as 1)\",\n },\n {\n key: \"aliasPrefix\",\n label: \"Alias prefix\",\n type: \"text\",\n defaultValue: \"@/\",\n description: \"The path alias prefix to use (e.g., @/, ~/)\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnforces the use of path aliases (like \\`@/\\`) for imports that traverse multiple\nparent directories. This prevents fragile relative imports that are hard to\nmaintain and refactor.\n\n## Why it's useful\n\n- **Maintainability**: Absolute imports don't break when files move\n- **Readability**: Clear indication of where imports come from\n- **Consistency**: Standardizes import style across the codebase\n- **Refactoring**: Easier to move files without updating import paths\n\n## Examples\n\n### ❌ Incorrect (with maxRelativeDepth: 1)\n\n\\`\\`\\`tsx\n// Too many parent traversals\nimport { Button } from '../../components/Button';\nimport { utils } from '../../../lib/utils';\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using alias imports\nimport { Button } from '@/components/Button';\nimport { utils } from '@/lib/utils';\n\n// Single parent traversal (within threshold)\nimport { sibling } from '../sibling';\nimport { local } from './local';\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/enforce-absolute-imports\": [\"warn\", {\n maxRelativeDepth: 1, // Allow ../ but not ../../\n aliasPrefix: \"@/\", // Suggested alias prefix\n ignorePaths: [\".css\", \".scss\", \"node_modules\"]\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Count the number of parent directory traversals in an import path\n */\nfunction countParentTraversals(importSource: string): number {\n // Match all occurrences of ../ or ..\\\\ (Windows)\n const matches = importSource.match(/\\.\\.\\//g);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check if an import is a relative path\n */\nfunction isRelativeImport(importSource: string): boolean {\n return importSource.startsWith(\"./\") || importSource.startsWith(\"../\");\n}\n\n/**\n * Check if the import should be ignored\n */\nfunction shouldIgnore(importSource: string, ignorePaths: string[]): boolean {\n return ignorePaths.some((pattern) => importSource.includes(pattern));\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"enforce-absolute-imports\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Require alias imports for paths beyond a configurable directory depth\",\n },\n messages: {\n preferAbsoluteImport:\n \"Import traverses {{depth}} parent director{{plural}}. Use an alias like '{{aliasPrefix}}...' instead of '{{importSource}}'.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxRelativeDepth: {\n type: \"number\",\n minimum: 0,\n description:\n \"Maximum number of parent directory traversals allowed\",\n },\n aliasPrefix: {\n type: \"string\",\n description: \"The path alias prefix to suggest\",\n },\n ignorePaths: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Patterns to ignore\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n maxRelativeDepth: 1,\n aliasPrefix: \"@/\",\n ignorePaths: [],\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const maxRelativeDepth = options.maxRelativeDepth ?? 1;\n const aliasPrefix = options.aliasPrefix ?? \"@/\";\n const ignorePaths = options.ignorePaths ?? [];\n\n /**\n * Check an import source and report if it exceeds the depth threshold\n */\n function checkImportSource(\n source: string,\n node: TSESTree.StringLiteral\n ): void {\n // Skip non-relative imports (node_modules, aliases, etc.)\n if (!isRelativeImport(source)) {\n return;\n }\n\n // Skip ignored paths\n if (shouldIgnore(source, ignorePaths)) {\n return;\n }\n\n const depth = countParentTraversals(source);\n\n if (depth > maxRelativeDepth) {\n context.report({\n node,\n messageId: \"preferAbsoluteImport\",\n data: {\n depth: String(depth),\n plural: depth === 1 ? \"y\" : \"ies\",\n aliasPrefix,\n importSource: source,\n },\n });\n }\n }\n\n return {\n // Standard import declarations: import { x } from '../../utils'\n ImportDeclaration(node) {\n const source = node.source.value as string;\n checkImportSource(source, node.source);\n },\n\n // Re-exports with source: export { x } from '../../utils'\n ExportNamedDeclaration(node) {\n if (node.source) {\n const source = node.source.value as string;\n checkImportSource(source, node.source);\n }\n },\n\n // Export all: export * from '../../utils'\n ExportAllDeclaration(node) {\n const source = node.source.value as string;\n checkImportSource(source, node.source);\n },\n };\n },\n});\n","/**\n * Rule: no-any-in-props\n *\n * Prevents React components from using `any` type in their props, ensuring\n * type safety at component boundaries.\n *\n * Examples:\n * - Bad: function Component(props: any) {}\n * - Bad: function Component({ x }: { x: any }) {}\n * - Bad: const Component: FC<any> = () => {}\n * - Good: function Component(props: { name: string }) {}\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"anyInProps\" | \"anyInPropsProperty\";\ntype Options = [\n {\n /** Also check FC<any> and React.FC<any> patterns */\n checkFCGenerics?: boolean;\n /** Allow any in generic defaults (e.g., <T = any>) */\n allowInGenericDefaults?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-any-in-props\",\n version: \"1.0.0\",\n name: \"No Any in Props\",\n description: \"Disallow 'any' type in React component props\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🔒\",\n hint: \"Ensures type safety in component props\",\n defaultEnabled: true,\n defaultOptions: [{ checkFCGenerics: true, allowInGenericDefaults: false }],\n optionSchema: {\n fields: [\n {\n key: \"checkFCGenerics\",\n label: \"Check FC generics\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Check FC<any> and React.FC<any> patterns\",\n },\n {\n key: \"allowInGenericDefaults\",\n label: \"Allow in generic defaults\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Allow any in generic type parameter defaults\",\n },\n ],\n },\n docs: `\n## What it does\n\nPrevents the use of \\`any\\` type in React component props. This ensures type\nsafety at component boundaries, catching type errors at compile time rather\nthan runtime.\n\n## Why it's useful\n\n- **Type Safety**: Catches prop type errors at compile time\n- **Documentation**: Props serve as self-documenting API\n- **Refactoring**: IDE can track prop usage across codebase\n- **Code Quality**: Encourages thoughtful API design\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Direct any annotation\nfunction Component(props: any) {}\n\n// Any in destructured props\nfunction Component({ data }: { data: any }) {}\n\n// FC with any generic\nconst Component: FC<any> = () => {};\n\n// Any in props interface\ninterface Props { value: any }\nfunction Component(props: Props) {}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Properly typed props\nfunction Component(props: { name: string }) {}\n\n// Using unknown for truly unknown types\nfunction Component({ data }: { data: unknown }) {}\n\n// Typed FC\nconst Component: FC<{ count: number }> = () => {};\n\n// Generic component with constraint\nfunction List<T extends object>(props: { items: T[] }) {}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-any-in-props\": [\"error\", {\n checkFCGenerics: true, // Check FC<any> patterns\n allowInGenericDefaults: false // Disallow <T = any>\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Check if a name is likely a React component (PascalCase, not a hook)\n */\nfunction isComponentName(name: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(name) && !name.startsWith(\"Use\");\n}\n\n/**\n * Check if a type node contains 'any'\n */\nfunction containsAnyType(\n node: TSESTree.TypeNode,\n allowInGenericDefaults: boolean\n): { hasAny: boolean; location: string | null } {\n if (!node) {\n return { hasAny: false, location: null };\n }\n\n switch (node.type) {\n case \"TSAnyKeyword\":\n return { hasAny: true, location: null };\n\n case \"TSTypeLiteral\":\n // Check each property in { prop: any }\n for (const member of node.members) {\n if (\n member.type === \"TSPropertySignature\" &&\n member.typeAnnotation?.typeAnnotation\n ) {\n const result = containsAnyType(\n member.typeAnnotation.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n const propName =\n member.key.type === \"Identifier\" ? member.key.name : \"property\";\n return { hasAny: true, location: `property '${propName}'` };\n }\n }\n // Index signature [key: string]: any\n if (\n member.type === \"TSIndexSignature\" &&\n member.typeAnnotation?.typeAnnotation\n ) {\n const result = containsAnyType(\n member.typeAnnotation.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n return { hasAny: true, location: \"index signature\" };\n }\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSUnionType\":\n case \"TSIntersectionType\":\n for (const typeNode of node.types) {\n const result = containsAnyType(typeNode, allowInGenericDefaults);\n if (result.hasAny) {\n return result;\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSArrayType\":\n return containsAnyType(node.elementType, allowInGenericDefaults);\n\n case \"TSTypeReference\":\n // Check generic arguments like Array<any>, Record<string, any>\n if (node.typeArguments) {\n for (const param of node.typeArguments.params) {\n const result = containsAnyType(param, allowInGenericDefaults);\n if (result.hasAny) {\n return { hasAny: true, location: \"generic argument\" };\n }\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSFunctionType\":\n // Check return type and parameters\n if (node.returnType?.typeAnnotation) {\n const result = containsAnyType(\n node.returnType.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n return { hasAny: true, location: \"function return type\" };\n }\n }\n for (const param of node.params) {\n // Skip TSParameterProperty (doesn't have typeAnnotation) and RestElement\n if (\n param.type !== \"RestElement\" &&\n param.type !== \"TSParameterProperty\" &&\n \"typeAnnotation\" in param &&\n param.typeAnnotation?.typeAnnotation\n ) {\n const result = containsAnyType(\n param.typeAnnotation.typeAnnotation,\n allowInGenericDefaults\n );\n if (result.hasAny) {\n return { hasAny: true, location: \"function parameter\" };\n }\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSTupleType\":\n for (const elementType of node.elementTypes) {\n // Handle both TSNamedTupleMember and regular type nodes\n const typeToCheck =\n elementType.type === \"TSNamedTupleMember\"\n ? elementType.elementType\n : elementType;\n const result = containsAnyType(typeToCheck, allowInGenericDefaults);\n if (result.hasAny) {\n return { hasAny: true, location: \"tuple element\" };\n }\n }\n return { hasAny: false, location: null };\n\n case \"TSConditionalType\":\n // Check all parts of conditional type\n const checkResult = containsAnyType(\n node.checkType,\n allowInGenericDefaults\n );\n if (checkResult.hasAny) return checkResult;\n const extendsResult = containsAnyType(\n node.extendsType,\n allowInGenericDefaults\n );\n if (extendsResult.hasAny) return extendsResult;\n const trueResult = containsAnyType(\n node.trueType,\n allowInGenericDefaults\n );\n if (trueResult.hasAny) return trueResult;\n const falseResult = containsAnyType(\n node.falseType,\n allowInGenericDefaults\n );\n if (falseResult.hasAny) return falseResult;\n return { hasAny: false, location: null };\n\n case \"TSMappedType\":\n if (node.typeAnnotation) {\n return containsAnyType(node.typeAnnotation, allowInGenericDefaults);\n }\n return { hasAny: false, location: null };\n\n default:\n return { hasAny: false, location: null };\n }\n}\n\n/**\n * Get the name of a function or component\n */\nfunction getComponentName(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression\n): string | null {\n // Function declaration: function Foo() {}\n if (node.type === \"FunctionDeclaration\" && node.id) {\n return node.id.name;\n }\n\n // Variable declarator: const Foo = () => {}\n const parent = node.parent;\n if (\n parent?.type === \"VariableDeclarator\" &&\n parent.id.type === \"Identifier\"\n ) {\n return parent.id.name;\n }\n\n // forwardRef/memo wrapper: const Foo = forwardRef(() => {})\n if (parent?.type === \"CallExpression\") {\n const callParent = parent.parent;\n if (\n callParent?.type === \"VariableDeclarator\" &&\n callParent.id.type === \"Identifier\"\n ) {\n return callParent.id.name;\n }\n }\n\n // Named function expression: const x = function Foo() {}\n if (node.type === \"FunctionExpression\" && node.id) {\n return node.id.name;\n }\n\n return null;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-any-in-props\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Disallow 'any' type in React component props\",\n },\n messages: {\n anyInProps:\n \"Component '{{componentName}}' has 'any' type in props. Use a specific type or 'unknown' instead.\",\n anyInPropsProperty:\n \"Component '{{componentName}}' has 'any' type in {{location}}. Use a specific type or 'unknown' instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n checkFCGenerics: {\n type: \"boolean\",\n description: \"Check FC<any> and React.FC<any> patterns\",\n },\n allowInGenericDefaults: {\n type: \"boolean\",\n description: \"Allow any in generic type parameter defaults\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n checkFCGenerics: true,\n allowInGenericDefaults: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const checkFCGenerics = options.checkFCGenerics ?? true;\n const allowInGenericDefaults = options.allowInGenericDefaults ?? false;\n\n /**\n * Check a function's first parameter for any type\n */\n function checkFunctionProps(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression\n ): void {\n const componentName = getComponentName(node);\n\n // Skip if not a component (not PascalCase)\n if (!componentName || !isComponentName(componentName)) {\n return;\n }\n\n // Check first parameter (props)\n const firstParam = node.params[0];\n if (!firstParam) {\n return;\n }\n\n // Get type annotation\n let typeAnnotation: TSESTree.TypeNode | null = null;\n\n if (firstParam.type === \"Identifier\" && firstParam.typeAnnotation) {\n typeAnnotation = firstParam.typeAnnotation.typeAnnotation;\n } else if (\n firstParam.type === \"ObjectPattern\" &&\n firstParam.typeAnnotation\n ) {\n typeAnnotation = firstParam.typeAnnotation.typeAnnotation;\n }\n\n if (typeAnnotation) {\n const result = containsAnyType(typeAnnotation, allowInGenericDefaults);\n if (result.hasAny) {\n context.report({\n node: firstParam,\n messageId: result.location ? \"anyInPropsProperty\" : \"anyInProps\",\n data: {\n componentName,\n location: result.location || \"props\",\n },\n });\n }\n }\n }\n\n /**\n * Check FC<any> or React.FC<any> patterns\n */\n function checkFCGeneric(node: TSESTree.VariableDeclarator): void {\n if (!checkFCGenerics) {\n return;\n }\n\n // Get variable name\n if (node.id.type !== \"Identifier\") {\n return;\n }\n const componentName = node.id.name;\n\n // Skip if not a component name\n if (!isComponentName(componentName)) {\n return;\n }\n\n // Check type annotation\n const typeAnnotation = node.id.typeAnnotation?.typeAnnotation;\n if (!typeAnnotation || typeAnnotation.type !== \"TSTypeReference\") {\n return;\n }\n\n // Check if it's FC or React.FC\n let isFCType = false;\n if (\n typeAnnotation.typeName.type === \"Identifier\" &&\n [\"FC\", \"FunctionComponent\", \"VFC\"].includes(typeAnnotation.typeName.name)\n ) {\n isFCType = true;\n } else if (\n typeAnnotation.typeName.type === \"TSQualifiedName\" &&\n typeAnnotation.typeName.left.type === \"Identifier\" &&\n typeAnnotation.typeName.left.name === \"React\" &&\n [\"FC\", \"FunctionComponent\", \"VFC\"].includes(\n typeAnnotation.typeName.right.name\n )\n ) {\n isFCType = true;\n }\n\n if (!isFCType || !typeAnnotation.typeArguments) {\n return;\n }\n\n // Check the type argument\n const firstTypeArg = typeAnnotation.typeArguments.params[0];\n if (firstTypeArg) {\n const result = containsAnyType(firstTypeArg, allowInGenericDefaults);\n if (result.hasAny) {\n context.report({\n node: firstTypeArg,\n messageId: result.location ? \"anyInPropsProperty\" : \"anyInProps\",\n data: {\n componentName,\n location: result.location || \"FC type parameter\",\n },\n });\n }\n }\n }\n\n return {\n FunctionDeclaration(node) {\n checkFunctionProps(node);\n },\n\n ArrowFunctionExpression(node) {\n checkFunctionProps(node);\n },\n\n FunctionExpression(node) {\n checkFunctionProps(node);\n },\n\n VariableDeclarator(node) {\n checkFCGeneric(node);\n },\n };\n },\n});\n","/**\n * Rule: zustand-use-selectors\n *\n * Requires selector functions when accessing Zustand store state to prevent\n * unnecessary re-renders.\n *\n * Examples:\n * - Bad: const state = useStore()\n * - Bad: const { count } = useStore()\n * - Good: const count = useStore((s) => s.count)\n * - Good: const count = useStore(selectCount)\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"missingSelector\" | \"useSelectorFunction\";\ntype Options = [\n {\n /** Regex pattern for store hook names (default: \"^use\\\\w*Store$\") */\n storePattern?: string;\n /** Allow useShallow() wrapper without selector */\n allowShallow?: boolean;\n /** Require named selector functions instead of inline arrows */\n requireNamedSelectors?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"zustand-use-selectors\",\n version: \"1.0.0\",\n name: \"Zustand Use Selectors\",\n description: \"Require selector functions when accessing Zustand store state\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"⚡\",\n hint: \"Prevents unnecessary re-renders\",\n defaultEnabled: true,\n defaultOptions: [\n { storePattern: \"^use\\\\w*Store$\", allowShallow: true, requireNamedSelectors: false },\n ],\n optionSchema: {\n fields: [\n {\n key: \"storePattern\",\n label: \"Store hook pattern\",\n type: \"text\",\n defaultValue: \"^use\\\\w*Store$\",\n description: \"Regex pattern for identifying Zustand store hooks\",\n },\n {\n key: \"allowShallow\",\n label: \"Allow useShallow\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Allow useShallow() wrapper without explicit selector\",\n },\n {\n key: \"requireNamedSelectors\",\n label: \"Require named selectors\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Require named selector functions instead of inline arrows\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnforces the use of selector functions when accessing Zustand store state.\nWhen you call a Zustand store without a selector, your component subscribes\nto the entire store and re-renders on any state change.\n\n## Why it's useful\n\n- **Performance**: Prevents unnecessary re-renders\n- **Optimization**: Components only update when selected state changes\n- **Best Practice**: Follows Zustand's recommended patterns\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Subscribes to entire store - re-renders on any change\nconst state = useStore();\nconst { count, user } = useStore();\n\n// Component re-renders when anything changes, not just count\nfunction Counter() {\n const { count } = useStore();\n return <span>{count}</span>;\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Only re-renders when count changes\nconst count = useStore((state) => state.count);\n\n// Named selector\nconst selectCount = (state) => state.count;\nconst count = useStore(selectCount);\n\n// Multiple values with shallow\nimport { useShallow } from 'zustand/shallow';\nconst { count, user } = useStore(\n useShallow((state) => ({ count: state.count, user: state.user }))\n);\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/zustand-use-selectors\": [\"warn\", {\n storePattern: \"^use\\\\\\\\w*Store$\", // Match useXxxStore pattern\n allowShallow: true, // Allow useShallow without inline selector\n requireNamedSelectors: false // Allow inline arrow selectors\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Check if a node is a Zustand store call based on the pattern\n */\nfunction isZustandStoreCall(\n callee: TSESTree.Node,\n storePattern: RegExp\n): boolean {\n if (callee.type === \"Identifier\") {\n return storePattern.test(callee.name);\n }\n return false;\n}\n\n/**\n * Check if the first argument is a selector function or reference\n */\nfunction hasSelector(args: TSESTree.CallExpressionArgument[]): boolean {\n if (args.length === 0) {\n return false;\n }\n\n const firstArg = args[0];\n\n // Arrow function: (s) => s.count\n if (firstArg.type === \"ArrowFunctionExpression\") {\n return true;\n }\n\n // Function expression: function(s) { return s.count; }\n if (firstArg.type === \"FunctionExpression\") {\n return true;\n }\n\n // Named selector reference: selectCount\n if (firstArg.type === \"Identifier\") {\n return true;\n }\n\n // Member expression: selectors.count or module.selectCount\n if (firstArg.type === \"MemberExpression\") {\n return true;\n }\n\n // Call expression (might be useShallow or similar)\n if (firstArg.type === \"CallExpression\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if the selector is wrapped in useShallow\n */\nfunction isShallowWrapped(args: TSESTree.CallExpressionArgument[]): boolean {\n if (args.length === 0) {\n return false;\n }\n\n const firstArg = args[0];\n\n if (firstArg.type === \"CallExpression\") {\n if (\n firstArg.callee.type === \"Identifier\" &&\n firstArg.callee.name === \"useShallow\"\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if the selector is an inline arrow function\n */\nfunction isInlineSelector(args: TSESTree.CallExpressionArgument[]): boolean {\n if (args.length === 0) {\n return false;\n }\n\n const firstArg = args[0];\n return (\n firstArg.type === \"ArrowFunctionExpression\" ||\n firstArg.type === \"FunctionExpression\"\n );\n}\n\n/**\n * Get the store name from the call expression\n */\nfunction getStoreName(callee: TSESTree.Node): string {\n if (callee.type === \"Identifier\") {\n return callee.name;\n }\n return \"useStore\";\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"zustand-use-selectors\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require selector functions when accessing Zustand store state\",\n },\n messages: {\n missingSelector:\n \"Call to '{{storeName}}' is missing a selector. Use '{{storeName}}((state) => state.property)' to prevent unnecessary re-renders.\",\n useSelectorFunction:\n \"Consider using a named selector function instead of an inline arrow for '{{storeName}}'. Example: '{{storeName}}(selectProperty)'\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n storePattern: {\n type: \"string\",\n description: \"Regex pattern for store hook names\",\n },\n allowShallow: {\n type: \"boolean\",\n description: \"Allow useShallow() wrapper\",\n },\n requireNamedSelectors: {\n type: \"boolean\",\n description: \"Require named selector functions\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n storePattern: \"^use\\\\w*Store$\",\n allowShallow: true,\n requireNamedSelectors: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const storePatternStr = options.storePattern ?? \"^use\\\\w*Store$\";\n const allowShallow = options.allowShallow ?? true;\n const requireNamedSelectors = options.requireNamedSelectors ?? false;\n\n let storePattern: RegExp;\n try {\n storePattern = new RegExp(storePatternStr);\n } catch {\n // If invalid regex, use default\n storePattern = /^use\\w*Store$/;\n }\n\n return {\n CallExpression(node) {\n // Check if this is a Zustand store call\n if (!isZustandStoreCall(node.callee, storePattern)) {\n return;\n }\n\n const storeName = getStoreName(node.callee);\n\n // Check for selector\n if (!hasSelector(node.arguments)) {\n context.report({\n node,\n messageId: \"missingSelector\",\n data: { storeName },\n });\n return;\n }\n\n // If useShallow is used and allowed, that's fine\n if (allowShallow && isShallowWrapped(node.arguments)) {\n return;\n }\n\n // Check for named selectors if required\n if (requireNamedSelectors && isInlineSelector(node.arguments)) {\n context.report({\n node,\n messageId: \"useSelectorFunction\",\n data: { storeName },\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: no-prop-drilling-depth\n *\n * Warns when a prop is passed through multiple intermediate components\n * without being used, indicating prop drilling that should be refactored\n * to context or state management.\n *\n * Examples:\n * - Bad: Prop passed through 3+ components without use\n * - Good: Prop used directly in receiving component\n * - Good: Using Context or Zustand instead of drilling\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"propDrilling\";\ntype Options = [\n {\n /** Maximum depth before warning (default: 2) */\n maxDepth?: number;\n /** Props to ignore (e.g., className, style, children) */\n ignoredProps?: string[];\n /** Component patterns to skip (regex strings) */\n ignoreComponents?: string[];\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-prop-drilling-depth\",\n version: \"1.0.0\",\n name: \"No Prop Drilling Depth\",\n description: \"Warn when props are drilled through too many components\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🔗\",\n hint: \"Detects excessive prop passing\",\n defaultEnabled: true,\n defaultOptions: [\n {\n maxDepth: 2,\n ignoredProps: [\"className\", \"style\", \"children\", \"key\", \"ref\", \"id\"],\n ignoreComponents: [],\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"maxDepth\",\n label: \"Maximum drilling depth\",\n type: \"number\",\n defaultValue: 2,\n description:\n \"Maximum number of components a prop can pass through without use\",\n },\n {\n key: \"ignoredProps\",\n label: \"Ignored props\",\n type: \"text\",\n defaultValue: \"className, style, children, key, ref, id\",\n description: \"Comma-separated prop names to ignore (common pass-through props)\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects when props are passed through multiple intermediate components without\nbeing used (prop drilling). This is often a sign that you should use React\nContext, Zustand, or another state management solution.\n\n## Why it's useful\n\n- **Maintainability**: Deep prop drilling creates tight coupling\n- **Refactoring**: Changes require updates in many files\n- **Readability**: Hard to trace where props come from\n- **Performance**: Unnecessary re-renders in intermediate components\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Grandparent passes user through Parent to Child\nfunction Grandparent({ user }) {\n return <Parent user={user} />;\n}\n\nfunction Parent({ user }) {\n // Parent doesn't use 'user', just passes it along\n return <Child user={user} />;\n}\n\nfunction Child({ user }) {\n return <div>{user.name}</div>;\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Use Context instead\nconst UserContext = createContext();\n\nfunction Grandparent({ user }) {\n return (\n <UserContext.Provider value={user}>\n <Parent />\n </UserContext.Provider>\n );\n}\n\nfunction Child() {\n const user = useContext(UserContext);\n return <div>{user.name}</div>;\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-prop-drilling-depth\": [\"warn\", {\n maxDepth: 2, // Allow passing through 2 components\n ignoredProps: [\"className\", \"style\", \"children\"], // Common pass-through props\n ignoreComponents: [\"^Layout\", \"^Wrapper\"] // Skip wrapper components\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Information about a component's prop usage\n */\ninterface ComponentPropInfo {\n /** Props received by the component */\n receivedProps: Set<string>;\n /** Props passed to child components: propName -> childComponentNames[] */\n passedProps: Map<string, string[]>;\n /** Props actually used in the component (not just passed) */\n usedProps: Set<string>;\n /** Child components that receive props from this component */\n childComponents: string[];\n}\n\n/**\n * Cache for analyzed component prop information\n */\nconst componentPropCache = new Map<string, ComponentPropInfo>();\n\n/**\n * Clear the prop analysis cache\n */\nexport function clearPropCache(): void {\n componentPropCache.clear();\n}\n\n/**\n * Check if a name is a React component (PascalCase)\n */\nfunction isComponentName(name: string): boolean {\n return /^[A-Z][a-zA-Z0-9]*$/.test(name);\n}\n\n/**\n * Extract props from a function parameter\n */\nfunction extractPropsFromParam(\n param: TSESTree.Parameter\n): { propNames: Set<string>; isSpread: boolean } {\n const propNames = new Set<string>();\n let isSpread = false;\n\n if (param.type === \"ObjectPattern\") {\n for (const prop of param.properties) {\n if (prop.type === \"RestElement\") {\n isSpread = true;\n } else if (\n prop.type === \"Property\" &&\n prop.key.type === \"Identifier\"\n ) {\n propNames.add(prop.key.name);\n }\n }\n } else if (param.type === \"Identifier\") {\n // Single props parameter - assume all props accessed via props.x\n isSpread = true;\n }\n\n return { propNames, isSpread };\n}\n\n/**\n * Find all JSX elements in a function body and extract prop passing info\n */\nfunction analyzeJSXPropPassing(\n body: TSESTree.Node,\n receivedProps: Set<string>\n): { passedProps: Map<string, string[]>; usedProps: Set<string> } {\n const passedProps = new Map<string, string[]>();\n const usedProps = new Set<string>();\n\n function visit(node: TSESTree.Node): void {\n if (!node || typeof node !== \"object\") return;\n\n // Check JSX elements for prop passing\n if (node.type === \"JSXOpeningElement\") {\n const elementName = getJSXElementName(node.name);\n\n // Only care about component elements (PascalCase)\n if (elementName && isComponentName(elementName)) {\n for (const attr of node.attributes) {\n if (attr.type === \"JSXAttribute\" && attr.name.type === \"JSXIdentifier\") {\n const attrName = attr.name.name;\n const propValue = attr.value;\n\n // Check if the attribute value is a received prop\n if (propValue?.type === \"JSXExpressionContainer\") {\n const expr = propValue.expression;\n if (expr.type === \"Identifier\" && receivedProps.has(expr.name)) {\n // This prop is being passed to a child\n const existing = passedProps.get(expr.name) || [];\n existing.push(elementName);\n passedProps.set(expr.name, existing);\n } else if (\n expr.type === \"MemberExpression\" &&\n expr.object.type === \"Identifier\" &&\n expr.object.name === \"props\" &&\n expr.property.type === \"Identifier\"\n ) {\n // props.x pattern\n const propName = expr.property.name;\n if (receivedProps.has(propName) || receivedProps.size === 0) {\n const existing = passedProps.get(propName) || [];\n existing.push(elementName);\n passedProps.set(propName, existing);\n }\n }\n }\n }\n\n // Check for spread props: {...props} or {...rest}\n if (attr.type === \"JSXSpreadAttribute\") {\n if (attr.argument.type === \"Identifier\") {\n const spreadName = attr.argument.name;\n if (spreadName === \"props\" || receivedProps.has(spreadName)) {\n // All props are being spread\n for (const prop of receivedProps) {\n const existing = passedProps.get(prop) || [];\n existing.push(elementName);\n passedProps.set(prop, existing);\n }\n }\n }\n }\n }\n }\n }\n\n // Check for prop usage (not just passing)\n // e.g., {user.name} or {props.user.name} or just {user}\n if (\n node.type === \"MemberExpression\" &&\n node.object.type === \"Identifier\" &&\n receivedProps.has(node.object.name)\n ) {\n usedProps.add(node.object.name);\n }\n\n if (\n node.type === \"Identifier\" &&\n receivedProps.has(node.name) &&\n node.parent?.type !== \"JSXExpressionContainer\"\n ) {\n // Prop used in expression (but not directly passed to child)\n usedProps.add(node.name);\n }\n\n // Check for props.x.something usage\n if (\n node.type === \"MemberExpression\" &&\n node.object.type === \"MemberExpression\" &&\n node.object.object.type === \"Identifier\" &&\n node.object.object.name === \"props\" &&\n node.object.property.type === \"Identifier\"\n ) {\n usedProps.add(node.object.property.name);\n }\n\n // Recurse into children\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") continue;\n const child = (node as unknown as Record<string, unknown>)[key];\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\") {\n visit(item as TSESTree.Node);\n }\n }\n } else if (child && typeof child === \"object\") {\n visit(child as TSESTree.Node);\n }\n }\n }\n\n visit(body);\n return { passedProps, usedProps };\n}\n\n/**\n * Get the name of a JSX element\n */\nfunction getJSXElementName(node: TSESTree.JSXTagNameExpression): string | null {\n if (node.type === \"JSXIdentifier\") {\n return node.name;\n }\n if (node.type === \"JSXMemberExpression\") {\n // Get the root object for namespace components\n let current = node.object;\n while (current.type === \"JSXMemberExpression\") {\n current = current.object;\n }\n return current.type === \"JSXIdentifier\" ? current.name : null;\n }\n return null;\n}\n\n/**\n * Track prop drilling within a single file\n */\ninterface PropDrillingInfo {\n propName: string;\n component: string;\n passedTo: string[];\n usedDirectly: boolean;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-prop-drilling-depth\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Warn when props are drilled through too many components\",\n },\n messages: {\n propDrilling:\n \"Prop '{{propName}}' is passed through {{depth}} component(s) without being used. Consider using Context or state management. Path: {{path}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n maxDepth: {\n type: \"number\",\n minimum: 1,\n description: \"Maximum drilling depth before warning\",\n },\n ignoredProps: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Props to ignore\",\n },\n ignoreComponents: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Component patterns to skip (regex)\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n maxDepth: 2,\n ignoredProps: [\"className\", \"style\", \"children\", \"key\", \"ref\", \"id\"],\n ignoreComponents: [],\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const maxDepth = options.maxDepth ?? 2;\n const ignoredProps = new Set(\n options.ignoredProps ?? [\n \"className\",\n \"style\",\n \"children\",\n \"key\",\n \"ref\",\n \"id\",\n ]\n );\n const ignoreComponentPatterns = (options.ignoreComponents ?? []).map(\n (p) => new RegExp(p)\n );\n\n // Track components and their prop flows within the file\n const componentProps = new Map<string, ComponentPropInfo>();\n const imports = new Map<string, string>(); // localName -> importSource\n const componentNodes = new Map<string, TSESTree.Node>(); // componentName -> node\n\n function shouldIgnoreComponent(name: string): boolean {\n return ignoreComponentPatterns.some((pattern) => pattern.test(name));\n }\n\n function shouldIgnoreProp(name: string): boolean {\n return ignoredProps.has(name);\n }\n\n /**\n * Analyze a component function for prop drilling\n */\n function analyzeComponent(\n name: string,\n node: TSESTree.FunctionDeclaration | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n reportNode: TSESTree.Node\n ): void {\n if (shouldIgnoreComponent(name)) return;\n\n const firstParam = node.params[0];\n if (!firstParam) return;\n\n const { propNames, isSpread } = extractPropsFromParam(firstParam);\n\n // If using spread without destructuring, we can't easily track props\n if (isSpread && propNames.size === 0) return;\n\n const body = node.body;\n if (!body) return;\n\n const { passedProps, usedProps } = analyzeJSXPropPassing(body, propNames);\n\n componentProps.set(name, {\n receivedProps: propNames,\n passedProps,\n usedProps,\n childComponents: [...new Set([...passedProps.values()].flat())],\n });\n\n componentNodes.set(name, reportNode);\n }\n\n return {\n // Track imports for cross-file analysis\n ImportDeclaration(node) {\n const source = node.source.value as string;\n for (const spec of node.specifiers) {\n if (spec.type === \"ImportSpecifier\" || spec.type === \"ImportDefaultSpecifier\") {\n imports.set(spec.local.name, source);\n }\n }\n },\n\n // Analyze function declarations\n FunctionDeclaration(node) {\n if (node.id && isComponentName(node.id.name)) {\n analyzeComponent(node.id.name, node, node);\n }\n },\n\n // Analyze arrow functions\n VariableDeclarator(node) {\n if (\n node.id.type === \"Identifier\" &&\n isComponentName(node.id.name) &&\n node.init?.type === \"ArrowFunctionExpression\"\n ) {\n analyzeComponent(node.id.name, node.init, node);\n }\n },\n\n // Analyze at the end of the file\n \"Program:exit\"() {\n // Find drilling chains within the file\n for (const [componentName, info] of componentProps) {\n for (const [propName, children] of info.passedProps) {\n if (shouldIgnoreProp(propName)) continue;\n\n // Check if prop is used directly\n if (info.usedProps.has(propName)) continue;\n\n // Track the drilling chain\n const chain: string[] = [componentName];\n let depth = 0;\n let current = children;\n\n while (current.length > 0 && depth < maxDepth + 1) {\n depth++;\n const nextChildren: string[] = [];\n\n for (const child of current) {\n chain.push(child);\n const childInfo = componentProps.get(child);\n\n if (childInfo) {\n // Check if child uses the prop\n if (childInfo.usedProps.has(propName)) {\n // Prop is used here, drilling stops\n break;\n }\n\n // Check if child passes the prop further\n const childPasses = childInfo.passedProps.get(propName);\n if (childPasses) {\n nextChildren.push(...childPasses);\n }\n }\n }\n\n current = nextChildren;\n }\n\n // Report if depth exceeds threshold\n if (depth > maxDepth) {\n const reportNode = componentNodes.get(componentName);\n if (reportNode) {\n context.report({\n node: reportNode,\n messageId: \"propDrilling\",\n data: {\n propName,\n depth: String(depth),\n path: chain.slice(0, maxDepth + 2).join(\" → \"),\n },\n });\n }\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: no-secrets-in-code\n *\n * Detects hardcoded secrets, API keys, passwords, and tokens in source code.\n * Prevents accidental exposure of sensitive credentials.\n *\n * Examples:\n * - Bad: const apiKey = 'AKIA1234567890ABCDEF'\n * - Bad: const password = 'mySecretPassword123'\n * - Good: const apiKey = process.env.API_KEY\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"secretDetected\" | \"suspiciousVariable\";\ntype Options = [\n {\n /** Additional regex patterns to detect (as strings) */\n additionalPatterns?: Array<{ name: string; pattern: string }>;\n /** Check variable names for suspicious patterns */\n checkVariableNames?: boolean;\n /** Minimum length for generic secret detection */\n minSecretLength?: number;\n /** Relax rules in test files */\n allowInTestFiles?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"no-secrets-in-code\",\n version: \"1.0.0\",\n name: \"No Secrets in Code\",\n description: \"Detect hardcoded secrets, API keys, and tokens\",\n defaultSeverity: \"error\",\n category: \"static\",\n icon: \"🔐\",\n hint: \"Prevents credential leaks\",\n defaultEnabled: true,\n defaultOptions: [\n {\n checkVariableNames: true,\n minSecretLength: 16,\n allowInTestFiles: false,\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"checkVariableNames\",\n label: \"Check variable names\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Check for suspicious variable names with high-entropy values\",\n },\n {\n key: \"minSecretLength\",\n label: \"Minimum secret length\",\n type: \"number\",\n defaultValue: 16,\n description: \"Minimum string length for generic secret detection\",\n },\n {\n key: \"allowInTestFiles\",\n label: \"Allow in test files\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Skip detection in test files (*.test.*, *.spec.*)\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects hardcoded secrets, API keys, passwords, and tokens in source code.\nThese should be stored in environment variables or secure vaults instead.\n\n## Why it's useful\n\n- **Security**: Prevents credential leaks in version control\n- **Compliance**: Helps meet security audit requirements\n- **Best Practice**: Enforces proper secrets management\n\n## Detected Patterns\n\n- AWS Access Keys and Secret Keys\n- GitHub Personal Access Tokens (ghp_*)\n- Stripe API Keys (sk_live_*, sk_test_*)\n- Google API Keys\n- Firebase Keys\n- Slack Tokens\n- npm Tokens\n- JWT Tokens\n- Private Keys (PEM format)\n- Generic API keys, passwords, and secrets in suspicious variables\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Hardcoded AWS credentials\nconst accessKey = 'AKIA1234567890ABCDEF';\nconst secretKey = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY';\n\n// Hardcoded passwords\nconst dbPassword = 'supersecretpassword123';\n\n// Hardcoded tokens\nconst token = 'ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Use environment variables\nconst accessKey = process.env.AWS_ACCESS_KEY_ID;\nconst secretKey = process.env.AWS_SECRET_ACCESS_KEY;\n\n// Reference from config\nconst dbPassword = config.database.password;\n\n// Use a secrets manager\nconst token = await secretsManager.getSecret('github-token');\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-secrets-in-code\": [\"error\", {\n checkVariableNames: true, // Check suspicious variable names\n minSecretLength: 16, // Minimum length for generic detection\n allowInTestFiles: false, // Don't skip test files\n additionalPatterns: [ // Add custom patterns\n { name: \"Custom API\", pattern: \"^myapi_[a-z0-9]{32}$\" }\n ]\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * Known secret patterns with names and regex\n */\nconst SECRET_PATTERNS: Array<{ name: string; pattern: RegExp }> = [\n // AWS\n { name: \"AWS Access Key ID\", pattern: /\\bAKIA[0-9A-Z]{16}\\b/ },\n { name: \"AWS Secret Access Key\", pattern: /\\b[A-Za-z0-9/+=]{40}\\b/ },\n\n // GitHub\n { name: \"GitHub Personal Access Token\", pattern: /\\bghp_[A-Za-z0-9]{36}\\b/ },\n { name: \"GitHub OAuth Token\", pattern: /\\bgho_[A-Za-z0-9]{36}\\b/ },\n { name: \"GitHub App Token\", pattern: /\\bghu_[A-Za-z0-9]{36}\\b/ },\n { name: \"GitHub Refresh Token\", pattern: /\\bghr_[A-Za-z0-9]{36}\\b/ },\n\n // Stripe\n { name: \"Stripe Live Secret Key\", pattern: /\\bsk_live_[A-Za-z0-9]{24,}\\b/ },\n { name: \"Stripe Test Secret Key\", pattern: /\\bsk_test_[A-Za-z0-9]{24,}\\b/ },\n { name: \"Stripe Restricted Key\", pattern: /\\brk_live_[A-Za-z0-9]{24,}\\b/ },\n\n // Google\n { name: \"Google API Key\", pattern: /\\bAIza[A-Za-z0-9_-]{35}\\b/ },\n\n // Slack\n { name: \"Slack Token\", pattern: /\\bxox[baprs]-[A-Za-z0-9-]{10,48}\\b/ },\n { name: \"Slack Webhook\", pattern: /\\bhooks\\.slack\\.com\\/services\\/T[A-Za-z0-9]+\\/B[A-Za-z0-9]+\\/[A-Za-z0-9]+\\b/ },\n\n // npm\n { name: \"npm Token\", pattern: /\\bnpm_[A-Za-z0-9]{36}\\b/ },\n\n // SendGrid\n { name: \"SendGrid API Key\", pattern: /\\bSG\\.[A-Za-z0-9_-]{22}\\.[A-Za-z0-9_-]{43}\\b/ },\n\n // Twilio\n { name: \"Twilio API Key\", pattern: /\\bSK[a-z0-9]{32}\\b/ },\n\n // Firebase\n { name: \"Firebase Key\", pattern: /\\bAAAA[A-Za-z0-9_-]{7}:[A-Za-z0-9_-]{140}\\b/ },\n\n // Generic patterns\n { name: \"Private Key\", pattern: /-----BEGIN\\s+(RSA\\s+|EC\\s+|DSA\\s+|OPENSSH\\s+)?PRIVATE\\s+KEY-----/ },\n { name: \"JWT Token\", pattern: /\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/ },\n\n // Anthropic\n { name: \"Anthropic API Key\", pattern: /\\bsk-ant-api[A-Za-z0-9_-]{20,}\\b/ },\n\n // OpenAI\n { name: \"OpenAI API Key\", pattern: /\\bsk-proj-[A-Za-z0-9_-]{20,}\\b/ },\n { name: \"OpenAI API Key (old)\", pattern: /\\bsk-[A-Za-z0-9]{48}\\b/ },\n];\n\n/**\n * Variable name patterns that suggest secrets\n */\nconst SUSPICIOUS_VARIABLE_PATTERNS: RegExp[] = [\n /^api[_-]?key$/i,\n /^secret[_-]?key$/i,\n /^private[_-]?key$/i,\n /^access[_-]?key$/i,\n /^auth[_-]?key$/i,\n /^access[_-]?token$/i,\n /^auth[_-]?token$/i,\n /^api[_-]?token$/i,\n /^bearer[_-]?token$/i,\n /^jwt[_-]?token$/i,\n /^refresh[_-]?token$/i,\n /^password$/i,\n /^passwd$/i,\n /^pwd$/i,\n /^db[_-]?password$/i,\n /^database[_-]?password$/i,\n /^secret$/i,\n /^client[_-]?secret$/i,\n /^app[_-]?secret$/i,\n];\n\n/**\n * Patterns that indicate safe/placeholder values\n */\nconst PLACEHOLDER_PATTERNS: RegExp[] = [\n /^your[_-]?/i,\n /^xxx+$/i,\n /^placeholder/i,\n /^example/i,\n /^test[_-]?/i,\n /^fake[_-]?/i,\n /^dummy/i,\n /^sample/i,\n /<[^>]+>/, // <your-key-here>\n /\\${[^}]+}/, // ${API_KEY}\n /^\\*+$/, // ****\n];\n\n/**\n * Calculate Shannon entropy of a string\n */\nfunction calculateEntropy(str: string): number {\n if (str.length === 0) return 0;\n\n const freq: Record<string, number> = {};\n for (const char of str) {\n freq[char] = (freq[char] || 0) + 1;\n }\n\n let entropy = 0;\n const len = str.length;\n for (const count of Object.values(freq)) {\n const p = count / len;\n entropy -= p * Math.log2(p);\n }\n\n return entropy;\n}\n\n/**\n * Check if a value looks like a placeholder\n */\nfunction isPlaceholder(value: string): boolean {\n return PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(value));\n}\n\n/**\n * Check if a value is likely an environment variable reference\n */\nfunction isEnvReference(value: string): boolean {\n return value.includes(\"process.env\") || value.includes(\"import.meta.env\");\n}\n\n/**\n * Get a preview of the secret (first and last few chars)\n */\nfunction getPreview(value: string, maxLength: number = 20): string {\n if (value.length <= maxLength) {\n return value.substring(0, 8) + \"...\";\n }\n return value.substring(0, 8) + \"...\" + value.substring(value.length - 4);\n}\n\n/**\n * Check if file is a test file\n */\nfunction isTestFile(filename: string): boolean {\n return /\\.(test|spec)\\.[jt]sx?$/.test(filename) ||\n /\\/__tests__\\//.test(filename) ||\n /\\/test\\//.test(filename);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-secrets-in-code\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Detect hardcoded secrets, API keys, and tokens\",\n },\n messages: {\n secretDetected:\n \"Potential {{secretType}} detected: '{{preview}}'. Use environment variables instead of hardcoding secrets.\",\n suspiciousVariable:\n \"Variable '{{variableName}}' appears to contain a secret. Use environment variables instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n additionalPatterns: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n name: { type: \"string\" },\n pattern: { type: \"string\" },\n },\n required: [\"name\", \"pattern\"],\n },\n description: \"Additional patterns to detect\",\n },\n checkVariableNames: {\n type: \"boolean\",\n description: \"Check variable names for suspicious patterns\",\n },\n minSecretLength: {\n type: \"number\",\n description: \"Minimum length for generic secret detection\",\n },\n allowInTestFiles: {\n type: \"boolean\",\n description: \"Skip detection in test files\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n checkVariableNames: true,\n minSecretLength: 16,\n allowInTestFiles: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const checkVariableNames = options.checkVariableNames ?? true;\n const minSecretLength = options.minSecretLength ?? 16;\n const allowInTestFiles = options.allowInTestFiles ?? false;\n const additionalPatterns = options.additionalPatterns ?? [];\n\n const filename = context.filename || context.getFilename?.() || \"\";\n\n // Skip test files if configured\n if (allowInTestFiles && isTestFile(filename)) {\n return {};\n }\n\n // Build full pattern list\n const allPatterns = [...SECRET_PATTERNS];\n for (const custom of additionalPatterns) {\n try {\n allPatterns.push({\n name: custom.name,\n pattern: new RegExp(custom.pattern),\n });\n } catch {\n // Invalid regex, skip\n }\n }\n\n /**\n * Check a string value for secrets\n */\n function checkStringForSecrets(\n value: string,\n node: TSESTree.Node,\n variableName?: string\n ): void {\n // Skip empty strings and short strings\n if (!value || value.length < 8) {\n return;\n }\n\n // Skip placeholders\n if (isPlaceholder(value)) {\n return;\n }\n\n // Check against known patterns\n for (const { name, pattern } of allPatterns) {\n if (pattern.test(value)) {\n context.report({\n node,\n messageId: \"secretDetected\",\n data: {\n secretType: name,\n preview: getPreview(value),\n },\n });\n return;\n }\n }\n\n // Check for suspicious variable names with high-entropy values\n if (checkVariableNames && variableName) {\n const isSuspiciousName = SUSPICIOUS_VARIABLE_PATTERNS.some((pattern) =>\n pattern.test(variableName)\n );\n\n if (isSuspiciousName && value.length >= minSecretLength) {\n const entropy = calculateEntropy(value);\n // High entropy (> 3.5) suggests random/secret data\n if (entropy > 3.5) {\n context.report({\n node,\n messageId: \"suspiciousVariable\",\n data: {\n variableName,\n },\n });\n }\n }\n }\n }\n\n /**\n * Get variable name from declarator\n */\n function getVariableName(node: TSESTree.Node): string | undefined {\n if (node.parent?.type === \"VariableDeclarator\") {\n const declarator = node.parent;\n if (declarator.id.type === \"Identifier\") {\n return declarator.id.name;\n }\n }\n if (node.parent?.type === \"Property\") {\n const prop = node.parent;\n if (prop.key.type === \"Identifier\") {\n return prop.key.name;\n }\n }\n return undefined;\n }\n\n return {\n // Check string literals\n Literal(node) {\n if (typeof node.value === \"string\") {\n const variableName = getVariableName(node);\n checkStringForSecrets(node.value, node, variableName);\n }\n },\n\n // Check template literals\n TemplateLiteral(node) {\n // Only check if no expressions (pure string)\n if (node.expressions.length === 0 && node.quasis.length === 1) {\n const value = node.quasis[0].value.raw;\n const variableName = getVariableName(node);\n checkStringForSecrets(value, node, variableName);\n }\n },\n };\n },\n});\n","/**\n * Rule: require-input-validation\n *\n * Requires API route handlers to validate request body using schema validation\n * libraries like Zod, Yup, or Joi before accessing request data.\n *\n * Examples:\n * - Bad: const { name } = await req.json()\n * - Good: const data = schema.parse(await req.json())\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"missingValidation\" | \"unvalidatedBodyAccess\";\ntype Options = [\n {\n /** HTTP methods that require validation (default: POST, PUT, PATCH, DELETE) */\n httpMethods?: string[];\n /** File patterns that indicate API routes */\n routePatterns?: string[];\n /** Allow manual type guards/if-checks as validation */\n allowManualValidation?: boolean;\n }\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"require-input-validation\",\n version: \"1.0.0\",\n name: \"Require Input Validation\",\n description: \"Require schema validation in API route handlers\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"✅\",\n hint: \"Enforces input validation in APIs\",\n defaultEnabled: true,\n defaultOptions: [\n {\n httpMethods: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n routePatterns: [\"route.ts\", \"route.tsx\", \"/api/\", \"/app/api/\"],\n allowManualValidation: false,\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"httpMethods\",\n label: \"HTTP methods requiring validation\",\n type: \"multiselect\",\n defaultValue: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n options: [\n { value: \"GET\", label: \"GET\" },\n { value: \"POST\", label: \"POST\" },\n { value: \"PUT\", label: \"PUT\" },\n { value: \"PATCH\", label: \"PATCH\" },\n { value: \"DELETE\", label: \"DELETE\" },\n ],\n description: \"HTTP methods that require request body validation\",\n },\n {\n key: \"allowManualValidation\",\n label: \"Allow manual validation\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Allow if-checks and type guards instead of schema validation\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnsures that API route handlers validate request body data using a schema\nvalidation library (Zod, Yup, Joi, etc.) before accessing it.\n\n## Why it's useful\n\n- **Security**: Prevents injection attacks and malformed data\n- **Type Safety**: Ensures runtime data matches expected types\n- **Error Handling**: Provides clear validation error messages\n- **Best Practice**: Follows defense-in-depth principles\n\n## Supported Validation Libraries\n\n- Zod: \\`parse()\\`, \\`safeParse()\\`, \\`parseAsync()\\`\n- Yup: \\`validate()\\`, \\`validateSync()\\`\n- Joi: \\`validate()\\`\n- Superstruct: \\`create()\\`, \\`assert()\\`\n- io-ts: \\`decode()\\`\n- Valibot: \\`parse()\\`, \\`safeParse()\\`\n\n## Examples\n\n### ❌ Incorrect\n\n\\`\\`\\`tsx\n// Next.js App Router\nexport async function POST(request: Request) {\n const body = await request.json();\n // Body accessed without validation\n await db.users.create({ name: body.name });\n}\n\n// Next.js Pages API\nexport default function handler(req, res) {\n const { email } = req.body; // Unvalidated\n sendEmail(email);\n}\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\nimport { z } from 'zod';\n\nconst CreateUserSchema = z.object({\n name: z.string().min(1),\n email: z.string().email(),\n});\n\nexport async function POST(request: Request) {\n const body = await request.json();\n const data = CreateUserSchema.parse(body); // Validated!\n await db.users.create(data);\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/require-input-validation\": [\"warn\", {\n httpMethods: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n routePatterns: [\"route.ts\", \"/api/\"],\n allowManualValidation: false\n}]\n\\`\\`\\`\n`,\n});\n\n/**\n * HTTP method names (Next.js App Router style)\n */\nconst HTTP_METHODS = [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\", \"OPTIONS\"];\n\n/**\n * Validation method names from common libraries\n */\nconst VALIDATION_METHODS = [\n // Zod\n \"parse\",\n \"safeParse\",\n \"parseAsync\",\n \"safeParseAsync\",\n // Yup\n \"validate\",\n \"validateSync\",\n \"validateAt\",\n \"validateSyncAt\",\n // Joi\n \"validate\",\n \"validateAsync\",\n // Superstruct\n \"create\",\n \"assert\",\n // io-ts\n \"decode\",\n // Valibot\n \"parse\",\n \"safeParse\",\n // Generic\n \"validateBody\",\n \"validateRequest\",\n \"validateInput\",\n];\n\n/**\n * Check if file matches route patterns\n */\nfunction isApiRouteFile(filename: string, patterns: string[]): boolean {\n return patterns.some((pattern) => filename.includes(pattern));\n}\n\n/**\n * Check if a function is an HTTP method handler\n */\nfunction isHttpMethodHandler(\n node: TSESTree.Node,\n methods: string[]\n): { isHandler: boolean; method: string | null } {\n // Check export function GET/POST/etc\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n const name = node.declaration.id.name.toUpperCase();\n if (methods.includes(name)) {\n return { isHandler: true, method: name };\n }\n }\n\n // Check export const GET = async () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (decl.id.type === \"Identifier\") {\n const name = decl.id.name.toUpperCase();\n if (methods.includes(name)) {\n return { isHandler: true, method: name };\n }\n }\n }\n }\n\n return { isHandler: false, method: null };\n}\n\n/**\n * Check if a call expression is a validation call\n */\nfunction isValidationCall(node: TSESTree.CallExpression): boolean {\n // Check method calls: schema.parse(), schema.validate()\n if (\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\"\n ) {\n const methodName = node.callee.property.name;\n\n // Exclude JSON.parse as it's not schema validation\n if (\n node.callee.object.type === \"Identifier\" &&\n node.callee.object.name === \"JSON\" &&\n methodName === \"parse\"\n ) {\n return false;\n }\n\n return VALIDATION_METHODS.includes(methodName);\n }\n\n // Check direct calls: validate(schema, data)\n if (node.callee.type === \"Identifier\") {\n const funcName = node.callee.name;\n return VALIDATION_METHODS.includes(funcName);\n }\n\n return false;\n}\n\n/**\n * Check if a node is a body access pattern\n */\nfunction isBodyAccess(node: TSESTree.Node): {\n isAccess: boolean;\n accessType: string | null;\n} {\n // req.body\n if (\n node.type === \"MemberExpression\" &&\n node.property.type === \"Identifier\" &&\n node.property.name === \"body\"\n ) {\n return { isAccess: true, accessType: \"req.body\" };\n }\n\n // request.json() or req.json()\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n node.callee.property.name === \"json\"\n ) {\n return { isAccess: true, accessType: \"request.json()\" };\n }\n\n // request.formData()\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n node.callee.property.name === \"formData\"\n ) {\n return { isAccess: true, accessType: \"request.formData()\" };\n }\n\n // request.text()\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n node.callee.property.name === \"text\"\n ) {\n return { isAccess: true, accessType: \"request.text()\" };\n }\n\n return { isAccess: false, accessType: null };\n}\n\n/**\n * Track if we're inside a validation context\n */\ninterface ValidationContext {\n hasValidation: boolean;\n bodyAccessNodes: Array<{ node: TSESTree.Node; accessType: string }>;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"require-input-validation\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Require schema validation in API route handlers\",\n },\n messages: {\n missingValidation:\n \"API route handler '{{method}}' accesses request body without validation. Use a schema validation library like Zod.\",\n unvalidatedBodyAccess:\n \"Accessing '{{accessType}}' without prior validation. Validate the data first using a schema.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n httpMethods: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"HTTP methods that require validation\",\n },\n routePatterns: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"File patterns that indicate API routes\",\n },\n allowManualValidation: {\n type: \"boolean\",\n description: \"Allow manual type guards as validation\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n httpMethods: [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n routePatterns: [\"route.ts\", \"route.tsx\", \"/api/\", \"/app/api/\"],\n allowManualValidation: false,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const httpMethods = (options.httpMethods ?? [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"]).map(\n (m) => m.toUpperCase()\n );\n const routePatterns = options.routePatterns ?? [\n \"route.ts\",\n \"route.tsx\",\n \"/api/\",\n \"/app/api/\",\n ];\n\n const filename = context.filename || context.getFilename?.() || \"\";\n\n // Only check API route files\n if (!isApiRouteFile(filename, routePatterns)) {\n return {};\n }\n\n // Track handlers and their validation status\n const handlerContexts = new Map<TSESTree.Node, ValidationContext>();\n let currentHandler: TSESTree.Node | null = null;\n let currentMethod: string | null = null;\n\n return {\n // Detect HTTP method handlers\n ExportNamedDeclaration(node) {\n const { isHandler, method } = isHttpMethodHandler(node, httpMethods);\n if (isHandler) {\n currentHandler = node;\n currentMethod = method;\n handlerContexts.set(node, {\n hasValidation: false,\n bodyAccessNodes: [],\n });\n }\n },\n\n // Track body access within handlers\n MemberExpression(node) {\n if (!currentHandler) return;\n\n const ctx = handlerContexts.get(currentHandler);\n if (!ctx) return;\n\n const { isAccess, accessType } = isBodyAccess(node);\n if (isAccess && accessType) {\n ctx.bodyAccessNodes.push({ node, accessType });\n }\n },\n\n CallExpression(node) {\n if (!currentHandler) return;\n\n const ctx = handlerContexts.get(currentHandler);\n if (!ctx) return;\n\n // Check for body access\n const { isAccess, accessType } = isBodyAccess(node);\n if (isAccess && accessType) {\n // Check if this is inside a validation call\n // e.g., schema.parse(await request.json())\n if (\n node.parent?.type === \"AwaitExpression\" &&\n node.parent.parent?.type === \"CallExpression\" &&\n isValidationCall(node.parent.parent)\n ) {\n ctx.hasValidation = true;\n return;\n }\n\n // Check if this is directly wrapped in validation\n if (\n node.parent?.type === \"CallExpression\" &&\n isValidationCall(node.parent)\n ) {\n ctx.hasValidation = true;\n return;\n }\n\n ctx.bodyAccessNodes.push({ node, accessType });\n }\n\n // Check for validation calls\n if (isValidationCall(node)) {\n ctx.hasValidation = true;\n }\n },\n\n \"ExportNamedDeclaration:exit\"(node: TSESTree.ExportNamedDeclaration) {\n const ctx = handlerContexts.get(node);\n if (!ctx) return;\n\n // If we have body access but no validation, report\n if (ctx.bodyAccessNodes.length > 0 && !ctx.hasValidation) {\n // Report on the first body access\n const firstAccess = ctx.bodyAccessNodes[0];\n context.report({\n node: firstAccess.node,\n messageId: \"unvalidatedBodyAccess\",\n data: {\n accessType: firstAccess.accessType,\n },\n });\n }\n\n // Clean up\n if (currentHandler === node) {\n currentHandler = null;\n currentMethod = null;\n }\n handlerContexts.delete(node);\n },\n };\n },\n});\n","/**\n * Rule: no-semantic-duplicates\n *\n * Warns when code is semantically similar to existing indexed code.\n * This rule queries a pre-built semantic index (from uilint duplicates index)\n * rather than calling the LLM during linting - making it fast.\n *\n * Prerequisites:\n * - Run `uilint duplicates index` to build the semantic index first\n * - The index is stored at .uilint/.duplicates-index/\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { existsSync, readFileSync, appendFileSync, writeFileSync } from \"fs\";\nimport { dirname, join, relative } from \"path\";\n\n// Debug logging - writes to .uilint/no-semantic-duplicates.log in the project root\nlet logFile: string | null = null;\nlet logInitialized = false;\n\nfunction initLog(projectRoot: string): void {\n if (logFile) return;\n const uilintDir = join(projectRoot, \".uilint\");\n if (existsSync(uilintDir)) {\n logFile = join(uilintDir, \"no-semantic-duplicates.log\");\n }\n}\n\nfunction log(message: string): void {\n if (!logFile) return;\n try {\n const timestamp = new Date().toISOString();\n const line = `[${timestamp}] ${message}\\n`;\n if (!logInitialized) {\n writeFileSync(logFile, line);\n logInitialized = true;\n } else {\n appendFileSync(logFile, line);\n }\n } catch {\n // Ignore logging errors\n }\n}\n\ntype MessageIds = \"semanticDuplicate\" | \"noIndex\";\ntype Options = [\n {\n /** Similarity threshold (0-1). Default: 0.85 */\n threshold?: number;\n /** Path to the index directory */\n indexPath?: string;\n /** Minimum number of lines for a chunk to be reported (default: 3) */\n minLines?: number;\n }\n];\n\n/**\n * Rule metadata\n */\nexport const meta = defineRuleMeta({\n id: \"no-semantic-duplicates\",\n version: \"1.0.0\",\n name: \"No Semantic Duplicates\",\n description: \"Warn when code is semantically similar to existing code\",\n defaultSeverity: \"warn\",\n category: \"semantic\",\n icon: \"🔍\",\n hint: \"Finds similar code via embeddings\",\n defaultEnabled: false,\n plugin: \"semantic\",\n customInspector: \"duplicates\",\n requirements: [\n {\n type: \"semantic-index\",\n description: \"Requires semantic index for duplicate detection\",\n setupHint: \"Run: uilint duplicates index\",\n },\n ],\n postInstallInstructions: \"Run 'uilint duplicates index' to build the semantic index before using this rule.\",\n defaultOptions: [{ threshold: 0.85, indexPath: \".uilint/.duplicates-index\", minLines: 3 }],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Similarity threshold\",\n type: \"number\",\n defaultValue: 0.85,\n description:\n \"Minimum similarity score (0-1) to report as duplicate. Higher = stricter.\",\n },\n {\n key: \"indexPath\",\n label: \"Index path\",\n type: \"text\",\n defaultValue: \".uilint/.duplicates-index\",\n description: \"Path to the semantic duplicates index directory\",\n },\n {\n key: \"minLines\",\n label: \"Minimum lines\",\n type: \"number\",\n defaultValue: 3,\n description:\n \"Minimum number of lines for a chunk to be reported as a potential duplicate.\",\n },\n ],\n },\n docs: `\n## What it does\n\nWarns when code (components, hooks, functions) is semantically similar to other\ncode in the codebase. Unlike syntactic duplicate detection, this finds code that\nimplements similar functionality even if written differently.\n\n## Prerequisites\n\nBefore using this rule, you must build the semantic index:\n\n\\`\\`\\`bash\nuilint duplicates index\n\\`\\`\\`\n\nThis creates an embedding-based index at \\`.uilint/.duplicates-index/\\`.\n\n## Why it's useful\n\n- **Reduce Duplication**: Find components/hooks that could be consolidated\n- **Discover Patterns**: Identify similar code that could be abstracted\n- **Code Quality**: Encourage reuse over reimplementation\n- **Fast**: Queries pre-built index, no LLM calls during linting\n\n## How it works\n\n1. The rule checks if the current file is in the semantic index\n2. For each indexed code chunk, it looks up similar chunks\n3. If similar chunks exist above the threshold, it reports a warning\n\n## Examples\n\n### Semantic duplicates detected:\n\n\\`\\`\\`tsx\n// UserCard.tsx - Original component\nexport function UserCard({ user }) {\n return (\n <div className=\"card\">\n <img src={user.avatar} />\n <h3>{user.name}</h3>\n </div>\n );\n}\n\n// ProfileCard.tsx - Semantically similar (warning!)\nexport function ProfileCard({ profile }) {\n return (\n <article className=\"profile\">\n <img src={profile.avatarUrl} />\n <h2>{profile.displayName}</h2>\n </article>\n );\n}\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/no-semantic-duplicates\": [\"warn\", {\n threshold: 0.85, // Similarity threshold (0-1)\n indexPath: \".uilint/.duplicates-index\",\n minLines: 3 // Minimum lines to report (default: 3)\n}]\n\\`\\`\\`\n\n## Notes\n\n- Run \\`uilint duplicates index\\` after significant code changes\n- Use \\`uilint duplicates find\\` to explore all duplicate groups\n- The rule only reports if the file is in the index\n`,\n});\n\n// Cache for loaded index data across files in a single ESLint run\nlet indexCache: {\n projectRoot: string;\n vectorStore: Map<string, number[]>;\n metadataStore: Map<\n string,\n {\n filePath: string;\n startLine: number;\n endLine: number;\n startColumn: number;\n endColumn: number;\n name: string | null;\n kind: string;\n }\n >;\n fileToChunks: Map<string, string[]>;\n} | null = null;\n\n/**\n * Clear the index cache (useful for testing)\n */\nexport function clearIndexCache(): void {\n indexCache = null;\n}\n\n/**\n * Find project root by looking for the .uilint directory (preferred)\n * or falling back to the root package.json (monorepo root)\n */\nfunction findProjectRoot(startPath: string, indexPath: string): string {\n let current = startPath;\n let lastPackageJson: string | null = null;\n\n // Walk up the directory tree\n while (current !== dirname(current)) {\n // Check for .uilint directory with index (highest priority)\n const uilintDir = join(current, indexPath);\n if (existsSync(join(uilintDir, \"manifest.json\"))) {\n return current;\n }\n\n // Track package.json locations\n if (existsSync(join(current, \"package.json\"))) {\n lastPackageJson = current;\n }\n\n current = dirname(current);\n }\n\n // Return the topmost package.json location (monorepo root) or start path\n return lastPackageJson || startPath;\n}\n\n/**\n * Load the index into memory (cached across files)\n */\nfunction loadIndex(\n projectRoot: string,\n indexPath: string\n): typeof indexCache | null {\n const fullIndexPath = join(projectRoot, indexPath);\n log(`loadIndex called: projectRoot=${projectRoot}, indexPath=${indexPath}`);\n log(`fullIndexPath=${fullIndexPath}`);\n\n // Check if we already have a cached index for this project\n if (indexCache && indexCache.projectRoot === projectRoot) {\n log(`Using cached index (${indexCache.vectorStore.size} vectors, ${indexCache.fileToChunks.size} files)`);\n return indexCache;\n }\n\n // Check if index exists\n const manifestPath = join(fullIndexPath, \"manifest.json\");\n if (!existsSync(manifestPath)) {\n log(`Index not found: manifest.json missing at ${manifestPath}`);\n return null;\n }\n\n try {\n // Load metadata\n const metadataPath = join(fullIndexPath, \"metadata.json\");\n if (!existsSync(metadataPath)) {\n log(`Index not found: metadata.json missing at ${metadataPath}`);\n return null;\n }\n\n const metadataContent = readFileSync(metadataPath, \"utf-8\");\n const metadataJson = JSON.parse(metadataContent);\n\n // Support both formats: { entries: {...} } and direct { chunkId: {...} }\n const entries = metadataJson.entries || metadataJson;\n log(`Loaded metadata.json: ${Object.keys(entries).length} entries`);\n\n const metadataStore = new Map<\n string,\n {\n filePath: string;\n startLine: number;\n endLine: number;\n startColumn: number;\n endColumn: number;\n name: string | null;\n kind: string;\n }\n >();\n const fileToChunks = new Map<string, string[]>();\n\n for (const [id, meta] of Object.entries(entries)) {\n const m = meta as {\n filePath: string;\n startLine: number;\n endLine: number;\n startColumn: number;\n endColumn: number;\n name: string | null;\n kind: string;\n };\n metadataStore.set(id, {\n filePath: m.filePath,\n startLine: m.startLine,\n endLine: m.endLine,\n startColumn: m.startColumn ?? 0,\n endColumn: m.endColumn ?? 0,\n name: m.name,\n kind: m.kind,\n });\n\n // Build file -> chunks mapping\n const chunks = fileToChunks.get(m.filePath) || [];\n chunks.push(id);\n fileToChunks.set(m.filePath, chunks);\n }\n\n log(`File to chunks mapping:`);\n for (const [filePath, chunks] of fileToChunks.entries()) {\n log(` ${filePath}: ${chunks.length} chunks (${chunks.join(\", \")})`);\n }\n\n // Load vectors (binary format)\n const vectorsPath = join(fullIndexPath, \"embeddings.bin\");\n const idsPath = join(fullIndexPath, \"ids.json\");\n const vectorStore = new Map<string, number[]>();\n\n if (existsSync(vectorsPath) && existsSync(idsPath)) {\n const idsContent = readFileSync(idsPath, \"utf-8\");\n const ids = JSON.parse(idsContent) as string[];\n log(`Loaded ids.json: ${ids.length} IDs`);\n\n const buffer = readFileSync(vectorsPath);\n // Must use byteOffset and byteLength because Node's Buffer uses pooling\n // and buffer.buffer may contain data from other buffers at different offsets\n const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);\n\n // Read header\n const dimension = view.getUint32(0, true);\n const count = view.getUint32(4, true);\n log(`Embeddings binary: dimension=${dimension}, count=${count}`);\n\n // Read vectors\n let offset = 8;\n for (let i = 0; i < count && i < ids.length; i++) {\n const vector: number[] = [];\n for (let j = 0; j < dimension; j++) {\n vector.push(view.getFloat32(offset, true));\n offset += 4;\n }\n vectorStore.set(ids[i], vector);\n }\n log(`Loaded ${vectorStore.size} vectors into store`);\n } else {\n log(`Missing vectors or ids files: vectorsPath=${existsSync(vectorsPath)}, idsPath=${existsSync(idsPath)}`);\n }\n\n indexCache = {\n projectRoot,\n vectorStore,\n metadataStore,\n fileToChunks,\n };\n\n log(`Index loaded successfully: ${vectorStore.size} vectors, ${metadataStore.size} metadata entries, ${fileToChunks.size} files`);\n return indexCache;\n } catch (err) {\n log(`Error loading index: ${err}`);\n return null;\n }\n}\n\n/**\n * Calculate cosine similarity between two vectors\n */\nfunction cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) return 0;\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i] * b[i];\n normA += a[i] * a[i];\n normB += b[i] * b[i];\n }\n\n const denominator = Math.sqrt(normA) * Math.sqrt(normB);\n return denominator === 0 ? 0 : dotProduct / denominator;\n}\n\n/**\n * Find similar chunks to a given chunk\n */\nfunction findSimilarChunks(\n index: NonNullable<typeof indexCache>,\n chunkId: string,\n threshold: number\n): Array<{ id: string; score: number }> {\n log(`findSimilarChunks: chunkId=${chunkId}, threshold=${threshold}`);\n\n const vector = index.vectorStore.get(chunkId);\n if (!vector) {\n log(` No vector found for chunk ${chunkId}`);\n return [];\n }\n log(` Vector found: dimension=${vector.length}`);\n\n const results: Array<{ id: string; score: number }> = [];\n const allScores: Array<{ id: string; score: number }> = [];\n\n for (const [id, vec] of index.vectorStore.entries()) {\n if (id === chunkId) continue;\n\n const score = cosineSimilarity(vector, vec);\n allScores.push({ id, score });\n if (score >= threshold) {\n results.push({ id, score });\n }\n }\n\n // Log top 10 scores regardless of threshold\n const sortedAll = allScores.sort((a, b) => b.score - a.score).slice(0, 10);\n log(` Top 10 similarity scores (threshold=${threshold}):`);\n for (const { id, score } of sortedAll) {\n const meta = index.metadataStore.get(id);\n const meetsThreshold = score >= threshold ? \"✓\" : \"✗\";\n log(` ${meetsThreshold} ${(score * 100).toFixed(1)}% - ${id} (${meta?.name || \"anonymous\"} in ${meta?.filePath})`);\n }\n\n log(` Found ${results.length} chunks above threshold`);\n return results.sort((a, b) => b.score - a.score);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-semantic-duplicates\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Warn when code is semantically similar to existing code\",\n },\n messages: {\n semanticDuplicate:\n \"This {{kind}} '{{name}}' is {{similarity}}% similar to '{{otherName}}' at {{otherLocation}}. Consider consolidating.\",\n noIndex:\n \"Semantic duplicates index not found. Run 'uilint duplicates index' first.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n threshold: {\n type: \"number\",\n minimum: 0,\n maximum: 1,\n description: \"Similarity threshold (0-1)\",\n },\n indexPath: {\n type: \"string\",\n description: \"Path to the index directory\",\n },\n minLines: {\n type: \"integer\",\n minimum: 1,\n description: \"Minimum number of lines for a chunk to be reported\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n threshold: 0.85,\n indexPath: \".uilint/.duplicates-index\",\n minLines: 3,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const threshold = options.threshold ?? 0.85;\n const indexPath = options.indexPath ?? \".uilint/.duplicates-index\";\n const minLines = options.minLines ?? 3;\n\n const filename = context.filename || context.getFilename();\n const projectRoot = findProjectRoot(dirname(filename), indexPath);\n\n // Initialize logging to .uilint folder\n initLog(projectRoot);\n\n log(`\\n========== Rule create() ==========`);\n log(`Filename: ${filename}`);\n log(`Threshold: ${threshold}`);\n log(`Index path: ${indexPath}`);\n log(`Min lines: ${minLines}`);\n log(`Project root: ${projectRoot}`);\n\n const index = loadIndex(projectRoot, indexPath);\n\n // Track which chunks we've already reported to avoid duplicates\n const reportedChunks = new Set<string>();\n\n /**\n * Check if a node location corresponds to an indexed chunk\n * and if so, check for similar chunks\n */\n function checkForDuplicates(\n node: TSESTree.Node,\n name: string | null\n ): void {\n log(`checkForDuplicates: name=${name}, file=${filename}`);\n\n if (!index) {\n log(` No index loaded`);\n return;\n }\n\n // Get chunks for this file\n const fileChunks = index.fileToChunks.get(filename);\n log(` Looking for chunks for file: ${filename}`);\n log(` Files in index: ${Array.from(index.fileToChunks.keys()).join(\", \")}`);\n\n if (!fileChunks || fileChunks.length === 0) {\n log(` No chunks found for this file`);\n return;\n }\n log(` Found ${fileChunks.length} chunks: ${fileChunks.join(\", \")}`);\n\n // Find the chunk that contains this node's location\n const nodeLine = node.loc?.start.line;\n if (!nodeLine) {\n log(` No node line number`);\n return;\n }\n log(` Node starts at line ${nodeLine}`);\n\n for (const chunkId of fileChunks) {\n if (reportedChunks.has(chunkId)) {\n log(` Chunk ${chunkId} already reported, skipping`);\n continue;\n }\n\n const meta = index.metadataStore.get(chunkId);\n if (!meta) {\n log(` No metadata for chunk ${chunkId}`);\n continue;\n }\n\n log(` Checking chunk ${chunkId}: lines ${meta.startLine}-${meta.endLine} (node at line ${nodeLine})`);\n\n // Check if this node is within the chunk's line range\n if (nodeLine >= meta.startLine && nodeLine <= meta.endLine) {\n log(` Node is within chunk range, searching for similar chunks...`);\n\n // Find similar chunks\n const similar = findSimilarChunks(index, chunkId, threshold);\n\n if (similar.length > 0) {\n const best = similar[0];\n const bestMeta = index.metadataStore.get(best.id);\n\n if (bestMeta) {\n // Check minimum lines threshold\n const chunkLines = meta.endLine - meta.startLine + 1;\n if (chunkLines < minLines) {\n log(` Skipping: chunk has ${chunkLines} lines, below minLines=${minLines}`);\n continue;\n }\n\n reportedChunks.add(chunkId);\n\n const relPath = relative(projectRoot, bestMeta.filePath);\n const similarity = Math.round(best.score * 100);\n\n log(` REPORTING: ${meta.kind} '${name || meta.name}' is ${similarity}% similar to '${bestMeta.name}' at ${relPath}:${bestMeta.startLine}`);\n\n context.report({\n node,\n loc: {\n start: { line: meta.startLine, column: meta.startColumn },\n end: { line: meta.endLine, column: meta.endColumn },\n },\n messageId: \"semanticDuplicate\",\n data: {\n kind: meta.kind,\n name: name || meta.name || \"(anonymous)\",\n similarity: String(similarity),\n otherName: bestMeta.name || \"(anonymous)\",\n otherLocation: `${relPath}:${bestMeta.startLine}`,\n },\n });\n }\n } else {\n log(` No similar chunks found above threshold`);\n }\n } else {\n log(` Node line ${nodeLine} not in chunk range ${meta.startLine}-${meta.endLine}`);\n }\n }\n }\n\n return {\n // Check function declarations\n FunctionDeclaration(node) {\n const name = node.id?.name || null;\n checkForDuplicates(node, name);\n },\n\n // Check arrow functions assigned to variables\n \"VariableDeclarator[init.type='ArrowFunctionExpression']\"(\n node: TSESTree.VariableDeclarator\n ) {\n const name =\n node.id.type === \"Identifier\" ? node.id.name : null;\n if (node.init) {\n checkForDuplicates(node.init, name);\n }\n },\n\n // Check function expressions\n \"VariableDeclarator[init.type='FunctionExpression']\"(\n node: TSESTree.VariableDeclarator\n ) {\n const name =\n node.id.type === \"Identifier\" ? node.id.name : null;\n if (node.init) {\n checkForDuplicates(node.init, name);\n }\n },\n };\n },\n});\n","/**\n * Rule: require-test-coverage\n *\n * Enforces that source files have test coverage above a configurable threshold.\n * Checks for:\n * - Existence of test files\n * - Coverage data in Istanbul JSON format\n * - Statement coverage percentage\n */\n\nimport { createRule, defineRuleMeta } from \"../../utils/create-rule.js\";\nimport { existsSync, readFileSync, statSync } from \"fs\";\nimport { dirname, join, basename, relative } from \"path\";\nimport { execSync } from \"child_process\";\nimport {\n aggregateCoverage,\n type IstanbulCoverage as AggregatorIstanbulCoverage,\n} from \"./lib/coverage-aggregator.js\";\nimport {\n analyzeJSXElementCoverage,\n type IstanbulCoverage as JSXAnalyzerIstanbulCoverage,\n} from \"./lib/jsx-coverage-analyzer.js\";\nimport { analyzeChunks, getChunkThreshold } from \"./lib/chunk-analyzer.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\n/**\n * Simple glob pattern matching function\n * Supports: *, **, ?\n */\nfunction simpleGlobMatch(pattern: string, path: string): boolean {\n // Normalize path separators\n const normalizedPath = path.replace(/\\\\/g, \"/\");\n const normalizedPattern = pattern.replace(/\\\\/g, \"/\");\n\n // Escape regex special chars except our glob patterns\n let regexStr = normalizedPattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\") // Escape regex special chars\n .replace(/\\*\\*/g, \"{{GLOBSTAR}}\") // Placeholder for **\n .replace(/\\*/g, \"[^/]*\") // * matches anything except /\n .replace(/\\?/g, \"[^/]\") // ? matches single char except /\n .replace(/{{GLOBSTAR}}/g, \".*\"); // ** matches anything including /\n\n // Add anchors\n const regex = new RegExp(`^${regexStr}$`);\n return regex.test(normalizedPath);\n}\n\ntype MessageIds =\n | \"noCoverage\"\n | \"belowThreshold\"\n | \"noCoverageData\"\n | \"belowAggregateThreshold\"\n | \"jsxBelowThreshold\"\n | \"chunkBelowThreshold\"\n | \"untestedFunction\";\n\ntype SeverityLevel = \"error\" | \"warn\" | \"off\";\n\ntype Options = [\n {\n /** Path to coverage JSON file. Default: \"coverage/coverage-final.json\" */\n coveragePath?: string;\n /** Coverage threshold percentage. Default: 80 */\n threshold?: number;\n /** Pattern-specific thresholds */\n thresholdsByPattern?: Array<{ pattern: string; threshold: number }>;\n /** Severity levels for different issue types */\n severity?: {\n noCoverage?: SeverityLevel;\n belowThreshold?: SeverityLevel;\n };\n /** Patterns to detect test files. Default: [\".test.ts\", \".test.tsx\", \".spec.ts\", \".spec.tsx\", \"__tests__/\"] */\n testPatterns?: string[];\n /** Glob patterns for files to ignore. Default: [\"**\\/*.d.ts\", \"**\\/index.ts\"] */\n ignorePatterns?: string[];\n /** Mode: \"all\" checks all code, \"changed\" only checks git-changed lines. Default: \"all\" */\n mode?: \"all\" | \"changed\";\n /** Base branch for \"changed\" mode. Default: \"main\" */\n baseBranch?: string;\n /** Aggregate coverage threshold for components. Default: 70 */\n aggregateThreshold?: number;\n /** Severity for aggregate coverage check. Default: \"warn\" */\n aggregateSeverity?: SeverityLevel;\n /** JSX element coverage threshold percentage. Default: 50 */\n jsxThreshold?: number;\n /** Severity for JSX element coverage check. Default: \"warn\" */\n jsxSeverity?: SeverityLevel;\n /** Enable chunk-level coverage reporting (replaces file-level). Default: false */\n chunkCoverage?: boolean;\n /** Threshold for strict categories (utility/hook/store). Default: 80 */\n chunkThreshold?: number;\n /** Focus on non-React code with relaxed thresholds for components. Default: false */\n focusNonReact?: boolean;\n /** Threshold for relaxed categories (component/handler). Default: 50 */\n relaxedThreshold?: number;\n /** Severity for chunk coverage. Default: \"warn\" */\n chunkSeverity?: SeverityLevel;\n /** Minimum statements in file to require coverage. Default: 5 */\n minStatements?: number;\n }\n];\n\n/**\n * Istanbul coverage JSON format\n */\ninterface IstanbulCoverage {\n [filePath: string]: {\n path: string;\n statementMap: {\n [key: string]: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n fnMap: {\n [key: string]: {\n name: string;\n decl: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n };\n branchMap: {\n [key: string]: {\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n type: string;\n locations: Array<{\n start: { line: number; column: number };\n end: { line: number; column: number };\n }>;\n };\n };\n s: { [key: string]: number }; // Statement hit counts\n f: { [key: string]: number }; // Function hit counts\n b: { [key: string]: number[] }; // Branch hit counts\n };\n}\n\n/**\n * Rule metadata\n */\nexport const meta = defineRuleMeta({\n id: \"require-test-coverage\",\n version: \"1.0.0\",\n name: \"Require Test Coverage\",\n description: \"Enforce that source files have adequate test coverage\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🧪\",\n hint: \"Ensures code has tests\",\n defaultEnabled: true,\n isDirectoryBased: true,\n requirements: [\n {\n type: \"coverage\",\n description: \"Requires test coverage data\",\n setupHint: \"Run tests with coverage: npm test -- --coverage\",\n },\n ],\n defaultOptions: [\n {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\",\n ],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\",\n baseBranch: \"main\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description: \"Minimum coverage percentage required (0-100)\",\n },\n {\n key: \"coveragePath\",\n label: \"Coverage file path\",\n type: \"text\",\n defaultValue: \"coverage/coverage-final.json\",\n description: \"Path to Istanbul coverage JSON file\",\n },\n {\n key: \"mode\",\n label: \"Mode\",\n type: \"select\",\n defaultValue: \"all\",\n options: [\n { value: \"all\", label: \"Check all code\" },\n { value: \"changed\", label: \"Only check changed lines\" },\n ],\n description: \"Whether to check all code or only git-changed lines\",\n },\n {\n key: \"chunkCoverage\",\n label: \"Enable chunk-level coverage\",\n type: \"boolean\",\n defaultValue: true,\n description:\n \"Report coverage for individual functions instead of file level\",\n },\n {\n key: \"focusNonReact\",\n label: \"Focus on non-React code\",\n type: \"boolean\",\n defaultValue: false,\n description:\n \"Apply strict thresholds to utilities/stores/hooks, relaxed to components\",\n },\n {\n key: \"chunkThreshold\",\n label: \"Chunk coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description:\n \"Minimum coverage for utility/hook/store chunks (0-100)\",\n },\n {\n key: \"relaxedThreshold\",\n label: \"Relaxed threshold for React code\",\n type: \"number\",\n defaultValue: 50,\n description:\n \"Threshold for components/handlers when focusNonReact is enabled\",\n },\n {\n key: \"minStatements\",\n label: \"Minimum statements for coverage\",\n type: \"number\",\n defaultValue: 5,\n description:\n \"Files with fewer statements are exempt from coverage requirements\",\n },\n ],\n },\n docs: `\n## What it does\n\nEnforces that source files have test coverage above a configurable threshold.\nIt checks for:\n- Existence of corresponding test files\n- Coverage data in Istanbul JSON format\n- Statement coverage percentage meeting the threshold\n\n## Why it's useful\n\n- **Quality Assurance**: Ensures critical code is tested\n- **Catch Regressions**: Prevents merging untested changes\n- **Configurable**: Different thresholds for different file patterns\n- **Git Integration**: Can focus only on changed lines\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/require-test-coverage\": [\"warn\", {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [\n { pattern: \"**/utils/*.ts\", threshold: 90 },\n { pattern: \"**/generated/**\", threshold: 0 },\n ],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\".test.ts\", \".test.tsx\", \".spec.ts\", \".spec.tsx\", \"__tests__/\"],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\", // or \"changed\"\n baseBranch: \"main\" // for \"changed\" mode\n}]\n\\`\\`\\`\n\n## Examples\n\n### Below threshold:\n\\`\\`\\`ts\n// src/api.ts - 40% coverage (threshold: 80%)\nexport function fetchData() { ... } // Warning: Coverage below threshold\n\\`\\`\\`\n`,\n});\n\n// Cache for loaded coverage data\nlet coverageCache: {\n projectRoot: string;\n coveragePath: string;\n mtime: number;\n data: IstanbulCoverage;\n} | null = null;\n\n/**\n * Clear the coverage cache (useful for testing)\n */\nexport function clearCoverageCache(): void {\n coverageCache = null;\n}\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startPath: string): string {\n let current = startPath;\n let lastPackageJson: string | null = null;\n\n while (current !== dirname(current)) {\n if (existsSync(join(current, \"package.json\"))) {\n lastPackageJson = current;\n }\n // If we find a coverage directory, use this as project root\n if (existsSync(join(current, \"coverage\"))) {\n return current;\n }\n current = dirname(current);\n }\n\n return lastPackageJson || startPath;\n}\n\n/**\n * Load coverage data from JSON file\n */\nfunction loadCoverage(\n projectRoot: string,\n coveragePath: string\n): IstanbulCoverage | null {\n const fullPath = join(projectRoot, coveragePath);\n\n if (!existsSync(fullPath)) {\n return null;\n }\n\n try {\n const stat = statSync(fullPath);\n const mtime = stat.mtimeMs;\n\n // Check cache\n if (\n coverageCache &&\n coverageCache.projectRoot === projectRoot &&\n coverageCache.coveragePath === coveragePath &&\n coverageCache.mtime === mtime\n ) {\n return coverageCache.data;\n }\n\n const content = readFileSync(fullPath, \"utf-8\");\n const data = JSON.parse(content) as IstanbulCoverage;\n\n // Update cache\n coverageCache = {\n projectRoot,\n coveragePath,\n mtime,\n data,\n };\n\n return data;\n } catch {\n return null;\n }\n}\n\n/**\n * Calculate statement coverage percentage for a file\n */\nfunction calculateCoverage(fileCoverage: IstanbulCoverage[string]): number {\n const statements = fileCoverage.s;\n const keys = Object.keys(statements);\n\n if (keys.length === 0) {\n return 100; // No statements = 100% covered\n }\n\n const covered = keys.filter((key) => statements[key] > 0).length;\n return Math.round((covered / keys.length) * 100);\n}\n\n/**\n * Check if a file matches any of the ignore patterns\n */\nfunction shouldIgnore(filePath: string, ignorePatterns: string[]): boolean {\n for (const pattern of ignorePatterns) {\n if (simpleGlobMatch(pattern, filePath)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Get threshold for a file, checking pattern-specific thresholds first\n */\nfunction getThreshold(\n filePath: string,\n globalThreshold: number,\n thresholdsByPattern: Array<{ pattern: string; threshold: number }>\n): number {\n for (const { pattern, threshold } of thresholdsByPattern) {\n if (simpleGlobMatch(pattern, filePath)) {\n return threshold;\n }\n }\n return globalThreshold;\n}\n\n/**\n * Get changed line numbers from git diff\n */\nfunction getChangedLines(\n projectRoot: string,\n filePath: string,\n baseBranch: string\n): Set<number> | null {\n try {\n const relPath = relative(projectRoot, filePath);\n const diff = execSync(`git diff ${baseBranch}...HEAD -- \"${relPath}\"`, {\n cwd: projectRoot,\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n const changedLines = new Set<number>();\n const lines = diff.split(\"\\n\");\n\n let currentLine = 0;\n for (const line of lines) {\n // Parse hunk header: @@ -start,count +start,count @@\n const hunkMatch = line.match(/^@@ -\\d+(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (hunkMatch) {\n currentLine = parseInt(hunkMatch[1], 10);\n continue;\n }\n\n if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n changedLines.add(currentLine);\n currentLine++;\n } else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) {\n // Deleted line, don't increment\n } else if (!line.startsWith(\"\\\\\")) {\n currentLine++;\n }\n }\n\n return changedLines;\n } catch {\n // Git command failed, return null to fall back to \"all\" mode\n return null;\n }\n}\n\n/**\n * Calculate coverage for only changed lines\n */\nfunction calculateChangedLinesCoverage(\n fileCoverage: IstanbulCoverage[string],\n changedLines: Set<number>\n): number {\n const statementMap = fileCoverage.statementMap;\n const statements = fileCoverage.s;\n\n let relevantStatements = 0;\n let coveredStatements = 0;\n\n for (const [key, location] of Object.entries(statementMap)) {\n // Check if any line of this statement was changed\n let isRelevant = false;\n for (let line = location.start.line; line <= location.end.line; line++) {\n if (changedLines.has(line)) {\n isRelevant = true;\n break;\n }\n }\n\n if (isRelevant) {\n relevantStatements++;\n if (statements[key] > 0) {\n coveredStatements++;\n }\n }\n }\n\n if (relevantStatements === 0) {\n return 100; // No changed statements = 100% covered\n }\n\n return Math.round((coveredStatements / relevantStatements) * 100);\n}\n\n/**\n * Normalize file path for coverage lookup\n * Coverage JSON may store paths in different formats\n */\nfunction findCoverageForFile(\n coverage: IstanbulCoverage,\n filePath: string,\n projectRoot: string\n): IstanbulCoverage[string] | null {\n // Try exact match first\n if (coverage[filePath]) {\n return coverage[filePath];\n }\n\n // Try relative path from project root\n const relPath = relative(projectRoot, filePath);\n if (coverage[relPath]) {\n return coverage[relPath];\n }\n\n // Try with leading slash (common in Istanbul output)\n const withSlash = \"/\" + relPath;\n if (coverage[withSlash]) {\n return coverage[withSlash];\n }\n\n // Try just the src-relative path\n const srcMatch = relPath.match(/src\\/.+$/);\n if (srcMatch) {\n const srcPath = \"/\" + srcMatch[0];\n if (coverage[srcPath]) {\n return coverage[srcPath];\n }\n }\n\n return null;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"require-test-coverage\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Enforce that source files have adequate test coverage\",\n },\n messages: {\n noCoverage:\n \"No coverage data found for '{{fileName}}' in coverage report\",\n belowThreshold:\n \"Coverage for '{{fileName}}' is {{coverage}}%, below threshold of {{threshold}}%\",\n noCoverageData:\n \"Coverage data not found at '{{coveragePath}}'. Run tests with coverage first.\",\n belowAggregateThreshold:\n \"Aggregate coverage ({{coverage}}%) is below threshold ({{threshold}}%). \" +\n \"Includes {{fileCount}} files. Lowest: {{lowestFile}} ({{lowestCoverage}}%)\",\n jsxBelowThreshold:\n \"<{{tagName}}> element coverage is {{coverage}}%, below threshold of {{threshold}}%\",\n chunkBelowThreshold:\n \"{{category}} '{{name}}' has {{coverage}}% coverage, below {{threshold}}% threshold\",\n untestedFunction:\n \"Function '{{name}}' ({{category}}) is not covered by tests\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n coveragePath: {\n type: \"string\",\n description: \"Path to coverage JSON file\",\n },\n threshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description: \"Coverage threshold percentage\",\n },\n thresholdsByPattern: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n pattern: { type: \"string\" },\n threshold: { type: \"number\", minimum: 0, maximum: 100 },\n },\n required: [\"pattern\", \"threshold\"],\n additionalProperties: false,\n },\n description: \"Pattern-specific thresholds\",\n },\n severity: {\n type: \"object\",\n properties: {\n noCoverage: { type: \"string\", enum: [\"error\", \"warn\", \"off\"] },\n belowThreshold: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n },\n },\n additionalProperties: false,\n },\n testPatterns: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Patterns to detect test files\",\n },\n ignorePatterns: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Glob patterns for files to ignore\",\n },\n mode: {\n type: \"string\",\n enum: [\"all\", \"changed\"],\n description: \"Check all code or only changed lines\",\n },\n baseBranch: {\n type: \"string\",\n description: \"Base branch for changed mode\",\n },\n aggregateThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description:\n \"Aggregate coverage threshold for components (includes dependencies)\",\n },\n aggregateSeverity: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n description: \"Severity for aggregate coverage check\",\n },\n jsxThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description:\n \"JSX element coverage threshold percentage (includes event handlers)\",\n },\n jsxSeverity: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n description: \"Severity for JSX element coverage check\",\n },\n chunkCoverage: {\n type: \"boolean\",\n description:\n \"Enable chunk-level coverage reporting (replaces file-level)\",\n },\n chunkThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description:\n \"Threshold for strict categories (utility/hook/store)\",\n },\n focusNonReact: {\n type: \"boolean\",\n description:\n \"Focus on non-React code with relaxed thresholds for components\",\n },\n relaxedThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 100,\n description: \"Threshold for relaxed categories (component/handler)\",\n },\n chunkSeverity: {\n type: \"string\",\n enum: [\"error\", \"warn\", \"off\"],\n description: \"Severity for chunk coverage check\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\",\n ],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\",\n baseBranch: \"main\",\n aggregateThreshold: 70,\n aggregateSeverity: \"warn\",\n jsxThreshold: 50,\n jsxSeverity: \"warn\",\n chunkCoverage: true,\n chunkThreshold: 80,\n focusNonReact: false,\n relaxedThreshold: 50,\n chunkSeverity: \"warn\",\n minStatements: 5,\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const coveragePath = options.coveragePath ?? \"coverage/coverage-final.json\";\n const threshold = options.threshold ?? 80;\n const thresholdsByPattern = options.thresholdsByPattern ?? [];\n const severity = {\n noCoverage: options.severity?.noCoverage ?? \"error\",\n belowThreshold: options.severity?.belowThreshold ?? \"warn\",\n };\n const aggregateThreshold = options.aggregateThreshold ?? 70;\n const aggregateSeverity = options.aggregateSeverity ?? \"warn\";\n const testPatterns = options.testPatterns ?? [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\",\n ];\n const ignorePatterns = options.ignorePatterns ?? [\n \"**/*.d.ts\",\n \"**/index.ts\",\n ];\n const mode = options.mode ?? \"all\";\n const baseBranch = options.baseBranch ?? \"main\";\n const jsxThreshold = options.jsxThreshold ?? 50;\n const jsxSeverity = options.jsxSeverity ?? \"warn\";\n const chunkCoverage = options.chunkCoverage ?? true;\n const chunkThreshold = options.chunkThreshold ?? 80;\n const focusNonReact = options.focusNonReact ?? false;\n const relaxedThreshold = options.relaxedThreshold ?? 50;\n const chunkSeverity = options.chunkSeverity ?? \"warn\";\n const minStatements = options.minStatements ?? 5;\n\n const filename = context.filename || context.getFilename();\n const projectRoot = findProjectRoot(dirname(filename));\n\n // Check if file should be ignored\n const relPath = relative(projectRoot, filename);\n if (shouldIgnore(relPath, ignorePatterns)) {\n return {};\n }\n\n // Skip test files themselves\n if (\n testPatterns.some((p) =>\n filename.includes(p.replace(\"__tests__/\", \"__tests__\"))\n )\n ) {\n return {};\n }\n\n // Track if we've already reported for this file\n let reported = false;\n\n // Collect JSX elements with their ancestors for element-level coverage\n const jsxElements: Array<{\n node: TSESTree.JSXElement;\n ancestors: TSESTree.Node[];\n }> = [];\n\n return {\n // Collect JSX elements for element-level coverage analysis\n JSXElement(node: TSESTree.JSXElement) {\n // Get ancestors using context.sourceCode (ESLint v9) or context.getAncestors (legacy)\n const ancestors = context.sourceCode?.getAncestors?.(node) ?? [];\n jsxElements.push({ node, ancestors });\n },\n\n \"Program:exit\"(node: TSESTree.Program) {\n if (reported) return;\n reported = true;\n\n // Load coverage data\n const coverage = loadCoverage(projectRoot, coveragePath);\n\n // Check if coverage data exists\n if (!coverage) {\n if (severity.noCoverage !== \"off\") {\n context.report({\n node,\n messageId: \"noCoverageData\",\n data: {\n coveragePath,\n },\n });\n }\n return;\n }\n\n // Find coverage for this file\n const fileCoverage = findCoverageForFile(\n coverage,\n filename,\n projectRoot\n );\n\n if (!fileCoverage) {\n // File is not in coverage report - this is OK if coverage data exists\n // but this specific file wasn't covered (different from no coverage data at all)\n return;\n }\n\n // Skip small files (fewer statements than minStatements threshold)\n const statementCount = Object.keys(fileCoverage.s).length;\n if (statementCount < minStatements) {\n return;\n }\n\n // Calculate coverage\n let coveragePercent: number;\n\n if (mode === \"changed\") {\n const changedLines = getChangedLines(\n projectRoot,\n filename,\n baseBranch\n );\n if (changedLines && changedLines.size > 0) {\n coveragePercent = calculateChangedLinesCoverage(\n fileCoverage,\n changedLines\n );\n } else {\n // No changed lines or git failed - use full coverage\n coveragePercent = calculateCoverage(fileCoverage);\n }\n } else {\n coveragePercent = calculateCoverage(fileCoverage);\n }\n\n // Get threshold for this file\n const fileThreshold = getThreshold(\n relPath,\n threshold,\n thresholdsByPattern\n );\n\n // Check if below threshold (file-level) - skipped when chunkCoverage is enabled\n if (\n !chunkCoverage &&\n severity.belowThreshold !== \"off\" &&\n coveragePercent < fileThreshold\n ) {\n context.report({\n node,\n messageId: \"belowThreshold\",\n data: {\n fileName: basename(filename),\n coverage: String(coveragePercent),\n threshold: String(fileThreshold),\n },\n });\n }\n\n // Check chunk-level coverage (replaces file-level when enabled)\n if (chunkCoverage && chunkSeverity !== \"off\" && fileCoverage) {\n const chunks = analyzeChunks(\n context.sourceCode.ast,\n filename,\n fileCoverage\n );\n\n // Report one message per chunk below threshold, highlighting just the declaration\n for (const chunk of chunks) {\n const chunkThresholdValue = getChunkThreshold(chunk, {\n focusNonReact,\n chunkThreshold,\n relaxedThreshold,\n });\n\n if (chunk.coverage.percentage < chunkThresholdValue) {\n const messageId =\n chunk.coverage.functionCalled\n ? \"chunkBelowThreshold\"\n : \"untestedFunction\";\n\n context.report({\n loc: chunk.declarationLoc,\n messageId,\n data: {\n name: chunk.name,\n category: chunk.category,\n coverage: String(chunk.coverage.percentage),\n threshold: String(chunkThresholdValue),\n },\n });\n }\n }\n }\n\n // Check aggregate coverage for component files (JSX)\n if (\n aggregateSeverity !== \"off\" &&\n (filename.endsWith(\".tsx\") || filename.endsWith(\".jsx\"))\n ) {\n // Check if file actually contains JSX by looking at the AST\n const hasJSX = checkForJSX(context.sourceCode.ast);\n\n if (hasJSX) {\n const aggregateResult = aggregateCoverage(\n filename,\n projectRoot,\n coverage as AggregatorIstanbulCoverage\n );\n\n if (aggregateResult.aggregateCoverage < aggregateThreshold) {\n const lowestFile = aggregateResult.lowestCoverageFile;\n context.report({\n node,\n messageId: \"belowAggregateThreshold\",\n data: {\n coverage: String(\n Math.round(aggregateResult.aggregateCoverage)\n ),\n threshold: String(aggregateThreshold),\n fileCount: String(aggregateResult.totalFiles),\n lowestFile: lowestFile\n ? basename(lowestFile.path)\n : \"N/A\",\n lowestCoverage: lowestFile\n ? String(Math.round(lowestFile.percentage))\n : \"N/A\",\n },\n });\n }\n }\n }\n\n // Check JSX element-level coverage\n if (\n jsxSeverity !== \"off\" &&\n jsxElements.length > 0 &&\n coverage\n ) {\n // Compute relative path for dataLoc (consistent with overlay matching)\n const fileRelPath = relPath.startsWith(\"/\") ? relPath : `/${relPath}`;\n\n for (const { node: jsxNode, ancestors } of jsxElements) {\n // Only check elements with event handlers (interactive elements)\n const hasEventHandlers = jsxNode.openingElement.attributes.some(\n (attr) =>\n attr.type === \"JSXAttribute\" &&\n attr.name.type === \"JSXIdentifier\" &&\n /^on[A-Z]/.test(attr.name.name)\n );\n\n // Skip non-interactive elements to reduce noise\n if (!hasEventHandlers) {\n continue;\n }\n\n const result = analyzeJSXElementCoverage(\n jsxNode,\n fileRelPath,\n coverage as JSXAnalyzerIstanbulCoverage,\n ancestors,\n projectRoot\n );\n\n if (result.coverage.percentage < jsxThreshold) {\n // Get the tag name for the error message\n const openingElement = jsxNode.openingElement;\n let tagName = \"unknown\";\n if (openingElement.name.type === \"JSXIdentifier\") {\n tagName = openingElement.name.name;\n } else if (openingElement.name.type === \"JSXMemberExpression\") {\n // For Foo.Bar, use \"Foo.Bar\"\n let current: TSESTree.JSXTagNameExpression = openingElement.name;\n const parts: string[] = [];\n while (current.type === \"JSXMemberExpression\") {\n if (current.property.type === \"JSXIdentifier\") {\n parts.unshift(current.property.name);\n }\n current = current.object;\n }\n if (current.type === \"JSXIdentifier\") {\n parts.unshift(current.name);\n }\n tagName = parts.join(\".\");\n }\n\n context.report({\n node: jsxNode,\n messageId: \"jsxBelowThreshold\",\n data: {\n tagName,\n coverage: String(result.coverage.percentage),\n threshold: String(jsxThreshold),\n dataLoc: result.dataLoc,\n },\n });\n }\n }\n }\n },\n };\n },\n});\n\n/**\n * Check if an AST contains JSX elements\n * Uses a visited set to avoid infinite recursion from circular references (e.g., parent pointers)\n */\nfunction checkForJSX(ast: unknown, visited: WeakSet<object> = new WeakSet()): boolean {\n if (!ast || typeof ast !== \"object\") return false;\n\n // Avoid circular references\n if (visited.has(ast as object)) return false;\n visited.add(ast as object);\n\n const node = ast as Record<string, unknown>;\n\n // Check if this node is JSX\n if (\n node.type === \"JSXElement\" ||\n node.type === \"JSXFragment\" ||\n node.type === \"JSXText\"\n ) {\n return true;\n }\n\n // Only traverse known AST child properties to avoid parent/token references\n const childKeys = [\"body\", \"declarations\", \"declaration\", \"expression\", \"expressions\",\n \"argument\", \"arguments\", \"callee\", \"elements\", \"properties\", \"value\", \"init\",\n \"consequent\", \"alternate\", \"test\", \"left\", \"right\", \"object\", \"property\",\n \"children\", \"openingElement\", \"closingElement\", \"attributes\"];\n\n for (const key of childKeys) {\n const child = node[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (checkForJSX(item, visited)) return true;\n }\n } else {\n if (checkForJSX(child, visited)) return true;\n }\n }\n }\n\n return false;\n}\n","/**\n * File Categorizer\n *\n * Categorizes TypeScript/React files by their role in the codebase.\n * Used for smart weighting in coverage aggregation.\n *\n * Categories:\n * - core (1.0): hooks, components, services, stores - critical logic\n * - utility (0.5): formatters, validators, helpers - supporting code\n * - constant (0.25): config, constants, enums - static data\n * - type (0): .d.ts files, type-only exports - no runtime impact\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { basename } from \"path\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\nexport type FileCategory = \"core\" | \"utility\" | \"constant\" | \"type\";\n\nexport interface FileCategoryResult {\n category: FileCategory;\n weight: number;\n reason: string;\n}\n\nconst CATEGORY_WEIGHTS: Record<FileCategory, number> = {\n core: 1.0,\n utility: 0.5,\n constant: 0.25,\n type: 0,\n};\n\n/**\n * Categorize a TypeScript/React file by its role\n */\nexport function categorizeFile(\n filePath: string,\n _projectRoot: string\n): FileCategoryResult {\n const fileName = basename(filePath);\n\n // 1. Type definition files are always \"type\"\n if (filePath.endsWith(\".d.ts\")) {\n return {\n category: \"type\",\n weight: 0,\n reason: \"TypeScript declaration file (.d.ts)\",\n };\n }\n\n // 2. Check file name patterns for core files\n // Hooks: use*.ts or use*.tsx\n if (/^use[A-Z]/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"React hook (use* pattern)\",\n };\n }\n\n // Services: *.service.ts\n if (/\\.service\\.(ts|tsx)$/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"Service file (*.service.ts pattern)\",\n };\n }\n\n // Stores: *.store.ts\n if (/\\.store\\.(ts|tsx)$/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"Store file (*.store.ts pattern)\",\n };\n }\n\n // API files: *.api.ts\n if (/\\.api\\.(ts|tsx)$/.test(fileName)) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"API file (*.api.ts pattern)\",\n };\n }\n\n // 3. Parse AST to analyze exports\n if (!existsSync(filePath)) {\n return {\n category: \"utility\",\n weight: 0.5,\n reason: \"File not found, defaulting to utility\",\n };\n }\n\n let ast: TSESTree.Program;\n try {\n const content = readFileSync(filePath, \"utf-8\");\n ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n });\n } catch {\n return {\n category: \"utility\",\n weight: 0.5,\n reason: \"Failed to parse file, defaulting to utility\",\n };\n }\n\n // Analyze the file's exports\n const analysis = analyzeExports(ast);\n\n // 4. Type-only files (only type/interface exports, no runtime code)\n if (analysis.hasOnlyTypeExports) {\n return {\n category: \"type\",\n weight: 0,\n reason: \"File contains only type/interface exports\",\n };\n }\n\n // 5. Check for JSX (React component)\n if (analysis.hasJSX) {\n return {\n category: \"core\",\n weight: 1.0,\n reason: \"React component (contains JSX)\",\n };\n }\n\n // 6. Constant files (only const/enum exports, no functions)\n if (analysis.hasOnlyConstantExports) {\n return {\n category: \"constant\",\n weight: 0.25,\n reason: \"File contains only constant/enum exports\",\n };\n }\n\n // 7. Default to utility\n return {\n category: \"utility\",\n weight: 0.5,\n reason: \"General utility file with function exports\",\n };\n}\n\ninterface ExportAnalysis {\n hasOnlyTypeExports: boolean;\n hasOnlyConstantExports: boolean;\n hasJSX: boolean;\n hasFunctionExports: boolean;\n hasConstExports: boolean;\n hasTypeExports: boolean;\n}\n\n/**\n * Analyze exports in an AST to determine file category\n */\nfunction analyzeExports(ast: TSESTree.Program): ExportAnalysis {\n let hasFunctionExports = false;\n let hasConstExports = false;\n let hasTypeExports = false;\n let hasJSX = false;\n\n // Walk the AST to find exports and JSX\n function visit(node: TSESTree.Node): void {\n // Check for JSX\n if (\n node.type === \"JSXElement\" ||\n node.type === \"JSXFragment\" ||\n node.type === \"JSXText\"\n ) {\n hasJSX = true;\n }\n\n // Export named declaration\n if (node.type === \"ExportNamedDeclaration\") {\n const decl = node.declaration;\n\n // Type/interface exports\n if (\n node.exportKind === \"type\" ||\n decl?.type === \"TSTypeAliasDeclaration\" ||\n decl?.type === \"TSInterfaceDeclaration\"\n ) {\n hasTypeExports = true;\n }\n // Function exports\n else if (\n decl?.type === \"FunctionDeclaration\" ||\n (decl?.type === \"VariableDeclaration\" &&\n decl.declarations.some(\n (d) =>\n d.init?.type === \"ArrowFunctionExpression\" ||\n d.init?.type === \"FunctionExpression\"\n ))\n ) {\n hasFunctionExports = true;\n }\n // Const/enum exports\n else if (\n decl?.type === \"VariableDeclaration\" ||\n decl?.type === \"TSEnumDeclaration\"\n ) {\n // Check if it's a const with non-function value\n if (decl.type === \"VariableDeclaration\") {\n const hasNonFunctionInit = decl.declarations.some(\n (d) =>\n d.init &&\n d.init.type !== \"ArrowFunctionExpression\" &&\n d.init.type !== \"FunctionExpression\"\n );\n if (hasNonFunctionInit) {\n hasConstExports = true;\n }\n } else {\n hasConstExports = true;\n }\n }\n // Re-exports without declaration - check specifiers\n else if (!decl && node.specifiers.length > 0) {\n // For re-exports, we can't easily determine the type without resolving\n // Treat as potential function exports to be safe\n // Note: if exportKind was \"type\", we would have matched the first branch\n hasFunctionExports = true;\n }\n }\n\n // Export default\n if (node.type === \"ExportDefaultDeclaration\") {\n const decl = node.declaration;\n if (\n decl.type === \"FunctionDeclaration\" ||\n decl.type === \"ArrowFunctionExpression\" ||\n decl.type === \"FunctionExpression\"\n ) {\n hasFunctionExports = true;\n } else if (decl.type === \"ClassDeclaration\") {\n // Classes are typically core logic\n hasFunctionExports = true;\n } else {\n hasConstExports = true;\n }\n }\n\n // Recurse into children\n for (const key of Object.keys(node)) {\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n visit(item as TSESTree.Node);\n }\n }\n } else if (\"type\" in child) {\n visit(child as TSESTree.Node);\n }\n }\n }\n }\n\n for (const node of ast.body) {\n visit(node);\n }\n\n // Determine derived properties\n const hasOnlyTypeExports =\n hasTypeExports && !hasFunctionExports && !hasConstExports;\n const hasOnlyConstantExports =\n hasConstExports && !hasFunctionExports && !hasTypeExports;\n\n return {\n hasOnlyTypeExports,\n hasOnlyConstantExports,\n hasJSX,\n hasFunctionExports,\n hasConstExports,\n hasTypeExports,\n };\n}\n\n/**\n * Get the weight for a category\n */\nexport function getCategoryWeight(category: FileCategory): number {\n return CATEGORY_WEIGHTS[category];\n}\n","/**\n * Dependency Graph Builder\n *\n * Builds a dependency graph by tracing all imports from an entry file.\n * Used for calculating aggregate test coverage across a component and its dependencies.\n *\n * Key behaviors:\n * - Traces transitive dependencies (full depth)\n * - Excludes node_modules (external packages)\n * - Handles circular dependencies via visited set\n * - Follows re-exports to actual source files\n * - Caches results for performance\n */\n\nimport { existsSync, readFileSync, statSync } from \"fs\";\nimport { dirname, resolve } from \"path\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { resolveImportPath, parseFile } from \"./export-resolver.js\";\n\nexport interface DependencyGraph {\n /** The entry file that was analyzed */\n root: string;\n /** All transitive dependencies (absolute paths, project files only) */\n allDependencies: Set<string>;\n}\n\ninterface CacheEntry {\n graph: DependencyGraph;\n mtime: number;\n}\n\n/**\n * Cache for dependency graphs (per entry file)\n */\nconst dependencyCache = new Map<string, CacheEntry>();\n\n/**\n * Build a dependency graph starting from an entry file\n *\n * @param entryFile - Absolute path to the entry file\n * @param projectRoot - Project root directory (used for determining project boundaries)\n * @returns DependencyGraph with all transitive dependencies\n */\nexport function buildDependencyGraph(\n entryFile: string,\n projectRoot: string\n): DependencyGraph {\n // Check cache\n const cached = dependencyCache.get(entryFile);\n if (cached) {\n // Validate cache by checking entry file mtime\n try {\n const currentMtime = statSync(entryFile).mtimeMs;\n if (currentMtime === cached.mtime) {\n return cached.graph;\n }\n } catch {\n // File doesn't exist or can't be read, invalidate cache\n }\n }\n\n const allDependencies = new Set<string>();\n const visited = new Set<string>();\n\n // Recursively collect dependencies\n collectDependencies(entryFile, projectRoot, allDependencies, visited);\n\n const graph: DependencyGraph = {\n root: entryFile,\n allDependencies,\n };\n\n // Cache the result\n try {\n const mtime = statSync(entryFile).mtimeMs;\n dependencyCache.set(entryFile, { graph, mtime });\n } catch {\n // If we can't get mtime, don't cache\n }\n\n return graph;\n}\n\n/**\n * Recursively collect dependencies from a file\n */\nfunction collectDependencies(\n filePath: string,\n projectRoot: string,\n allDependencies: Set<string>,\n visited: Set<string>\n): void {\n // Prevent infinite loops from circular dependencies\n if (visited.has(filePath)) {\n return;\n }\n visited.add(filePath);\n\n // Parse the file to extract imports\n const imports = extractImports(filePath);\n\n for (const importSource of imports) {\n // Resolve the import to an absolute path\n const resolvedPath = resolveImportPath(importSource, filePath);\n\n if (!resolvedPath) {\n // Could not resolve (external package or unresolvable)\n continue;\n }\n\n // Skip node_modules\n if (resolvedPath.includes(\"node_modules\")) {\n continue;\n }\n\n // Skip files outside the project\n if (!resolvedPath.startsWith(projectRoot)) {\n continue;\n }\n\n // Skip already visited files (handles circular dependencies)\n // This prevents adding the root file back as a dependency\n if (visited.has(resolvedPath)) {\n continue;\n }\n\n // Add to dependencies\n allDependencies.add(resolvedPath);\n\n // Recurse into this dependency\n collectDependencies(resolvedPath, projectRoot, allDependencies, visited);\n }\n}\n\n/**\n * Extract all import sources from a file\n */\nfunction extractImports(filePath: string): string[] {\n if (!existsSync(filePath)) {\n return [];\n }\n\n const ast = parseFile(filePath);\n if (!ast) {\n return [];\n }\n\n const imports: string[] = [];\n\n for (const node of ast.body) {\n // import ... from \"source\"\n if (node.type === \"ImportDeclaration\" && node.source.value) {\n imports.push(node.source.value as string);\n }\n\n // export ... from \"source\" (re-exports)\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.source?.value\n ) {\n imports.push(node.source.value as string);\n }\n\n // export * from \"source\"\n if (node.type === \"ExportAllDeclaration\" && node.source.value) {\n imports.push(node.source.value as string);\n }\n }\n\n // Also check for dynamic imports in the AST\n const dynamicImports = extractDynamicImports(ast);\n imports.push(...dynamicImports);\n\n return imports;\n}\n\n/**\n * Extract dynamic import() calls from the AST\n */\nfunction extractDynamicImports(ast: TSESTree.Program): string[] {\n const imports: string[] = [];\n\n function visit(node: TSESTree.Node): void {\n // import(\"source\")\n if (\n node.type === \"ImportExpression\" &&\n node.source.type === \"Literal\" &&\n typeof node.source.value === \"string\"\n ) {\n imports.push(node.source.value);\n }\n\n // Recurse into children\n for (const key of Object.keys(node)) {\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n visit(item as TSESTree.Node);\n }\n }\n } else if (\"type\" in child) {\n visit(child as TSESTree.Node);\n }\n }\n }\n }\n\n for (const node of ast.body) {\n visit(node);\n }\n\n return imports;\n}\n\n/**\n * Invalidate the cache for a specific file\n *\n * Call this when a file changes to ensure fresh data\n */\nexport function invalidateDependencyCache(filePath: string): void {\n dependencyCache.delete(filePath);\n\n // Also invalidate any graphs that include this file as a dependency\n for (const [entryFile, entry] of dependencyCache) {\n if (entry.graph.allDependencies.has(filePath)) {\n dependencyCache.delete(entryFile);\n }\n }\n}\n\n/**\n * Clear the entire dependency cache\n */\nexport function clearDependencyCache(): void {\n dependencyCache.clear();\n}\n\n/**\n * Get cache statistics (for debugging/monitoring)\n */\nexport function getDependencyCacheStats(): {\n size: number;\n entries: string[];\n} {\n return {\n size: dependencyCache.size,\n entries: Array.from(dependencyCache.keys()),\n };\n}\n","/**\n * Export Resolver\n *\n * Resolves import paths and finds export definitions, following re-exports\n * to their original source files.\n */\n\nimport { ResolverFactory } from \"oxc-resolver\";\nimport { parse } from \"@typescript-eslint/typescript-estree\";\nimport { readFileSync, existsSync } from \"fs\";\nimport { dirname, join, extname } from \"path\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\n// Module-level resolver instance (reused across calls)\nlet resolverInstance: ReturnType<typeof ResolverFactory.prototype.sync> | null =\n null;\nlet resolverFactory: ResolverFactory | null = null;\n\n/**\n * Information about a resolved export\n */\nexport interface ResolvedExport {\n /** The name of the export (e.g., \"Button\") */\n name: string;\n /** Absolute path to the file containing the actual definition */\n filePath: string;\n /** The local name in the source file (may differ from export name) */\n localName: string;\n /** Whether this is a re-export (export { X } from './other') */\n isReexport: boolean;\n}\n\n/**\n * Cache for file exports to avoid re-parsing\n */\nconst exportCache = new Map<\n string,\n Map<string, { localName: string; reexportSource?: string }>\n>();\n\n/**\n * Cache for parsed ASTs\n */\nconst astCache = new Map<string, TSESTree.Program>();\n\n/**\n * Cache for resolved paths\n */\nconst resolvedPathCache = new Map<string, string | null>();\n\n/**\n * Get or create the resolver factory\n */\nfunction getResolverFactory(): ResolverFactory {\n if (!resolverFactory) {\n resolverFactory = new ResolverFactory({\n extensions: [\".tsx\", \".ts\", \".jsx\", \".js\"],\n mainFields: [\"module\", \"main\"],\n conditionNames: [\"import\", \"require\", \"node\", \"default\"],\n // Enable TypeScript path resolution\n tsconfig: {\n configFile: \"tsconfig.json\",\n references: \"auto\",\n },\n });\n }\n return resolverFactory;\n}\n\n/**\n * Resolve an import path to an absolute file path\n */\nexport function resolveImportPath(\n importSource: string,\n fromFile: string\n): string | null {\n const cacheKey = `${fromFile}::${importSource}`;\n\n if (resolvedPathCache.has(cacheKey)) {\n return resolvedPathCache.get(cacheKey) ?? null;\n }\n\n // Skip node_modules\n if (\n importSource.startsWith(\"react\") ||\n importSource.startsWith(\"next\") ||\n (!importSource.startsWith(\".\") &&\n !importSource.startsWith(\"@/\") &&\n !importSource.startsWith(\"~/\"))\n ) {\n // Check if it's a known external package\n if (\n importSource.includes(\"@mui/\") ||\n importSource.includes(\"@chakra-ui/\") ||\n importSource.includes(\"antd\") ||\n importSource.includes(\"@radix-ui/\")\n ) {\n // Return a marker for external packages - we don't resolve them but track them\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n resolvedPathCache.set(cacheKey, null);\n return null;\n }\n\n try {\n const factory = getResolverFactory();\n const fromDir = dirname(fromFile);\n const result = factory.sync(fromDir, importSource);\n\n if (result.path) {\n resolvedPathCache.set(cacheKey, result.path);\n return result.path;\n }\n } catch {\n // Fallback: try manual resolution for common patterns\n const resolved = manualResolve(importSource, fromFile);\n resolvedPathCache.set(cacheKey, resolved);\n return resolved;\n }\n\n resolvedPathCache.set(cacheKey, null);\n return null;\n}\n\n/**\n * Manual fallback resolution for common patterns\n */\nfunction manualResolve(importSource: string, fromFile: string): string | null {\n const fromDir = dirname(fromFile);\n const extensions = [\".tsx\", \".ts\", \".jsx\", \".js\"];\n\n // Handle @/ alias - find tsconfig and resolve\n if (importSource.startsWith(\"@/\")) {\n const projectRoot = findProjectRoot(fromFile);\n if (projectRoot) {\n const relativePath = importSource.slice(2); // Remove @/\n for (const ext of extensions) {\n const candidate = join(projectRoot, relativePath + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(projectRoot, relativePath, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n }\n\n // Handle relative imports\n if (importSource.startsWith(\".\")) {\n for (const ext of extensions) {\n const candidate = join(fromDir, importSource + ext);\n if (existsSync(candidate)) {\n return candidate;\n }\n // Try index file\n const indexCandidate = join(fromDir, importSource, `index${ext}`);\n if (existsSync(indexCandidate)) {\n return indexCandidate;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Find the project root by looking for tsconfig.json or package.json\n */\nfunction findProjectRoot(fromFile: string): string | null {\n let dir = dirname(fromFile);\n const root = \"/\";\n\n while (dir !== root) {\n if (existsSync(join(dir, \"tsconfig.json\"))) {\n return dir;\n }\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n dir = dirname(dir);\n }\n\n return null;\n}\n\n/**\n * Parse a file and cache the AST\n */\nexport function parseFile(filePath: string): TSESTree.Program | null {\n if (astCache.has(filePath)) {\n return astCache.get(filePath)!;\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const ast = parse(content, {\n jsx: true,\n loc: true,\n range: true,\n });\n astCache.set(filePath, ast);\n return ast;\n } catch {\n return null;\n }\n}\n\n/**\n * Extract export information from a file\n */\nfunction extractExports(\n filePath: string\n): Map<string, { localName: string; reexportSource?: string }> {\n if (exportCache.has(filePath)) {\n return exportCache.get(filePath)!;\n }\n\n const exports = new Map<\n string,\n { localName: string; reexportSource?: string }\n >();\n const ast = parseFile(filePath);\n\n if (!ast) {\n exportCache.set(filePath, exports);\n return exports;\n }\n\n for (const node of ast.body) {\n // Handle: export function Button() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(node.declaration.id.name, {\n localName: node.declaration.id.name,\n });\n }\n\n // Handle: export const Button = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (decl.id.type === \"Identifier\") {\n exports.set(decl.id.name, { localName: decl.id.name });\n }\n }\n }\n\n // Handle: export { Button } or export { Button as Btn }\n if (node.type === \"ExportNamedDeclaration\" && node.specifiers.length > 0) {\n const source = node.source?.value as string | undefined;\n for (const spec of node.specifiers) {\n if (spec.type === \"ExportSpecifier\") {\n const exportedName =\n spec.exported.type === \"Identifier\"\n ? spec.exported.name\n : spec.exported.value;\n const localName =\n spec.local.type === \"Identifier\"\n ? spec.local.name\n : spec.local.value;\n\n exports.set(exportedName, {\n localName,\n reexportSource: source,\n });\n }\n }\n }\n\n // Handle: export default function Button() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n exports.set(\"default\", { localName: node.declaration.id.name });\n }\n\n // Handle: export default Button\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"Identifier\"\n ) {\n exports.set(\"default\", { localName: node.declaration.name });\n }\n }\n\n exportCache.set(filePath, exports);\n return exports;\n}\n\n/**\n * Resolve an export to its original definition, following re-exports\n */\nexport function resolveExport(\n exportName: string,\n filePath: string,\n visited = new Set<string>()\n): ResolvedExport | null {\n // Cycle detection\n const key = `${filePath}::${exportName}`;\n if (visited.has(key)) {\n return null;\n }\n visited.add(key);\n\n const exports = extractExports(filePath);\n const exportInfo = exports.get(exportName);\n\n if (!exportInfo) {\n return null;\n }\n\n // If it's a re-export, follow the chain\n if (exportInfo.reexportSource) {\n const resolvedPath = resolveImportPath(exportInfo.reexportSource, filePath);\n if (resolvedPath) {\n return resolveExport(exportInfo.localName, resolvedPath, visited);\n }\n return null;\n }\n\n // This is the actual definition\n return {\n name: exportName,\n filePath,\n localName: exportInfo.localName,\n isReexport: false,\n };\n}\n\n/**\n * Clear all caches (useful for testing or watch mode)\n */\nexport function clearResolverCaches(): void {\n exportCache.clear();\n astCache.clear();\n resolvedPathCache.clear();\n}\n","/**\n * Coverage Aggregator\n *\n * Calculates weighted aggregate coverage for a component by tracing its\n * dependencies and combining their coverage using smart weighting.\n *\n * Weighting strategy:\n * - core (1.0): hooks, components, services - critical logic\n * - utility (0.5): formatters, validators - supporting code\n * - constant (0.25): config, constants - static data\n * - type (0): .d.ts, type-only - no runtime impact\n */\n\nimport { categorizeFile, type FileCategory } from \"./file-categorizer.js\";\nimport { buildDependencyGraph } from \"./dependency-graph.js\";\n\n/**\n * Istanbul coverage JSON format (matching require-test-coverage.ts)\n */\nexport interface IstanbulCoverage {\n [filePath: string]: {\n path: string;\n statementMap: {\n [key: string]: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n fnMap: {\n [key: string]: {\n name: string;\n decl: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n };\n };\n branchMap: {\n [key: string]: {\n loc: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n type: string;\n locations: Array<{\n start: { line: number; column: number };\n end: { line: number; column: number };\n }>;\n };\n };\n s: { [key: string]: number }; // Statement hit counts\n f: { [key: string]: number }; // Function hit counts\n b: { [key: string]: number[] }; // Branch hit counts\n };\n}\n\n/**\n * Coverage information for a single file\n */\nexport interface FileCoverageInfo {\n filePath: string;\n category: FileCategory;\n weight: number;\n statements: { covered: number; total: number };\n percentage: number;\n}\n\n/**\n * Aggregated coverage result for a component\n */\nexport interface AggregatedCoverage {\n /** The component file that was analyzed */\n componentFile: string;\n /** Coverage percentage for just the component file */\n componentCoverage: number;\n /** Weighted aggregate coverage across component + all dependencies */\n aggregateCoverage: number;\n /** Total number of files analyzed (component + dependencies) */\n totalFiles: number;\n /** Detailed coverage info for each file */\n filesAnalyzed: FileCoverageInfo[];\n /** Files with 0% coverage */\n uncoveredFiles: string[];\n /** The file with lowest coverage (excluding 0% files) */\n lowestCoverageFile: { path: string; percentage: number } | null;\n}\n\n/**\n * Calculate aggregate coverage for a component and its dependencies\n *\n * @param componentFile - Absolute path to the component file\n * @param projectRoot - Project root directory\n * @param coverageData - Istanbul coverage data\n * @returns Aggregated coverage information\n */\nexport function aggregateCoverage(\n componentFile: string,\n projectRoot: string,\n coverageData: IstanbulCoverage\n): AggregatedCoverage {\n // Build dependency graph\n const graph = buildDependencyGraph(componentFile, projectRoot);\n\n // Collect all files to analyze (component + dependencies)\n const allFiles = new Set<string>([componentFile, ...graph.allDependencies]);\n\n // Analyze each file\n const filesAnalyzed: FileCoverageInfo[] = [];\n const uncoveredFiles: string[] = [];\n let lowestCoverageFile: { path: string; percentage: number } | null = null;\n let componentCoverageInfo: FileCoverageInfo | null = null;\n\n for (const filePath of allFiles) {\n const coverageInfo = getFileCoverage(filePath, projectRoot, coverageData);\n filesAnalyzed.push(coverageInfo);\n\n // Track component coverage separately\n if (filePath === componentFile) {\n componentCoverageInfo = coverageInfo;\n }\n\n // Track uncovered files (0%)\n if (coverageInfo.percentage === 0 && coverageInfo.statements.total > 0) {\n uncoveredFiles.push(filePath);\n }\n\n // Track lowest coverage (excluding 0% and type files with weight 0)\n if (\n coverageInfo.percentage > 0 &&\n coverageInfo.weight > 0 &&\n coverageInfo.statements.total > 0\n ) {\n if (\n !lowestCoverageFile ||\n coverageInfo.percentage < lowestCoverageFile.percentage\n ) {\n lowestCoverageFile = {\n path: filePath,\n percentage: coverageInfo.percentage,\n };\n }\n }\n }\n\n // Calculate weighted aggregate coverage\n const aggregateCoverageValue = calculateWeightedCoverage(filesAnalyzed);\n\n return {\n componentFile,\n componentCoverage: componentCoverageInfo?.percentage ?? 0,\n aggregateCoverage: aggregateCoverageValue,\n totalFiles: filesAnalyzed.length,\n filesAnalyzed,\n uncoveredFiles,\n lowestCoverageFile,\n };\n}\n\n/**\n * Get coverage information for a single file\n */\nfunction getFileCoverage(\n filePath: string,\n projectRoot: string,\n coverageData: IstanbulCoverage\n): FileCoverageInfo {\n // Categorize the file\n const categoryResult = categorizeFile(filePath, projectRoot);\n\n // Find coverage data for this file\n const fileCoverage = findCoverageForFile(filePath, coverageData, projectRoot);\n\n if (!fileCoverage) {\n // No coverage data - could mean not tested or file not found\n return {\n filePath,\n category: categoryResult.category,\n weight: categoryResult.weight,\n statements: { covered: 0, total: 0 },\n percentage: 0,\n };\n }\n\n // Calculate statement coverage\n const statementHits = fileCoverage.s;\n const totalStatements = Object.keys(statementHits).length;\n const coveredStatements = Object.values(statementHits).filter(\n (hits) => hits > 0\n ).length;\n\n const percentage =\n totalStatements > 0 ? (coveredStatements / totalStatements) * 100 : 0;\n\n return {\n filePath,\n category: categoryResult.category,\n weight: categoryResult.weight,\n statements: { covered: coveredStatements, total: totalStatements },\n percentage: Math.round(percentage * 100) / 100, // Round to 2 decimal places\n };\n}\n\n/**\n * Find coverage data for a file, handling path normalization\n */\nfunction findCoverageForFile(\n filePath: string,\n coverageData: IstanbulCoverage,\n projectRoot: string\n): IstanbulCoverage[string] | null {\n // Try exact match first\n if (coverageData[filePath]) {\n return coverageData[filePath];\n }\n\n // Try relative path from project root\n const relativePath = filePath.startsWith(projectRoot)\n ? filePath.slice(projectRoot.length)\n : filePath;\n\n // Try with and without leading slash\n const pathVariants = [\n relativePath,\n relativePath.startsWith(\"/\") ? relativePath.slice(1) : `/${relativePath}`,\n relativePath.startsWith(\"/\") ? relativePath : `/${relativePath}`,\n ];\n\n for (const variant of pathVariants) {\n if (coverageData[variant]) {\n return coverageData[variant];\n }\n }\n\n // Try matching by checking if coverage path ends with relative path\n for (const [coveragePath, coverage] of Object.entries(coverageData)) {\n if (\n coveragePath.endsWith(relativePath) ||\n coveragePath.endsWith(relativePath.slice(1))\n ) {\n return coverage;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate weighted average coverage across files\n *\n * Uses statement count * weight for each file to determine contribution.\n * Files with weight 0 (type files) are excluded from calculation.\n */\nfunction calculateWeightedCoverage(files: FileCoverageInfo[]): number {\n let totalWeightedStatements = 0;\n let totalWeightedCovered = 0;\n\n for (const file of files) {\n // Skip files with weight 0 (type files)\n if (file.weight === 0) {\n continue;\n }\n\n // Skip files with no statements\n if (file.statements.total === 0) {\n continue;\n }\n\n const weightedTotal = file.statements.total * file.weight;\n const weightedCovered = file.statements.covered * file.weight;\n\n totalWeightedStatements += weightedTotal;\n totalWeightedCovered += weightedCovered;\n }\n\n if (totalWeightedStatements === 0) {\n return 0;\n }\n\n const percentage = (totalWeightedCovered / totalWeightedStatements) * 100;\n return Math.round(percentage * 100) / 100; // Round to 2 decimal places\n}\n","/**\n * JSX Coverage Analyzer\n *\n * Analyzes JSX elements to determine test coverage for interactive elements\n * like event handlers. Uses Istanbul coverage data to check if the code\n * associated with JSX elements has been executed during tests.\n *\n * Phase 1: Core functions for statement-level coverage analysis\n * Phase 2: Event handler extraction and analysis\n * Phase 3: Conditional parent analysis + Component-level aggregation (partial TODO)\n * Phase 4: Import dependency coverage + ESLint rule reporting (partial TODO)\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport type { IstanbulCoverage } from \"./coverage-aggregator.js\";\n\n/**\n * Re-export IstanbulCoverage for consumers of this module\n */\nexport type { IstanbulCoverage } from \"./coverage-aggregator.js\";\n\n/**\n * Istanbul coverage data for a single file\n */\nexport type IstanbulFileCoverage = IstanbulCoverage[string];\n\n/**\n * Source location with start and end positions\n */\nexport interface SourceLocation {\n start: { line: number; column: number };\n end: { line: number; column: number };\n}\n\n/**\n * Coverage statistics for a code region\n */\nexport interface CoverageStats {\n /** Number of statements that were executed at least once */\n covered: number;\n /** Total number of statements in the region */\n total: number;\n /** Coverage percentage (0-100) */\n percentage: number;\n}\n\n/**\n * Coverage result for a single JSX element\n */\nexport interface JSXCoverageResult {\n /** The data-loc attribute value for this element */\n dataLoc: string;\n /** Whether this element has any event handlers */\n hasEventHandlers: boolean;\n /** Names of event handlers found (e.g., [\"onClick\", \"onSubmit\"]) */\n eventHandlerNames: string[];\n /** Coverage statistics for statements within this element */\n coverage: CoverageStats;\n /** Whether the element is considered \"covered\" (percentage > 0) */\n isCovered: boolean;\n}\n\n// =============================================================================\n// Phase 1: Core Functions\n// =============================================================================\n\n/**\n * Creates a \"file:line:column\" format string for data-loc attribute\n *\n * @param filePath - Absolute or relative path to the file\n * @param loc - Source location with start position\n * @returns Formatted string like \"src/Button.tsx:15:4\"\n */\nexport function buildDataLoc(filePath: string, loc: SourceLocation): string {\n return `${filePath}:${loc.start.line}:${loc.start.column}`;\n}\n\n/**\n * Find statement IDs that overlap with the given source location\n *\n * A statement overlaps if its line range intersects with the location's\n * line range. Column-level precision is not used for overlap detection.\n *\n * @param loc - The source location to check\n * @param fileCoverage - Istanbul coverage data for the file\n * @returns Set of statement IDs (keys from statementMap) that overlap\n */\nexport function findStatementsInRange(\n loc: SourceLocation,\n fileCoverage: IstanbulFileCoverage\n): Set<string> {\n const overlappingStatements = new Set<string>();\n\n for (const [statementId, statementLoc] of Object.entries(\n fileCoverage.statementMap\n )) {\n // Check if statement's line range overlaps with location's line range\n const statementStart = statementLoc.start.line;\n const statementEnd = statementLoc.end.line;\n const locStart = loc.start.line;\n const locEnd = loc.end.line;\n\n // Two ranges overlap if: start1 <= end2 AND start2 <= end1\n if (statementStart <= locEnd && locStart <= statementEnd) {\n overlappingStatements.add(statementId);\n }\n }\n\n return overlappingStatements;\n}\n\n/**\n * Calculate coverage statistics from a set of statement IDs\n *\n * @param statementIds - Set of statement IDs to check\n * @param fileCoverage - Istanbul coverage data for the file\n * @returns Coverage statistics with covered count, total, and percentage\n */\nexport function calculateCoverageFromStatements(\n statementIds: Set<string>,\n fileCoverage: IstanbulFileCoverage\n): CoverageStats {\n if (statementIds.size === 0) {\n return { covered: 0, total: 0, percentage: 0 };\n }\n\n let covered = 0;\n const total = statementIds.size;\n\n for (const statementId of statementIds) {\n const hitCount = fileCoverage.s[statementId];\n if (hitCount !== undefined && hitCount > 0) {\n covered++;\n }\n }\n\n const percentage = total > 0 ? Math.round((covered / total) * 100) : 0;\n\n return { covered, total, percentage };\n}\n\n/**\n * Find coverage data for a file with path normalization\n *\n * Handles various path formats:\n * - Absolute paths\n * - Relative paths with or without leading slash\n * - Paths that may differ in their base directory\n *\n * @param coverage - Full Istanbul coverage data\n * @param filePath - The file path to find coverage for\n * @returns File coverage data if found, undefined otherwise\n */\nexport function findCoverageForFile(\n coverage: IstanbulCoverage,\n filePath: string\n): IstanbulFileCoverage | undefined {\n // Try exact match first\n if (coverage[filePath]) {\n return coverage[filePath];\n }\n\n // Normalize the path for comparison (remove leading slashes, standardize)\n const normalizedPath = filePath.replace(/^\\/+/, \"\");\n\n // Try with and without leading slash\n const pathVariants = [\n normalizedPath,\n `/${normalizedPath}`,\n filePath,\n ];\n\n for (const variant of pathVariants) {\n if (coverage[variant]) {\n return coverage[variant];\n }\n }\n\n // Try matching by checking if coverage path ends with our path\n for (const [coveragePath, fileCoverage] of Object.entries(coverage)) {\n const normalizedCoveragePath = coveragePath.replace(/^\\/+/, \"\");\n\n if (\n normalizedCoveragePath.endsWith(normalizedPath) ||\n normalizedPath.endsWith(normalizedCoveragePath)\n ) {\n return fileCoverage;\n }\n }\n\n return undefined;\n}\n\n/**\n * Check if a JSX attribute is an event handler (starts with \"on\" followed by uppercase)\n *\n * Event handlers follow the pattern: onClick, onSubmit, onChange, etc.\n * This excludes spread attributes and non-event props like \"only\" or \"once\".\n *\n * @param attr - JSX attribute or spread attribute\n * @returns true if the attribute is an event handler\n */\nexport function isEventHandlerAttribute(\n attr: TSESTree.JSXAttribute | TSESTree.JSXSpreadAttribute\n): boolean {\n // Spread attributes are not event handlers by themselves\n if (attr.type === \"JSXSpreadAttribute\") {\n return false;\n }\n\n // Only handle JSXIdentifier names (not namespaced like xml:lang)\n if (attr.name.type !== \"JSXIdentifier\") {\n return false;\n }\n\n const name = attr.name.name;\n\n // Match pattern: on[A-Z]...\n return /^on[A-Z]/.test(name);\n}\n\n/**\n * Analyze a JSX element for test coverage\n *\n * Main entry point that combines all the above functions to produce\n * a complete coverage analysis for a single JSX element.\n *\n * @param jsxNode - The JSX element node from the AST\n * @param filePath - Path to the file containing this element\n * @param coverage - Istanbul coverage data\n * @param ancestors - Optional ancestor nodes for resolving handler references\n * @param projectRoot - Optional project root for resolving import paths\n * @returns Coverage result for the JSX element\n */\nexport function analyzeJSXElementCoverage(\n jsxNode: TSESTree.JSXElement,\n filePath: string,\n coverage: IstanbulCoverage,\n ancestors: TSESTree.Node[] = [],\n projectRoot?: string\n): JSXCoverageResult {\n // Build the data-loc identifier\n const loc = jsxNode.loc;\n const dataLoc = buildDataLoc(filePath, loc);\n\n // Find event handlers on this element\n const eventHandlerNames: string[] = [];\n for (const attr of jsxNode.openingElement.attributes) {\n if (isEventHandlerAttribute(attr) && attr.type === \"JSXAttribute\") {\n if (attr.name.type === \"JSXIdentifier\") {\n eventHandlerNames.push(attr.name.name);\n }\n }\n }\n const hasEventHandlers = eventHandlerNames.length > 0;\n\n // Find coverage data for this file\n const fileCoverage = findCoverageForFile(coverage, filePath);\n\n if (!fileCoverage) {\n // No coverage data available for this file\n return {\n dataLoc,\n hasEventHandlers,\n eventHandlerNames,\n coverage: { covered: 0, total: 0, percentage: 0 },\n isCovered: false,\n };\n }\n\n // Find statements that overlap with this JSX element\n const statementIds = findStatementsInRange(loc, fileCoverage);\n\n // Also include statements from event handler bodies (Phase 2)\n if (hasEventHandlers) {\n const handlerStatementIds = getHandlerStatements(\n jsxNode,\n fileCoverage,\n ancestors\n );\n for (const stmtId of handlerStatementIds) {\n statementIds.add(stmtId);\n }\n }\n\n // Include statements from conditional ancestors (Phase 3)\n // This ensures conditionally rendered elements include the condition's coverage\n const conditionalAncestor = findConditionalAncestor(jsxNode, ancestors);\n if (conditionalAncestor) {\n const conditionalStatementIds = getConditionalStatements(\n conditionalAncestor,\n fileCoverage\n );\n for (const stmtId of conditionalStatementIds) {\n statementIds.add(stmtId);\n }\n }\n\n // Calculate local coverage statistics (statements in this file)\n const localCoverage = calculateCoverageFromStatements(\n statementIds,\n fileCoverage\n );\n\n // Phase 4: Include import dependency coverage\n // Find imports used in this JSX element and aggregate their coverage\n let importCoverage = { covered: 0, total: 0 };\n if (projectRoot && ancestors.length > 0) {\n const importPaths = findImportsUsedInJSX(jsxNode, ancestors);\n if (importPaths.size > 0) {\n importCoverage = aggregateImportCoverage(\n importPaths,\n coverage,\n projectRoot,\n filePath\n );\n }\n }\n\n // Combine local and import coverage (weighted by statement count)\n const totalCovered = localCoverage.covered + importCoverage.covered;\n const totalStatements = localCoverage.total + importCoverage.total;\n const combinedPercentage =\n totalStatements > 0 ? Math.round((totalCovered / totalStatements) * 100) : 0;\n\n const coverageStats: CoverageStats = {\n covered: totalCovered,\n total: totalStatements,\n percentage: combinedPercentage,\n };\n\n return {\n dataLoc,\n hasEventHandlers,\n eventHandlerNames,\n coverage: coverageStats,\n isCovered: coverageStats.percentage > 0,\n };\n}\n\n// =============================================================================\n// Phase 2: Event Handler Analysis\n// =============================================================================\n\n/**\n * Extract the expression from an event handler attribute value\n *\n * Handles various forms of event handler values:\n * - {handleClick} - identifier reference\n * - {() => doSomething()} - inline arrow function\n * - {fn.bind(this)} - call expression (like bind)\n * - {obj.method} - member expression\n *\n * @param attr - The JSX attribute to extract from\n * @returns The expression if found, null for string literals or empty values\n */\nexport function extractEventHandlerExpression(\n attr: TSESTree.JSXAttribute\n): TSESTree.Expression | null {\n // No value means no expression (e.g., <input disabled />)\n if (!attr.value) {\n return null;\n }\n\n // String literals are not expressions we can analyze\n // e.g., onClick=\"someGlobalFunction()\"\n if (attr.value.type === \"Literal\") {\n return null;\n }\n\n // JSX expression container: {expression}\n if (attr.value.type === \"JSXExpressionContainer\") {\n const expression = attr.value.expression;\n\n // Empty expression container {} or JSXEmptyExpression\n if (expression.type === \"JSXEmptyExpression\") {\n return null;\n }\n\n // Return the actual expression (Identifier, ArrowFunctionExpression, CallExpression, etc.)\n return expression;\n }\n\n // JSXElement as value (rare, but possible)\n // e.g., onClick={<SomeComponent />} - not a valid handler expression\n return null;\n}\n\n/**\n * Find the function declaration for an identifier used as an event handler\n *\n * Searches through the ancestor chain to find where an identifier is declared.\n * Handles:\n * - Variable declarations with function expressions\n * - Variable declarations with arrow functions\n * - Function declarations\n * - Function parameters (destructured or direct)\n *\n * @param identifier - The identifier node (e.g., the \"handleClick\" in onClick={handleClick})\n * @param ancestors - The ancestor nodes from the AST traversal (innermost first or any order)\n * @returns The function body node if found, null otherwise\n */\nexport function findHandlerFunctionDeclaration(\n identifier: TSESTree.Identifier,\n ancestors: TSESTree.Node[]\n): TSESTree.Node | null {\n const targetName = identifier.name;\n\n for (const ancestor of ancestors) {\n // Check FunctionDeclaration\n if (\n ancestor.type === \"FunctionDeclaration\" &&\n ancestor.id?.name === targetName\n ) {\n return ancestor.body;\n }\n\n // Check VariableDeclaration\n if (ancestor.type === \"VariableDeclaration\") {\n for (const declarator of ancestor.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n // Check if the init is a function\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n\n // Check BlockStatement and Program for contained declarations\n if (ancestor.type === \"BlockStatement\" || ancestor.type === \"Program\") {\n const body =\n ancestor.type === \"Program\" ? ancestor.body : ancestor.body;\n\n for (const statement of body) {\n // Function declarations in block\n if (\n statement.type === \"FunctionDeclaration\" &&\n statement.id?.name === targetName\n ) {\n return statement.body;\n }\n\n // Variable declarations in block\n if (statement.type === \"VariableDeclaration\") {\n for (const declarator of statement.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n\n // Export declarations\n if (statement.type === \"ExportNamedDeclaration\" && statement.declaration) {\n if (\n statement.declaration.type === \"FunctionDeclaration\" &&\n statement.declaration.id?.name === targetName\n ) {\n return statement.declaration.body;\n }\n\n if (statement.declaration.type === \"VariableDeclaration\") {\n for (const declarator of statement.declaration.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n }\n }\n }\n\n // Check function body for nested declarations (component functions)\n if (\n ancestor.type === \"ArrowFunctionExpression\" ||\n ancestor.type === \"FunctionExpression\" ||\n ancestor.type === \"FunctionDeclaration\"\n ) {\n const funcBody = ancestor.body;\n\n // Only check BlockStatement bodies (not expression bodies)\n if (funcBody.type === \"BlockStatement\") {\n for (const statement of funcBody.body) {\n if (\n statement.type === \"FunctionDeclaration\" &&\n statement.id?.name === targetName\n ) {\n return statement.body;\n }\n\n if (statement.type === \"VariableDeclaration\") {\n for (const declarator of statement.declarations) {\n if (\n declarator.id.type === \"Identifier\" &&\n declarator.id.name === targetName &&\n declarator.init\n ) {\n if (\n declarator.init.type === \"ArrowFunctionExpression\" ||\n declarator.init.type === \"FunctionExpression\"\n ) {\n return declarator.init.body;\n }\n }\n }\n }\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Get statement IDs for all event handlers on a JSX element\n *\n * For each event handler attribute on the element:\n * - Extract the handler expression\n * - For inline arrows: find statements within the arrow body range\n * - For identifier references: find the handler declaration and its body range\n *\n * @param jsxNode - The JSX element to analyze\n * @param fileCoverage - Istanbul coverage data for the file\n * @param ancestors - Optional ancestor nodes for identifier resolution\n * @returns Set of statement IDs that are part of event handler bodies\n */\nexport function getHandlerStatements(\n jsxNode: TSESTree.JSXElement,\n fileCoverage: IstanbulFileCoverage,\n ancestors: TSESTree.Node[] = []\n): Set<string> {\n const handlerStatements = new Set<string>();\n\n for (const attr of jsxNode.openingElement.attributes) {\n // Skip non-event-handler attributes\n if (!isEventHandlerAttribute(attr) || attr.type !== \"JSXAttribute\") {\n continue;\n }\n\n const expression = extractEventHandlerExpression(attr);\n if (!expression) {\n continue;\n }\n\n // Handle inline arrow functions and function expressions\n if (\n expression.type === \"ArrowFunctionExpression\" ||\n expression.type === \"FunctionExpression\"\n ) {\n const body = expression.body;\n if (body.loc) {\n const bodyStatements = findStatementsInRange(body.loc, fileCoverage);\n for (const stmtId of bodyStatements) {\n handlerStatements.add(stmtId);\n }\n }\n continue;\n }\n\n // Handle identifier references (e.g., onClick={handleClick})\n if (expression.type === \"Identifier\") {\n const functionBody = findHandlerFunctionDeclaration(expression, ancestors);\n if (functionBody && functionBody.loc) {\n const bodyStatements = findStatementsInRange(functionBody.loc, fileCoverage);\n for (const stmtId of bodyStatements) {\n handlerStatements.add(stmtId);\n }\n }\n continue;\n }\n\n // Handle call expressions (e.g., onClick={fn.bind(this)})\n // We analyze the entire call expression range\n if (expression.type === \"CallExpression\" && expression.loc) {\n const callStatements = findStatementsInRange(expression.loc, fileCoverage);\n for (const stmtId of callStatements) {\n handlerStatements.add(stmtId);\n }\n continue;\n }\n\n // Handle member expressions (e.g., onClick={obj.method})\n // These typically point to methods that we can't easily resolve\n // without more complex analysis, so we just note the expression location\n if (expression.type === \"MemberExpression\" && expression.loc) {\n const memberStatements = findStatementsInRange(expression.loc, fileCoverage);\n for (const stmtId of memberStatements) {\n handlerStatements.add(stmtId);\n }\n }\n }\n\n return handlerStatements;\n}\n\n// =============================================================================\n// Phase 3: Conditional Parent Analysis\n// =============================================================================\n\n/**\n * Find a conditional ancestor that controls this element's rendering\n *\n * Walks up the ancestor chain to find the first conditional expression\n * that determines whether this JSX element is rendered:\n * - LogicalExpression with `&&`: {condition && <Element />}\n * - ConditionalExpression (ternary): {condition ? <A /> : <B />}\n *\n * @param node - The current JSX element node\n * @param ancestors - The ancestor nodes from the AST traversal\n * @returns The conditional expression if found, null otherwise\n */\nexport function findConditionalAncestor(\n node: TSESTree.Node,\n ancestors: TSESTree.Node[]\n): TSESTree.LogicalExpression | TSESTree.ConditionalExpression | null {\n for (const ancestor of ancestors) {\n // Check for logical expression with && operator\n // Pattern: {condition && <Element />}\n if (\n ancestor.type === \"LogicalExpression\" &&\n ancestor.operator === \"&&\"\n ) {\n return ancestor;\n }\n\n // Check for conditional (ternary) expression\n // Pattern: {condition ? <A /> : <B />}\n if (ancestor.type === \"ConditionalExpression\") {\n return ancestor;\n }\n\n // Stop searching when we hit a JSX element boundary\n // (we don't want to cross into parent JSX elements)\n if (ancestor.type === \"JSXElement\" && ancestor !== node) {\n break;\n }\n\n // Stop at function boundaries\n if (\n ancestor.type === \"ArrowFunctionExpression\" ||\n ancestor.type === \"FunctionExpression\" ||\n ancestor.type === \"FunctionDeclaration\"\n ) {\n break;\n }\n }\n\n return null;\n}\n\n/**\n * Get statement IDs for the condition/test part of a conditional expression\n *\n * For LogicalExpression (&&): gets statements in the left operand (the condition)\n * For ConditionalExpression (ternary): gets statements in the test expression\n *\n * @param conditional - The conditional expression node\n * @param fileCoverage - Istanbul coverage data for the file\n * @returns Set of statement IDs that are part of the condition\n */\nexport function getConditionalStatements(\n conditional: TSESTree.LogicalExpression | TSESTree.ConditionalExpression,\n fileCoverage: IstanbulFileCoverage\n): Set<string> {\n const conditionStatements = new Set<string>();\n\n if (conditional.type === \"LogicalExpression\") {\n // For &&, the left side is the condition\n const condition = conditional.left;\n if (condition.loc) {\n const statements = findStatementsInRange(condition.loc, fileCoverage);\n for (const stmtId of statements) {\n conditionStatements.add(stmtId);\n }\n }\n } else if (conditional.type === \"ConditionalExpression\") {\n // For ternary, the test is the condition\n const condition = conditional.test;\n if (condition.loc) {\n const statements = findStatementsInRange(condition.loc, fileCoverage);\n for (const stmtId of statements) {\n conditionStatements.add(stmtId);\n }\n }\n }\n\n return conditionStatements;\n}\n\n// =============================================================================\n// Phase 4: Import Dependency Coverage\n// =============================================================================\n\n/**\n * Recursively collect all identifiers used within a node\n *\n * @param node - AST node to traverse\n * @param identifiers - Set to accumulate identifier names\n */\nfunction collectIdentifiersFromNode(\n node: TSESTree.Node,\n identifiers: Set<string>\n): void {\n switch (node.type) {\n case \"Identifier\":\n identifiers.add(node.name);\n break;\n\n case \"JSXIdentifier\":\n // JSX element names (e.g., <Component />) - these are components from imports\n identifiers.add(node.name);\n break;\n\n case \"JSXExpressionContainer\":\n if (node.expression.type !== \"JSXEmptyExpression\") {\n collectIdentifiersFromNode(node.expression, identifiers);\n }\n break;\n\n case \"JSXElement\":\n // Collect from opening element (tag name and attributes)\n collectIdentifiersFromNode(node.openingElement, identifiers);\n // Collect from children\n for (const child of node.children) {\n collectIdentifiersFromNode(child, identifiers);\n }\n break;\n\n case \"JSXOpeningElement\":\n // Collect from element name\n collectIdentifiersFromNode(node.name, identifiers);\n // Collect from attributes\n for (const attr of node.attributes) {\n collectIdentifiersFromNode(attr, identifiers);\n }\n break;\n\n case \"JSXAttribute\":\n // Collect from attribute value if it exists\n if (node.value) {\n collectIdentifiersFromNode(node.value, identifiers);\n }\n break;\n\n case \"JSXSpreadAttribute\":\n collectIdentifiersFromNode(node.argument, identifiers);\n break;\n\n case \"JSXMemberExpression\":\n // e.g., <Foo.Bar /> - collect the object\n collectIdentifiersFromNode(node.object, identifiers);\n break;\n\n case \"CallExpression\":\n collectIdentifiersFromNode(node.callee, identifiers);\n for (const arg of node.arguments) {\n collectIdentifiersFromNode(arg, identifiers);\n }\n break;\n\n case \"MemberExpression\":\n collectIdentifiersFromNode(node.object, identifiers);\n break;\n\n case \"ArrowFunctionExpression\":\n case \"FunctionExpression\":\n collectIdentifiersFromNode(node.body, identifiers);\n break;\n\n case \"BlockStatement\":\n for (const statement of node.body) {\n collectIdentifiersFromNode(statement, identifiers);\n }\n break;\n\n case \"ExpressionStatement\":\n collectIdentifiersFromNode(node.expression, identifiers);\n break;\n\n case \"ReturnStatement\":\n if (node.argument) {\n collectIdentifiersFromNode(node.argument, identifiers);\n }\n break;\n\n case \"BinaryExpression\":\n case \"LogicalExpression\":\n collectIdentifiersFromNode(node.left, identifiers);\n collectIdentifiersFromNode(node.right, identifiers);\n break;\n\n case \"ConditionalExpression\":\n collectIdentifiersFromNode(node.test, identifiers);\n collectIdentifiersFromNode(node.consequent, identifiers);\n collectIdentifiersFromNode(node.alternate, identifiers);\n break;\n\n case \"UnaryExpression\":\n collectIdentifiersFromNode(node.argument, identifiers);\n break;\n\n case \"TemplateLiteral\":\n for (const expr of node.expressions) {\n collectIdentifiersFromNode(expr, identifiers);\n }\n break;\n\n case \"ArrayExpression\":\n for (const element of node.elements) {\n if (element) {\n collectIdentifiersFromNode(element, identifiers);\n }\n }\n break;\n\n case \"ObjectExpression\":\n for (const prop of node.properties) {\n collectIdentifiersFromNode(prop, identifiers);\n }\n break;\n\n case \"Property\":\n collectIdentifiersFromNode(node.value, identifiers);\n break;\n\n case \"SpreadElement\":\n collectIdentifiersFromNode(node.argument, identifiers);\n break;\n\n case \"JSXText\":\n case \"JSXFragment\":\n case \"Literal\":\n // No identifiers in these\n break;\n\n default:\n // For other node types, we don't recurse to avoid complexity\n break;\n }\n}\n\n/**\n * Find imports used within a JSX element\n *\n * Identifies which imported modules are used within the JSX element by:\n * 1. Collecting all identifiers used in the JSX (props, children expressions, etc.)\n * 2. Walking up to the Program node to find ImportDeclaration nodes\n * 3. Matching used identifiers to their import sources\n *\n * @param jsxNode - The JSX element to analyze\n * @param ancestors - Ancestor nodes from AST traversal (should include Program)\n * @returns Set of import module specifiers (the 'from' paths) used in this JSX\n */\nexport function findImportsUsedInJSX(\n jsxNode: TSESTree.JSXElement,\n ancestors: TSESTree.Node[]\n): Set<string> {\n const importPaths = new Set<string>();\n\n // Step 1: Collect all identifiers used in this JSX element\n const usedIdentifiers = new Set<string>();\n collectIdentifiersFromNode(jsxNode, usedIdentifiers);\n\n // Step 2: Find the Program node in ancestors to access imports\n let programNode: TSESTree.Program | null = null;\n for (const ancestor of ancestors) {\n if (ancestor.type === \"Program\") {\n programNode = ancestor;\n break;\n }\n }\n\n if (!programNode) {\n return importPaths;\n }\n\n // Step 3: Build a map of imported identifiers to their module sources\n const importedIdentifiers = new Map<string, string>();\n\n for (const statement of programNode.body) {\n if (statement.type === \"ImportDeclaration\") {\n const source = statement.source.value;\n if (typeof source !== \"string\") {\n continue;\n }\n\n for (const specifier of statement.specifiers) {\n switch (specifier.type) {\n case \"ImportDefaultSpecifier\":\n // import Foo from 'module' -> Foo maps to 'module'\n importedIdentifiers.set(specifier.local.name, source);\n break;\n\n case \"ImportSpecifier\":\n // import { Foo } from 'module' -> Foo maps to 'module'\n // import { Foo as Bar } from 'module' -> Bar maps to 'module'\n importedIdentifiers.set(specifier.local.name, source);\n break;\n\n case \"ImportNamespaceSpecifier\":\n // import * as Foo from 'module' -> Foo maps to 'module'\n importedIdentifiers.set(specifier.local.name, source);\n break;\n }\n }\n }\n }\n\n // Step 4: Match used identifiers to their import sources\n for (const identifier of usedIdentifiers) {\n const importSource = importedIdentifiers.get(identifier);\n if (importSource) {\n importPaths.add(importSource);\n }\n }\n\n return importPaths;\n}\n\n/**\n * Resolve an import path to a file path\n *\n * Handles relative imports by resolving them against the current file's directory.\n * For non-relative imports (node_modules), returns null as we don't analyze those.\n *\n * @param importPath - The import specifier (e.g., './utils' or 'react')\n * @param currentFilePath - Path of the file containing the import\n * @param projectRoot - Project root directory\n * @returns Resolved file path or null if can't be resolved\n */\nfunction resolveImportPath(\n importPath: string,\n currentFilePath: string,\n projectRoot: string\n): string | null {\n // Skip non-relative imports (node_modules packages)\n if (!importPath.startsWith(\".\") && !importPath.startsWith(\"/\")) {\n return null;\n }\n\n // Get the directory of the current file\n const lastSlashIndex = currentFilePath.lastIndexOf(\"/\");\n const currentDir =\n lastSlashIndex >= 0 ? currentFilePath.slice(0, lastSlashIndex) : projectRoot;\n\n // Resolve the relative path\n let resolvedPath: string;\n if (importPath.startsWith(\"/\")) {\n // Absolute from project root\n resolvedPath = projectRoot + importPath;\n } else {\n // Relative path - need to resolve . and ..\n const parts = currentDir.split(\"/\").filter(Boolean);\n const importParts = importPath.split(\"/\");\n\n for (const part of importParts) {\n if (part === \".\") {\n continue;\n } else if (part === \"..\") {\n parts.pop();\n } else {\n parts.push(part);\n }\n }\n\n resolvedPath = \"/\" + parts.join(\"/\");\n }\n\n // Common extensions to try\n const extensions = [\"\", \".ts\", \".tsx\", \".js\", \".jsx\", \"/index.ts\", \"/index.tsx\", \"/index.js\", \"/index.jsx\"];\n\n for (const ext of extensions) {\n const fullPath = resolvedPath + ext;\n // We just return the resolved path - the caller will check if coverage exists\n // This is a simplified resolution that doesn't check file existence\n if (ext === \"\" && (resolvedPath.endsWith(\".ts\") || resolvedPath.endsWith(\".tsx\") ||\n resolvedPath.endsWith(\".js\") || resolvedPath.endsWith(\".jsx\"))) {\n return resolvedPath;\n }\n if (ext !== \"\") {\n return fullPath;\n }\n }\n\n return resolvedPath;\n}\n\n/**\n * Aggregate coverage from imported files\n *\n * For each import path, attempts to find coverage data for that file\n * and aggregates the statement coverage across all imported files.\n *\n * Note: When an import is used, the entire imported file's coverage is included\n * in the calculation (full file coverage when any part of a dependency is used).\n *\n * @param importPaths - Set of import module specifiers\n * @param coverage - Istanbul coverage data\n * @param projectRoot - Project root directory\n * @param currentFilePath - Path of the file containing the imports (for resolving relative paths)\n * @returns Aggregated coverage stats: { covered: number, total: number }\n */\nexport function aggregateImportCoverage(\n importPaths: Set<string>,\n coverage: IstanbulCoverage,\n projectRoot: string,\n currentFilePath: string = \"\"\n): { covered: number; total: number } {\n let totalCovered = 0;\n let totalStatements = 0;\n\n for (const importPath of importPaths) {\n // Try to resolve the import path to a file path\n const resolvedPath = resolveImportPath(importPath, currentFilePath, projectRoot);\n\n if (!resolvedPath) {\n // Non-relative import (node_modules) - skip\n continue;\n }\n\n // Try to find coverage for this file\n const fileCoverage = findCoverageForFile(coverage, resolvedPath);\n\n if (!fileCoverage) {\n // Also try with the raw import path in case coverage uses that format\n const rawCoverage = findCoverageForFile(coverage, importPath);\n if (!rawCoverage) {\n continue;\n }\n // Use the raw coverage\n const statementCount = Object.keys(rawCoverage.s).length;\n const coveredCount = Object.values(rawCoverage.s).filter((hits) => hits > 0).length;\n totalStatements += statementCount;\n totalCovered += coveredCount;\n continue;\n }\n\n // Aggregate full file coverage (all statements in the imported file)\n const statementCount = Object.keys(fileCoverage.s).length;\n const coveredCount = Object.values(fileCoverage.s).filter((hits) => hits > 0).length;\n\n totalStatements += statementCount;\n totalCovered += coveredCount;\n }\n\n return { covered: totalCovered, total: totalStatements };\n}\n","/**\n * Chunk Analyzer\n *\n * Analyzes individual \"chunks\" (exported functions, classes, hooks, stores)\n * for test coverage. Used for granular coverage reporting at the function level\n * instead of file level.\n *\n * Categories:\n * - utility: formatters, validators, helpers (strict threshold)\n * - hook: React hooks (use* pattern) (strict threshold)\n * - store: Zustand/Redux stores (strict threshold)\n * - handler: event handler functions (relaxed threshold)\n * - component: JSX-returning functions (relaxed threshold)\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport {\n findStatementsInRange,\n calculateCoverageFromStatements,\n type IstanbulFileCoverage,\n type SourceLocation,\n type CoverageStats,\n} from \"./jsx-coverage-analyzer.js\";\n\nexport type ChunkCategory =\n | \"utility\"\n | \"hook\"\n | \"store\"\n | \"handler\"\n | \"component\";\n\nexport interface ChunkInfo {\n /** Function/export name */\n name: string;\n /** Category of this chunk */\n category: ChunkCategory;\n /** Whether this is React-related code */\n isReactRelated: boolean;\n /** Location in source (full function body) */\n loc: SourceLocation;\n /** Location of just the declaration line (for error highlighting) */\n declarationLoc: SourceLocation;\n /** Function ID in fnMap (if found) */\n fnId: string | null;\n /** Is this an export? */\n isExport: boolean;\n}\n\nexport interface ChunkCoverageResult extends ChunkInfo {\n /** Coverage stats for this chunk */\n coverage: {\n /** Was the function ever called during tests? */\n functionCalled: boolean;\n /** Number of statements covered */\n statementsCovered: number;\n /** Total statements in the function */\n statementsTotal: number;\n /** Coverage percentage (0-100) */\n percentage: number;\n };\n}\n\n/**\n * Check if an AST node contains JSX elements\n */\nfunction containsJSX(\n node: TSESTree.Node,\n visited: WeakSet<object> = new WeakSet()\n): boolean {\n if (!node || typeof node !== \"object\") return false;\n if (visited.has(node)) return false;\n visited.add(node);\n\n if (\n node.type === \"JSXElement\" ||\n node.type === \"JSXFragment\" ||\n node.type === \"JSXText\"\n ) {\n return true;\n }\n\n // Only traverse known child properties to avoid parent references\n const childKeys = [\n \"body\",\n \"declarations\",\n \"declaration\",\n \"expression\",\n \"expressions\",\n \"argument\",\n \"arguments\",\n \"callee\",\n \"elements\",\n \"properties\",\n \"value\",\n \"init\",\n \"consequent\",\n \"alternate\",\n \"test\",\n \"left\",\n \"right\",\n \"object\",\n \"property\",\n \"children\",\n \"openingElement\",\n \"closingElement\",\n ];\n\n for (const key of childKeys) {\n const child = (node as unknown as Record<string, unknown>)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n if (containsJSX(item as TSESTree.Node, visited)) return true;\n }\n }\n } else if (\"type\" in child) {\n if (containsJSX(child as TSESTree.Node, visited)) return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Categorize a function based on its name and content\n */\nexport function categorizeChunk(\n name: string,\n functionBody: TSESTree.Node | null,\n isInStoreFile: boolean\n): { category: ChunkCategory; isReactRelated: boolean } {\n // Hooks: starts with \"use\" followed by uppercase\n if (/^use[A-Z]/.test(name)) {\n return { category: \"hook\", isReactRelated: true };\n }\n\n // Store: in a .store.ts file or name ends with Store\n if (isInStoreFile || /Store$/.test(name)) {\n return { category: \"store\", isReactRelated: false };\n }\n\n // Handler: starts with \"handle\" or \"on\" followed by uppercase\n if (/^handle[A-Z]/.test(name) || /^on[A-Z]/.test(name)) {\n return { category: \"handler\", isReactRelated: true };\n }\n\n // Component: contains JSX (check the function body)\n if (functionBody && containsJSX(functionBody)) {\n return { category: \"component\", isReactRelated: true };\n }\n\n // Default: utility\n return { category: \"utility\", isReactRelated: false };\n}\n\n/**\n * Extract function name from various AST patterns\n */\nfunction getFunctionName(\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression,\n parent: TSESTree.Node | undefined\n): string | null {\n // Named function declaration\n if (node.type === \"FunctionDeclaration\" && node.id) {\n return node.id.name;\n }\n\n // Variable declarator: const foo = () => {}\n if (parent?.type === \"VariableDeclarator\" && parent.id.type === \"Identifier\") {\n return parent.id.name;\n }\n\n // Property: { foo: () => {} }\n if (parent?.type === \"Property\" && parent.key.type === \"Identifier\") {\n return parent.key.name;\n }\n\n return null;\n}\n\n/**\n * Find function ID in fnMap by matching name and location\n */\nfunction findFnId(\n name: string,\n loc: SourceLocation,\n fileCoverage: IstanbulFileCoverage | null\n): string | null {\n if (!fileCoverage) return null;\n\n for (const [fnId, fnInfo] of Object.entries(fileCoverage.fnMap)) {\n // Match by name first\n if (fnInfo.name === name) {\n return fnId;\n }\n\n // If name doesn't match (anonymous or different), match by location\n // Function declaration location should be close to our AST location\n if (\n fnInfo.decl.start.line === loc.start.line ||\n fnInfo.loc.start.line === loc.start.line\n ) {\n return fnId;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate coverage for a specific function\n */\nfunction calculateChunkCoverage(\n fnId: string | null,\n loc: SourceLocation,\n fileCoverage: IstanbulFileCoverage | null\n): ChunkCoverageResult[\"coverage\"] {\n if (!fileCoverage) {\n return {\n functionCalled: false,\n statementsCovered: 0,\n statementsTotal: 0,\n percentage: 0,\n };\n }\n\n // Check if function was called\n const functionCalled = fnId !== null && (fileCoverage.f[fnId] ?? 0) > 0;\n\n // Find statements within function body\n const statementIds = findStatementsInRange(loc, fileCoverage);\n const stats = calculateCoverageFromStatements(statementIds, fileCoverage);\n\n return {\n functionCalled,\n statementsCovered: stats.covered,\n statementsTotal: stats.total,\n percentage: stats.percentage,\n };\n}\n\n/**\n * Collect all exported functions/classes from an AST\n */\ninterface ExportedFunction {\n name: string;\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.ArrowFunctionExpression\n | TSESTree.FunctionExpression;\n loc: SourceLocation;\n /** Location of just the declaration line (for highlighting) */\n declarationLoc: SourceLocation;\n body: TSESTree.Node | null;\n}\n\n/**\n * Get declaration location - just the first line of the function\n * This is used for error highlighting to avoid highlighting the entire function body\n */\nfunction getDeclarationLoc(loc: SourceLocation): SourceLocation {\n return {\n start: loc.start,\n end: { line: loc.start.line, column: 999 },\n };\n}\n\nfunction collectExportedFunctions(ast: TSESTree.Program): ExportedFunction[] {\n const exports: ExportedFunction[] = [];\n\n for (const node of ast.body) {\n // export function foo() {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"FunctionDeclaration\" &&\n node.declaration.id\n ) {\n const loc = node.declaration.loc;\n exports.push({\n name: node.declaration.id.name,\n node: node.declaration,\n loc,\n declarationLoc: getDeclarationLoc(loc),\n body: node.declaration.body,\n });\n }\n\n // export const foo = () => {}\n if (\n node.type === \"ExportNamedDeclaration\" &&\n node.declaration?.type === \"VariableDeclaration\"\n ) {\n for (const decl of node.declaration.declarations) {\n if (\n decl.id.type === \"Identifier\" &&\n decl.init &&\n (decl.init.type === \"ArrowFunctionExpression\" ||\n decl.init.type === \"FunctionExpression\")\n ) {\n // For arrow functions, use the variable declaration line, not the function body\n const loc = decl.init.loc;\n const declarationLoc = getDeclarationLoc(decl.loc);\n exports.push({\n name: decl.id.name,\n node: decl.init,\n loc,\n declarationLoc,\n body: decl.init.body,\n });\n }\n }\n }\n\n // export default function foo() {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n node.declaration.type === \"FunctionDeclaration\"\n ) {\n const name = node.declaration.id?.name ?? \"default\";\n const loc = node.declaration.loc;\n exports.push({\n name,\n node: node.declaration,\n loc,\n declarationLoc: getDeclarationLoc(loc),\n body: node.declaration.body,\n });\n }\n\n // export default () => {}\n if (\n node.type === \"ExportDefaultDeclaration\" &&\n (node.declaration.type === \"ArrowFunctionExpression\" ||\n node.declaration.type === \"FunctionExpression\")\n ) {\n const loc = node.declaration.loc;\n exports.push({\n name: \"default\",\n node: node.declaration,\n loc,\n declarationLoc: getDeclarationLoc(loc),\n body: node.declaration.body,\n });\n }\n }\n\n return exports;\n}\n\n/**\n * Analyze all exported chunks in a file for coverage\n *\n * @param ast - The parsed AST of the file\n * @param filePath - Path to the file (used for store detection)\n * @param fileCoverage - Istanbul coverage data for the file (or null)\n * @returns Array of chunks with their coverage information\n */\nexport function analyzeChunks(\n ast: TSESTree.Program,\n filePath: string,\n fileCoverage: IstanbulFileCoverage | null\n): ChunkCoverageResult[] {\n const isInStoreFile = /\\.store\\.(ts|tsx)$/.test(filePath);\n const exportedFunctions = collectExportedFunctions(ast);\n const results: ChunkCoverageResult[] = [];\n\n for (const exported of exportedFunctions) {\n const { category, isReactRelated } = categorizeChunk(\n exported.name,\n exported.body,\n isInStoreFile\n );\n\n const fnId = findFnId(exported.name, exported.loc, fileCoverage);\n const coverage = calculateChunkCoverage(fnId, exported.loc, fileCoverage);\n\n results.push({\n name: exported.name,\n category,\n isReactRelated,\n loc: exported.loc,\n declarationLoc: exported.declarationLoc,\n fnId,\n isExport: true,\n coverage,\n });\n }\n\n return results;\n}\n\n/**\n * Get the appropriate threshold for a chunk based on options\n */\nexport function getChunkThreshold(\n chunk: ChunkCoverageResult,\n options: {\n focusNonReact?: boolean;\n chunkThreshold?: number;\n relaxedThreshold?: number;\n }\n): number {\n const strictThreshold = options.chunkThreshold ?? 80;\n const relaxedThreshold = options.relaxedThreshold ?? 50;\n\n if (!options.focusNonReact) {\n // Uniform threshold for all chunks\n return strictThreshold;\n }\n\n // focusNonReact mode: relaxed threshold for React-related code\n if (chunk.category === \"component\" || chunk.category === \"handler\") {\n return relaxedThreshold;\n }\n\n // Strict threshold for utility, hook, store\n return strictThreshold;\n}\n","/**\n * Rule: prefer-tailwind\n *\n * Encourages using Tailwind className over inline style attributes.\n * - Detects files with a high ratio of inline `style` vs `className` usage\n * - Warns at each element using style without className when ratio exceeds threshold\n */\n\nimport { createRule, defineRuleMeta } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferTailwind\" | \"preferSemanticColors\";\ntype Options = [\n {\n /** Minimum ratio of style-only elements before warnings trigger (0-1). Default: 0.3 */\n styleRatioThreshold?: number;\n /** Don't warn if file has fewer than N JSX elements with styling. Default: 3 */\n minElementsForAnalysis?: number;\n /** Style properties to ignore (e.g., [\"transform\", \"animation\"] for dynamic values). Default: [] */\n allowedStyleProperties?: string[];\n /** Component names to skip (e.g., [\"motion.div\", \"animated.View\"]). Default: [] */\n ignoreComponents?: string[];\n /** Prefer semantic colors (bg-destructive) over hard-coded (bg-red-500). Default: false */\n preferSemanticColors?: boolean;\n /** Hard-coded color names to allow when preferSemanticColors is enabled. Default: [] */\n allowedHardCodedColors?: string[];\n }?\n];\n\n/**\n * Rule metadata - colocated with implementation for maintainability\n */\nexport const meta = defineRuleMeta({\n id: \"prefer-tailwind\",\n version: \"1.0.0\",\n name: \"Prefer Tailwind\",\n description: \"Encourage Tailwind className over inline style attributes\",\n defaultSeverity: \"warn\",\n category: \"static\",\n icon: \"🎨\",\n hint: \"Prefers className over inline styles\",\n defaultEnabled: true,\n defaultOptions: [\n {\n styleRatioThreshold: 0.3,\n minElementsForAnalysis: 3,\n allowedStyleProperties: [],\n ignoreComponents: [],\n preferSemanticColors: true,\n allowedHardCodedColors: [],\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"styleRatioThreshold\",\n label: \"Style ratio threshold\",\n type: \"number\",\n defaultValue: 0.3,\n description:\n \"Minimum ratio (0-1) of style-only elements before warnings trigger\",\n },\n {\n key: \"minElementsForAnalysis\",\n label: \"Minimum elements\",\n type: \"number\",\n defaultValue: 3,\n description: \"Don't warn if file has fewer styled elements than this\",\n },\n {\n key: \"allowedStyleProperties\",\n label: \"Allowed style properties\",\n type: \"text\",\n defaultValue: \"\",\n description:\n \"Comma-separated list of style properties to allow (e.g., transform,animation)\",\n },\n {\n key: \"ignoreComponents\",\n label: \"Ignored components\",\n type: \"text\",\n defaultValue: \"\",\n description:\n \"Comma-separated component names to skip (e.g., motion.div,animated.View)\",\n },\n {\n key: \"preferSemanticColors\",\n label: \"Prefer semantic colors\",\n type: \"boolean\",\n defaultValue: true,\n description:\n \"Warn against hard-coded colors (bg-red-500) in favor of semantic theme colors (bg-destructive)\",\n },\n {\n key: \"allowedHardCodedColors\",\n label: \"Allowed hard-coded colors\",\n type: \"text\",\n defaultValue: \"\",\n description:\n \"Comma-separated color names to allow when preferSemanticColors is enabled (e.g., gray,slate)\",\n },\n ],\n },\n docs: `\n## What it does\n\nDetects files with a high ratio of inline \\`style\\` attributes versus \\`className\\` usage\nin JSX elements. Reports warnings on elements that use \\`style\\` without \\`className\\`,\nbut only when the file exceeds a configurable threshold ratio.\n\n## Why it's useful\n\n- **Consistency**: Encourages using Tailwind's utility classes for styling\n- **Maintainability**: Tailwind classes are easier to read and maintain than inline styles\n- **Performance**: Tailwind generates optimized CSS; inline styles can't be deduplicated\n- **Theming**: Tailwind classes work with dark mode and responsive variants\n\n## Examples\n\n### ❌ Incorrect (when file exceeds threshold)\n\n\\`\\`\\`tsx\n// Many elements using style without className\n<div style={{ color: 'red' }}>Red text</div>\n<span style={{ marginTop: '10px' }}>Spaced</span>\n<p style={{ fontSize: '16px' }}>Paragraph</p>\n\\`\\`\\`\n\n### ✅ Correct\n\n\\`\\`\\`tsx\n// Using Tailwind className\n<div className=\"text-red-500\">Red text</div>\n<span className=\"mt-2\">Spaced</span>\n<p className=\"text-base\">Paragraph</p>\n\n// Both style and className (acceptable for dynamic values)\n<div className=\"p-4\" style={{ backgroundColor: dynamicColor }}>Mixed</div>\n\\`\\`\\`\n\n## Configuration\n\n\\`\\`\\`js\n// eslint.config.js\n\"uilint/prefer-tailwind\": [\"warn\", {\n styleRatioThreshold: 0.3, // Warn when >30% of elements are style-only\n minElementsForAnalysis: 3, // Need at least 3 styled elements to analyze\n allowedStyleProperties: [\"transform\", \"animation\"], // Skip these properties\n ignoreComponents: [\"motion.div\", \"animated.View\"], // Skip animation libraries\n preferSemanticColors: true, // Warn on hard-coded colors like bg-red-500\n allowedHardCodedColors: [\"gray\", \"slate\"] // Allow specific color palettes\n}]\n\\`\\`\\`\n\n## Semantic Colors\n\nWhen \\`preferSemanticColors\\` is enabled, the rule warns against hard-coded Tailwind color classes\nin favor of semantic theme colors:\n\n### ❌ Hard-coded colors (when enabled)\n\n\\`\\`\\`tsx\n<div className=\"bg-red-500 text-white\">Error</div>\n<button className=\"hover:bg-blue-600\">Click</button>\n\\`\\`\\`\n\n### ✅ Semantic colors (preferred)\n\n\\`\\`\\`tsx\n<div className=\"bg-destructive text-destructive-foreground\">Error</div>\n<button className=\"hover:bg-primary\">Click</button>\n\\`\\`\\`\n\nSemantic colors like \\`bg-background\\`, \\`text-foreground\\`, \\`bg-primary\\`, \\`bg-destructive\\`,\n\\`bg-muted\\`, etc. work better with theming and dark mode.\n\nColors that are always allowed: \\`white\\`, \\`black\\`, \\`transparent\\`, \\`inherit\\`, \\`current\\`.\n\n## Notes\n\n- Elements with BOTH \\`style\\` and \\`className\\` are considered acceptable\n- Files with few styled elements are not analyzed (prevents false positives)\n- The rule uses a ratio-based approach to catch systematic patterns, not isolated cases\n- Use \\`allowedStyleProperties\\` for dynamic values that can't use Tailwind\n- Use \\`ignoreComponents\\` for animation libraries that require inline styles\n`,\n});\n\n/**\n * Get the component name from a JSX opening element\n */\nfunction getComponentName(node: TSESTree.JSXOpeningElement): string {\n const name = node.name;\n\n if (name.type === \"JSXIdentifier\") {\n return name.name;\n }\n\n if (name.type === \"JSXMemberExpression\") {\n // Handle motion.div, animated.View, etc.\n const parts: string[] = [];\n let current: TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier = name;\n\n while (current.type === \"JSXMemberExpression\") {\n if (current.property.type === \"JSXIdentifier\") {\n parts.unshift(current.property.name);\n }\n current = current.object as\n | TSESTree.JSXMemberExpression\n | TSESTree.JSXIdentifier;\n }\n\n if (current.type === \"JSXIdentifier\") {\n parts.unshift(current.name);\n }\n\n return parts.join(\".\");\n }\n\n return \"\";\n}\n\n/**\n * Extract property names from a style object expression\n */\nfunction getStylePropertyNames(\n value: TSESTree.JSXExpressionContainer\n): string[] {\n const expr = value.expression;\n\n // Handle style={{ prop: value }}\n if (expr.type === \"ObjectExpression\") {\n return expr.properties\n .filter((prop): prop is TSESTree.Property => prop.type === \"Property\")\n .map((prop) => {\n if (prop.key.type === \"Identifier\") {\n return prop.key.name;\n }\n if (prop.key.type === \"Literal\" && typeof prop.key.value === \"string\") {\n return prop.key.value;\n }\n return \"\";\n })\n .filter(Boolean);\n }\n\n // For style={variable} or style={{...spread}}, we can't determine properties\n return [];\n}\n\n/**\n * Check if all style properties are in the allowed list\n */\nfunction hasOnlyAllowedProperties(\n styleProperties: string[],\n allowedProperties: string[]\n): boolean {\n if (allowedProperties.length === 0 || styleProperties.length === 0) {\n return false;\n }\n\n return styleProperties.every((prop) => allowedProperties.includes(prop));\n}\n\ninterface ElementInfo {\n node: TSESTree.JSXOpeningElement;\n hasStyle: boolean;\n hasClassName: boolean;\n styleProperties: string[];\n}\n\n/**\n * Tailwind color names that should use semantic alternatives\n * Excludes neutral colors that are often acceptable\n */\nconst HARD_CODED_COLOR_NAMES = [\n \"red\",\n \"orange\",\n \"amber\",\n \"yellow\",\n \"lime\",\n \"green\",\n \"emerald\",\n \"teal\",\n \"cyan\",\n \"sky\",\n \"blue\",\n \"indigo\",\n \"violet\",\n \"purple\",\n \"fuchsia\",\n \"pink\",\n \"rose\",\n \"slate\",\n \"gray\",\n \"zinc\",\n \"neutral\",\n \"stone\",\n];\n\n/**\n * Colors that are always allowed (not theme-dependent)\n */\nconst ALWAYS_ALLOWED_COLORS = [\n \"white\",\n \"black\",\n \"transparent\",\n \"inherit\",\n \"current\",\n];\n\n/**\n * Regex to match hard-coded Tailwind color classes\n * Matches patterns like: bg-red-500, text-blue-600/50, hover:bg-green-400, dark:text-slate-100\n * Color utilities: bg, text, border, ring, outline, decoration, accent, fill, stroke,\n * from, via, to (gradients), divide, placeholder, caret, shadow\n */\nfunction createHardCodedColorRegex(colorNames: string[]): RegExp {\n const colorPattern = colorNames.join(\"|\");\n // Match color utilities with color-shade pattern, optional opacity, with optional variant prefixes\n return new RegExp(\n `(?:^|\\\\s)(?:[a-z-]+:)*(?:bg|text|border|ring|outline|decoration|accent|fill|stroke|from|via|to|divide|placeholder|caret|shadow)-(${colorPattern})-\\\\d{1,3}(?:/\\\\d{1,3})?(?=\\\\s|$)`,\n \"g\"\n );\n}\n\n/**\n * Extract className value from a JSX attribute\n */\nfunction getClassNameValue(attr: TSESTree.JSXAttribute): string | null {\n if (!attr.value) return null;\n\n // className=\"...\"\n if (attr.value.type === \"Literal\" && typeof attr.value.value === \"string\") {\n return attr.value.value;\n }\n\n // className={\"...\"}\n if (\n attr.value.type === \"JSXExpressionContainer\" &&\n attr.value.expression.type === \"Literal\" &&\n typeof attr.value.expression.value === \"string\"\n ) {\n return attr.value.expression.value;\n }\n\n // className={`...`}\n if (\n attr.value.type === \"JSXExpressionContainer\" &&\n attr.value.expression.type === \"TemplateLiteral\"\n ) {\n // Extract static parts of template literal\n return attr.value.expression.quasis.map((q) => q.value.raw).join(\" \");\n }\n\n return null;\n}\n\n/**\n * Check if a className string contains hard-coded color classes\n */\nfunction findHardCodedColors(\n className: string,\n allowedColors: string[]\n): string[] {\n const disallowedColorNames = HARD_CODED_COLOR_NAMES.filter(\n (c) => !allowedColors.includes(c)\n );\n\n if (disallowedColorNames.length === 0) return [];\n\n const regex = createHardCodedColorRegex(disallowedColorNames);\n const matches: string[] = [];\n let match;\n\n while ((match = regex.exec(className)) !== null) {\n matches.push(match[0].trim());\n }\n\n return matches;\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"prefer-tailwind\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Encourage Tailwind className over inline style attributes\",\n },\n messages: {\n preferTailwind:\n \"Prefer Tailwind className over inline style. This element uses style attribute without className.\",\n preferSemanticColors:\n \"Prefer semantic color classes (e.g., bg-destructive, text-primary) over hard-coded colors (e.g., bg-red-500).\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n styleRatioThreshold: {\n type: \"number\",\n minimum: 0,\n maximum: 1,\n description:\n \"Minimum ratio of style-only elements to trigger warnings\",\n },\n minElementsForAnalysis: {\n type: \"number\",\n minimum: 1,\n description: \"Minimum styled elements required for analysis\",\n },\n allowedStyleProperties: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Style properties to ignore\",\n },\n ignoreComponents: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Component names to skip\",\n },\n preferSemanticColors: {\n type: \"boolean\",\n description:\n \"Warn against hard-coded colors in favor of semantic theme colors\",\n },\n allowedHardCodedColors: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Hard-coded color names to allow when preferSemanticColors is enabled\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [\n {\n styleRatioThreshold: 0.3,\n minElementsForAnalysis: 3,\n allowedStyleProperties: [],\n ignoreComponents: [],\n preferSemanticColors: false,\n allowedHardCodedColors: [],\n },\n ],\n create(context) {\n const options = context.options[0] || {};\n const styleRatioThreshold = options.styleRatioThreshold ?? 0.3;\n const minElementsForAnalysis = options.minElementsForAnalysis ?? 3;\n const allowedStyleProperties = options.allowedStyleProperties ?? [];\n const ignoreComponents = options.ignoreComponents ?? [];\n const preferSemanticColors = options.preferSemanticColors ?? false;\n const allowedHardCodedColors = options.allowedHardCodedColors ?? [];\n\n // Tracking state for file-level analysis\n const styledElements: ElementInfo[] = [];\n\n /**\n * Check if a JSXAttribute is a style attribute with an expression\n */\n function isStyleAttribute(attr: TSESTree.JSXAttribute): boolean {\n return (\n attr.name.type === \"JSXIdentifier\" &&\n attr.name.name === \"style\" &&\n attr.value?.type === \"JSXExpressionContainer\"\n );\n }\n\n /**\n * Check if a JSXAttribute is a className attribute\n */\n function isClassNameAttribute(attr: TSESTree.JSXAttribute): boolean {\n return (\n attr.name.type === \"JSXIdentifier\" &&\n (attr.name.name === \"className\" || attr.name.name === \"class\")\n );\n }\n\n return {\n JSXOpeningElement(node) {\n // Check if component should be ignored\n const componentName = getComponentName(node);\n if (ignoreComponents.includes(componentName)) {\n return;\n }\n\n let hasStyle = false;\n let hasClassName = false;\n let styleProperties: string[] = [];\n\n for (const attr of node.attributes) {\n if (attr.type === \"JSXAttribute\") {\n if (isStyleAttribute(attr)) {\n hasStyle = true;\n styleProperties = getStylePropertyNames(\n attr.value as TSESTree.JSXExpressionContainer\n );\n }\n if (isClassNameAttribute(attr)) {\n hasClassName = true;\n\n // Check for hard-coded colors if preferSemanticColors is enabled\n if (preferSemanticColors) {\n const classNameValue = getClassNameValue(attr);\n if (classNameValue) {\n const hardCodedColors = findHardCodedColors(\n classNameValue,\n allowedHardCodedColors\n );\n if (hardCodedColors.length > 0) {\n context.report({\n node,\n messageId: \"preferSemanticColors\",\n });\n }\n }\n }\n }\n }\n }\n\n // Only track elements that have style OR className (or both)\n if (hasStyle || hasClassName) {\n styledElements.push({\n node,\n hasStyle,\n hasClassName,\n styleProperties,\n });\n }\n },\n\n \"Program:exit\"() {\n // Don't analyze if not enough styled elements\n if (styledElements.length < minElementsForAnalysis) {\n return;\n }\n\n // Filter out elements where all style properties are allowed\n const styleOnlyElements = styledElements.filter((el) => {\n if (!el.hasStyle || el.hasClassName) {\n return false;\n }\n\n // If all style properties are in the allowed list, don't count this element\n if (\n hasOnlyAllowedProperties(el.styleProperties, allowedStyleProperties)\n ) {\n return false;\n }\n\n return true;\n });\n\n const ratio = styleOnlyElements.length / styledElements.length;\n\n // Only report if ratio exceeds threshold\n if (ratio > styleRatioThreshold) {\n for (const element of styleOnlyElements) {\n context.report({\n node: element.node,\n messageId: \"preferTailwind\",\n });\n }\n }\n },\n };\n },\n});\n","/**\n * Category Registry\n *\n * Centralized metadata for rule categories.\n * Used by CLI installers and UI components to display category information\n * without hardcoding assumptions.\n */\n\n/**\n * Metadata for a rule category\n */\nexport interface CategoryMeta {\n /** Category identifier */\n id: \"static\" | \"semantic\";\n /** Display name */\n name: string;\n /** Short description */\n description: string;\n /** Icon for display (emoji) */\n icon: string;\n /** Whether rules in this category are enabled by default during install */\n defaultEnabled: boolean;\n}\n\n/**\n * Registry of all rule categories\n */\nexport const categoryRegistry: CategoryMeta[] = [\n {\n id: \"static\",\n name: \"Static Rules\",\n description: \"Pattern-based, fast analysis\",\n icon: \"\\u{1F4CB}\",\n defaultEnabled: true,\n },\n {\n id: \"semantic\",\n name: \"Semantic Rules\",\n description: \"LLM-powered analysis\",\n icon: \"\\u{1F9E0}\",\n defaultEnabled: false,\n },\n];\n\n/**\n * Get metadata for a specific category\n */\nexport function getCategoryMeta(id: string): CategoryMeta | undefined {\n return categoryRegistry.find((cat) => cat.id === id);\n}\n","/**\n * Rule Registry\n *\n * Central registry of all UILint ESLint rules with metadata for CLI tooling.\n * Metadata is now colocated with each rule file - this module re-exports\n * the collected metadata for use by installers and other tools.\n */\n\n// Re-export types from create-rule for consumers\nexport type {\n RuleMeta,\n RuleOptionSchema,\n OptionFieldSchema,\n RuleRequirement,\n RuleMigration,\n} from \"./utils/create-rule.js\";\n\n// Backward compatibility alias\nexport type { RuleMeta as RuleMetadata } from \"./utils/create-rule.js\";\n\n// Re-export category registry\nexport {\n categoryRegistry,\n getCategoryMeta,\n type CategoryMeta,\n} from \"./category-registry.js\";\n\n// Import colocated metadata from each rule file\n// Single-file rules\nimport { meta as consistentDarkMode } from \"./rules/consistent-dark-mode.js\";\nimport { meta as noDirectStoreImport } from \"./rules/no-direct-store-import.js\";\nimport { meta as preferZustandStateManagement } from \"./rules/prefer-zustand-state-management.js\";\nimport { meta as semanticVision } from \"./rules/semantic-vision.js\";\nimport { meta as enforceAbsoluteImports } from \"./rules/enforce-absolute-imports.js\";\nimport { meta as noAnyInProps } from \"./rules/no-any-in-props.js\";\nimport { meta as zustandUseSelectors } from \"./rules/zustand-use-selectors.js\";\nimport { meta as noSecretsInCode } from \"./rules/no-secrets-in-code.js\";\nimport { meta as requireInputValidation } from \"./rules/require-input-validation.js\";\nimport { meta as noPropDrillingDepth } from \"./rules/no-prop-drilling-depth.js\";\nimport { meta as noSemanticDuplicates } from \"./rules/no-semantic-duplicates.js\";\nimport { meta as preferTailwind } from \"./rules/prefer-tailwind.js\";\n\n// Directory-based rules (complex rules with colocated utilities)\nimport { meta as noMixedComponentLibraries } from \"./rules/no-mixed-component-libraries/index.js\";\nimport { meta as semantic } from \"./rules/semantic/index.js\";\nimport { meta as requireTestCoverage } from \"./rules/require-test-coverage/index.js\";\n\nimport type { RuleMeta } from \"./utils/create-rule.js\";\n\n/**\n * Registry of all available UILint ESLint rules\n *\n * When adding a new rule:\n * 1. Create the rule file in src/rules/\n * 2. Export a `meta` object using `defineRuleMeta()`\n * 3. Import and add the meta to this array\n * 4. Run `pnpm generate:index` to regenerate exports\n */\nexport const ruleRegistry: RuleMeta[] = [\n // Existing rules\n consistentDarkMode,\n noDirectStoreImport,\n preferZustandStateManagement,\n noMixedComponentLibraries,\n semantic,\n semanticVision,\n // New UI rules\n enforceAbsoluteImports,\n noAnyInProps,\n zustandUseSelectors,\n noPropDrillingDepth,\n // New security rules\n noSecretsInCode,\n requireInputValidation,\n // Semantic duplicate detection\n noSemanticDuplicates,\n // Test coverage enforcement\n requireTestCoverage,\n // Style preferences\n preferTailwind,\n];\n\n/**\n * Get rule metadata by ID\n */\nexport function getRuleMetadata(id: string): RuleMeta | undefined {\n return ruleRegistry.find((rule) => rule.id === id);\n}\n\n/**\n * Get all rules in a category\n */\nexport function getRulesByCategory(\n category: \"static\" | \"semantic\"\n): RuleMeta[] {\n return ruleRegistry.filter((rule) => rule.category === category);\n}\n\n/**\n * Get documentation for a rule (useful for CLI help commands)\n */\nexport function getRuleDocs(id: string): string | undefined {\n const rule = getRuleMetadata(id);\n return rule?.docs;\n}\n\n/**\n * Get all rule IDs\n */\nexport function getAllRuleIds(): string[] {\n return ruleRegistry.map((rule) => rule.id);\n}\n","/**\n * UILint ESLint Plugin\n *\n * THIS FILE IS AUTO-GENERATED from src/rule-registry.ts.\n * Do not edit by hand. Run: pnpm -C packages/uilint-eslint generate:index\n */\n\nimport type { Linter } from \"eslint\";\nimport consistentDarkMode from \"./rules/consistent-dark-mode.js\";\nimport noDirectStoreImport from \"./rules/no-direct-store-import.js\";\nimport preferZustandStateManagement from \"./rules/prefer-zustand-state-management.js\";\nimport noMixedComponentLibraries from \"./rules/no-mixed-component-libraries/index.js\";\nimport semantic from \"./rules/semantic/index.js\";\nimport semanticVision from \"./rules/semantic-vision.js\";\nimport enforceAbsoluteImports from \"./rules/enforce-absolute-imports.js\";\nimport noAnyInProps from \"./rules/no-any-in-props.js\";\nimport zustandUseSelectors from \"./rules/zustand-use-selectors.js\";\nimport noPropDrillingDepth from \"./rules/no-prop-drilling-depth.js\";\nimport noSecretsInCode from \"./rules/no-secrets-in-code.js\";\nimport requireInputValidation from \"./rules/require-input-validation.js\";\nimport noSemanticDuplicates from \"./rules/no-semantic-duplicates.js\";\nimport requireTestCoverage from \"./rules/require-test-coverage/index.js\";\nimport preferTailwind from \"./rules/prefer-tailwind.js\";\n\n/**\n * All available rules\n */\nconst rules = {\n \"consistent-dark-mode\": consistentDarkMode,\n \"no-direct-store-import\": noDirectStoreImport,\n \"prefer-zustand-state-management\": preferZustandStateManagement,\n \"no-mixed-component-libraries\": noMixedComponentLibraries,\n \"semantic\": semantic,\n \"semantic-vision\": semanticVision,\n \"enforce-absolute-imports\": enforceAbsoluteImports,\n \"no-any-in-props\": noAnyInProps,\n \"zustand-use-selectors\": zustandUseSelectors,\n \"no-prop-drilling-depth\": noPropDrillingDepth,\n \"no-secrets-in-code\": noSecretsInCode,\n \"require-input-validation\": requireInputValidation,\n \"no-semantic-duplicates\": noSemanticDuplicates,\n \"require-test-coverage\": requireTestCoverage,\n \"prefer-tailwind\": preferTailwind,\n};\n\n// Package version (injected at build time or fallback)\nconst version = \"0.1.0\";\n\n/**\n * Plugin metadata\n */\nconst meta = {\n name: \"uilint\",\n version,\n};\n\n/**\n * The ESLint plugin object\n */\nconst plugin = {\n meta,\n rules,\n};\n\n/**\n * Shared language options for all configs\n */\nconst jsxLanguageOptions: Linter.Config[\"languageOptions\"] = {\n parserOptions: {\n ecmaFeatures: {\n jsx: true,\n },\n },\n};\n\n/**\n * Recommended config - static rules only\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.recommended];\n * ```\n */\nconst recommendedConfig: Linter.Config = {\n name: \"uilint/recommended\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/consistent-dark-mode\": [\"error\", ...[\n {\n \"warnOnMissingDarkMode\": true\n }\n ]],\n \"uilint/no-direct-store-import\": [\"warn\", ...[\n {\n \"storePattern\": \"use*Store\"\n }\n ]],\n \"uilint/prefer-zustand-state-management\": [\"warn\", ...[\n {\n \"maxStateHooks\": 3,\n \"countUseState\": true,\n \"countUseReducer\": true,\n \"countUseContext\": true\n }\n ]],\n \"uilint/no-mixed-component-libraries\": [\"error\", ...[\n {\n \"preferred\": \"shadcn\",\n \"libraries\": [\n \"shadcn\",\n \"mui\"\n ]\n }\n ]],\n \"uilint/enforce-absolute-imports\": [\"warn\", ...[\n {\n \"maxRelativeDepth\": 1,\n \"aliasPrefix\": \"@/\"\n }\n ]],\n \"uilint/no-any-in-props\": [\"error\", ...[\n {\n \"checkFCGenerics\": true,\n \"allowInGenericDefaults\": false\n }\n ]],\n \"uilint/zustand-use-selectors\": [\"warn\", ...[\n {\n \"storePattern\": \"^use\\\\w*Store$\",\n \"allowShallow\": true,\n \"requireNamedSelectors\": false\n }\n ]],\n \"uilint/no-prop-drilling-depth\": [\"warn\", ...[\n {\n \"maxDepth\": 2,\n \"ignoredProps\": [\n \"className\",\n \"style\",\n \"children\",\n \"key\",\n \"ref\",\n \"id\"\n ],\n \"ignoreComponents\": []\n }\n ]],\n \"uilint/no-secrets-in-code\": [\"error\", ...[\n {\n \"checkVariableNames\": true,\n \"minSecretLength\": 16,\n \"allowInTestFiles\": false\n }\n ]],\n \"uilint/require-input-validation\": [\"warn\", ...[\n {\n \"httpMethods\": [\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\"\n ],\n \"routePatterns\": [\n \"route.ts\",\n \"route.tsx\",\n \"/api/\",\n \"/app/api/\"\n ],\n \"allowManualValidation\": false\n }\n ]],\n \"uilint/require-test-coverage\": [\"warn\", ...[\n {\n \"coveragePath\": \"coverage/coverage-final.json\",\n \"threshold\": 80,\n \"thresholdsByPattern\": [],\n \"severity\": {\n \"noCoverage\": \"error\",\n \"belowThreshold\": \"warn\"\n },\n \"testPatterns\": [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\"\n ],\n \"ignorePatterns\": [\n \"**/*.d.ts\",\n \"**/index.ts\"\n ],\n \"mode\": \"all\",\n \"baseBranch\": \"main\"\n }\n ]],\n \"uilint/prefer-tailwind\": [\"warn\", ...[\n {\n \"styleRatioThreshold\": 0.3,\n \"minElementsForAnalysis\": 3,\n \"allowedStyleProperties\": [],\n \"ignoreComponents\": [],\n \"preferSemanticColors\": true,\n \"allowedHardCodedColors\": []\n }\n ]],\n },\n};\n\n/**\n * Strict config - static rules + semantic rules\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.strict];\n * ```\n */\nconst strictConfig: Linter.Config = {\n name: \"uilint/strict\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/consistent-dark-mode\": [\"error\", ...[\n {\n \"warnOnMissingDarkMode\": true\n }\n ]],\n \"uilint/no-direct-store-import\": [\"warn\", ...[\n {\n \"storePattern\": \"use*Store\"\n }\n ]],\n \"uilint/prefer-zustand-state-management\": [\"warn\", ...[\n {\n \"maxStateHooks\": 3,\n \"countUseState\": true,\n \"countUseReducer\": true,\n \"countUseContext\": true\n }\n ]],\n \"uilint/no-mixed-component-libraries\": [\"error\", ...[\n {\n \"preferred\": \"shadcn\",\n \"libraries\": [\n \"shadcn\",\n \"mui\"\n ]\n }\n ]],\n \"uilint/semantic\": [\"warn\", ...[\n {\n \"model\": \"qwen3-coder:30b\",\n \"styleguidePath\": \".uilint/styleguide.md\"\n }\n ]],\n \"uilint/semantic-vision\": [\"warn\", ...[\n {\n \"maxAgeMs\": 3600000,\n \"screenshotsPath\": \".uilint/screenshots\"\n }\n ]],\n \"uilint/enforce-absolute-imports\": [\"warn\", ...[\n {\n \"maxRelativeDepth\": 1,\n \"aliasPrefix\": \"@/\"\n }\n ]],\n \"uilint/no-any-in-props\": [\"error\", ...[\n {\n \"checkFCGenerics\": true,\n \"allowInGenericDefaults\": false\n }\n ]],\n \"uilint/zustand-use-selectors\": [\"warn\", ...[\n {\n \"storePattern\": \"^use\\\\w*Store$\",\n \"allowShallow\": true,\n \"requireNamedSelectors\": false\n }\n ]],\n \"uilint/no-prop-drilling-depth\": [\"warn\", ...[\n {\n \"maxDepth\": 2,\n \"ignoredProps\": [\n \"className\",\n \"style\",\n \"children\",\n \"key\",\n \"ref\",\n \"id\"\n ],\n \"ignoreComponents\": []\n }\n ]],\n \"uilint/no-secrets-in-code\": [\"error\", ...[\n {\n \"checkVariableNames\": true,\n \"minSecretLength\": 16,\n \"allowInTestFiles\": false\n }\n ]],\n \"uilint/require-input-validation\": [\"warn\", ...[\n {\n \"httpMethods\": [\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\"\n ],\n \"routePatterns\": [\n \"route.ts\",\n \"route.tsx\",\n \"/api/\",\n \"/app/api/\"\n ],\n \"allowManualValidation\": false\n }\n ]],\n \"uilint/no-semantic-duplicates\": [\"warn\", ...[\n {\n \"threshold\": 0.85,\n \"indexPath\": \".uilint/.duplicates-index\",\n \"minLines\": 3\n }\n ]],\n \"uilint/require-test-coverage\": [\"warn\", ...[\n {\n \"coveragePath\": \"coverage/coverage-final.json\",\n \"threshold\": 80,\n \"thresholdsByPattern\": [],\n \"severity\": {\n \"noCoverage\": \"error\",\n \"belowThreshold\": \"warn\"\n },\n \"testPatterns\": [\n \".test.ts\",\n \".test.tsx\",\n \".spec.ts\",\n \".spec.tsx\",\n \"__tests__/\"\n ],\n \"ignorePatterns\": [\n \"**/*.d.ts\",\n \"**/index.ts\"\n ],\n \"mode\": \"all\",\n \"baseBranch\": \"main\"\n }\n ]],\n \"uilint/prefer-tailwind\": [\"warn\", ...[\n {\n \"styleRatioThreshold\": 0.3,\n \"minElementsForAnalysis\": 3,\n \"allowedStyleProperties\": [],\n \"ignoreComponents\": [],\n \"preferSemanticColors\": true,\n \"allowedHardCodedColors\": []\n }\n ]],\n },\n};\n\n/**\n * Pre-configured configs\n */\nconst configs: Record<string, Linter.Config> = {\n recommended: recommendedConfig,\n strict: strictConfig,\n};\n\n/**\n * UILint ESLint export interface\n */\nexport interface UILintESLint {\n meta: typeof meta;\n plugin: typeof plugin;\n rules: typeof rules;\n configs: Record<string, Linter.Config>;\n}\n\n/**\n * Default export for ESLint flat config\n */\nconst uilintEslint: UILintESLint = {\n meta,\n plugin,\n rules,\n configs,\n};\n\nexport default uilintEslint;\n\n// Named exports for convenience\nexport { plugin, rules, configs, meta };\n\n// Re-export utilities for custom rule creation\nexport { createRule } from \"./utils/create-rule.js\";\n\n// Re-export styleguide utilities (from semantic rule)\nexport {\n loadStyleguide,\n findStyleguidePath,\n getStyleguide,\n} from \"./rules/semantic/lib/styleguide-loader.js\";\n\n// Re-export cache utilities (from semantic rule)\nexport {\n hashContent,\n hashContentSync,\n getCacheEntry,\n setCacheEntry,\n clearCache,\n clearCacheEntry,\n loadCache,\n saveCache,\n type CacheEntry,\n type CachedIssue,\n type CacheStore,\n} from \"./rules/semantic/lib/cache.js\";\n\n// Re-export import graph utilities (from no-mixed-component-libraries rule)\nexport {\n getComponentLibrary,\n clearCache as clearImportGraphCache,\n type LibraryName,\n} from \"./rules/no-mixed-component-libraries/lib/import-graph.js\";\n\n// Re-export rule registry for CLI tooling\nexport {\n ruleRegistry,\n getRuleMetadata,\n getRulesByCategory,\n getRuleDocs,\n getAllRuleIds,\n categoryRegistry,\n getCategoryMeta,\n type RuleMeta,\n type RuleMetadata, // Backward compatibility alias\n type OptionFieldSchema,\n type RuleOptionSchema,\n type RuleRequirement,\n type RuleMigration,\n type CategoryMeta,\n} from \"./rule-registry.js\";\n\n// Re-export defineRuleMeta for rule authors\nexport { defineRuleMeta } from \"./utils/create-rule.js\";\n\n// Re-export coverage utilities (from require-test-coverage rule)\nexport {\n aggregateCoverage,\n type IstanbulCoverage,\n type FileCoverageInfo,\n type AggregatedCoverage,\n} from \"./rules/require-test-coverage/lib/coverage-aggregator.js\";\n\nexport {\n buildDependencyGraph,\n type DependencyGraph,\n} from \"./rules/require-test-coverage/lib/dependency-graph.js\";\n\nexport {\n categorizeFile,\n type FileCategory,\n type FileCategoryResult,\n} from \"./rules/require-test-coverage/lib/file-categorizer.js\";\n\n// Re-export JSX coverage analyzer utilities (from require-test-coverage rule)\nexport {\n analyzeJSXElementCoverage,\n buildDataLoc,\n findStatementsInRange,\n calculateCoverageFromStatements,\n findCoverageForFile,\n isEventHandlerAttribute,\n type IstanbulFileCoverage,\n type SourceLocation,\n type CoverageStats,\n type JSXCoverageResult,\n} from \"./rules/require-test-coverage/lib/jsx-coverage-analyzer.js\";\n\n// Re-export oxc-resolver for custom rules that need import resolution\nexport { ResolverFactory } from \"oxc-resolver\";\n"],"mappings":"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","names":["meta","meta","meta","isComponentName","meta","existsSync","readFileSync","dirname","join","existsSync","readFileSync","dirname","join","clearCache","existsSync","readFileSync","dirname","join","workspaceRoot","meta","dirname","readFileSync","findProjectRoot","existsSync","join","existsSync","readFileSync","dirname","join","relative","meta","findProjectRoot","existsSync","join","dirname","readFileSync","relative","meta","meta","meta","meta","isComponentName","meta","meta","existsSync","readFileSync","writeFileSync","dirname","join","relative","meta","findProjectRoot","dirname","join","existsSync","readFileSync","meta","relative","existsSync","readFileSync","statSync","dirname","join","basename","relative","existsSync","readFileSync","parse","existsSync","readFileSync","parse","existsSync","ResolverFactory","parse","readFileSync","existsSync","dirname","join","resolverFactory","astCache","resolvedPathCache","getResolverFactory","resolverFactory","ResolverFactory","resolveImportPath","dirname","manualResolve","findProjectRoot","join","existsSync","parseFile","readFileSync","parse","extractImports","resolveImportPath","existsSync","parseFile","findCoverageForFile","resolveImportPath","statementCount","coveredCount","meta","findProjectRoot","dirname","existsSync","join","statSync","readFileSync","shouldIgnore","relative","findCoverageForFile","basename","meta","getComponentName","getComponentName","meta","ResolverFactory","meta"]}
|