159 lines
7.0 KiB
JavaScript
159 lines
7.0 KiB
JavaScript
|
|
export const codeReviewTool = {
|
|||
|
|
name: "code_review",
|
|||
|
|
description: "审查代码质量。根据审查重点返回结构化的检查清单和分析结果,涵盖 bug、安全、性能、风格等维度。",
|
|||
|
|
inputSchema: {
|
|||
|
|
type: "object",
|
|||
|
|
properties: {
|
|||
|
|
code: {
|
|||
|
|
type: "string",
|
|||
|
|
description: "要审查的代码",
|
|||
|
|
},
|
|||
|
|
language: {
|
|||
|
|
type: "string",
|
|||
|
|
description: "编程语言(如 typescript, python, java 等)",
|
|||
|
|
},
|
|||
|
|
focus: {
|
|||
|
|
type: "string",
|
|||
|
|
description: "审查重点(可选):security=安全性, performance=性能, style=代码风格, all=全面审查",
|
|||
|
|
enum: ["security", "performance", "style", "all"],
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
required: ["code", "language"],
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
const reviewChecklists = {
|
|||
|
|
security: [
|
|||
|
|
"检查是否存在 SQL 注入、XSS、CSRF 等注入攻击风险",
|
|||
|
|
"检查是否硬编码了密钥、密码、Token 等敏感信息",
|
|||
|
|
"检查用户输入是否经过验证和清洗",
|
|||
|
|
"检查权限控制是否完善,是否有越权风险",
|
|||
|
|
"检查是否使用了不安全的加密算法或随机数生成",
|
|||
|
|
"检查第三方依赖是否有已知安全漏洞",
|
|||
|
|
],
|
|||
|
|
performance: [
|
|||
|
|
"检查是否存在不必要的循环嵌套或 O(n²) 以上复杂度",
|
|||
|
|
"检查是否有内存泄漏(未清理的定时器、事件监听、闭包)",
|
|||
|
|
"检查是否有不必要的重复计算,是否需要缓存/记忆化",
|
|||
|
|
"检查异步操作是否可以并行化(Promise.all)",
|
|||
|
|
"检查是否有阻塞主线程的同步操作",
|
|||
|
|
"检查数据库查询是否有 N+1 问题",
|
|||
|
|
],
|
|||
|
|
style: [
|
|||
|
|
"检查命名是否清晰表达意图(变量、函数、类)",
|
|||
|
|
"检查函数长度是否超过 50 行,是否需要拆分",
|
|||
|
|
"检查嵌套层级是否过深(>3 层),是否可用 guard clause",
|
|||
|
|
"检查是否有重复代码(DRY 原则)",
|
|||
|
|
"检查注释是否准确且必要,而非冗余",
|
|||
|
|
"检查是否遵循语言社区的标准代码风格",
|
|||
|
|
],
|
|||
|
|
};
|
|||
|
|
export async function executeCodeReview(args) {
|
|||
|
|
const { code, language, focus = "all" } = args;
|
|||
|
|
const lines = code.split("\n");
|
|||
|
|
const lineCount = lines.length;
|
|||
|
|
// 基础代码统计
|
|||
|
|
const stats = {
|
|||
|
|
totalLines: lineCount,
|
|||
|
|
blankLines: lines.filter((l) => l.trim() === "").length,
|
|||
|
|
commentLines: lines.filter((l) => {
|
|||
|
|
const t = l.trim();
|
|||
|
|
return t.startsWith("//") || t.startsWith("#") || t.startsWith("/*") || t.startsWith("*");
|
|||
|
|
}).length,
|
|||
|
|
codeLines: 0,
|
|||
|
|
maxLineLength: Math.max(...lines.map((l) => l.length)),
|
|||
|
|
maxNestingDepth: 0,
|
|||
|
|
};
|
|||
|
|
stats.codeLines = stats.totalLines - stats.blankLines - stats.commentLines;
|
|||
|
|
// 计算最大嵌套深度
|
|||
|
|
let depth = 0;
|
|||
|
|
for (const line of lines) {
|
|||
|
|
const opens = (line.match(/{/g) || []).length;
|
|||
|
|
const closes = (line.match(/}/g) || []).length;
|
|||
|
|
depth += opens - closes;
|
|||
|
|
if (depth > stats.maxNestingDepth)
|
|||
|
|
stats.maxNestingDepth = depth;
|
|||
|
|
}
|
|||
|
|
// 检测潜在问题
|
|||
|
|
const issues = [];
|
|||
|
|
// 通用检查
|
|||
|
|
if (stats.maxLineLength > 120)
|
|||
|
|
issues.push(`⚠️ 存在超长行(最长 ${stats.maxLineLength} 字符),建议不超过 120`);
|
|||
|
|
if (stats.maxNestingDepth > 4)
|
|||
|
|
issues.push(`⚠️ 嵌套层级过深(${stats.maxNestingDepth} 层),建议重构`);
|
|||
|
|
if (stats.codeLines > 300)
|
|||
|
|
issues.push(`⚠️ 文件过长(${stats.codeLines} 行代码),建议拆分`);
|
|||
|
|
if (stats.commentLines === 0 && stats.codeLines > 30)
|
|||
|
|
issues.push("🔵 缺少注释,建议为关键逻辑添加说明");
|
|||
|
|
// 安全检查
|
|||
|
|
if (focus === "security" || focus === "all") {
|
|||
|
|
if (/eval\s*\(/.test(code))
|
|||
|
|
issues.push("🔴 使用了 eval(),存在代码注入风险");
|
|||
|
|
if (/innerHTML\s*=/.test(code))
|
|||
|
|
issues.push("🔴 使用了 innerHTML,存在 XSS 风险");
|
|||
|
|
if (/(password|secret|api_?key|token)\s*=\s*["'][^"']+["']/i.test(code))
|
|||
|
|
issues.push("🔴 可能硬编码了敏感信息");
|
|||
|
|
if (/\bhttp:\/\//.test(code))
|
|||
|
|
issues.push("🟡 使用了 HTTP 而非 HTTPS");
|
|||
|
|
if (/exec\s*\(|spawn\s*\(/.test(code) && !/sanitize|escape|validate/.test(code))
|
|||
|
|
issues.push("🟡 执行了外部命令,确认输入已清洗");
|
|||
|
|
}
|
|||
|
|
// 性能检查
|
|||
|
|
if (focus === "performance" || focus === "all") {
|
|||
|
|
if (/for\s*\(.*for\s*\(/s.test(code))
|
|||
|
|
issues.push("🟡 存在嵌套循环,注意时间复杂度");
|
|||
|
|
if (/setTimeout|setInterval/.test(code) && !/clearTimeout|clearInterval/.test(code))
|
|||
|
|
issues.push("<22> 设置了定时器但未见清理,可能内存泄漏");
|
|||
|
|
if (/\.forEach\(.*await/.test(code))
|
|||
|
|
issues.push("🟡 在 forEach 中使用 await,不会等待完成,建议用 for...of");
|
|||
|
|
if (/new RegExp\(/.test(code) && /for|while|map|forEach/.test(code))
|
|||
|
|
issues.push("🔵 循环中创建正则表达式,建议提取到循环外");
|
|||
|
|
}
|
|||
|
|
// 风格检查
|
|||
|
|
if (focus === "style" || focus === "all") {
|
|||
|
|
if (/var\s+/.test(code) && (language === "typescript" || language === "javascript"))
|
|||
|
|
issues.push("🔵 使用了 var,建议改用 const/let");
|
|||
|
|
if (/console\.log/.test(code))
|
|||
|
|
issues.push("🔵 包含 console.log,确认是否需要在生产环境移除");
|
|||
|
|
if (/any/.test(code) && language === "typescript")
|
|||
|
|
issues.push("🔵 使用了 any 类型,建议使用具体类型");
|
|||
|
|
if (/TODO|FIXME|HACK|XXX/.test(code))
|
|||
|
|
issues.push("🔵 存在 TODO/FIXME 标记,建议处理");
|
|||
|
|
}
|
|||
|
|
// 获取对应的检查清单
|
|||
|
|
let checklist;
|
|||
|
|
if (focus === "all") {
|
|||
|
|
checklist = [
|
|||
|
|
...reviewChecklists.security,
|
|||
|
|
...reviewChecklists.performance,
|
|||
|
|
...reviewChecklists.style,
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
checklist = reviewChecklists[focus] || reviewChecklists.style;
|
|||
|
|
}
|
|||
|
|
// 组装结果
|
|||
|
|
const output = [
|
|||
|
|
`# 代码审查报告`,
|
|||
|
|
``,
|
|||
|
|
`**语言**: ${language} | **审查重点**: ${focus}`,
|
|||
|
|
``,
|
|||
|
|
`## 代码统计`,
|
|||
|
|
`- 总行数: ${stats.totalLines}(代码 ${stats.codeLines} / 注释 ${stats.commentLines} / 空行 ${stats.blankLines})`,
|
|||
|
|
`- 最长行: ${stats.maxLineLength} 字符`,
|
|||
|
|
`- 最大嵌套深度: ${stats.maxNestingDepth} 层`,
|
|||
|
|
``,
|
|||
|
|
`## 自动检测到的问题(${issues.length} 项)`,
|
|||
|
|
issues.length > 0 ? issues.map((i) => `- ${i}`).join("\n") : "- ✅ 未检测到明显问题",
|
|||
|
|
``,
|
|||
|
|
`## 人工审查清单`,
|
|||
|
|
`请逐项检查以下内容:`,
|
|||
|
|
...checklist.map((item, idx) => `${idx + 1}. ${item}`),
|
|||
|
|
``,
|
|||
|
|
`## 待审查代码`,
|
|||
|
|
"```" + language,
|
|||
|
|
code,
|
|||
|
|
"```",
|
|||
|
|
];
|
|||
|
|
return output.join("\n");
|
|||
|
|
}
|
|||
|
|
//# sourceMappingURL=codeReview.js.map
|