in doc-architect/doc-architect-core/src/main/java/com/docarchitect/core/scanner/impl/dotnet/AspNetCoreApiScanner.java [391:449]
public ScanResult scan(ScanContext context) {
log.info("Scanning ASP.NET Core API endpoints in: {}", context.rootPath());
List<ApiEndpoint> apiEndpoints = new ArrayList<>();
ScanStatistics.Builder statsBuilder = new ScanStatistics.Builder();
// Need to search both subdirectories and root level
List<Path> csFiles = new ArrayList<>();
csFiles.addAll(context.findFiles(CS_FILE_PATTERN).toList());
csFiles.addAll(context.findFiles(CS_FILE_PATTERN_ROOT).toList());
// Remove duplicates (in case a file matches both patterns)
csFiles = csFiles.stream().distinct().toList();
statsBuilder.filesDiscovered(csFiles.size());
if (csFiles.isEmpty()) {
return emptyResult();
}
int skippedFiles = 0;
for (Path csFile : csFiles) {
// Pre-filter files before attempting to parse
if (!shouldScanFile(csFile)) {
skippedFiles++;
continue;
}
statsBuilder.incrementFilesScanned();
// Use three-tier parsing with fallback
FileParseResult<ApiEndpoint> result = parseWithFallback(
csFile,
classes -> extractEndpointsFromAST(classes, csFile),
createFallbackStrategy(),
statsBuilder
);
if (result.isSuccess()) {
apiEndpoints.addAll(result.getData());
}
}
log.debug("Pre-filtered {} files (not ASP.NET Core controllers)", skippedFiles);
ScanStatistics statistics = statsBuilder.build();
log.info("Found {} ASP.NET Core API endpoints (success rate: {:.1f}%, overall parse rate: {:.1f}%)",
apiEndpoints.size(), statistics.getSuccessRate(), statistics.getOverallParseRate());
return buildSuccessResult(
List.of(),
List.of(),
apiEndpoints,
List.of(),
List.of(),
List.of(),
List.of(),
statistics
);
}