初始化
This commit is contained in:
209
.cursor/skills/code-review/SKILL.md
Normal file
209
.cursor/skills/code-review/SKILL.md
Normal file
@@ -0,0 +1,209 @@
|
||||
---
|
||||
name: code-review
|
||||
version: 2.0.0
|
||||
description: "从六个维度系统化代码审查(安全/正确/可维护/性能/可测试/一致性)。当需要 Review 代码、检查质量或预提交检查时使用。"
|
||||
---
|
||||
|
||||
> ⚠️ 核心执行流程已在 `.cursor/rules/skill-code-review.mdc` 中由 Cursor 自动注入。
|
||||
> 本文件提供完整模板、代码示例和边缘场景处理,供 Agent 按需深入 Read。
|
||||
|
||||
# Code Review
|
||||
|
||||
## 触发条件
|
||||
|
||||
用户要求审查代码、检查 PR、评估代码质量或执行预提交检查。
|
||||
|
||||
## 执行流程
|
||||
|
||||
### 1. 确定审查范围
|
||||
|
||||
- 具体文件 → 审查指定文件
|
||||
- 目录范围 → 审查目录下所有变更
|
||||
- Git diff → `git diff HEAD~1` 审查最近变更
|
||||
|
||||
### 2. 六维度审查
|
||||
|
||||
按以下顺序逐一审查:
|
||||
|
||||
**🔴 安全性 (Security)**
|
||||
- 硬编码密钥/凭证?
|
||||
- SQL 注入 / XSS 风险?
|
||||
- 未验证的用户输入?
|
||||
- 不安全的认证/授权?
|
||||
|
||||
```php
|
||||
// ❌ BAD: 直接拼接用户输入到 SQL
|
||||
$users = Db::select("SELECT * FROM users WHERE name = '{$name}'");
|
||||
|
||||
// ✅ GOOD: 参数绑定
|
||||
$users = Db::select("SELECT * FROM users WHERE name = ?", [$name]);
|
||||
// ✅ GOOD: Hyperf ORM
|
||||
$users = User::where('name', $name)->get();
|
||||
```
|
||||
|
||||
```vue
|
||||
<!-- ❌ BAD: 直接渲染用户输入的 HTML -->
|
||||
<div v-html="userInput" />
|
||||
|
||||
<!-- ✅ GOOD: 文本插值自动转义 -->
|
||||
<div>{{ userInput }}</div>
|
||||
|
||||
<!-- ✅ GOOD: 如必须用 v-html,先经过 DOMPurify 清洗 -->
|
||||
<div v-html="sanitize(userInput)" />
|
||||
```
|
||||
|
||||
**🟠 正确性 (Correctness)**
|
||||
- 逻辑是否正确?
|
||||
- 边界条件处理?
|
||||
- 错误处理完善?
|
||||
- null/undefined 安全?
|
||||
|
||||
```php
|
||||
// ❌ BAD: 无空值保护
|
||||
$userName = $user->profile->name;
|
||||
|
||||
// ✅ GOOD: 空安全访问
|
||||
$userName = $user?->profile?->name ?? 'Unknown';
|
||||
```
|
||||
|
||||
```typescript
|
||||
// ❌ BAD: 解构可能为 null 的响应
|
||||
const { data } = await api.getUser(id)
|
||||
|
||||
// ✅ GOOD: 防御性解构
|
||||
const response = await api.getUser(id)
|
||||
const data = response?.data ?? null
|
||||
```
|
||||
|
||||
**🟡 可维护性 (Maintainability)**
|
||||
- 命名清晰?
|
||||
- 函数长度合理(< 50 行)?
|
||||
- 单一职责?
|
||||
- 业务逻辑是否已提取到纯函数/composable?
|
||||
|
||||
```vue
|
||||
<!-- ❌ BAD: 组件内嵌大量业务逻辑 -->
|
||||
<script setup>
|
||||
const result = computed(() => {
|
||||
// 30 行复杂计算逻辑...
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- ✅ GOOD: 逻辑提取到 .utils.ts -->
|
||||
<script setup>
|
||||
import { calculateResult } from './MyComponent.utils'
|
||||
const result = computed(() => calculateResult(props.data))
|
||||
</script>
|
||||
```
|
||||
|
||||
**🔵 性能 (Performance)**
|
||||
- 不必要的渲染?
|
||||
- N+1 查询?
|
||||
- 大数据集未分页?
|
||||
- 缺少缓存机会?
|
||||
|
||||
```php
|
||||
// ❌ BAD: N+1 查询
|
||||
$orders = Order::all();
|
||||
foreach ($orders as $order) {
|
||||
echo $order->user->name; // each iteration queries DB
|
||||
}
|
||||
|
||||
// ✅ GOOD: 预加载关联
|
||||
$orders = Order::with('user')->get();
|
||||
```
|
||||
|
||||
```vue
|
||||
<!-- ❌ BAD: v-for 内使用复杂计算 -->
|
||||
<div v-for="item in list" :key="item.id">
|
||||
{{ heavyCompute(item) }}
|
||||
</div>
|
||||
|
||||
<!-- ✅ GOOD: 预计算或使用 computed -->
|
||||
<div v-for="item in computedList" :key="item.id">
|
||||
{{ item.computedValue }}
|
||||
</div>
|
||||
```
|
||||
|
||||
**🟣 可测试性 (Testability)**
|
||||
- 纯函数是否已提取到 `.utils.ts`?
|
||||
- composable 是否可独立测试?
|
||||
- 关键路径是否有 `data-testid`?
|
||||
- 是否有过度耦合使测试困难?
|
||||
|
||||
```typescript
|
||||
// ❌ BAD: 逻辑耦合在组件中,无法独立测试
|
||||
// 必须 mount 整个组件才能测试 formatDate
|
||||
|
||||
// ✅ GOOD: 提取为可独立测试的纯函数
|
||||
// date.utils.ts
|
||||
export function formatDate(date, format = 'YYYY-MM-DD') { ... }
|
||||
// date.utils.test.ts
|
||||
it('should format date correctly', () => { ... })
|
||||
```
|
||||
|
||||
**⚪ 一致性 (Consistency)**
|
||||
- 命名风格统一?
|
||||
- 遵循项目模式?
|
||||
- import 顺序统一?
|
||||
- 错误处理模式统一?
|
||||
|
||||
### 3. 预提交检查联动
|
||||
|
||||
审查代码时,同步执行以下自动化检查:
|
||||
|
||||
```bash
|
||||
# PHP 后端
|
||||
cd Case-Database-Backend
|
||||
vendor/bin/phpstan analyse --level=5 --no-progress # 静态分析
|
||||
vendor/bin/php-cs-fixer fix --dry-run --diff # 代码格式
|
||||
|
||||
# Vue 前端
|
||||
cd Case-Database-Frontend-user
|
||||
npx eslint --quiet src/ # ESLint
|
||||
npx vitest run --reporter=verbose # 单元测试
|
||||
cd ..
|
||||
```
|
||||
|
||||
如果项目配置了 husky + lint-staged,确认 `.husky/pre-commit` 钩子覆盖:
|
||||
- [ ] ESLint (前端)
|
||||
- [ ] PHPStan (后端)
|
||||
- [ ] 代码格式检查 (Prettier / PHP CS Fixer)
|
||||
|
||||
### 4. 输出格式
|
||||
|
||||
```markdown
|
||||
## 代码审查报告
|
||||
|
||||
**范围**: <文件/目录/PR>
|
||||
**总体评价**: ✅ 建议合并 | ⚠️ 需修改后合并 | ❌ 需重写
|
||||
|
||||
### 自动化检查
|
||||
- ESLint: ✅ 通过 | ❌ N 个错误
|
||||
- PHPStan: ✅ 通过 | ❌ N 个错误
|
||||
- 测试: ✅ 通过 | ❌ N 个失败
|
||||
|
||||
### 发现
|
||||
|
||||
#### 🔴 Must Fix
|
||||
1. **[SEC]** `file.ts:23` — 硬编码 API Key
|
||||
→ 修复:移入环境变量
|
||||
|
||||
#### 🟡 Should Fix
|
||||
2. **[MAINT]** `service.ts:45` — 函数过长(87 行)
|
||||
→ 建议:拆分为 3 个私有方法
|
||||
3. **[TEST]** `OrderForm.vue` — 价格计算逻辑未提取到 .utils.ts
|
||||
→ 建议:提取为纯函数并添加单元测试
|
||||
|
||||
#### 🟢 Suggestion
|
||||
4. **[PERF]** `list.vue:12` — 列表项未使用 `v-memo`
|
||||
→ 建议:添加 `v-memo="[item.id]"` 减少重渲染
|
||||
```
|
||||
|
||||
## 验证
|
||||
|
||||
1. [ ] 六个维度全部覆盖(含可测试性)
|
||||
2. [ ] 每个发现有具体文件和行号
|
||||
3. [ ] 每个发现有修复建议(含 BAD/GOOD 代码对比)
|
||||
4. [ ] 发现按严重程度分级
|
||||
5. [ ] 预提交检查已执行(ESLint + PHPStan + 测试)
|
||||
Reference in New Issue
Block a user