All files / src/orchestrator orchestrator.ts

45.71% Statements 48/105
100% Branches 2/2
28.57% Functions 2/7
45.71% Lines 48/105

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 1061x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                                                                                                   1x 1x     1x 1x     1x 1x     1x 1x     1x  
import * as vscode from 'vscode';
import type { LinterAdapter, LinterDiagnostic } from '../types';
import { getLinterForLanguage, isAdapterEnabled } from '../config';
import { ESLintAdapter } from '../adapters/eslint';
import { PmdAdapter } from '../adapters/pmd';
import { StylelintAdapter } from '../adapters/stylelint';
import { SqlFluffAdapter } from '../adapters/sqlfluff';
import { JspAdapter } from '../adapters/jsp';
 
export interface StaticAnalysisResult {
  diagnostics: LinterDiagnostic[];
  errors: string[];
  adapterIds: string[];
  duration: number;
}
 
export interface CachedAnalysis {
  diagnostics: LinterDiagnostic[];
  adapterId: string;
  workingDir: string;
}
 
export class Orchestrator {
  private adapters: LinterAdapter[];
  private analysisCache = new Map<string, CachedAnalysis>();
 
  constructor() {
    // 单语言单 linter 设计:按 linters.<language> 单选配置分派一个适配器;
    // 需多引擎的文件走组合适配器(如 JspAdapter = PMD + ESLint + Stylelint)。
    this.adapters = [
      new ESLintAdapter(),
      new PmdAdapter(),
      new StylelintAdapter(),
      new SqlFluffAdapter(),
      new JspAdapter(),
    ];
  }
 
  async runStaticAnalysis(
    document: vscode.TextDocument,
    workingDir: string
  ): Promise<StaticAnalysisResult> {
    const startTime = Date.now();
    const languageId = document.languageId;

    const selectedLinter = getLinterForLanguage(languageId);
    if (!selectedLinter) {
      return { diagnostics: [], errors: [], adapterIds: [], duration: 0 };
    }

    const adapter = this.adapters.find(a => a.id === selectedLinter);
    if (!adapter) {
      return {
        diagnostics: [],
        errors: [`未找到适配器: ${selectedLinter}`],
        adapterIds: [],
        duration: Date.now() - startTime,
      };
    }

    if (!isAdapterEnabled(adapter.id)) {
      return {
        diagnostics: [],
        errors: [],
        adapterIds: [],
        duration: Date.now() - startTime,
      };
    }

    const result = await adapter.check(document, workingDir);
    const errors: string[] = [];
    if (result.status !== 'ok') {
      errors.push(`[${adapter.id}] ${result.errorMessage ?? result.status}`);
    }

    this.analysisCache.set(document.uri.toString(), {
      diagnostics: result.diagnostics,
      adapterId: adapter.id,
      workingDir,
    });

    return {
      diagnostics: result.diagnostics,
      errors,
      adapterIds: [adapter.id],
      duration: Date.now() - startTime,
    };
  }
 
  setAnalysisResult(uri: vscode.Uri, result: CachedAnalysis): void {
    this.analysisCache.set(uri.toString(), result);
  }
 
  getAnalysisResult(uri: vscode.Uri): CachedAnalysis | undefined {
    return this.analysisCache.get(uri.toString());
  }
 
  clearAnalysisResult(uri: vscode.Uri): void {
    this.analysisCache.delete(uri.toString());
  }
 
  getAdapter(adapterId: string): LinterAdapter | undefined {
    return this.adapters.find(a => a.id === adapterId);
  }
}