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