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
|