Update code
This commit is contained in:
159
dev-assistant-mcp/dist/tools/codeReview.js
vendored
Normal file
159
dev-assistant-mcp/dist/tools/codeReview.js
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
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
|
||||
Reference in New Issue
Block a user