docs: upload code files and config
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
# Step 14 — Phase 4.6: 报告导出
|
||||
|
||||
**依赖**: Step 12(Merger)
|
||||
**参考设计**: §14.2
|
||||
|
||||
## 目标
|
||||
|
||||
将 `MergedReport` 导出为 Markdown 格式报告。
|
||||
|
||||
## 新建文件
|
||||
|
||||
| # | 文件 | 说明 |
|
||||
|---|------|------|
|
||||
| 1 | `src/utils/report.ts` | `reportToMarkdown()` |
|
||||
|
||||
---
|
||||
|
||||
## `src/utils/report.ts`
|
||||
|
||||
```typescript
|
||||
import { MergedReport } from '../merger/merger';
|
||||
|
||||
function severityEmoji(severity: string): string {
|
||||
switch (severity) {
|
||||
case 'error': return '🔴';
|
||||
case 'warning': return '🟡';
|
||||
case 'info': return '🔵';
|
||||
default: return '⚪';
|
||||
}
|
||||
}
|
||||
|
||||
function formatLine(line: number): string {
|
||||
return `L${line + 1}`;
|
||||
}
|
||||
|
||||
export function reportToMarkdown(report: MergedReport): string {
|
||||
const lines: string[] = [];
|
||||
|
||||
lines.push('# 代码审查报告');
|
||||
lines.push('');
|
||||
lines.push(`**文件:** \`${report.filePath}\``);
|
||||
lines.push(`**语言:** ${report.language}`);
|
||||
lines.push(`**耗时:** ${(report.duration / 1000).toFixed(1)}s`);
|
||||
if (report.adapterNames.length > 0) {
|
||||
lines.push(`**分析工具:** ${report.adapterNames.join(', ')}`);
|
||||
}
|
||||
if (report.degraded) {
|
||||
lines.push('');
|
||||
lines.push('> ⚠️ 部分 AI 功能不可用,报告已降级');
|
||||
}
|
||||
if (report.errors.length > 0) {
|
||||
lines.push('');
|
||||
lines.push('## 错误');
|
||||
for (const err of report.errors) {
|
||||
lines.push(`- ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
lines.push('---');
|
||||
lines.push('');
|
||||
|
||||
const total = report.linterCount + report.customRuleCount + report.aiCount;
|
||||
const errors = report.linterDiagnostics.filter(d => d.severity === 'error').length
|
||||
+ report.customRuleDiagnostics.filter(d => d.severity === 'error').length
|
||||
+ report.aiFindings.filter(f => f.severity === 'error').length;
|
||||
const warnings = report.linterDiagnostics.filter(d => d.severity === 'warning').length
|
||||
+ report.customRuleDiagnostics.filter(d => d.severity === 'warning').length
|
||||
+ report.aiFindings.filter(f => f.severity === 'warning').length;
|
||||
const infos = total - errors - warnings;
|
||||
|
||||
lines.push(`**总计:** ${total} | **错误:** ${errors} | **警告:** ${warnings} | **建议:** ${infos}`);
|
||||
lines.push('');
|
||||
|
||||
if (report.linterDiagnostics.length > 0) {
|
||||
lines.push(`## 🔧 静态分析 · ${report.linterCount} 个问题`);
|
||||
lines.push('');
|
||||
for (const diag of report.linterDiagnostics) {
|
||||
lines.push(`- ${severityEmoji(diag.severity)} \`${diag.ruleId}\` ${formatLine(diag.range.start.line)}`);
|
||||
lines.push(` ${diag.message}`);
|
||||
if (diag.suggestion) {
|
||||
lines.push(` 建议: ${diag.suggestion}`);
|
||||
}
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
if (report.customRuleDiagnostics.length > 0) {
|
||||
lines.push(`## 📋 自定义规则 · ${report.customRuleCount} 个问题`);
|
||||
lines.push('');
|
||||
for (const diag of report.customRuleDiagnostics) {
|
||||
lines.push(`- ${severityEmoji(diag.severity)} \`${diag.ruleId}\` ${formatLine(diag.range.start.line)}`);
|
||||
lines.push(` ${diag.message}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
if (report.aiFindings.length > 0) {
|
||||
lines.push(`## 🤖 AI 审查 · ${report.aiCount} 条建议`);
|
||||
lines.push('');
|
||||
for (const finding of report.aiFindings) {
|
||||
lines.push(`- ${severityEmoji(finding.severity)} [AI] [${finding.category}] \`${finding.ruleId}\` ${formatLine(finding.line)}`);
|
||||
lines.push(` **${finding.title}**`);
|
||||
lines.push(` ${finding.description}`);
|
||||
if (finding.suggestion) {
|
||||
lines.push(` 建议: ${finding.suggestion}`);
|
||||
}
|
||||
if (finding.codeDiff) {
|
||||
lines.push(' ```diff');
|
||||
lines.push(` ${finding.codeDiff.split('\n').join('\n ')}`);
|
||||
lines.push(' ```');
|
||||
}
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
if (total === 0) {
|
||||
lines.push('✅ 未发现问题');
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键逻辑
|
||||
|
||||
- 报告格式与设计 §14.2 一致
|
||||
- 按来源分三个段:静态分析 / 自定义规则 / AI 审查
|
||||
- 统计卡片:总计 + 按严重级别拆分
|
||||
- AI 审查结果包含 category、codeDiff(diff 代码块)
|
||||
- 降级和错误信息在报告顶部单独显示
|
||||
|
||||
---
|
||||
|
||||
## 验收
|
||||
|
||||
- [ ] 文件创建完成
|
||||
- [ ] `npm run compile` 通过
|
||||
- [ ] `npm run lint` 通过
|
||||
Reference in New Issue
Block a user