Files
Claude-Code-Workflow/.claude/skills/review-code/phases/actions/action-deep-review.md
catlog22 15514c8f91 Add multi-dimensional code review rules for architecture, correctness, performance, readability, security, and testing
- Introduced architecture rules to detect circular dependencies, god classes, layer violations, and mixed concerns.
- Added correctness rules focusing on null checks, empty catch blocks, unreachable code, and type coercion.
- Implemented performance rules addressing nested loops, synchronous I/O, memory leaks, and unnecessary re-renders in React.
- Created readability rules to improve function length, variable naming, deep nesting, magic numbers, and commented code.
- Established security rules to identify XSS risks, hardcoded secrets, SQL injection vulnerabilities, and insecure random generation.
- Developed testing rules to enhance test quality, coverage, and maintainability, including missing assertions and error path testing.
- Documented the structure and schema for rule files in the index.md for better understanding and usage.
2026-01-13 14:53:20 +08:00

303 lines
7.9 KiB
Markdown

# Action: Deep Review
深入审查指定维度的代码质量。
## Purpose
针对单个维度进行深入审查:
- 逐文件检查
- 记录发现的问题
- 提供具体的修复建议
## Preconditions
- [ ] state.status === 'running'
- [ ] state.scan_completed === true
- [ ] 存在未审查的维度
## Dimension Focus Areas
### Correctness (正确性)
- 逻辑错误和边界条件
- Null/undefined 处理
- 错误处理完整性
- 类型安全
- 资源泄漏
### Readability (可读性)
- 命名规范
- 函数长度和复杂度
- 代码重复
- 注释质量
- 代码组织
### Performance (性能)
- 算法复杂度
- 不必要的计算
- 内存使用
- I/O 效率
- 缓存策略
### Security (安全性)
- 注入风险 (SQL, XSS, Command)
- 认证和授权
- 敏感数据处理
- 加密使用
- 依赖安全
### Testing (测试)
- 测试覆盖率
- 边界条件测试
- 错误路径测试
- 测试可维护性
- Mock 使用
### Architecture (架构)
- 分层结构
- 依赖方向
- 单一职责
- 接口设计
- 扩展性
## Execution
```javascript
async function execute(state, workDir, currentDimension) {
const context = state.context;
const dimension = currentDimension;
const findings = [];
// 从外部 JSON 文件加载规则
const rulesConfig = loadRulesConfig(dimension, workDir);
const rules = rulesConfig.rules || [];
const prefix = rulesConfig.prefix || getDimensionPrefix(dimension);
// 优先审查高风险区域
const filesToReview = state.scan_summary?.risk_areas
?.map(r => r.file)
?.filter(f => context.files.includes(f)) || context.files;
const filesToCheck = [...new Set([
...filesToReview.slice(0, 20),
...context.files.slice(0, 30)
])].slice(0, 50); // 最多50个文件
let findingCounter = 1;
for (const file of filesToCheck) {
try {
const content = Read(file);
const lines = content.split('\n');
// 应用外部规则文件中的规则
for (const rule of rules) {
const matches = detectByPattern(content, lines, file, rule);
for (const match of matches) {
findings.push({
id: `${prefix}-${String(findingCounter++).padStart(3, '0')}`,
severity: rule.severity || match.severity,
dimension: dimension,
category: rule.category,
file: file,
line: match.line,
code_snippet: match.snippet,
description: rule.description,
recommendation: rule.recommendation,
fix_example: rule.fixExample
});
}
}
} catch (e) {
// 跳过无法读取的文件
}
}
// 保存维度发现
Write(`${workDir}/findings/${dimension}.json`, JSON.stringify(findings, null, 2));
return {
stateUpdates: {
reviewed_dimensions: [...(state.reviewed_dimensions || []), dimension],
current_dimension: null,
[`findings.${dimension}`]: findings
}
};
}
/**
* 从外部 JSON 文件加载规则配置
* 规则文件位于 specs/rules/{dimension}-rules.json
* @param {string} dimension - 维度名称 (correctness, security, etc.)
* @param {string} workDir - 工作目录 (用于日志记录)
* @returns {object} 规则配置对象,包含 rules 数组和 prefix
*/
function loadRulesConfig(dimension, workDir) {
// 规则文件路径:相对于 skill 目录
const rulesPath = `specs/rules/${dimension}-rules.json`;
try {
const rulesFile = Read(rulesPath);
const rulesConfig = JSON.parse(rulesFile);
return rulesConfig;
} catch (e) {
console.warn(`Failed to load rules for ${dimension}: ${e.message}`);
// 返回空规则配置,保持向后兼容
return { rules: [], prefix: getDimensionPrefix(dimension) };
}
}
/**
* 根据规则的 patternType 检测代码问题
* 支持的 patternType: regex, includes
* @param {string} content - 文件内容
* @param {string[]} lines - 按行分割的内容
* @param {string} file - 文件路径
* @param {object} rule - 规则配置对象
* @returns {Array} 匹配结果数组
*/
function detectByPattern(content, lines, file, rule) {
const matches = [];
const { pattern, patternType, negativePatterns, caseInsensitive } = rule;
if (!pattern) return matches;
switch (patternType) {
case 'regex':
return detectByRegex(content, lines, pattern, negativePatterns, caseInsensitive);
case 'includes':
return detectByIncludes(content, lines, pattern, negativePatterns);
default:
// 默认使用 includes 模式
return detectByIncludes(content, lines, pattern, negativePatterns);
}
}
/**
* 使用正则表达式检测代码问题
* @param {string} content - 文件完整内容
* @param {string[]} lines - 按行分割的内容
* @param {string} pattern - 正则表达式模式
* @param {string[]} negativePatterns - 排除模式列表
* @param {boolean} caseInsensitive - 是否忽略大小写
* @returns {Array} 匹配结果数组
*/
function detectByRegex(content, lines, pattern, negativePatterns, caseInsensitive) {
const matches = [];
const flags = caseInsensitive ? 'gi' : 'g';
try {
const regex = new RegExp(pattern, flags);
let match;
while ((match = regex.exec(content)) !== null) {
const lineNum = content.substring(0, match.index).split('\n').length;
const lineContent = lines[lineNum - 1] || '';
// 检查排除模式 - 如果行内容匹配任一排除模式则跳过
if (negativePatterns && negativePatterns.length > 0) {
const shouldExclude = negativePatterns.some(np => {
try {
return new RegExp(np).test(lineContent);
} catch {
return lineContent.includes(np);
}
});
if (shouldExclude) continue;
}
matches.push({
line: lineNum,
snippet: lineContent.trim().substring(0, 100),
matchedText: match[0]
});
}
} catch (e) {
console.warn(`Invalid regex pattern: ${pattern}`);
}
return matches;
}
/**
* 使用字符串包含检测代码问题
* @param {string} content - 文件完整内容 (未使用但保持接口一致)
* @param {string[]} lines - 按行分割的内容
* @param {string} pattern - 要查找的字符串
* @param {string[]} negativePatterns - 排除模式列表
* @returns {Array} 匹配结果数组
*/
function detectByIncludes(content, lines, pattern, negativePatterns) {
const matches = [];
lines.forEach((line, i) => {
if (line.includes(pattern)) {
// 检查排除模式 - 如果行内容包含任一排除字符串则跳过
if (negativePatterns && negativePatterns.length > 0) {
const shouldExclude = negativePatterns.some(np => line.includes(np));
if (shouldExclude) return;
}
matches.push({
line: i + 1,
snippet: line.trim().substring(0, 100),
matchedText: pattern
});
}
});
return matches;
}
/**
* 获取维度前缀(作为规则文件不存在时的备用)
* @param {string} dimension - 维度名称
* @returns {string} 4字符前缀
*/
function getDimensionPrefix(dimension) {
const prefixes = {
correctness: 'CORR',
readability: 'READ',
performance: 'PERF',
security: 'SEC',
testing: 'TEST',
architecture: 'ARCH'
};
return prefixes[dimension] || 'MISC';
}
```
## State Updates
```javascript
return {
stateUpdates: {
reviewed_dimensions: [...state.reviewed_dimensions, currentDimension],
current_dimension: null,
findings: {
...state.findings,
[currentDimension]: newFindings
}
}
};
```
## Output
- **File**: `findings/{dimension}.json`
- **Location**: `${workDir}/findings/`
- **Format**: JSON array of Finding objects
## Error Handling
| Error Type | Recovery |
|------------|----------|
| 文件读取失败 | 跳过该文件,记录警告 |
| 规则执行错误 | 跳过该规则,继续其他规则 |
## Next Actions
- 还有未审查维度: 继续 action-deep-review
- 所有维度完成: action-generate-report