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"));