This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new d524d9ff92b1 CAMEL-26932: camel-jbang - a catalog lookup of a 
misspelled name suggests the name it is a typo of (#29938)
d524d9ff92b1 is described below

commit d524d9ff92b11674595ae72531b97d2933c67ec6
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Nov 14 19:29:26 2026 +0100

    CAMEL-26932: camel-jbang - a catalog lookup of a misspelled name suggests 
the name it is a typo of (#29938)
    
    The suggestions of camel_catalog_doc match by name, alias and title, so 
kafak had none. When
    there are none, the name within a few edits (ArtifactUtils.closest) is 
suggested.
    
    CAMEL-26932: camel-jbang - the data format, language and EIP lookups also 
suggest the name a typo is of
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../dsl/jbang/core/commands/ai/CatalogDocs.java    | 31 +++++++++++++++++++---
 .../jbang/core/commands/ai/CatalogDocsTest.java    | 20 ++++++++++++++
 2 files changed, 47 insertions(+), 4 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
index dd08c2badcc3..4d71055711af 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java
@@ -20,6 +20,7 @@ import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -49,6 +50,7 @@ import org.apache.camel.tooling.model.JsonMapper;
 import org.apache.camel.tooling.model.LanguageModel;
 import org.apache.camel.tooling.model.PojoBeanModel;
 import org.apache.camel.tooling.model.TransformerModel;
+import org.apache.camel.util.ArtifactUtils;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 import org.apache.camel.util.json.Jsoner;
@@ -413,7 +415,8 @@ public final class CatalogDocs {
                 return group;
             }
             if (kind != null) {
-                return notFound("Component", name, 
catalog.suggestComponentNames(name, 5));
+                return notFound("Component", name,
+                        withNearSpelling(name, 
catalog.suggestComponentNames(name, 5), catalog.findComponentNames()));
             }
         }
         if (kind == null || "dataformat".equals(kind)) {
@@ -439,7 +442,8 @@ public final class CatalogDocs {
                 return result;
             }
             if (kind != null) {
-                return notFound("Data format", name, 
catalog.suggestDataFormatNames(name, 5));
+                return notFound("Data format", name,
+                        withNearSpelling(name, 
catalog.suggestDataFormatNames(name, 5), catalog.findDataFormatNames()));
             }
         }
         if (kind == null || "language".equals(kind)) {
@@ -488,7 +492,8 @@ public final class CatalogDocs {
                 return answer;
             }
             if (kind != null) {
-                return notFound("Language", name, 
catalog.suggestLanguageNames(name, 5));
+                return notFound("Language", name,
+                        withNearSpelling(name, 
catalog.suggestLanguageNames(name, 5), catalog.findLanguageNames()));
             }
         }
         if (kind == null || "eip".equals(kind)) {
@@ -516,7 +521,8 @@ public final class CatalogDocs {
                 if (byTerm != null) {
                     return byTerm;
                 }
-                return withErrorHandling(notFound("EIP", name, 
catalog.suggestEipNames(name, 5)), name);
+                return withErrorHandling(notFound("EIP", name,
+                        withNearSpelling(name, catalog.suggestEipNames(name, 
5), catalog.findModelNames())), name);
             }
         }
         if (kind == null || "api".equals(kind)) {
@@ -573,6 +579,11 @@ public final class CatalogDocs {
         suggestions.addAll(catalog.suggestEipNames(name, 3));
         suggestions.addAll(findBeans(catalog, 
name).stream().map(PojoBeanModel::getName).limit(3).toList());
         suggestions.addAll(KameletDefinitions.suggest(name, 
KameletDefinitions.catalog().keySet(), 3));
+        List<String> names = new ArrayList<>(catalog.findComponentNames());
+        names.addAll(catalog.findDataFormatNames());
+        names.addAll(catalog.findLanguageNames());
+        names.addAll(catalog.findModelNames());
+        suggestions = withNearSpelling(name, suggestions, names);
         JsonObject answer = withErrorHandling(notFound("Artifact", name, 
suggestions), name);
         if (name.toLowerCase(Locale.ROOT).contains("kamelet")) {
             // kamelet-custom, custom-kamelet: how to write one
@@ -1948,6 +1959,18 @@ public final class CatalogDocs {
         return err;
     }
 
+    /**
+     * The suggestions, or the name that is a typo away from the given one 
when the catalog suggests nothing: kafak is
+     * kafka (CAMEL-26932). The suggestions match by name, alias and title, 
which a misspelled name has none of.
+     */
+    static List<String> withNearSpelling(String name, List<String> 
suggestions, Collection<String> names) {
+        if (!suggestions.isEmpty()) {
+            return suggestions;
+        }
+        String closest = ArtifactUtils.closest(name, names);
+        return closest != null ? List.of(closest) : suggestions;
+    }
+
     /**
      * Error for a catalog lookup that found nothing, with the names the 
catalog suggests for the term (a protocol or
      * product name such as mqtt or s3) so the next call can use one of them.
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
index 894002065520..30e44323f163 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
@@ -260,6 +260,26 @@ class CatalogDocsTest {
         
assertTrue(catalogDoc(Map.of()).getString("error").contains("required"));
     }
 
+    @Test
+    void aMisspelledNameSuggestsTheNameItIsATypoOf() throws Exception {
+        // the suggestions match by name, alias and title: a typo had none 
(CAMEL-26932)
+        JsonObject artifact = catalogDoc(Map.of("name", "kafak"));
+        assertTrue(artifact.getString("error").contains("not found"), 
artifact.toJson());
+        assertEquals(List.of("kafka"), artifact.getCollection("suggestions"), 
artifact.toJson());
+
+        JsonObject component = catalogDoc(Map.of("name", "platfrom-http", 
"kind", "component"));
+        assertEquals(List.of("platform-http"), 
component.getCollection("suggestions"), component.toJson());
+        JsonObject dataFormat = catalogDoc(Map.of("name", "jakson", "kind", 
"dataformat"));
+        assertEquals(List.of("jackson"), 
dataFormat.getCollection("suggestions"), dataFormat.toJson());
+        JsonObject language = catalogDoc(Map.of("name", "simpel", "kind", 
"language"));
+        assertEquals(List.of("simple"), language.getCollection("suggestions"), 
language.toJson());
+        JsonObject eip = catalogDoc(Map.of("name", "spilt", "kind", "eip"));
+        assertEquals(List.of("split"), eip.getCollection("suggestions"), 
eip.toJson());
+
+        // a name that is close to nothing still has no suggestions
+        assertNull(catalogDoc(Map.of("name", 
"nosuchthing")).get("suggestions"));
+    }
+
     @Test
     void docPageReturnsALanguageSubPageAsText() throws Exception {
         JsonObject operators = catalogDoc(Map.of("name", "simple", "kind", 
"language", "docPage", "operators"));

Reply via email to