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 80ef823cc2b7 CAMEL-25235: camel_catalog_doc carries the start of a 
language's and a data format's documentation too (#27218)
80ef823cc2b7 is described below

commit 80ef823cc2b7d6a34c5a9bc50fc5fdbdb0004517
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Oct 1 19:45:16 2026 +0200

    CAMEL-25235: camel_catalog_doc carries the start of a language's and a data 
format's documentation too (#27218)
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 .../dsl/jbang/core/commands/ai/CatalogDocs.java    | 35 ++++++++++++---
 .../core/commands/ai/CatalogDocExcerptTest.java    | 50 ++++++++++++++++++++++
 2 files changed, 80 insertions(+), 5 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 7db9f6066114..8472684617c3 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
@@ -105,6 +105,12 @@ public final class CatalogDocs {
 
     /** How much of a component's documentation prose is carried in the answer 
by default (CAMEL-25040). */
     static final int DOC_EXCERPT_BUDGET = 1400;
+    /**
+     * The same for a language or a data format (CAMEL-25235). More than a 
component's, because a component says most of
+     * what it does through its options and these say it in prose: the 
semantic language's named questions, their type,
+     * instructions, criteria and threshold are not options at all.
+     */
+    static final int DOC_EXCERPT_BUDGET_PROSE = 3600;
 
     private static final Pattern XREF = 
Pattern.compile("xref:[^\\[]*\\[([^]]*)]");
     private static final Pattern INTERNAL_REF = 
Pattern.compile("<<[^,>]*,([^>]*)>>");
@@ -143,6 +149,10 @@ public final class CatalogDocs {
                     || trimmed.startsWith("ifndef::")) {
                 continue;
             }
+            if (!fenced && trimmed.startsWith("//")) {
+                // an asciidoc line comment, such as the "// language options: 
START" markers around a generated table
+                continue;
+            }
             if (trimmed.startsWith("----")) {
                 fenced = !fenced;
             } else if (!fenced) {
@@ -206,8 +216,9 @@ public final class CatalogDocs {
             String artifact = 
YAML_DATAFORMAT_NAMES.getOrDefault(name.toLowerCase(), name);
             DataFormatModel dm = catalog.dataFormatModel(artifact);
             if (dm != null) {
-                String doc = includeDoc ? catalog.asciiDoc(artifact + 
"-dataformat") : null;
-                JsonObject result = dataFormatDoc(dm, lowerFilter, scope, doc);
+                String adoc = catalog.asciiDoc(artifact + "-dataformat");
+                JsonObject result = dataFormatDoc(dm, lowerFilter, scope, 
includeDoc ? adoc : null,
+                        includeDoc ? null : docExcerpt(adoc, 
DOC_EXCERPT_BUDGET_PROSE));
                 String shape = YAML_DATAFORMAT_SHAPES.get(artifact);
                 if (shape != null) {
                     result.put("yaml", "marshal: {" + shape + "} or unmarshal: 
{" + shape + "}"
@@ -234,7 +245,10 @@ public final class CatalogDocs {
                     doc = catalog.asciiDoc(name + "-language");
                 }
                 boolean docPageOnly = page != null && !page.isEmpty();
-                return languageDoc(lm, lowerFilter, scope, doc, 
languageDocPages(catalog, name), docPageOnly);
+                // the start of the page unless the whole of it, or one of its 
sub-pages, was asked for
+                String excerpt = docPageOnly || includeDoc
+                        ? null : docExcerpt(catalog.asciiDoc(name + 
"-language"), DOC_EXCERPT_BUDGET_PROSE);
+                return languageDoc(lm, lowerFilter, scope, doc, 
languageDocPages(catalog, name), docPageOnly, excerpt);
             }
             if (kind != null) {
                 return notFound("Language", name, 
catalog.suggestLanguageNames(name, 5));
@@ -1103,7 +1117,8 @@ public final class CatalogDocs {
         return result;
     }
 
-    private static JsonObject dataFormatDoc(DataFormatModel model, String 
filter, OptionScope scope, String doc) {
+    private static JsonObject dataFormatDoc(
+            DataFormatModel model, String filter, OptionScope scope, String 
doc, String docExcerpt) {
         JsonObject result = new JsonObject();
         result.put("kind", "dataformat");
         result.put("name", model.getName());
@@ -1121,6 +1136,11 @@ public final class CatalogDocs {
         if (doc != null) {
             result.put("doc", doc);
         }
+        if (docExcerpt != null) {
+            // what the options cannot say: the syntax and the essentials, 
from the page itself
+            result.put("documentation", docExcerpt);
+            result.put("documentationHint", "the start of the documentation 
page; includeDoc=true for all of it");
+        }
         return result;
     }
 
@@ -1136,7 +1156,7 @@ public final class CatalogDocs {
 
     private static JsonObject languageDoc(
             LanguageModel model, String filter, OptionScope scope, String doc, 
List<String> docPages,
-            boolean docPageOnly) {
+            boolean docPageOnly, String docExcerpt) {
         JsonObject result = new JsonObject();
         result.put("kind", "language");
         result.put("name", model.getName());
@@ -1172,6 +1192,11 @@ public final class CatalogDocs {
         if (doc != null) {
             result.put("doc", doc);
         }
+        if (docExcerpt != null) {
+            // what the options cannot say: the syntax and the essentials, 
from the page itself
+            result.put("documentation", docExcerpt);
+            result.put("documentationHint", "the start of the documentation 
page; includeDoc=true for all of it");
+        }
         return result;
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocExcerptTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocExcerptTest.java
index 49076846941d..8da10bbe9563 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocExcerptTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocExcerptTest.java
@@ -85,6 +85,56 @@ class CatalogDocExcerptTest {
         assertNull(answer.getString("documentation"), "the whole page is 
there, so the excerpt would repeat it");
     }
 
+    @Test
+    public void testALanguageCarriesWhatItsOptionsCannotSay() throws Exception 
{
+        // CAMEL-25235: the semantic language is configured by named 
questions, which are not options at all, so its
+        // option list (id, language, expression) says nothing about how to 
use it
+        JsonObject answer = catalogDoc(Map.of("name", "semantic", "kind", 
"language"));
+        String documentation = answer.getString("documentation");
+        assertNotNull(documentation, "no documentation in: " + 
answer.toJson());
+        for (String needed : new String[] { "question", "instructions", 
"criteria", "threshold" }) {
+            assertTrue(documentation.contains(needed), needed + " is not in 
the excerpt:\n" + documentation);
+        }
+        assertNotNull(answer.getString("documentationHint"));
+    }
+
+    @Test
+    public void testADataFormatCarriesItToo() throws Exception {
+        String documentation = catalogDoc(Map.of("name", "csv", "kind", 
"dataformat")).getString("documentation");
+        assertNotNull(documentation);
+        assertFalse(documentation.contains("include::"), documentation);
+    }
+
+    @Test
+    public void testASubPageOrTheWholePageIsNotAlsoExcerpted() throws 
Exception {
+        // docPage returns one page as text, includeDoc the whole of it: 
neither wants the start of it again
+        assertNull(catalogDoc(Map.of("name", "simple", "kind", "language", 
"docPage", "functions"))
+                .getString("documentation"));
+        assertNull(catalogDoc(Map.of("name", "simple", "kind", "language", 
"includeDoc", "true"))
+                .getString("documentation"));
+    }
+
+    @Test
+    public void testAsciiDocLineCommentsAreNotCarried() {
+        String page = """
+                == Options
+
+                // language options: START
+                // language options: END
+
+                == Usage
+
+                Text that matters.
+                ----
+                // a comment inside a fence is code and stays
+                ----
+                """;
+        String excerpt = CatalogDocs.docExcerpt(page, 
CatalogDocs.DOC_EXCERPT_BUDGET_PROSE);
+        assertFalse(excerpt.contains("language options: START"), excerpt);
+        assertTrue(excerpt.contains("Text that matters."), excerpt);
+        assertTrue(excerpt.contains("a comment inside a fence is code"), 
excerpt);
+    }
+
     @Test
     public void testAComponentWithNoPageIsStillAnswered() {
         // a page is not guaranteed; the answer must not depend on one

Reply via email to