- CodeGuard → Code Purifier / 净码特工(displayName、命令、配置标题) - 新增 ai.maxTokens 配置项,所有 Provider 及 fixer 传入 maxTokens - AI 引擎增强:repairJsonEscapes + JSON 解析 fallback + 详细错误信息 - 设置面板规则管理改为文件级(list/delete .yaml),addRule 改为 AI 从 Markdown 生成 YAML - yaml-parser 简化:移除 config.yaml 的 enable/disable 过滤逻辑 - 审查报告面板:errorBanner 优先显示具体错误、lint 诊断显示 suggestion、移除 translatedDiagnostics 独立渲染 - merger 中 translatedDiagnostics 覆盖原始 lint 诊断 message/suggestion - HTML linter 配置项、测试用例重写、typescript-eslint 移入 dependencies
646 lines
19 KiB
Markdown
646 lines
19 KiB
Markdown
# vscode-code-reviewer 实施拆分方案
|
||
|
||
## 决策汇总
|
||
|
||
| 决策项 | 选择 |
|
||
|--------|------|
|
||
| 拆分策略 | 按层级自底向上 |
|
||
| 适配器优先级 | 按复杂度递增:ESLint → Stylelint → sql-lint → PMD → JSP |
|
||
| 核心层B顺序 | 按依赖链:Provider → AI引擎 → 规则解析 → 结果合并 → 自动修复 → 报告导出 |
|
||
| UI层顺序 | 按依赖顺序:命令注册 → 设置面板 → 审查面板 → Code Action |
|
||
| 构建与测试 | 集中在最后 Phase |
|
||
|
||
## 整体 Phase 划分
|
||
|
||
```
|
||
Phase 1: 基础层 Types + Config 管理
|
||
Phase 2: 适配层 5 个 Linter 适配器
|
||
Phase 3: 核心层 A 编排器 Orchestrator
|
||
Phase 4: 核心层 B AI引擎 + 规则 + 合并 + 修复 + 报告
|
||
Phase 5: UI 层 命令 + 设置面板 + 审查面板
|
||
Phase 6: 构建与测试 esbuild + 测试
|
||
```
|
||
|
||
## 依赖关系图
|
||
|
||
```
|
||
Phase 1 ────→ Phase 2 ────→ Phase 3 ────→ Phase 4 ────→ Phase 5 ────→ Phase 6
|
||
↑ ↑
|
||
│ │
|
||
(2.1 接口) (4.1 Provider)
|
||
(2.2~2.6 适配器) (4.2~4.6 其余)
|
||
```
|
||
|
||
Phase 2 内部必须按 2.1 → 2.2 → 2.3 → 2.4 → 2.5 → 2.6 顺序,JSP 适配器依赖 PMD/ESLint/Stylelint。
|
||
Phase 4 内部必须按 4.1 → 4.2 → 4.3 → 4.4 → 4.5 → 4.6 顺序,Fixer 依赖 Provider 和 Merger。
|
||
|
||
---
|
||
|
||
## Phase 1: 基础层
|
||
|
||
**依赖**: 无
|
||
**目标**: 建立公共类型定义和配置管理,为所有上层模块提供基础能力
|
||
**参考设计**: §3.2, §6.4, §13.2
|
||
|
||
### 文件清单
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/types.ts` | 新建 | `LinterDiagnostic`、`AdapterResult`、`LinterAdapter` 等公共类型 |
|
||
| `src/config/index.ts` | 新建 | 统一导出 |
|
||
| `src/config/ai.ts` | 新建 | AI 配置 getter(provider/model/baseUrl/temperature/timeout/outputLanguage) |
|
||
| `src/config/linter.ts` | 新建 | Linter 配置 getter(linters.xxx 语言-linter 映射、PMD 路径) |
|
||
| `src/config/fixer.ts` | 新建 | 修复器配置(contextLines) |
|
||
| `src/config/secret.ts` | 新建 | API Key SecretStorage(get/set/delete/isConfigured) |
|
||
|
||
### 关键类型
|
||
|
||
```typescript
|
||
// src/types.ts
|
||
|
||
export type Severity = 'error' | 'warning' | 'info';
|
||
export type AdapterStatus = 'ok' | 'tool-unavailable' | 'execution-failed';
|
||
|
||
export interface LinterDiagnostic {
|
||
severity: Severity;
|
||
ruleId: string;
|
||
message: string;
|
||
range: vscode.Range;
|
||
suggestion?: string;
|
||
}
|
||
|
||
export interface AdapterResult {
|
||
diagnostics: LinterDiagnostic[];
|
||
status: AdapterStatus;
|
||
errorMessage?: string;
|
||
}
|
||
|
||
export interface LinterAdapter {
|
||
id: string;
|
||
supportedLanguages: string[];
|
||
check(document: vscode.TextDocument, workingDir: string): Promise<AdapterResult>;
|
||
isAvailable(): boolean;
|
||
}
|
||
```
|
||
|
||
### 配置 Key 映射
|
||
|
||
所有配置以 `vscode-code-reviewer.` 为前缀:
|
||
|
||
| 模块 | 配置项 | 类型 | 默认值 |
|
||
|------|--------|------|--------|
|
||
| ai | `ai.provider` | enum | `deepseek` |
|
||
| ai | `ai.model` | string | `deepseek-chat` |
|
||
| ai | `ai.baseUrl` | string | `https://api.deepseek.com/v1` |
|
||
| ai | `ai.temperature` | number | 0.2 |
|
||
| ai | `ai.timeout` | number | 300 |
|
||
| ai | `ai.outputLanguage` | string | `zh-CN` |
|
||
| linter | `linters.javascript` | enum | `eslint` |
|
||
| linter | `linters.typescript` | enum | `eslint` |
|
||
| linter | `linters.java` | enum | `pmd` |
|
||
| linter | `linters.jsp` | enum | `jsp` |
|
||
| linter | `linters.css` | enum | `stylelint` |
|
||
| linter | `linters.sql` | enum | `sql-lint` |
|
||
| linter | `linters.plsql` | enum | `sql-lint` |
|
||
| linter | `pmd.jarPath` | string | `""` |
|
||
| linter | `pmd.rulesetPath` | string | `""` |
|
||
| linter | `pmd.jspRulesetPath` | string | `""` |
|
||
| linter | `sql-lint.configFile` | string | `""` |
|
||
| fixer | `fixer.contextLines` | number | 5 |
|
||
| secret | API Key | SecretStorage | `vscode-code-reviewer.apiKey` |
|
||
|
||
---
|
||
|
||
## Phase 2: 适配层
|
||
|
||
**依赖**: Phase 1
|
||
**目标**: 实现 5 个语言适配器,统一 `LinterAdapter` 接口
|
||
**参考设计**: §3
|
||
|
||
### Phase 2.1: 适配器接口
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/adapters/adapter.ts` | 新建 | 重新导出 `LinterAdapter` 接口(或在此处定义,取决于代码组织) |
|
||
|
||
### Phase 2.2: ESLint 适配器
|
||
|
||
**参考设计**: §3.3
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/adapters/eslint.ts` | 新建 | `ESLintAdapter` implements `LinterAdapter` |
|
||
| | | `supportedLanguages`: `['javascript', 'typescript']` |
|
||
| | | `check()`: 使用 eslint npm 包 `lintText()` |
|
||
| | | `isAvailable()`: 检测 eslint 是否已安装 |
|
||
|
||
**npm 依赖**: `eslint` ^9.39.3
|
||
|
||
### Phase 2.3: Stylelint 适配器
|
||
|
||
**参考设计**: §3.3
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/adapters/stylelint.ts` | 新建 | `StylelintAdapter` implements `LinterAdapter` |
|
||
| | | `supportedLanguages`: `['css']` |
|
||
| | | `check()`: 使用 stylelint npm 包 `lint({ code })` |
|
||
| | | `isAvailable()`: 检测 stylelint 是否已安装 |
|
||
|
||
**npm 依赖**: `stylelint` ^17.14.0
|
||
|
||
### Phase 2.4: sql-lint 适配器
|
||
|
||
**参考设计**: §3.3
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/adapters/sql-lint.ts` | 新建 | `SqlLintAdapter` implements `LinterAdapter` |
|
||
| | | `supportedLanguages`: `['sql', 'plsql']` |
|
||
| | | `check()`: CLI 子进程调用 sqlfluff |
|
||
| | | `isAvailable()`: 检测 sqlfluff CLI 是否可用 |
|
||
| | | 方言映射:sql → ansi, plsql → postgres |
|
||
|
||
### Phase 2.5: PMD 适配器
|
||
|
||
**参考设计**: §3.3, §3.4
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/adapters/pmd.ts` | 新建 | `PmdAdapter` implements `LinterAdapter` |
|
||
| | | `supportedLanguages`: `['java']` |
|
||
| | | `check()`: Java 子进程调用 PmdRunner |
|
||
| | | 虚拟文档 (untitled) 通过 stdin 传入代码 |
|
||
| | | 真实文件传文件路径 |
|
||
| | | `isAvailable()`: 检测 Java 11+ 和 PMD JAR |
|
||
| `jars/pmd/PmdRunner.java` | 新建 | PMD 包装器:stdin 支持 + JSON 渲染器 |
|
||
| `jars/pmd/pmd-java-ruleset.xml` | 新建 | Java 规则集 |
|
||
| `jars/pmd/pmd-jsp-ruleset.xml` | 新建 | JSP 规则集 |
|
||
|
||
**PmdRunner.java 核心逻辑**:
|
||
```
|
||
参数: filePath (传 "-" 表示从 stdin 读取), ruleset
|
||
→ 构建 PMDConfiguration
|
||
→ 配置 JSON 渲染器
|
||
→ 若 filePath 为 "-",从 stdin 读代码 → 写入临时文件
|
||
→ 执行 PMD 分析
|
||
→ 输出 JSON 到 stdout
|
||
→ 清理临时文件
|
||
```
|
||
|
||
**PMD JAR 目录结构**:
|
||
```
|
||
jars/pmd/
|
||
├── lib/ # PMD 依赖 JAR(需下载)
|
||
├── PmdRunner.java # 包装器(编译为 .class)
|
||
├── pmd-java-ruleset.xml
|
||
└── pmd-jsp-ruleset.xml
|
||
```
|
||
|
||
### Phase 2.6: JSP 适配器
|
||
|
||
**依赖**: Phase 2.5, 2.2, 2.3(需要 PMD/ESLint/Stylelint 适配器)
|
||
**参考设计**: §3.5
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/jsp/jsp-extractor.ts` | 新建 | JSP 内嵌代码块提取器 |
|
||
| `src/adapters/jsp.ts` | 新建 | `JspAdapter` implements `LinterAdapter`(组合适配器) |
|
||
| | | `supportedLanguages`: `['jsp']` |
|
||
| | | `check()`: 三步流程 |
|
||
|
||
**JspAdapter.check() 流程**:
|
||
```
|
||
1. 调用 PmdAdapter.check(document) → JSP 规范检查
|
||
2. extractJspSections(document.getText()) → 提取内嵌代码块
|
||
3. 对每个 section:
|
||
a. 按 language 选择对应适配器
|
||
b. 创建虚拟文档 (vscode.workspace.openTextDocument)
|
||
c. 调用 adapter.check(virtualDoc)
|
||
d. 修正行号偏移 (section.lineOffset)
|
||
4. 合并所有结果
|
||
```
|
||
|
||
**提取器正则规则**:
|
||
|
||
| 代码块类型 | 正则匹配 | 目标适配器 |
|
||
|-----------|---------|-----------|
|
||
| `<script>` 标签 | `/<script\b[^>]*>([\s\S]*?)<\/script\s*>/gi` | ESLint |
|
||
| `<style>` 标签 | `/<style\b[^>]*>([\s\S]*?)<\/style\s*>/gi` | Stylelint |
|
||
| `<% %>` scriptlet | `/<%=?([\s\S]*?)%>/g` | PMD |
|
||
|
||
---
|
||
|
||
## Phase 3: 核心层 A — 编排器
|
||
|
||
**依赖**: Phase 2
|
||
**参考设计**: §3.6, §4
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/orchestrator/orchestrator.ts` | 新建 | `Orchestrator` 类 |
|
||
|
||
**关键函数**:
|
||
- `getAdapters()` — 硬编码返回 5 个适配器实例
|
||
- `runStaticAnalysis(document, workingDir)` — 按语言选择适配器 → 调用 `check()` → 聚合
|
||
- 保存监听 + debounce 500ms
|
||
|
||
**调度逻辑**:
|
||
```
|
||
1. 获取当前文档语言 ID
|
||
2. 查询 linters.<language> 配置 → 确定使用的适配器
|
||
3. 调用适配器 check(document, workingDir)
|
||
4. 收集结果,区分 status
|
||
5. 返回聚合后的 diagnostics 列表
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 4: 核心层 B
|
||
|
||
**依赖**: Phase 3
|
||
**参考设计**: §5, §8, §12, §14
|
||
|
||
### Phase 4.1: AI Provider 基础设施
|
||
|
||
**参考设计**: §5.2
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/ai/providers/base.ts` | 新建 | `AIProvider` 抽象基类 + `ChatOptions` 接口 |
|
||
| `src/ai/providers/deepseek.ts` | 新建 | `DeepSeekProvider extends AIProvider` |
|
||
| `src/ai/providers/openai.ts` | 新建 | `OpenAIProvider extends AIProvider` |
|
||
| `src/ai/factory.ts` | 新建 | `createProvider(providerId, apiKey, baseUrl)` 工厂函数 |
|
||
|
||
**Provider 接口**:
|
||
```typescript
|
||
interface ChatOptions {
|
||
model: string;
|
||
temperature: number;
|
||
timeoutMs: number;
|
||
}
|
||
|
||
abstract class AIProvider {
|
||
abstract id: string;
|
||
abstract name: string;
|
||
constructor(protected apiKey: string, protected baseUrl: string) {}
|
||
abstract chat(systemPrompt: string, userPrompt: string, options: ChatOptions): Promise<string>;
|
||
}
|
||
```
|
||
|
||
### Phase 4.2: AI 引擎 + Schema
|
||
|
||
**参考设计**: §5.3, §5.4, §5.5, §5.6
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/ai/schema.ts` | 新建 | `AIResponse`, `TranslatedDiagnostic`, `CustomRuleResult`, `AIFinding` 接口 |
|
||
| `src/ai/engine.ts` | 新建 | `runAIReview()` 主函数 |
|
||
|
||
**引擎核心逻辑**:
|
||
```typescript
|
||
async function runAIReview(code, staticDiagnostics, customRules) {
|
||
const [resultA, resultB] = await Promise.allSettled([
|
||
callCustomRuleReview(code, customRules), // 请求 A
|
||
callTranslateAndDeepReview(code, staticDiagnostics), // 请求 B
|
||
]);
|
||
return {
|
||
customRuleResults: ...,
|
||
translatedDiagnostics: ...,
|
||
findings: ...,
|
||
degraded: resultA.status === 'rejected' || resultB.status === 'rejected',
|
||
error: ...,
|
||
};
|
||
}
|
||
```
|
||
|
||
**两并行请求**:
|
||
- 请求 A: 自定义规则评估(system prompt 注入规则 description)
|
||
- 请求 B: 静态分析翻译 + AI 深度审查
|
||
|
||
**降级策略**:
|
||
1. 单请求失败不影响另一个请求(`Promise.allSettled`)
|
||
2. 所有 AI 功能都失败时,纯静态分析结果仍然展示
|
||
3. 失败信息在面板顶部以黄色/红色提示条展示
|
||
|
||
### Phase 4.3: 自定义规则系统
|
||
|
||
**参考设计**: §12
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/rules/yaml-parser.ts` | 新建 | `loadActiveRules(workspaceRoot)` |
|
||
|
||
**加载逻辑**:
|
||
```
|
||
1. 扫描 .code-review/rules/*.yaml → 加载所有规则定义
|
||
2. 读取 .code-review/config.yaml
|
||
3. 按文件级 enabled 列表过滤
|
||
4. 按规则级 rules.<id>.enabled 覆盖
|
||
5. 返回激活的规则列表
|
||
```
|
||
|
||
**CustomRule 类型**:
|
||
```typescript
|
||
interface CustomRule {
|
||
id: string; // 不含 custom: 前缀,运行时自动拼接
|
||
severity: Severity;
|
||
description: string; // AI 评估依据
|
||
message: string; // 触发时显示
|
||
languages?: string[];
|
||
}
|
||
```
|
||
|
||
### Phase 4.4: 结果合并
|
||
|
||
**参考设计**: §14.1
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/merger/merger.ts` | 新建 | `mergeResults()` → `MergedReport` |
|
||
|
||
```typescript
|
||
interface MergedReport {
|
||
linterDiagnostics: LinterDiagnostic[];
|
||
customRuleDiagnostics: LinterDiagnostic[];
|
||
translatedDiagnostics: TranslatedDiagnostic[];
|
||
aiFindings: AIFinding[];
|
||
linterCount: number;
|
||
customRuleCount: number;
|
||
aiCount: number;
|
||
errors: string[];
|
||
degraded: boolean;
|
||
duration: number;
|
||
filePath: string;
|
||
language: string;
|
||
adapterNames: string[];
|
||
fixableLinterIndices: number[];
|
||
fixableCustomIndices: number[];
|
||
}
|
||
```
|
||
|
||
### Phase 4.5: 自动修复
|
||
|
||
**参考设计**: §8
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/fixer/fixer.ts` | 新建 | `generateFix()`, `applyFix()`, `applyBatchFixes()`, `undoLastFix()` |
|
||
|
||
**核心流程**:
|
||
```
|
||
用户触发修复(单条 / 批量)
|
||
↓
|
||
prepareContext() 获取代码上下文(动态行数)
|
||
↓
|
||
generateFix() 调用 AI 生成修复方案(复用 Provider)
|
||
↓
|
||
matchAndValidate() 匹配验证(行号 → 代码搜索)
|
||
↓
|
||
applyFix() 应用修复到编辑器(单条 / 批量倒序)
|
||
↓
|
||
保存快照,更新撤销按钮状态
|
||
```
|
||
|
||
**动态上下文策略**:
|
||
|
||
| 问题类型 | 上下文范围 |
|
||
|---------|-----------|
|
||
| 命名(naming) | 问题行 ± 2 行 |
|
||
| 代码风格(style) | 问题行 ± 5 行 |
|
||
| 逻辑/安全/性能(bug/security/performance) | 整个函数/方法 |
|
||
|
||
**两阶段匹配**:
|
||
- 阶段 1: 按行号匹配原文
|
||
- 阶段 2: 全文搜索 originalText
|
||
|
||
### Phase 4.6: 报告导出
|
||
|
||
**参考设计**: §14.2
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/utils/report.ts` | 新建 | `reportToMarkdown(report: MergedReport): string` |
|
||
|
||
**Markdown 格式**: 文件信息 → 统计摘要 → 分来源列出问题(linter/自定义/AI)
|
||
|
||
---
|
||
|
||
## Phase 5: UI 层
|
||
|
||
**依赖**: Phase 4
|
||
**参考设计**: §6, §7, §13
|
||
|
||
### Phase 5.1: 命令注册 + extension.ts 更新
|
||
|
||
**参考设计**: §6.1
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/activation/commands.ts` | 新建 | 注册所有命令处理函数 |
|
||
| `package.json` | 修改 | 替换 helloWorld 为正式命令、添加 viewsContainers/views/menus/configuration |
|
||
| `src/extension.ts` | 修改 | activate 中注册命令、视图、监听保存事件 |
|
||
|
||
**8 个命令**:
|
||
|
||
| 命令 ID | 功能 | 快捷键 |
|
||
|---------|------|--------|
|
||
| `codeReviewer.review` | 运行完整审查(静态分析 + AI) | Ctrl+Shift+R |
|
||
| `codeReviewer.reviewSelection` | 审查选中代码 | — |
|
||
| `codeReviewer.openPanel` | 显示审查报告面板 | — |
|
||
| `codeReviewer.exportReport` | 导出 Markdown 报告 | — |
|
||
| `codeReviewer.addCustomRule` | 添加自定义规则 | — |
|
||
| `codeReviewer.fixIssue` | 修复单条问题 | — |
|
||
| `codeReviewer.fixAll` | 批量修复 | — |
|
||
| `codeReviewer.openSetup` | 打开设置面板(侧边栏) | — |
|
||
|
||
**package.json 需添加的贡献点**:
|
||
|
||
```jsonc
|
||
{
|
||
"viewsContainers": {
|
||
"activitybar": [{
|
||
"id": "code-reviewer",
|
||
"title": "净码特工",
|
||
"icon": "images/icon.png"
|
||
}]
|
||
},
|
||
"views": {
|
||
"code-reviewer": [{
|
||
"type": "tree",
|
||
"id": "codeReviewer.setupView",
|
||
"name": "设置"
|
||
}]
|
||
},
|
||
"menus": {
|
||
"editor/context": [
|
||
{ "command": "codeReviewer.review", "group": "navigation" },
|
||
{ "command": "codeReviewer.reviewSelection", "when": "editorHasSelection" }
|
||
]
|
||
},
|
||
"configuration": {
|
||
// 见 Phase 1 配置 Key 映射
|
||
}
|
||
}
|
||
```
|
||
|
||
### Phase 5.2: 设置面板(侧边栏 TreeView)
|
||
|
||
**参考设计**: §13
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/views/setupView.ts` | 新建 | `SetupViewProvider implements vscode.TreeDataProvider` |
|
||
|
||
**面板区域**:
|
||
|
||
| 区域 | 元素 | 数据源 |
|
||
|------|------|--------|
|
||
| 快速开始 | 三步引导(①②③ 圆形序号,完成变紫色) | 实时状态 |
|
||
| 审核引擎 | 三个模块标签(紫/琥珀/绿圆点) | 静态 |
|
||
| AI 模型配置 | 提供商下拉框 + 模型下拉框 + 状态标签 | `ai.provider` / `ai.model` |
|
||
| API Key | 密码输入框 + Base URL + 状态标签 | SecretStorage / `ai.baseUrl` |
|
||
| 输出语言 | 下拉框 | `ai.outputLanguage` |
|
||
| 自定义规则 | 开关列表 + 添加行 | `.code-review/config.yaml` |
|
||
|
||
**快速引导**:
|
||
|
||
| 步骤 | 触发条件 | 效果 |
|
||
|------|----------|------|
|
||
| ① 配置 AI 模型及 API Key | API Key 有值 | 序号变紫色 |
|
||
| ② 启用自定义规则 | 任意规则开关打开 | 序号变紫色 |
|
||
| ③ 保存并测试连接 | 前两步完成 + 测试成功 | 序号变紫色 |
|
||
|
||
### Phase 5.3: 审查面板(Webview)
|
||
|
||
**参考设计**: §7
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/panel/webview.ts` | 新建 | `ReviewPanel` 类(Webview 管理) |
|
||
|
||
**面板布局**:
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 📋 代码审查报告 │
|
||
│ xxx.java · Java · 3.2s │
|
||
├─────────────────────────────────────┤
|
||
│ [总计:10] [错误:3] [警告:5] [建议:2] │
|
||
├─────────────────────────────────────┤
|
||
│ 🔧 静态分析 | 📋 自定义规则 | 🤖 AI │
|
||
├─────────────────────────────────────┤
|
||
│ 问题列表(可跳转、修复、忽略) │
|
||
├─────────────────────────────────────┤
|
||
│ [🔄 重新审查] [📄 导出] [⚙️ 设置] │
|
||
│ [↩ 撤销上次修复] │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
**消息协议**:
|
||
|
||
```typescript
|
||
// Webview → Extension
|
||
interface PanelMessage {
|
||
type: 'navigate' | 'rerun' | 'export' | 'settings' | 'fix' | 'fixAll';
|
||
line?: number;
|
||
ruleId?: string;
|
||
source?: 'linter' | 'custom' | 'ai';
|
||
}
|
||
|
||
// Extension → Webview
|
||
interface PanelUpdate {
|
||
report: MergedReport;
|
||
degraded: boolean;
|
||
errors: string[];
|
||
hasSnapshot: boolean;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Phase 6: 构建与测试
|
||
|
||
**依赖**: Phase 5
|
||
**参考设计**: §15, §16, §17
|
||
|
||
### Phase 6.1: 构建脚本
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `scripts/build.mjs` | 新建 | esbuild 打包(bundle + minify + external vscode) |
|
||
| `package.json` | 修改 | 更新 vscode:prepublish / 添加 build 脚本 |
|
||
|
||
**esbuild 配置**:
|
||
```javascript
|
||
entryPoints: ['src/extension.ts'],
|
||
bundle: true,
|
||
outfile: 'out/extension.js',
|
||
external: ['vscode'],
|
||
format: 'cjs',
|
||
platform: 'node',
|
||
target: 'node22',
|
||
```
|
||
|
||
### Phase 6.2: 工具脚本
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `scripts/download-pmd.mjs` | 新建 | 自动下载 PMD 7.26.0 JAR 依赖 |
|
||
| `scripts/package-prod.mjs` | 新建 | 生产打包:esbuild + copy assets + vsce |
|
||
|
||
### Phase 6.3: 测试
|
||
|
||
| 文件 | 操作 | 内容 |
|
||
|------|------|------|
|
||
| `src/test/fixtures/` | 新建 | 测试用代码样本目录 |
|
||
| `src/test/adapter.test.ts` | 新建 | ESLint/Stylelint/sql-lint 输出解析测试 |
|
||
| `src/test/config.test.ts` | 新建 | 配置读取正确性测试 |
|
||
| `src/test/merger.test.ts` | 新建 | 多源结果合并 + 统计计算测试 |
|
||
| `src/test/pipeline.test.ts` | 新建 | 全链路集成测试 |
|
||
| `src/test/extension.test.ts` | 修改 | 替换占位测试 |
|
||
|
||
---
|
||
|
||
## 文件变更总数
|
||
|
||
| Phase | 新建 | 修改 | 合计 |
|
||
|-------|------|------|------|
|
||
| Phase 1 | 6 | 0 | 6 |
|
||
| Phase 2 | 10 | 0 | 10 |
|
||
| Phase 3 | 1 | 0 | 1 |
|
||
| Phase 4 | 9 | 0 | 9 |
|
||
| Phase 5 | 3 | 2 | 5 |
|
||
| Phase 6 | 4 | 2 | 6 |
|
||
| **总计** | **33** | **4** | **37** |
|
||
|
||
---
|
||
|
||
## npm 依赖(需在 Phase 2/4 时添加)
|
||
|
||
### 运行时依赖
|
||
|
||
```json
|
||
{
|
||
"eslint": "^9.39.3",
|
||
"stylelint": "^17.14.0",
|
||
"node-sql-parser": "^5.4.0"
|
||
}
|
||
```
|
||
|
||
### 开发依赖(新增)
|
||
|
||
```json
|
||
{
|
||
"esbuild": "^0.28.1",
|
||
"@vscode/vsce": "^3.9.2"
|
||
}
|
||
```
|
||
|
||
### 外部工具
|
||
|
||
| 工具 | 版本 | 用途 | 获取方式 |
|
||
|------|------|------|----------|
|
||
| PMD | 7.26.0 | Java/JSP 静态分析 | 自带 `jars/pmd/lib/` |
|
||
| Java | 11+ | PMD 运行环境 | 用户环境 |
|
||
| sqlfluff | — | SQL 静态分析 | 用户环境(pip install sqlfluff) |
|