fix: 审查报告修复与清理,升级至 1.3.0
- 版本号 1.2.0 -> 1.3.0;CHANGELOG 新增 1.3.0 条目(修复 6 项 + 清理 3 项) - addCustomRule 空壳命令改为打开设置面板(抽取 openSetupPanel 复用) - deactivate 清理 analysisTimers pending 定时器 + 显式 dispose markers - PMD execPmd 去掉 stdout.length>0 兜底,非零退出按 stderr 报错 - SQLFluff 项目配置检测全量支持 setup.cfg/tox.ini/pep8.ini/pyproject.toml(内容感知) - 删除 orchestrator 未使用的 getAdapterMap/getAdaptersByIds,补充单语言单 linter 设计注释 - 删除 pmd.ts 未使用的 jarPathChecked 死字段 - merger 翻译配对改为按 originalRuleId 匹配,新增 2 个测试 - runStaticAndApply 包 try-catch,消除未处理 Promise 拒绝 - AGENTS.md 日志规则新增打包排除项;_AI_USAGE_LOG.md 追加记录
This commit is contained in:
+17
-13
@@ -17,6 +17,20 @@ import type { CustomRule } from '../types';
|
||||
|
||||
let currentReport: MergedReport | null = null;
|
||||
|
||||
async function openSetupPanel(): Promise<void> {
|
||||
try {
|
||||
await vscode.commands.executeCommand('workbench.view.extension.code-reviewer');
|
||||
} catch {
|
||||
const action = await vscode.window.showErrorMessage(
|
||||
t('setup.openSetupFail'),
|
||||
t('setup.openSettingsJson')
|
||||
);
|
||||
if (action === t('setup.openSettingsJson')) {
|
||||
await vscode.commands.executeCommand('workbench.action.openSettingsJson');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function registerCommands(
|
||||
context: vscode.ExtensionContext,
|
||||
orchestrator: Orchestrator,
|
||||
@@ -224,13 +238,13 @@ export function registerCommands(
|
||||
);
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('codeReviewer.addCustomRule', () => {
|
||||
vscode.commands.registerCommand('codeReviewer.addCustomRule', async () => {
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
if (!workspaceRoot) {
|
||||
vscode.window.showWarningMessage(t('setup.noWorkspace'));
|
||||
return;
|
||||
}
|
||||
vscode.window.showInformationMessage(t('setup.manageRulesHint'));
|
||||
await openSetupPanel();
|
||||
})
|
||||
);
|
||||
|
||||
@@ -248,17 +262,7 @@ export function registerCommands(
|
||||
|
||||
context.subscriptions.push(
|
||||
vscode.commands.registerCommand('codeReviewer.openSetup', async () => {
|
||||
try {
|
||||
await vscode.commands.executeCommand('workbench.view.extension.code-reviewer');
|
||||
} catch {
|
||||
const action = await vscode.window.showErrorMessage(
|
||||
t('setup.openSetupFail'),
|
||||
t('setup.openSettingsJson')
|
||||
);
|
||||
if (action === t('setup.openSettingsJson')) {
|
||||
await vscode.commands.executeCommand('workbench.action.openSettingsJson');
|
||||
}
|
||||
}
|
||||
await openSetupPanel();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@ export class PmdAdapter implements LinterAdapter {
|
||||
id = 'pmd';
|
||||
supportedLanguages = ['java'];
|
||||
private pmdDir: string | null = null;
|
||||
private jarPathChecked = false;
|
||||
private auxResolver = new AuxClasspathResolver();
|
||||
|
||||
private resolvePmdDir(): string {
|
||||
@@ -117,7 +116,7 @@ export class PmdAdapter implements LinterAdapter {
|
||||
proc.stdout.on('data', (data: Buffer) => { stdout += data.toString(); });
|
||||
proc.stderr.on('data', (data: Buffer) => { stderr += data.toString(); });
|
||||
proc.on('close', (code) => {
|
||||
if (code === 0 || code === 4 || stdout.length > 0) {
|
||||
if (code === 0 || code === 4) {
|
||||
resolve(stdout);
|
||||
} else {
|
||||
reject(new Error(stderr || `PMD exited with code ${code}`));
|
||||
|
||||
@@ -52,11 +52,19 @@ export function buildPRSMessage(description: string, dialect: string): string {
|
||||
}
|
||||
|
||||
function hasProjectSqlfluffConfig(workspaceRoot: string): boolean {
|
||||
const candidates = ['.sqlfluff', '.sqlfluff.ini'];
|
||||
const candidates: Array<{ file: string; marker: string | null }> = [
|
||||
{ file: '.sqlfluff', marker: null },
|
||||
{ file: 'setup.cfg', marker: '[sqlfluff]' },
|
||||
{ file: 'tox.ini', marker: '[sqlfluff]' },
|
||||
{ file: 'pep8.ini', marker: '[sqlfluff]' },
|
||||
{ file: 'pyproject.toml', marker: '[tool.sqlfluff]' },
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
if (fs.existsSync(path.join(workspaceRoot, candidate))) {
|
||||
return true;
|
||||
}
|
||||
const filePath = path.join(workspaceRoot, candidate.file);
|
||||
if (!fs.existsSync(filePath)) { continue; }
|
||||
if (candidate.marker === null) { return true; }
|
||||
const content = fs.readFileSync(filePath, 'utf-8');
|
||||
if (content.includes(candidate.marker)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+16
-7
@@ -12,13 +12,17 @@ let orchestrator: Orchestrator;
|
||||
let markers: DiagnosticMarkers;
|
||||
|
||||
async function runStaticAndApply(document: vscode.TextDocument): Promise<void> {
|
||||
const version = document.version;
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
|
||||
const workingDir = workspaceRoot || vscode.Uri.joinPath(document.uri, '..').fsPath;
|
||||
const result = await orchestrator.runStaticAnalysis(document, workingDir);
|
||||
const current = vscode.workspace.textDocuments.find(d => d.uri.toString() === document.uri.toString());
|
||||
if (!current || current.version !== version) { return; }
|
||||
markers.apply(document.uri, result.diagnostics);
|
||||
try {
|
||||
const version = document.version;
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
|
||||
const workingDir = workspaceRoot || vscode.Uri.joinPath(document.uri, '..').fsPath;
|
||||
const result = await orchestrator.runStaticAnalysis(document, workingDir);
|
||||
const current = vscode.workspace.textDocuments.find(d => d.uri.toString() === document.uri.toString());
|
||||
if (!current || current.version !== version) { return; }
|
||||
markers.apply(document.uri, result.diagnostics);
|
||||
} catch (err) {
|
||||
console.error('[code-reviewer] static analysis failed:', err);
|
||||
}
|
||||
}
|
||||
|
||||
const analysisTimers = new Map<string, NodeJS.Timeout>();
|
||||
@@ -113,5 +117,10 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
|
||||
export function deactivate() {
|
||||
for (const timer of analysisTimers.values()) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
analysisTimers.clear();
|
||||
markers?.dispose();
|
||||
orchestrator = undefined!;
|
||||
}
|
||||
|
||||
+10
-2
@@ -66,9 +66,17 @@ export function mergeResults(input: MergeInput): MergedReport {
|
||||
d => d.range.start.line
|
||||
);
|
||||
|
||||
const translationsByRule = new Map<string, TranslatedDiagnostic[]>();
|
||||
for (const td of input.translatedDiagnostics) {
|
||||
const list = translationsByRule.get(td.originalRuleId) ?? [];
|
||||
list.push(td);
|
||||
translationsByRule.set(td.originalRuleId, list);
|
||||
}
|
||||
|
||||
const linterDiagnostics = sortBySeverityAndLine(
|
||||
input.staticDiagnostics.map((d, i) => {
|
||||
const td = input.translatedDiagnostics[i];
|
||||
input.staticDiagnostics.map(d => {
|
||||
const list = translationsByRule.get(d.ruleId);
|
||||
const td = list?.shift();
|
||||
if (td) {
|
||||
return { ...d, message: td.translatedMessage, suggestion: td.translatedSuggestion || d.suggestion };
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ export class Orchestrator {
|
||||
private adapters: LinterAdapter[];
|
||||
|
||||
constructor() {
|
||||
// 单语言单 linter 设计:按 linters.<language> 单选配置分派一个适配器;
|
||||
// 需多引擎的文件走组合适配器(如 JspAdapter = PMD + ESLint + Stylelint)。
|
||||
this.adapters = [
|
||||
new ESLintAdapter(),
|
||||
new PmdAdapter(),
|
||||
@@ -27,16 +29,6 @@ export class Orchestrator {
|
||||
];
|
||||
}
|
||||
|
||||
getAdapterMap(): Map<string, LinterAdapter> {
|
||||
const map = new Map<string, LinterAdapter>();
|
||||
for (const adapter of this.adapters) {
|
||||
for (const lang of adapter.supportedLanguages) {
|
||||
map.set(lang, adapter);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
async runStaticAnalysis(
|
||||
document: vscode.TextDocument,
|
||||
workingDir: string
|
||||
@@ -81,8 +73,4 @@ export class Orchestrator {
|
||||
duration: Date.now() - startTime,
|
||||
};
|
||||
}
|
||||
|
||||
getAdaptersByIds(ids: string[]): LinterAdapter[] {
|
||||
return ids.map(id => this.adapters.find(a => a.id === id)).filter(Boolean) as LinterAdapter[];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user