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 5ceb50c72874 CAMEL-24961: docs - the component, data format and 
language pages show the body types in a Message Body section (#28247)
5ceb50c72874 is described below

commit 5ceb50c7287447b4f4efbc2681284ab44565068c
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Oct 24 08:47:40 2026 +0200

    CAMEL-24961: docs - the component, data format and language pages show the 
body types in a Message Body section (#28247)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
 docs/components/modules/ROOT/examples/js/camel.js  | 44 ++++++++++++++++++++++
 .../modules/ROOT/partials/body-types.adoc          | 21 +++++++++++
 .../ROOT/partials/component-endpoint-headers.adoc  |  6 ++-
 .../dataformats/partials/dataformat-options.adoc   |  4 ++
 .../languages/partials/language-options.adoc       |  4 ++
 .../modules/ROOT/pages/camel-catalog.adoc          |  3 +-
 .../dsl/jbang/core/commands/ai/CatalogDocs.java    |  2 +-
 .../jbang/core/commands/catalog/CatalogDoc.java    | 41 ++++++++++++++++++++
 .../core/commands/catalog/CatalogDocTest.java      | 22 +++++++++++
 9 files changed, 144 insertions(+), 3 deletions(-)

diff --git a/docs/components/modules/ROOT/examples/js/camel.js 
b/docs/components/modules/ROOT/examples/js/camel.js
index 82c2c14e2d3e..d2584cc39237 100644
--- a/docs/components/modules/ROOT/examples/js/camel.js
+++ b/docs/components/modules/ROOT/examples/js/camel.js
@@ -39,4 +39,48 @@ module.exports = {
         return e.msg()
       }
   },
+
+  // the body types of the catalog (CAMEL-24961): one row per side of the 
bodyTypes section
+  bodySide: (side) => {
+    const sides = {
+      consumerOut: 'Consumer',
+      consumerReply: 'Consumer reply',
+      producerIn: 'Producer input',
+      producerOut: 'Producer output',
+      marshalIn: 'Marshal input',
+      marshalOut: 'Marshal output',
+      unmarshalIn: 'Unmarshal input',
+      unmarshalOut: 'Unmarshal output',
+      expressionIn: 'Expression input',
+      expressionOut: 'Expression result',
+    }
+    return `*${sides[side] || side}*`
+  },
+
+  // text, bytes or stream, with the Java type when the body is always of that 
type
+  bodyCarriers: (value) => {
+    const carriers = (value.carriers || []).map((carrier) => '`' + carrier + 
'`')
+    const words = carriers.length === 0 ? '`unknown`'
+      : carriers.length === 1 ? carriers[0]
+        : carriers.slice(0, -1).join(', ') + ' or ' + carriers[carriers.length 
- 1]
+    return words + (value.javaType ? ' (`' + value.javaType + '`)' : '') + 
(value.format ? ', as ' + value.format : '')
+  },
+
+  // the description, the bodies for other values of an option, and the 
options the body depends on
+  bodyDescription: (value) => {
+    // only what reads as an attribute reference ({body}, not {header.foo}, 
which keeps a backslash), and the cell separator
+    const escape = (text) => text.replace(/\{(\w[\w-]*)\}/g, 
'\\{$1}').split('|').join('\\|')
+    const parts = []
+    if (value.description) {
+      parts.push(escape(value.description) + (value.description.endsWith('.') 
? '' : '.'))
+    }
+    if (value.byOption && value.byOption.length) {
+      parts.push(value.byOption.map((option) => `* With 
\`${option.option}=${option.value}\`: `
+        + module.exports.bodyCarriers(option)).join('\n'))
+    }
+    if (value.dependsOn && value.dependsOn.length) {
+      parts.push('Not known when ' + value.dependsOn.map((option) => '`' + 
option + '`').join(' or ') + ' is set.')
+    }
+    return parts.join('\n\n')
+  },
 }
diff --git a/docs/components/modules/ROOT/partials/body-types.adoc 
b/docs/components/modules/ROOT/partials/body-types.adoc
new file mode 100644
index 000000000000..8df01700d940
--- /dev/null
+++ b/docs/components/modules/ROOT/partials/body-types.adoc
@@ -0,0 +1,21 @@
+// body types: START
+// the including partial sets body-types-module (the module of the page) and 
body-types-intro
+include::jsonpathcount${body-types-module}:example$json/{shortname}.json[queries='bodytypecount=nodes$.bodyTypes.*']
+
+ifeval::[{bodytypecount} != 0]
+== Message Body
+
+[subs="attributes,quotes"]
+{body-types-intro}
+
+[width="100%",cols="2,3,6a",options="header"]
+|===
+| Side | Body | Description
+|===
+
+jsonpathTable::{body-types-module}:example$json/{shortname}.json['nodes$.bodyTypes.*','camel.bodySide(path[2])|camel.bodyCarriers(value)|camel.bodyDescription(value)','camel=xref:ROOT:js/camel.js']
+
+The bodies are the ones with the default options. A side that is not listed is 
not known, and tooling does not guess
+it. The carriers are described in the xref:manual::camel-catalog.adoc[Camel 
Catalog].
+endif::[]
+// body types: END
diff --git 
a/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc 
b/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc
index f6c5b0b415cf..dac98068db71 100644
--- a/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc
+++ b/docs/components/modules/ROOT/partials/component-endpoint-headers.adoc
@@ -20,4 +20,8 @@ The {doctitle} component supports the following message 
header(s), which is/are
 
jsonpathTable::example$json/{shortname}.json['nodes$.headers.*',{cellformats},'util=camel-website-util,camel=xref:js/camel.js']
 
 endif::[]
-// component headers: END
\ No newline at end of file
+// component headers: END
+
+:body-types-module: ROOT
+:body-types-intro: The message body at each side of the {doctitle} component: 
_Consumer_ is the body of the messages the consumer creates, _Consumer reply_ 
the bodies a consumer that answers its caller can reply with, _Producer input_ 
the bodies the producer can send or write, and _Producer output_ the body after 
the producer.
+include::partial$body-types.adoc[]
diff --git 
a/docs/components/modules/dataformats/partials/dataformat-options.adoc 
b/docs/components/modules/dataformats/partials/dataformat-options.adoc
index fd65dff21b79..870c4df4f71e 100644
--- a/docs/components/modules/dataformats/partials/dataformat-options.adoc
+++ b/docs/components/modules/dataformats/partials/dataformat-options.adoc
@@ -14,3 +14,7 @@ The {doctitle} dataformat supports the following options 
which are listed below.
 
 
jsonpathTable::example$json/{shortname}.json['nodes$.properties[?(@.displayName!="Id")]',{cellformats},{requires}]
 
+
+:body-types-module: dataformats
+:body-types-intro: The message body at each side of the {doctitle} data 
format: _Marshal input_ and _Unmarshal input_ are the bodies marshal and 
unmarshal can take, and _Marshal output_ and _Unmarshal output_ the body after 
them.
+include::ROOT:partial$body-types.adoc[]
diff --git a/docs/components/modules/languages/partials/language-options.adoc 
b/docs/components/modules/languages/partials/language-options.adoc
index b042b09b8ded..66f2687fbc32 100644
--- a/docs/components/modules/languages/partials/language-options.adoc
+++ b/docs/components/modules/languages/partials/language-options.adoc
@@ -14,3 +14,7 @@ The {doctitle} language supports the following options which 
are listed below.
 
 
jsonpathTable::example$json/{shortname}.json['nodes$.properties[?(@.kind=="attribute"
 && @.displayName!="Id")]',{cellformats},{requires}]
 
+
+:body-types-module: languages
+:body-types-intro: The message body at each side of the {doctitle} language: 
_Expression input_ is the body its expressions can read, and _Expression 
result_ what they return.
+include::ROOT:partial$body-types.adoc[]
diff --git a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
index d97e2614ae78..573ada4c6125 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-catalog.adoc
@@ -163,7 +163,8 @@ description:
 ----
 
 The sides say what the body is with the default options. A side that is not in 
the catalog is not known, and tooling
-should not guess it. The Java API gives them on the model:
+should not guess it. The documentation page of a component, data format or 
language shows them in its _Message Body_
+section, and `camel catalog doc` prints them. The Java API gives them on the 
model:
 
 [source,java]
 ----
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 9f5196ce0128..10c9719778d7 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
@@ -1649,7 +1649,7 @@ public final class CatalogDocs {
      * The body types a line per side, as compact as the options are: the 
carriers, the Java type, the format, the
      * description, the body for other option values, and the options that 
make it not known (CAMEL-24961).
      */
-    static JsonObject bodyTypes(Map<String, BodyTypeModel> bodyTypes) {
+    public static JsonObject bodyTypes(Map<String, BodyTypeModel> bodyTypes) {
         JsonObject answer = new JsonObject();
         for (Map.Entry<String, BodyTypeModel> entry : bodyTypes.entrySet()) {
             BodyTypeModel side = entry.getValue();
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
index c3f250438043..9492c0ca720d 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
@@ -23,6 +23,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 import com.github.freva.asciitable.AsciiTable;
@@ -46,6 +47,7 @@ import org.apache.camel.dsl.jbang.core.common.VersionHelper;
 import org.apache.camel.main.util.SuggestSimilarHelper;
 import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.tooling.model.BaseOptionModel;
+import org.apache.camel.tooling.model.BodyTypeModel;
 import org.apache.camel.tooling.model.ComponentModel;
 import org.apache.camel.tooling.model.DataFormatModel;
 import org.apache.camel.tooling.model.EipModel;
@@ -124,6 +126,19 @@ public class CatalogDoc extends CamelCommand {
                         description = "Output in JSON Format: the 
documentation the MCP tool camel_catalog_doc gives")
     boolean jsonOutput;
 
+    /** The sides of the body types, as the documentation pages name them. */
+    private static final Map<String, String> BODY_SIDES = Map.of(
+            BodyTypeModel.CONSUMER_OUT, "Consumer",
+            BodyTypeModel.CONSUMER_REPLY, "Consumer reply",
+            BodyTypeModel.PRODUCER_IN, "Producer input",
+            BodyTypeModel.PRODUCER_OUT, "Producer output",
+            BodyTypeModel.MARSHAL_IN, "Marshal input",
+            BodyTypeModel.MARSHAL_OUT, "Marshal output",
+            BodyTypeModel.UNMARSHAL_IN, "Unmarshal input",
+            BodyTypeModel.UNMARSHAL_OUT, "Unmarshal output",
+            BodyTypeModel.EXPRESSION_IN, "Expression input",
+            BodyTypeModel.EXPRESSION_OUT, "Expression result");
+
     CamelCatalog catalog;
 
     public CatalogDoc(CamelJBangMain main) {
@@ -579,6 +594,7 @@ public class CatalogDoc extends CamelCommand {
             printer().println(optionTable(filtered));
             printer().println("");
         }
+        printBodyTypes(cm.getBodyTypes());
 
         if (link != null) {
             printer().println(link);
@@ -628,6 +644,7 @@ public class CatalogDoc extends CamelCommand {
         }
         printer().println(optionTable(filtered));
         printer().println("");
+        printBodyTypes(dm.getBodyTypes());
 
         if (link != null) {
             printer().println(link);
@@ -677,6 +694,7 @@ public class CatalogDoc extends CamelCommand {
         }
         printer().println(optionTable(filtered));
         printer().println("");
+        printBodyTypes(lm.getBodyTypes());
 
         if (link != null) {
             printer().println(link);
@@ -775,6 +793,29 @@ public class CatalogDoc extends CamelCommand {
         };
     }
 
+    /**
+     * The message body at each side, as the body types of the catalog say 
(CAMEL-24961) and the documentation page
+     * shows it: one line per side, with the default options. Nothing when the 
catalog does not say.
+     */
+    private void printBodyTypes(Map<String, BodyTypeModel> bodyTypes) {
+        if (bodyTypes.isEmpty()) {
+            return;
+        }
+        JsonObject lines = CatalogDocs.bodyTypes(bodyTypes);
+        // the side in one line (Expression result, with the padding of the 
cell), the body in the rest of the terminal
+        int sideWidth = 
BODY_SIDES.values().stream().mapToInt(String::length).max().orElse(17) + 2;
+        int bodyWidth = Math.max(15, Math.min(120, terminalWidth() - 
TerminalWidthHelper.fancyBorderOverhead(2) - sideWidth));
+        printer().println("Message body (with the default options; a side that 
is not listed is not known):");
+        printer().println(AsciiTable.getTable(AsciiTable.FANCY_ASCII, 
lines.entrySet(), Arrays.asList(
+                new Column().header("SIDE").dataAlign(HorizontalAlign.LEFT)
+                        .maxWidth(sideWidth, OverflowBehaviour.NEWLINE)
+                        .with(e -> BODY_SIDES.getOrDefault(e.getKey(), 
e.getKey())),
+                new Column().header("BODY").dataAlign(HorizontalAlign.LEFT)
+                        .maxWidth(bodyWidth, OverflowBehaviour.NEWLINE)
+                        .with(e -> String.valueOf(e.getValue())))));
+        printer().println("");
+    }
+
     private String optionTable(List<? extends BaseOptionModel> options) {
         int[] w = docColumnWidths(35, 80, 25, 25);
         return AsciiTable.getTable(AsciiTable.FANCY_ASCII, options, 
Arrays.asList(
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDocTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDocTest.java
index 30e04440c94a..b114ed5532b8 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDocTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDocTest.java
@@ -192,6 +192,28 @@ class CatalogDocTest extends CamelCommandBaseTestSupport {
         Assertions.assertTrue(printer.getOutput().startsWith("Language Name: 
simple"), printer.getOutput());
     }
 
+    @Test
+    public void shouldPrintTheMessageBody() throws Exception {
+        // CAMEL-24961: the body at each side, as the documentation page shows 
it
+        CatalogDoc command = createCommand("file", false);
+        Assertions.assertEquals(0, command.doCall());
+        String output = printer.getOutput();
+        Assertions.assertTrue(output.contains("Message body (with the default 
options"), output);
+        Assertions.assertTrue(output.contains("Producer input"), output);
+        Assertions.assertTrue(output.contains("text, bytes, stream or file"), 
output);
+
+        printer = new StringPrinter();
+        command = createCommand("jackson", false);
+        Assertions.assertEquals(0, command.doCall());
+        Assertions.assertTrue(printer.getOutput().contains("Unmarshal 
output"), printer.getOutput());
+
+        // a component whose body types are not in the catalog has no such 
table
+        printer = new StringPrinter();
+        command = createCommand("weather", false);
+        Assertions.assertEquals(0, command.doCall());
+        Assertions.assertFalse(printer.getOutput().contains("Message body"), 
printer.getOutput());
+    }
+
     @Test
     public void shouldFilterTheOptions() throws Exception {
         CatalogDoc command = createCommand("timer", false);

Reply via email to