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