- 设置面板:三步引导 / AI 配置 / API Key / 规则管理 / 连接测试 - Provider 重构:统一 OpenAICompatibleProvider 基类,新增 Gemini/Claude/混元/智谱等 - 审查面板 Webview:三 Tab、统计卡片、问题列表、postMessage 通信 - esbuild 构建脚本 + 生产打包 + PMD 下载 - 保存文件自动静态分析(500ms debounce)
207 lines
5.4 KiB
Markdown
207 lines
5.4 KiB
Markdown
# Step 01 — Phase 1: 基础层
|
||
|
||
**依赖**: 无
|
||
**参考设计**: §3.2, §6.4, §13.2
|
||
|
||
## 目标
|
||
|
||
建立公共类型定义和配置管理,为所有上层模块提供基础能力。
|
||
|
||
## 新建文件
|
||
|
||
| # | 文件 | 说明 |
|
||
|---|------|------|
|
||
| 1 | `src/types.ts` | 公共类型定义 |
|
||
| 2 | `src/config/ai.ts` | AI 配置 getter |
|
||
| 3 | `src/config/linter.ts` | Linter 配置 getter |
|
||
| 4 | `src/config/fixer.ts` | 修复器配置 getter |
|
||
| 5 | `src/config/secret.ts` | API Key SecretStorage |
|
||
| 6 | `src/config/index.ts` | 统一导出 |
|
||
|
||
---
|
||
|
||
## 1. `src/types.ts`
|
||
|
||
```typescript
|
||
import * as vscode from 'vscode';
|
||
|
||
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;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 2. `src/config/ai.ts`
|
||
|
||
```typescript
|
||
import * as vscode from 'vscode';
|
||
|
||
export interface AIConfig {
|
||
provider: string;
|
||
model: string;
|
||
baseUrl: string;
|
||
temperature: number;
|
||
timeout: number;
|
||
outputLanguage: string;
|
||
}
|
||
|
||
export function getAIConfig(): AIConfig {
|
||
const config = vscode.workspace.getConfiguration('vscode-code-reviewer');
|
||
return {
|
||
provider: config.get<string>('ai.provider', 'deepseek'),
|
||
model: config.get<string>('ai.model', 'deepseek-chat'),
|
||
baseUrl: config.get<string>('ai.baseUrl', 'https://api.deepseek.com/v1'),
|
||
temperature: config.get<number>('ai.temperature', 0.2),
|
||
timeout: config.get<number>('ai.timeout', 300),
|
||
outputLanguage: config.get<string>('ai.outputLanguage', 'zh-CN'),
|
||
};
|
||
}
|
||
```
|
||
|
||
**配置 Key**(前缀 `vscode-code-reviewer.`):
|
||
|
||
| Key | 类型 | 默认值 |
|
||
|-----|------|--------|
|
||
| `ai.provider` | enum | `deepseek` |
|
||
| `ai.model` | string | `deepseek-chat` |
|
||
| `ai.baseUrl` | string | `https://api.deepseek.com/v1` |
|
||
| `ai.temperature` | number | 0.2 |
|
||
| `ai.timeout` | number | 300 |
|
||
| `ai.outputLanguage` | string | `zh-CN` |
|
||
|
||
---
|
||
|
||
## 3. `src/config/linter.ts`
|
||
|
||
```typescript
|
||
import * as vscode from 'vscode';
|
||
|
||
export interface LinterConfig {
|
||
languageMap: Record<string, string>;
|
||
pmdJarPath: string;
|
||
pmdRulesetPath: string;
|
||
pmdJspRulesetPath: string;
|
||
sqlLintConfigFile: string;
|
||
}
|
||
|
||
export function getLinterConfig(): LinterConfig {
|
||
const config = vscode.workspace.getConfiguration('vscode-code-reviewer');
|
||
return {
|
||
languageMap: {
|
||
javascript: config.get<string>('linters.javascript', 'eslint'),
|
||
typescript: config.get<string>('linters.typescript', 'eslint'),
|
||
java: config.get<string>('linters.java', 'pmd'),
|
||
jsp: config.get<string>('linters.jsp', 'jsp'),
|
||
css: config.get<string>('linters.css', 'stylelint'),
|
||
sql: config.get<string>('linters.sql', 'sql-lint'),
|
||
plsql: config.get<string>('linters.plsql', 'sql-lint'),
|
||
},
|
||
pmdJarPath: config.get<string>('pmd.jarPath', ''),
|
||
pmdRulesetPath: config.get<string>('pmd.rulesetPath', ''),
|
||
pmdJspRulesetPath: config.get<string>('pmd.jspRulesetPath', ''),
|
||
sqlLintConfigFile: config.get<string>('sql-lint.configFile', ''),
|
||
};
|
||
}
|
||
```
|
||
|
||
| Key | 类型 | 默认值 | enum |
|
||
|-----|------|--------|------|
|
||
| `linters.javascript` | enum | `eslint` | `""` / `eslint` |
|
||
| `linters.typescript` | enum | `eslint` | `""` / `eslint` |
|
||
| `linters.java` | enum | `pmd` | `""` / `pmd` |
|
||
| `linters.jsp` | enum | `jsp` | `""` / `jsp` |
|
||
| `linters.css` | enum | `stylelint` | `""` / `stylelint` |
|
||
| `linters.sql` | enum | `sql-lint` | `""` / `sql-lint` |
|
||
| `linters.plsql` | enum | `sql-lint` | `""` / `sql-lint` |
|
||
| `pmd.jarPath` | string | `""` | — |
|
||
| `pmd.rulesetPath` | string | `""` | — |
|
||
| `pmd.jspRulesetPath` | string | `""` | — |
|
||
| `sql-lint.configFile` | string | `""` | — |
|
||
|
||
---
|
||
|
||
## 4. `src/config/fixer.ts`
|
||
|
||
```typescript
|
||
import * as vscode from 'vscode';
|
||
|
||
export interface FixerConfig {
|
||
contextLines: number;
|
||
}
|
||
|
||
export function getFixerConfig(): FixerConfig {
|
||
const config = vscode.workspace.getConfiguration('vscode-code-reviewer');
|
||
return {
|
||
contextLines: config.get<number>('fixer.contextLines', 5),
|
||
};
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. `src/config/secret.ts`
|
||
|
||
```typescript
|
||
import * as vscode from 'vscode';
|
||
|
||
const SECRET_KEY = 'vscode-code-reviewer.apiKey';
|
||
|
||
export async function getApiKey(context: vscode.ExtensionContext): Promise<string | undefined> {
|
||
return context.secrets.get(SECRET_KEY);
|
||
}
|
||
|
||
export async function setApiKey(context: vscode.ExtensionContext, key: string): Promise<void> {
|
||
await context.secrets.store(SECRET_KEY, key);
|
||
}
|
||
|
||
export async function deleteApiKey(context: vscode.ExtensionContext): Promise<void> {
|
||
await context.secrets.delete(SECRET_KEY);
|
||
}
|
||
|
||
export async function isApiKeyConfigured(context: vscode.ExtensionContext): Promise<boolean> {
|
||
const key = await getApiKey(context);
|
||
return !!key;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. `src/config/index.ts`
|
||
|
||
```typescript
|
||
export { getAIConfig, AIConfig } from './ai';
|
||
export { getLinterConfig, LinterConfig } from './linter';
|
||
export { getFixerConfig, FixerConfig } from './fixer';
|
||
export { getApiKey, setApiKey, deleteApiKey, isApiKeyConfigured } from './secret';
|
||
```
|
||
|
||
---
|
||
|
||
## 验收
|
||
|
||
- [ ] 6 个文件创建完成
|
||
- [ ] `npm run compile` 通过
|
||
- [ ] `npm run lint` 通过
|