- 适配器 i18n 接入(eslint/pmd/sql-lint/stylelint) - Provider 动态注册机制(registry.ts + providers.json + factory 重构) - SetupView 全面重构(setupView.ts 新增 600+ 行) - i18n 消息扩展(messages.ts +210 行) - 规则导入流程优化(import-service / prompt-builder) - 新增 PMD jars 依赖及测试用例
7.1 KiB
7.1 KiB
自定义规则导入去重增强方案
1. 架构概览
现状
static-rules.json ──→ buildDedupPromptSection() ──→ 嵌入 AI 提示词 → AI 判断 exact/overlap/none
目标
static-rules.json ──┐
├──→ buildDedupPromptSection(existingRules) ──→ AI 判断 exact/overlap/none
已导入自定义规则 ────┘
↑
loadActiveRules() ── 自动加载 .code-review/rules/*.yaml
数据流
ImportService.convert()
│ ① 调用 loadActiveRules(workspaceRoot) 加载已有自定义规则
│ ② 将 existingRules 传递给 converter.convert()
│ │
│ └─ converter.buildSystemPrompt(existingRules)
│ │
│ └─ buildDedupPromptSection(existingRules)
│ │
│ ├─ 输出静态 linter 规则(不变)
│ └─ 追加已导入自定义规则,ID 前缀 custom/
│
│ ③ AI 返回结果,含 duplicateOf: custom/xxx、duplicateLevel 等字段
│ ④ parseImportableYaml() 解析,字段不变
│
▼
showImportPreview()
│ ⑤ 识别 duplicateOf 的 custom/ 前缀,显示不同文案
│
▼
buildFinalYaml()
│ ⑥ 注释头文案区分 custom/ 前缀
│
▼
applyConversion() → 写入 .yaml
2. 文件变更清单
| 文件 | 变更类型 | 说明 |
|---|---|---|
src/rules/converters/prompt-builder.ts |
修改 | buildDedupPromptSection() 增加 existingCustomRules 参数 |
src/rules/converters/converter.ts |
修改 | convert() 增加可选参数 existingRules |
src/rules/converters/md-converter.ts |
修改 | 传递 existingRules 至 buildSystemPrompt() |
src/rules/converters/txt-converter.ts |
修改 | 同上 |
src/rules/converters/excel-converter.ts |
修改 | 同上 |
src/rules/converters/docx-converter.ts |
修改 | 同上 |
src/rules/converters/pptx-converter.ts |
修改 | 同上 |
src/rules/import-service.ts |
修改 | convert() 加载已有规则;buildFinalYaml() 格式化 custom 注释头 |
src/rules/import-preview.ts |
修改 | 识别 custom/ 前缀显示区分文案 |
src/test/import-dedup.test.ts |
修改 | 追加测试用例(自定义规则 exact/overlap/none) |
3. 关键接口变更
3.1 prompt-builder.ts
import type { CustomRule } from '../../types';
// 新增参数
export function buildDedupPromptSection(existingCustomRules?: CustomRule[]): string;
输出格式变更:
## 已知规则清单(用于重复检测)
### 内置 Linter 规则
#### eslint (XX 条)
- eslint/rule-id: description
...
### 已导入的自定义规则 (N 条)
- custom/my-rule: 禁止 console.log
- custom/no-var: 使用 const/let 替代 var
判定时请精确匹配上述规则 ID,而非模糊匹配分类。
3.2 converter.ts
import type { CustomRule } from '../../types';
export interface RuleConverter {
supportedExtensions: string[];
convert(
srcPath: string,
context: vscode.ExtensionContext,
existingRules?: CustomRule[], // 新增参数
): Promise<string | null>;
}
3.3 Converters(5 个文件,模式一致)
每个 converter 的 buildSystemPrompt 改为接受 existingRules 参数并向下传递。
改前:
function buildSystemPrompt(): string {
return `...${buildDedupPromptSection()}...`;
}
改后:
function buildSystemPrompt(existingRules?: CustomRule[]): string {
return `...${buildDedupPromptSection(existingRules)}...`;
}
对应 convert() 方法:
async convert(srcPath: string, context: vscode.ExtensionContext, existingRules?: CustomRule[]): Promise<string | null> {
const content = fs.readFileSync(srcPath, 'utf-8');
return convertContentWithAI(content, context, buildSystemPrompt(existingRules));
}
3.4 import-service.ts
ImportService.convert() — 新增加载已有规则
import { loadActiveRules } from './yaml-parser';
async convert(srcPath: string, context: vscode.ExtensionContext): Promise<ConversionResult> {
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
const existingRules = workspaceRoot ? loadActiveRules(workspaceRoot) : [];
const ext = path.extname(srcPath).toLowerCase();
const converter = this.converters.get(ext);
// ...
const yamlContent = await converter.convert(srcPath, context, existingRules);
// ...
}
buildFinalYaml() — 注释头区分 custom 前缀
在生成 # [DUPLICATE] 注释头时,判断 duplicateOf 是否以 custom/ 开头:
custom/xxx→# [DUPLICATE: exact] 重复自定义规则 xxx(检测目标完全一致)eslint/xxx→# [DUPLICATE: exact] 重复 eslint/xxx(检测目标完全一致)(不变)- overlap 同理
3.5 import-preview.ts
新增辅助函数,在 renderRuleCard 中调用:
function formatDuplicateOf(dupOf: string | undefined): { type: 'custom' | 'linter'; ruleName: string } {
if (!dupOf) return { type: 'linter', ruleName: 'unknown' };
if (dupOf.startsWith('custom/')) {
return { type: 'custom', ruleName: dupOf.slice(7) };
}
return { type: 'linter', ruleName: dupOf };
}
UI 显示规则:
| duplicateOf | type | 显示文案 |
|---|---|---|
custom/no-console-log |
custom | 重复:自定义规则 no-console-log |
eslint/no-console |
linter | 重复:eslint/no-console(不变) |
| overlap + custom | custom | 与自定义规则 no-console-log 部分重叠 |
| overlap + linter | linter | 与 eslint/no-console 部分重叠(不变) |
4. 不变的部分
ImportableRule接口(字段不变,duplicateOf 的值新加custom/前缀由 AI 输出)PreviewDecision接口ConversionResult接口YamlConverter(YAML 直接复制不走 AI,不需要去重)parseImportableYaml()(解析逻辑不变,duplicateOf 字段值变化不影响解析)buildFinalYaml()的保留逻辑(去重字段剥离、# 注释前缀)不变
5. 影响范围
正面
- 导入新规则时自动对比已有自定义规则,避免重复导入
- 已导入规则之间交叉重复也可检测(规则文件 A 和 B 之间有重复 ID/语义)
风险与应对
- 提示词长度增加:如果已有规则很多(>50条),prompt 会变长。应对:当前实测 1788 条静态规则 + 50 条自定义规则约 80KB token,主流模型可承受。如果未来规则量过大,可考虑只传 ID 列表。
- 自参考:正在导入的文件尚未写入
.code-review/rules/,不会出现自己检测自己的情况。 - custom/ 前缀规范:需要 AI 理解并准确输出,已在 prompt 中明确指定格式,并在已有示例中示范。
测试覆盖
需要在 src/test/import-dedup.test.ts 中新增:
- 自定义规则 exact → 默认注释
- 自定义规则 overlap → 默认保留
- 自定义规则 exact 用户恢复 → 取消注释
- 混合场景(部分与 linter 重复、部分与 custom 重复)