in doc-architect/doc-architect-cli/src/main/java/com/docarchitect/cli/ScanCommand.java [201:288]
private Map<String, ScanResult> executeScanners(List<Scanner> scanners, ProjectConfig config) {
log.debug("Executing scanners on project: {}", projectPath);
// Determine scanner selection mode
ProjectConfig.ScannerMode mode = config.scanners() != null
? config.scanners().getEffectiveMode()
: ProjectConfig.ScannerMode.AUTO;
log.info("Scanner selection mode: {}", mode);
System.out.println("Scanner mode: " + mode);
// Validate config and warn about unknown scanner IDs (EXPLICIT mode only)
if (mode == ProjectConfig.ScannerMode.EXPLICIT) {
validateScannerConfig(scanners, config);
}
Map<String, ScanResult> results = new LinkedHashMap<>();
ScanContext context = createScanContext(results);
int disabledByConfigCount = 0;
int notApplicableCount = 0;
for (Scanner scanner : scanners) {
try {
// Step 1: Check if scanner passes mode-based filtering
boolean enabledByMode = isScannerEnabledByMode(scanner.getId(), mode, config);
if (!enabledByMode) {
log.debug("Scanner {} disabled by {} mode", scanner.getId(), mode);
disabledByConfigCount++;
continue;
}
// Step 2: Check if scanner applies to this project (applicability strategy)
boolean applies = scanner.appliesTo(context);
if (applies) {
log.info("Running scanner: {} ({})", scanner.getDisplayName(), scanner.getId());
System.out.println(" → " + scanner.getDisplayName());
ScanResult result = scanner.scan(context);
results.put(scanner.getId(), result);
if (result.hasFindings()) {
log.debug("Scanner {} found: {} components, {} dependencies, {} endpoints, {} entities",
scanner.getId(),
result.components().size(),
result.dependencies().size(),
result.apiEndpoints().size(),
result.dataEntities().size());
}
} else {
log.debug("Scanner {} does not apply to this project (applicability check failed)", scanner.getId());
if (log.isTraceEnabled()) {
log.trace("Scanner {} applicability details:", scanner.getId());
log.trace(" - Supported file patterns: {}", scanner.getSupportedFilePatterns());
log.trace(" - Has applicability strategy: {}", scanner.getApplicabilityStrategy() != null);
log.trace(" - Previous scan results available: {}", !context.previousResults().isEmpty());
}
notApplicableCount++;
}
} catch (Exception e) {
log.error("Scanner {} failed: {}", scanner.getId(), e.getMessage(), e);
results.put(scanner.getId(), ScanResult.failed(scanner.getId(), List.of(e.getMessage())));
}
}
log.info("Scanner execution summary: {} executed, {} disabled by config, {} not applicable",
results.size(), disabledByConfigCount, notApplicableCount);
// Warn if no scanners executed
if (results.isEmpty()) {
System.err.println();
System.err.println("⚠ WARNING: 0 scanners executed!");
System.err.println(" Possible causes:");
if (mode == ProjectConfig.ScannerMode.EXPLICIT) {
System.err.println(" - Scanner IDs in config don't match available scanners");
} else if (mode == ProjectConfig.ScannerMode.GROUPS) {
System.err.println(" - No scanners match the configured groups");
}
System.err.println(" - No files match scanner patterns (applicability check)");
System.err.println(" - All scanners failed");
System.err.println();
System.err.println(" Available scanner IDs:");
scanners.forEach(s -> System.err.println(" - " + s.getId()));
System.err.println();
}
return results;
}