diff --git a/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java b/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java index 81fcf624..44b4a83a 100644 --- a/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java +++ b/src/main/java/io/github/randomcodespace/iq/cli/EnrichCommand.java @@ -145,7 +145,7 @@ private int enrichFromCache(AnalysisCache cache, Path root, NumberFormat nf, Ins CliOutput.step("\uD83C\uDFD7\uFE0F", "Detecting service boundaries..."); var serviceDetector = new io.github.randomcodespace.iq.analyzer.ServiceDetector(); String projectName = root.getFileName().toString(); - var serviceResult = serviceDetector.detect(enrichedNodes, enrichedEdges, projectName); + var serviceResult = serviceDetector.detect(enrichedNodes, enrichedEdges, projectName, root); if (!serviceResult.serviceNodes().isEmpty()) { // Add service nodes and edges to the builder builder.addNodes(serviceResult.serviceNodes()); diff --git a/src/test/java/io/github/randomcodespace/iq/analyzer/ServiceDetectorTest.java b/src/test/java/io/github/randomcodespace/iq/analyzer/ServiceDetectorTest.java index b4e25917..db939ffd 100644 --- a/src/test/java/io/github/randomcodespace/iq/analyzer/ServiceDetectorTest.java +++ b/src/test/java/io/github/randomcodespace/iq/analyzer/ServiceDetectorTest.java @@ -523,6 +523,38 @@ void deterministicWithContentExtraction(@TempDir Path tempDir) throws IOExceptio } } + @Test + void filesystemWalkFindsModulesNotPresentAsNodes(@TempDir Path tempDir) throws IOException { + // Simulate a .NET monorepo: .csproj files exist on disk but NO detector created CodeNodes for them + Files.createDirectories(tempDir.resolve("src/Basket.API")); + Files.writeString(tempDir.resolve("src/Basket.API/Basket.API.csproj"), + "", StandardCharsets.UTF_8); + + Files.createDirectories(tempDir.resolve("src/Catalog.API")); + Files.writeString(tempDir.resolve("src/Catalog.API/Catalog.API.csproj"), + "", StandardCharsets.UTF_8); + + Files.createDirectories(tempDir.resolve("src/Ordering.API")); + Files.writeString(tempDir.resolve("src/Ordering.API/Ordering.API.csproj"), + "", StandardCharsets.UTF_8); + + // No nodes have build file paths — they are only on the filesystem + List nodes = new ArrayList<>(); + nodes.add(makeNode("cls:BasketCtrl", NodeKind.CLASS, "BasketController", + "src/Basket.API/Controllers/BasketController.cs")); + nodes.add(makeNode("cls:CatalogCtrl", NodeKind.CLASS, "CatalogController", + "src/Catalog.API/Controllers/CatalogController.cs")); + + var result = detector.detect(nodes, List.of(), "eShop", tempDir); + + // Should detect 3 services via filesystem walk (not from node paths) + assertEquals(3, result.serviceNodes().size()); + var names = result.serviceNodes().stream().map(CodeNode::getLabel).sorted().toList(); + assertEquals(List.of("Basket.API", "Catalog.API", "Ordering.API"), names); + result.serviceNodes().forEach(svc -> + assertEquals("dotnet", svc.getProperties().get("build_tool"))); + } + private static CodeNode makeNode(String id, NodeKind kind, String label, String filePath) { CodeNode node = new CodeNode(id, kind, label); node.setFilePath(filePath);