mcpField
A
audit-code-quality

audit-code-quality

github.com/kensaurus测试与质量942 次安装2 周前更新
代码仓库

关于 audit-code-quality

用于审查并针对性修复 React 和 TypeScript 代码质量问题的技能。它检查反模式、命名、文件组织和模式一致性,并使用代码库自身的检查流程验证改动。

主要功能

  1. 01查找 React 和 TypeScript 反模式
  2. 02检查命名与文件组织
  3. 03审查模式一致性
  4. 04针对发现的问题进行修复
  5. 05运行代码库的类型检查、Lint 和测试

适用场景

  1. 01审查 React 和 TypeScript 代码库
  2. 02修复已发现的架构或状态问题
  3. 03合并改动前检查代码约定

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kensaurus/skills --skill audit-code-quality

安装后在 Claude Code 中输入/audit-code-quality确认已加载。

详细介绍

代码质量审计

自由度:混合——第 1–2 部分的判断 [高自由度];约定检查和验证 [低自由度 — 严格执行]。

审计并修复例外。 发现问题后要修复,而不是报告后就停止。

修复你报告的问题,并修改你指出的文件;报告中未列出的全仓库样式调整或重命名属于另一个会话。进行精准修改——只改有问题的 Hook、键或导入,而不是重写整个文件。过程中遇到的既有 Bug,作为后续事项写入报告。仅在任务要求,或仓库已为相关部分保留测试时,才添加或修改测试;临时 grep 和草稿脚本不要提交。

全仓库 React/TypeScript 反模式,以及命名、组织和模式一致性。针对指定 PR/diff → audit-code-review。

如何推理

  1. 观察——引用问题点(file:line),并说明 git blame / CONTRIBUTING 是否标明这是有意为之
  2. 解读——是否存在 Bug/性能风险,还是仅有风格偏差?
  3. 分类——反模式 / 命名 / 组织 / 模式分歧 / 有意为之
  4. 严重程度——运行时 Bug 或用于数据获取的 useEffect = 高;仅命名问题 = 低

示例

观察: components/PaymentForm.tsx 有 'use server',并用 useEffect 获取发票;四个可排序列表都使用 key={i}。 解读: 服务端 Action 位于 UI 中;组件重新挂载时会重新触发数据获取;重新排序会导致行组件重新挂载。 分类: 组织 + 用于数据获取的 useEffect + 将索引用作键。 严重程度: 高(Action 位于组件中);中(键)。 发现: PaymentForm.tsx | 高 | 将 Action 移至 features/*/server/; 用 TanStack Query 替换数据获取 Effect

任何修改之前 [低自由度 — 严格执行]

cat CONTRIBUTING.md .cursor/rules/*.md 2>/dev/null | head -100 # existing conventions
git log --oneline -20 | grep -i "convention\|pattern\|style" # recent decisions

确认这种“不一致”并非有意为之。修改现有代码之前,先检查 git blame。


第 1 部分 — 反模式 [高自由度]

React
Props 层层传递 → Context 或组合
// Bad: prop drilled through 5+ levels
<Layout user={user}><Sidebar user={user}><UserMenu user={user}><Avatar user={user} />

// Fix: context for global state
const UserContext = createContext<User | null>(null)
const useUser = () => useContext(UserContext)

// Fix: composition for UI concerns
<Layout><Layout.Sidebar><UserMenu /></Layout.Sidebar></Layout>
在 useState 中存储派生状态 → useMemo
// Bad
const [items, setItems] = useState([])
const [filtered, setFiltered] = useState([])
useEffect(() => { setFiltered(items.filter(i => i.active)) }, [items])

// Fix
const filtered = useMemo(() => items.filter(i => i.active), [items])
使用 useEffect 获取数据 → 服务端组件或 TanStack Query
// Fix (Next.js 16 Server Component)
async function DataDisplay() {
 const data = await db.getData()
 return <div>{data.name}</div>
}

// Fix (client with TanStack Query)
const { data, isLoading } = useQuery({ queryKey: ['data'], queryFn: fetchData })
依赖数组中包含对象/数组 → 使用 memo 或解构
// Bad: new object every render → infinite loop
useEffect(() => { doSomething(options) }, [options])

// Fix
const options = useMemo(() => ({ page, limit }), [page, limit])
useEffect(() => { doSomething(options) }, [options])
在动态列表中将索引用作键 → 稳定 ID
// Bad
{items.map((item, i) => <Item key={i} />)}
// Fix
{items.map(item => <Item key={item.id} />)}
巨型组件 → 组合
// Split by responsibility
export function UserDashboard() {
 const user = useUser()
 return (
 <DashboardLayout>
 <UserHeader user={user} />
 <UserStats userId={user.id} />
 <RecentActivity userId={user.id} />
 </DashboardLayout>
 )
}
TypeScript
// Bad: any
function processData(data: any) { return data.items.map((i: any) => i.name) }

// Fix: proper types + Zod validation
const DataSchema = z.object({ items: z.array(z.object({ id: z.string(), name: z.string() })) })
function processData(data: z.infer<typeof DataSchema>) { return data.items.map(i => i.name) }

// Bad: enums (runtime object, not tree-shakeable)
enum Status { Pending = 'pending', Active = 'active' }
// Fix: union types
type Status = 'pending' | 'active'

// Fix: exhaustive switch
function handle(s: Status): string {
 switch (s) {
 case 'pending': return 'Waiting'
 case 'active': return 'Running'
 default:
 const _: never = s
 throw new Error(`Unknown: ${_}`)
 }
}
状态管理
// Rule of thumb:
// URL state (nuqs) → shareable, bookmarkable
// Global state (Zustand) → cross-component, persisted
// Local state (useState) → component-specific, ephemeral

// Stale closure fix
useEffect(() => {
 const id = setInterval(() => setCount(c => c + 1), 1000) // functional update
 return () => clearInterval(id)
}, [])
架构
// Circular deps → extract shared code / dependency inversion
// Business logic in components → move to lib/feature/calculations.ts
// God files → feature-based organisation:
lib/
 date/format.ts
 currency/format.ts
 validation/schemas.ts

第 2 部分 — 一致性审计 [高自由度;grep 检查为低自由度]

命名约定
元素预期格式检查
组件PascalCaseuserCard 与 UserCard
Hookuse 前缀fetchData 与 useFetchData
工具函数camelCaseformat_date 与 formatDate
常量SCREAMING_SNAKEapiUrl 与 API_URL
文件kebab-caseUserCard.tsx 与 user-card.tsx
布尔型属性is/has/shouldloading 与 isLoading
rg "export (function|const|class) [a-z]" --type tsx # lowercase component exports
rg "use[A-Z]" --type ts # hook patterns
rg "export default" --type tsx -l | head -20 # mixed default/named exports
文件组织(按功能切片)
src/
 features/{name}/
 components/ # UI only
 hooks/ # custom hooks
 server/ # server actions
 types.ts
 schemas.ts
 components/ui/ # shared primitives
 lib/ # global utilities

警示项:

  • 在 /lib 或 /utils 中放置组件
  • 在组件文件中定义服务端 Action
  • 类型定义分散在各个组件文件中
  • 在组件中内联 Zod Schema
rg "z\.object" --glob "*/components/*" # inline schemas
rg "'use server'" --glob "*/components/*" # actions in wrong place
rg "from '\.\." --type tsx | head -20 # relative imports instead of @/
模式一致性
关注点检查
服务端状态是否全部使用 TanStack Query,还是混用了 useEffect?
表单是否全部使用 React Hook Form,还是也使用受控输入?
错误处理ActionResult 的结构是否一致?
样式是否处处使用 cn()?是否通过 CSS 变量实现深色模式?
测试使用 *.test.ts 还是 __tests__/?Mock 方式是否一致?

一致性报告模板

# Code Quality Audit

## Summary
- Verdict: [one line — what blocks, what is drift]
- Critical findings: X

## Anti-patterns found
| Pattern | Files | Severity |
|---------|-------|----------|
| useEffect for data | 3 files | High |
| Index as key | 2 files | Medium |

## Naming convention findings
| Element | Expected | Actual | Files |
|---------|----------|--------|-------|
| Components | PascalCase | Mixed | 4 |

## Organisation findings
- Server actions found in: components/PaymentForm.tsx
- Types scattered in: 6 component files

## Priority fixes
1. Move server actions to features/*/server/
2. Replace useEffect data fetching with TanStack Query
3. Standardise component naming to PascalCase

## Conventions to document
1. Decision on default vs named exports
2. Where Zod schemas live

反模式检测清单

React 检查
  • 不使用 useEffect 处理派生状态
  • 动态列表中不使用索引作为键
  • 依赖数组中不包含对象/数组
  • 组件少于 300 行
  • Props 传递不超过 2 层
TypeScript 检查
  • 不使用 any(使用 unknown + 验证)
  • 不使用不安全的类型断言
  • switch 语句覆盖所有情况
  • 所有外部数据都有 Zod Schema
架构检查
  • 无循环依赖
  • 业务逻辑与 UI 分离
  • 文件不超过 400 行
  • 模块边界清晰

修复前自我审查 [LOW freedom — do not skip]

  1. 有据可查 — 提供 file:line 或 rg 命中结果,而不是「代码库感觉很乱」
  2. 可复现 — 按照该约定执行 grep 仍能找到问题
  3. 严重性合理 — High = 缺陷/性能问题,而非命名偏好
  4. 责任归属正确 — 此 PR/diff → audit-code-review
  5. 避免虚假安全感 — 已检查 git blame;保留有意为之且正常工作的代码

验证 [LOW freedom — run exactly]

  1. 使用代码库自带的脚本进行类型检查(package.json → typecheck;否则运行 tsc --noEmit)
  2. 使用代码库自带的脚本进行 lint 检查,不要使用通用的 eslint src/
  3. 运行代码库的测试脚本,并确认没有新增失败
  4. 在 CONTRIBUTING.md 或 .cursor/rules/ 中记录任何强制执行的规范

评论

支持 Markdown