package com.codechecker.api.analyzer; import com.codechecker.api.model.EndpointChangeReport; import com.codechecker.api.model.EndpointSnapshot; import com.codechecker.api.parser.EndpointSnapshotParser; import com.codechecker.api.scanner.ApiFileChangeScanner; import com.codechecker.config.AppConfig; import com.codechecker.git.GitChangeScanner; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; /** * API 变更分析编排(与 {@link com.codechecker.analyzer.ClassChangeAnalyzer} 平行、互不调用)。 */ public class ApiChangeAnalyzer { private final GitChangeScanner gitScanner; private final ApiFileChangeScanner fileScanner; public ApiChangeAnalyzer(GitChangeScanner gitScanner) { this.gitScanner = gitScanner; this.fileScanner = new ApiFileChangeScanner(gitScanner); } public List analyze(Path repoRoot, AppConfig config, String oldSha, String newSha) throws IOException { List changedFiles = fileScanner.scanChangedFiles( repoRoot, config.getAllApiScanDirs(), oldSha, newSha); if (changedFiles.isEmpty()) { return List.of(); } EndpointSnapshotParser parser = new EndpointSnapshotParser(config.isApiExcludeFrameworkParams()); ParameterDiffEngine parameterDiffEngine = new ParameterDiffEngine( repoRoot, buildSearchDirs(config), gitScanner, oldSha, newSha, config.getNestMaxDepth()); EndpointDiffEngine endpointDiffEngine = new EndpointDiffEngine(parameterDiffEngine); List oldSnapshots = new ArrayList<>(); List newSnapshots = new ArrayList<>(); for (String path : changedFiles) { boolean feign = isFeignPath(path, config); String oldSource = gitScanner.readFileAtCommit(oldSha, path); String newSource = gitScanner.readFileAtCommit(newSha, path); oldSnapshots.addAll(parser.parseSource(oldSource, path, feign)); newSnapshots.addAll(parser.parseSource(newSource, path, feign)); } return endpointDiffEngine.diff(oldSnapshots, newSnapshots); } private List buildSearchDirs(AppConfig config) { List dirs = new ArrayList<>(); dirs.addAll(config.getModelDirs()); dirs.addAll(config.getAllApiScanDirs()); return dirs; } private boolean isFeignPath(String path, AppConfig config) { String normalized = path.replace('\\', '/'); for (String dir : config.getApiFeignScanDirs()) { String prefix = dir.replace('\\', '/'); if (!prefix.endsWith("/")) { prefix = prefix + "/"; } if (normalized.startsWith(prefix)) { return true; } } return false; } }