Files
CodePilot/eslint.config.mjs
T
7418andClaude Opus 4.6 27bf396cd3 refactor: migrate all Lucide icons to Phosphor + remove lucide-react (PR4)
Unified icon library:
- Create src/components/ui/icon.tsx as centralized icon re-export + size constants
- Migrate all 20+ files from lucide-react to @phosphor-icons/react
- Remove lucide-react from package.json dependencies
- Upgrade ESLint lucide-react rule from warn → error

Icon mappings applied:
  CheckIcon → Check, ChevronDown → CaretDown, ChevronUp → CaretUp,
  ChevronRight → CaretRight, X → X, Search → MagnifyingGlass,
  Loader2 → SpinnerGap, CornerDownLeft → ArrowElbowDownLeft,
  Image → Image, Brain → Brain, Terminal → Terminal, Book → Book,
  Dot → DotOutline, Circle → Circle

Files migrated: ui/ (6), ai-elements/ (11), layout/ (3)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 21:51:38 +08:00

115 lines
3.2 KiB
JavaScript

import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"release/**",
"dist-electron/**",
"next-env.d.ts",
// apps/site generated artifacts
"apps/site/.next/**",
"apps/site/.source/**",
]),
// ── Governance rules for business components ──
{
files: [
"src/components/settings/**/*.{ts,tsx}",
"src/components/bridge/**/*.{ts,tsx}",
"src/components/chat/**/*.{ts,tsx}",
"src/components/gallery/**/*.{ts,tsx}",
"src/components/plugins/**/*.{ts,tsx}",
"src/components/skills/**/*.{ts,tsx}",
"src/components/project/**/*.{ts,tsx}",
"src/components/layout/**/*.{ts,tsx}",
"src/components/cli-tools/**/*.{ts,tsx}",
"src/app/**/*.{ts,tsx}",
],
rules: {
// Discourage native HTML controls — use ui/ components instead
"no-restricted-syntax": [
"warn",
{
selector: "JSXOpeningElement[name.name='button']",
message: "Use <Button> from @/components/ui/button instead of native <button>.",
},
{
selector: "JSXOpeningElement[name.name='input']",
message: "Use <Input> from @/components/ui/input instead of native <input>.",
},
{
selector: "JSXOpeningElement[name.name='select']",
message: "Use <Select> from @/components/ui/select instead of native <select>.",
},
{
selector: "JSXOpeningElement[name.name='textarea']",
message: "Use <Textarea> from @/components/ui/textarea instead of native <textarea>.",
},
],
},
},
// ── Discourage Lucide imports project-wide ──
{
files: ["src/**/*.{ts,tsx}"],
rules: {
"no-restricted-imports": [
"error",
{
patterns: [
{
group: ["lucide-react"],
message: "Use @phosphor-icons/react instead. See docs/ui-governance.md for mapping.",
},
],
},
],
},
},
// ── Component file size limit ──
{
files: ["src/components/**/*.{ts,tsx}"],
ignores: [
"src/components/ui/**",
"src/components/ai-elements/**",
],
rules: {
"max-lines": ["warn", { max: 500, skipBlankLines: true, skipComments: true }],
},
},
// ── Patterns layer: no data logic imports ──
{
files: ["src/components/patterns/**/*.{ts,tsx}"],
rules: {
"no-restricted-imports": [
"error",
{
patterns: [
{
group: ["@/hooks/*", "@/hooks"],
message: "Pattern components must be pure presentation — no hooks imports.",
},
{
group: ["@/lib/*", "!@/lib/utils"],
message: "Pattern components must be pure presentation — no lib imports. Use @/lib/utils for cn() only.",
},
],
paths: [],
},
],
},
},
]);
export default eslintConfig;