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 fa779353ec19 CAMEL-25736: camel-jbang - the AI samples and the 
documentation tests read the YAML examples with a longer delimiter or a leading 
comment (#28021)
fa779353ec19 is described below

commit fa779353ec1958f0eefc2d41cd77642bcd1658f6
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Oct 17 20:29:18 2026 +0200

    CAMEL-25736: camel-jbang - the AI samples and the documentation tests read 
the YAML examples with a longer delimiter or a leading comment (#28021)
    
    DocBlocks, the extractor of the doc-samples plugin and of the documentation 
tests, now reads a listing with a
    delimiter longer than ---- (14 examples on 3 pages) and a block that opens 
with a comment before a top-level entry
    (35 examples on about 20 pages); a list of steps with a comment above it 
stays a fragment. CatalogSamples uses
    DocBlocks instead of its own regex, so camel_catalog_sample reads the docs 
as the plugin and the tests do, without
    the callout markers and the blocks marked as what to avoid.
    
    The examples the tests then checked for the first time that were wrong are 
fixed: docling-batch-processing (the
    aggregate's strategy, output and a property the strategy does not have), 
keycloak-consumer (a filter without steps,
    an extra expression level), keycloak-producer (an operation that does not 
exist, application.yaml syntax in the
    route file) and keycloak-security (handled as a plain value); with their 
catalog copies.
    
    Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../catalog/docs/docling-batch-processing.adoc     | 13 ++-
 .../camel/catalog/docs/keycloak-consumer.adoc      | 28 +++----
 .../camel/catalog/docs/keycloak-producer.adoc      | 19 +++--
 .../camel/catalog/docs/keycloak-security.adoc      |  4 +-
 .../src/main/docs/docling-batch-processing.adoc    | 13 ++-
 .../src/main/docs/keycloak-consumer.adoc           | 28 +++----
 .../src/main/docs/keycloak-producer.adoc           | 19 +++--
 .../src/main/docs/keycloak-security.adoc           |  4 +-
 .../dsl/jbang/core/commands/ai/CatalogSamples.java | 13 ++-
 .../apache/camel/dsl/yaml/validator/DocBlocks.java | 71 ++++++++++++++--
 .../camel/dsl/yaml/validator/DocBlocksTest.java    | 98 ++++++++++++++++++++++
 .../yaml/validator/UserManualDocExamplesTest.java  | 16 ++--
 12 files changed, 244 insertions(+), 82 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/docling-batch-processing.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/docling-batch-processing.adoc
index 477e747a0f1e..80d99254369f 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/docling-batch-processing.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/docling-batch-processing.adoc
@@ -174,8 +174,6 @@ YAML::
 - beans:
   - name: documentListProcessor
     type: 
"#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
-    properties:
-      strategyMethodName: "aggregate"
 
 # Route 1: Collect documents
 - route:
@@ -205,14 +203,15 @@ YAML::
         concurrentConsumers: 1
       steps:
         - aggregate:
-            aggregationStrategy:
-              bean: "documentListProcessor"
+            aggregationStrategy: documentListProcessor
             correlationExpression:
-              constant: true
+              constant:
+                expression: "true"
             completionSize: 10
             completionTimeout: 5000
-        - to:
-            uri: direct:batch-process
+            steps:
+              - to:
+                  uri: direct:batch-process
 
 # Route 3: Process batch
 - route:
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-consumer.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-consumer.adoc
index 9c0484ac670c..f2f0bb098fa4 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-consumer.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-consumer.adoc
@@ -563,21 +563,21 @@ YAML::
             expression:
               simple:
                 expression: "${body.type} == 'LOGIN_ERROR'"
-        - aggregate:
-            correlationExpression:
-              expression:
-                simple:
-                  expression: "${body.ipAddress}"
-            aggregationStrategy: "#arrayListAggregation"
-            completionSize: 5
-            completionTimeout: 300000
             steps:
-              - log:
-                  message: "SECURITY ALERT: Multiple failed login attempts 
from ${body[0].ipAddress}"
-              - to:
-                  uri: direct:block-ip
-              - to:
-                  uri: direct:send-security-alert
+              - aggregate:
+                  correlationExpression:
+                    simple:
+                      expression: "${body.ipAddress}"
+                  aggregationStrategy: 
"#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
+                  completionSize: 5
+                  completionTimeout: 300000
+                  steps:
+                    - log:
+                        message: "SECURITY ALERT: Multiple failed login 
attempts from ${body[0].ipAddress}"
+                    - to:
+                        uri: direct:block-ip
+                    - to:
+                        uri: direct:send-security-alert
 ----
 ====
 
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-producer.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-producer.adoc
index fe3c24e952a6..320d98815f57 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-producer.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-producer.adoc
@@ -784,7 +784,7 @@ YAML::
         - to:
             uri: keycloak:admin
             parameters:
-              operation: setUserPassword
+              operation: resetUserPassword
         - setHeader:
             name: CamelKeycloakRoleName
             constant: "admin"
@@ -794,14 +794,15 @@ YAML::
               operation: assignRoleToUser
         - transform:
             constant: "User environment setup completed successfully"
+----
+
+The component configuration, in `application.properties`:
 
-# Component configuration
-camel:
-  component:
-    keycloak:
-      server-url: "http://localhost:8080";
-      realm: "master"
-      username: "admin"
-      password: "admin"
+[source,properties]
+----
+camel.component.keycloak.server-url = http://localhost:8080
+camel.component.keycloak.realm = master
+camel.component.keycloak.username = admin
+camel.component.keycloak.password = admin
 ----
 ====
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-security.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-security.adoc
index e4b7da310e94..eebdd1767291 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-security.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/keycloak-security.adoc
@@ -1006,7 +1006,9 @@ YAML::
 - onException:
     exception:
       - "org.apache.camel.CamelAuthorizationException"
-    handled: true
+    handled:
+      constant:
+        expression: "true"
     steps:
       - setHeader:
           name: "CamelHttpResponseCode"
diff --git 
a/components/camel-ai/camel-docling/src/main/docs/docling-batch-processing.adoc 
b/components/camel-ai/camel-docling/src/main/docs/docling-batch-processing.adoc
index 477e747a0f1e..80d99254369f 100644
--- 
a/components/camel-ai/camel-docling/src/main/docs/docling-batch-processing.adoc
+++ 
b/components/camel-ai/camel-docling/src/main/docs/docling-batch-processing.adoc
@@ -174,8 +174,6 @@ YAML::
 - beans:
   - name: documentListProcessor
     type: 
"#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
-    properties:
-      strategyMethodName: "aggregate"
 
 # Route 1: Collect documents
 - route:
@@ -205,14 +203,15 @@ YAML::
         concurrentConsumers: 1
       steps:
         - aggregate:
-            aggregationStrategy:
-              bean: "documentListProcessor"
+            aggregationStrategy: documentListProcessor
             correlationExpression:
-              constant: true
+              constant:
+                expression: "true"
             completionSize: 10
             completionTimeout: 5000
-        - to:
-            uri: direct:batch-process
+            steps:
+              - to:
+                  uri: direct:batch-process
 
 # Route 3: Process batch
 - route:
diff --git a/components/camel-keycloak/src/main/docs/keycloak-consumer.adoc 
b/components/camel-keycloak/src/main/docs/keycloak-consumer.adoc
index 9c0484ac670c..f2f0bb098fa4 100644
--- a/components/camel-keycloak/src/main/docs/keycloak-consumer.adoc
+++ b/components/camel-keycloak/src/main/docs/keycloak-consumer.adoc
@@ -563,21 +563,21 @@ YAML::
             expression:
               simple:
                 expression: "${body.type} == 'LOGIN_ERROR'"
-        - aggregate:
-            correlationExpression:
-              expression:
-                simple:
-                  expression: "${body.ipAddress}"
-            aggregationStrategy: "#arrayListAggregation"
-            completionSize: 5
-            completionTimeout: 300000
             steps:
-              - log:
-                  message: "SECURITY ALERT: Multiple failed login attempts 
from ${body[0].ipAddress}"
-              - to:
-                  uri: direct:block-ip
-              - to:
-                  uri: direct:send-security-alert
+              - aggregate:
+                  correlationExpression:
+                    simple:
+                      expression: "${body.ipAddress}"
+                  aggregationStrategy: 
"#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
+                  completionSize: 5
+                  completionTimeout: 300000
+                  steps:
+                    - log:
+                        message: "SECURITY ALERT: Multiple failed login 
attempts from ${body[0].ipAddress}"
+                    - to:
+                        uri: direct:block-ip
+                    - to:
+                        uri: direct:send-security-alert
 ----
 ====
 
diff --git a/components/camel-keycloak/src/main/docs/keycloak-producer.adoc 
b/components/camel-keycloak/src/main/docs/keycloak-producer.adoc
index fe3c24e952a6..320d98815f57 100644
--- a/components/camel-keycloak/src/main/docs/keycloak-producer.adoc
+++ b/components/camel-keycloak/src/main/docs/keycloak-producer.adoc
@@ -784,7 +784,7 @@ YAML::
         - to:
             uri: keycloak:admin
             parameters:
-              operation: setUserPassword
+              operation: resetUserPassword
         - setHeader:
             name: CamelKeycloakRoleName
             constant: "admin"
@@ -794,14 +794,15 @@ YAML::
               operation: assignRoleToUser
         - transform:
             constant: "User environment setup completed successfully"
+----
+
+The component configuration, in `application.properties`:
 
-# Component configuration
-camel:
-  component:
-    keycloak:
-      server-url: "http://localhost:8080";
-      realm: "master"
-      username: "admin"
-      password: "admin"
+[source,properties]
+----
+camel.component.keycloak.server-url = http://localhost:8080
+camel.component.keycloak.realm = master
+camel.component.keycloak.username = admin
+camel.component.keycloak.password = admin
 ----
 ====
diff --git a/components/camel-keycloak/src/main/docs/keycloak-security.adoc 
b/components/camel-keycloak/src/main/docs/keycloak-security.adoc
index e4b7da310e94..eebdd1767291 100644
--- a/components/camel-keycloak/src/main/docs/keycloak-security.adoc
+++ b/components/camel-keycloak/src/main/docs/keycloak-security.adoc
@@ -1006,7 +1006,9 @@ YAML::
 - onException:
     exception:
       - "org.apache.camel.CamelAuthorizationException"
-    handled: true
+    handled:
+      constant:
+        expression: "true"
     steps:
       - setHeader:
           name: "CamelHttpResponseCode"
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
index 599e6cca0a36..208786c44d8b 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogSamples.java
@@ -34,6 +34,7 @@ import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.dsl.yaml.validator.DocBlocks;
 import org.apache.camel.tooling.model.ComponentModel;
 import org.apache.camel.tooling.model.DataFormatModel;
 import org.apache.camel.tooling.model.EipModel;
@@ -195,7 +196,6 @@ public final class CatalogSamples {
         return sample(catalog, null, name, limit);
     }
 
-    private static final Pattern YAML_BLOCK = 
Pattern.compile("\\[source,yaml\\]\\s*\\n----\\n(.*?)\\n----", Pattern.DOTALL);
     private static final Map<String, Found> DOC_CACHE = new 
ConcurrentHashMap<>();
 
     /** The validated examples of a page family, and for a component whether 
any of them uses its endpoint. */
@@ -274,13 +274,10 @@ public final class CatalogSamples {
             if (doc == null) {
                 continue;
             }
-            Matcher m = YAML_BLOCK.matcher(doc);
-            while (m.find()) {
-                String yaml = m.group(1).stripTrailing() + "\n";
-                if (!yaml.stripLeading().startsWith("- ")) {
-                    // a fragment (an option list, a manifest), not a route 
file
-                    continue;
-                }
+            // the route examples as the doc-samples plugin and the 
documentation tests read them (CAMEL-25736): a
+            // longer delimiter and a leading comment are fine, callout 
markers are left out, and a block marked as
+            // what to avoid is no sample; the fragments (an option list, a 
manifest) are not route files
+            for (String yaml : DocBlocks.examples(doc)) {
                 if (!SourceValidator.validateYamlSchema(yaml, 
catalog).isEmpty()) {
                     continue;
                 }
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DocBlocks.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DocBlocks.java
index 99f19e3523b8..e547538379e3 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DocBlocks.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/DocBlocks.java
@@ -18,6 +18,7 @@ package org.apache.camel.dsl.yaml.validator;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -34,7 +35,11 @@ public final class DocBlocks {
     /** The AsciiDoc comment that keeps a block out of the examples. */
     public static final String SKIP_MARKER = "// yaml-validator: skip";
 
-    private static final Pattern YAML_BLOCK = 
Pattern.compile("\\[source,yaml\\]\\s*\\n----\\n(.*?)\\n----",
+    /**
+     * A YAML listing block: four or more dashes, closed by the same line. A 
delimiter longer than four dashes is valid
+     * AsciiDoc and common in older pages, and their examples were not read 
(CAMEL-25736).
+     */
+    private static final Pattern YAML_BLOCK = 
Pattern.compile("\\[source,yaml\\]\\s*\\n(-{4,})\\n(.*?)\\n\\1(?=\\n|$)",
             Pattern.DOTALL);
 
     /** An AsciiDoc callout marker at the end of a line, which is 
documentation and not part of the route. */
@@ -46,25 +51,79 @@ public final class DocBlocks {
     private DocBlocks() {
     }
 
+    /** A route example of a page, and the offset in the page where its YAML 
starts (to tell its line). */
+    public record Example(int start, String yaml) {
+    }
+
     /**
-     * The route examples of the page: the YAML blocks that start with a 
top-level list entry, without their callout
-     * markers, and without the blocks that carry {@value #SKIP_MARKER}.
+     * The route examples of the page: the YAML blocks that start with a 
top-level list entry (after the comment lines
+     * that may come first), without their callout markers, and without the 
blocks that carry {@value #SKIP_MARKER}.
      */
     public static List<String> examples(String doc) {
         List<String> answer = new ArrayList<>();
+        for (Example example : examplesAt(doc)) {
+            answer.add(example.yaml());
+        }
+        return answer;
+    }
+
+    /** The route examples of the page as {@link #examples(String)} finds 
them, each with where it starts. */
+    public static List<Example> examplesAt(String doc) {
+        List<Example> answer = new ArrayList<>();
         if (doc == null) {
             return answer;
         }
         Matcher m = YAML_BLOCK.matcher(doc);
         while (m.find()) {
-            String yaml = 
CALLOUT.matcher(m.group(1)).replaceAll("").stripTrailing() + "\n";
-            if (yaml.stripLeading().startsWith("- ") && !markedToSkip(doc, 
m.start())) {
-                answer.add(yaml);
+            String yaml = 
CALLOUT.matcher(m.group(2)).replaceAll("").stripTrailing() + "\n";
+            if (startsWithEntry(yaml) && !markedToSkip(doc, m.start())) {
+                answer.add(new Example(m.start(2), yaml));
             }
         }
         return answer;
     }
 
+    /**
+     * The entries a YAML DSL file is a list of: the roots of the schema, and 
the kebab-case names the parser also
+     * accepts. A kamelet is a step, not one of them.
+     */
+    private static final Set<String> TOP_LEVEL = Set.of("beans", 
"dataFormats", "errorHandler", "from", "intercept",
+            "interceptFrom", "interceptSendToEndpoint", "onCompletion", 
"onException", "rest", "restConfiguration",
+            "route", "route-configuration", "route-template", 
"routeConfiguration", "routeTemplate", "semantic",
+            "sslContextParameters", "templated-route", "templatedRoute", 
"transformers", "validators");
+
+    /** The key of a list entry, as route in "- route:". */
+    private static final Pattern ENTRY_KEY = Pattern.compile("- ([\\w-]+):");
+
+    /**
+     * Whether the YAML is a route file: its first line that is not blank or a 
comment is a list entry. After a comment
+     * it must be a top-level entry: a block that opens with "# send the 
dataset to a queue" and then - route: is a
+     * route file, and was skipped (CAMEL-25736), while a list of steps with a 
comment above it is a fragment of a
+     * route.
+     */
+    static boolean startsWithEntry(String yaml) {
+        boolean comment = false;
+        for (String line : yaml.split("\n")) {
+            String s = line.strip();
+            if (s.isEmpty()) {
+                continue;
+            }
+            if (s.startsWith("#")) {
+                comment = true;
+                continue;
+            }
+            if (!s.startsWith("- ")) {
+                return false;
+            }
+            if (!comment) {
+                return true;
+            }
+            Matcher m = ENTRY_KEY.matcher(s);
+            return m.lookingAt() && TOP_LEVEL.contains(m.group(1));
+        }
+        return false;
+    }
+
     /** Whether the block at this offset carries {@link #SKIP_MARKER} in the 
lines before it. */
     public static boolean markedToSkip(String doc, int blockStart) {
         int from = Math.max(0, blockStart - MARKER_LOOKBEHIND);
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/DocBlocksTest.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/DocBlocksTest.java
new file mode 100644
index 000000000000..4b9144d2033d
--- /dev/null
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/DocBlocksTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.yaml.validator;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * CAMEL-25736: the route examples of a page include the blocks with a 
delimiter longer than four dashes, and the blocks
+ * that open with a comment; 53 examples of the documentation were not read 
before.
+ */
+class DocBlocksTest {
+
+    @Test
+    void aLongerDelimiterAndALeadingCommentAreRead() {
+        String doc = """
+                = A page
+
+                [source,yaml]
+                
--------------------------------------------------------------------------------
+                - from:
+                    uri: direct:search
+                    steps:
+                      - log:
+                          message: "${body}"
+                
--------------------------------------------------------------------------------
+
+                [source,yaml]
+                ----
+                # send the dataset to a queue
+                - route:
+                    from:
+                      uri: dataset:foo
+                      steps:
+                        - to:
+                            uri: seda:queue
+                ----
+
+                [source,yaml]
+                ----
+                key: a fragment, not a route
+                ----
+
+                [source,yaml]
+                ----
+                # the steps to add to the route: a fragment too
+                - setHeader:
+                    name: CamelJmsDestinationName
+                    expression:
+                      constant:
+                        expression: "queue:///MY_QUEUE"
+                ----
+                """;
+        List<String> examples = DocBlocks.examples(doc);
+        assertEquals(2, examples.size(), String.valueOf(examples));
+        assertTrue(examples.get(0).startsWith("- from:"), examples.get(0));
+        assertTrue(examples.get(1).startsWith("# send the dataset to a 
queue\n- route:"), examples.get(1));
+    }
+
+    @Test
+    void afterACommentOnlyARootOfTheDslIsARouteFile() {
+        // a kamelet is a step; semantic is a root of the schema
+        String doc = "[source,yaml]\n----\n# the step to add\n- kamelet:\n    
name: beer-source\n----\n"
+                     + "[source,yaml]\n----\n# the semantic entry\n- 
semantic:\n    id: orders\n----\n";
+        List<DocBlocks.Example> examples = DocBlocks.examplesAt(doc);
+        assertEquals(1, examples.size(), String.valueOf(examples));
+        assertTrue(examples.get(0).yaml().startsWith("# the semantic entry\n- 
semantic:"), examples.get(0).yaml());
+        assertEquals(doc.indexOf("# the semantic entry"), 
examples.get(0).start());
+    }
+
+    @Test
+    void aBlockClosesAtItsOwnDelimiter() {
+        // a shorter or a longer line of dashes inside the block is part of it
+        String doc = "[source,yaml]\n--------\n- from:\n    uri: direct:a\n    
steps:\n      - log:\n"
+                     + "          message: 
x\n----\n----------\n--------\nafter\n";
+        List<String> examples = DocBlocks.examples(doc);
+        assertEquals(1, examples.size());
+        assertTrue(examples.get(0).endsWith("----\n----------\n"), 
examples.get(0));
+    }
+}
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/UserManualDocExamplesTest.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/UserManualDocExamplesTest.java
index 174a198934f5..f545d1f34c0a 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/UserManualDocExamplesTest.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/UserManualDocExamplesTest.java
@@ -50,7 +50,6 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
 class UserManualDocExamplesTest {
 
     private static final Path PAGES = Path.of("docs", "user-manual", 
"modules", "ROOT", "pages");
-    private static final Pattern YAML_BLOCK = 
Pattern.compile("\\[source,yaml\\]\\n-{4,}\\n(.*?)\\n-{4,}", Pattern.DOTALL);
     private static final Pattern FIRST_KEY = 
Pattern.compile("^\\s*-\\s+([A-Za-z]+)\\s*:");
 
     private static YamlValidator validator;
@@ -104,10 +103,10 @@ class UserManualDocExamplesTest {
             String page = entry.getKey();
             String doc = entry.getValue();
             int n = 0;
-            Matcher m = YAML_BLOCK.matcher(doc);
-            while (m.find()) {
-                String yaml = m.group(1).stripTrailing() + "\n";
-                Matcher key = FIRST_KEY.matcher(yaml.stripLeading());
+            // the blocks as the doc-samples plugin and the other 
documentation tests read them
+            for (DocBlocks.Example example : DocBlocks.examplesAt(doc)) {
+                String yaml = example.yaml();
+                Matcher key = FIRST_KEY.matcher(firstEntry(yaml));
                 if (!key.find() || !roots.contains(key.group(1))) {
                     // a step or an option fragment, or the YAML of another 
tool: not a route file
                     continue;
@@ -116,7 +115,7 @@ class UserManualDocExamplesTest {
                 examples++;
                 List<Error> errors = validator.validate(yaml);
                 if (!errors.isEmpty()) {
-                    int line = 1 + countLines(doc, m.start(1));
+                    int line = 1 + countLines(doc, example.start());
                     failures.add(page + ".adoc:" + line + " example " + n + ": 
" + errors.get(0).getMessage());
                 }
             }
@@ -151,6 +150,11 @@ class UserManualDocExamplesTest {
         return answer;
     }
 
+    /** The first line of the YAML that is not blank or a comment. */
+    private static String firstEntry(String yaml) {
+        return yaml.lines().map(String::strip).filter(l -> !l.isEmpty() && 
!l.startsWith("#")).findFirst().orElse("");
+    }
+
     private static int countLines(String text, int end) {
         int n = 0;
         for (int i = 0; i < end; i++) {

Reply via email to