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 92040109d14c CAMEL-25761: camel-jbang - the AI validator finds the
parameters of an endpoint wherever they stand in the step (#28057)
92040109d14c is described below
commit 92040109d14c466cdcf85b4365558769f4865616
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Oct 18 18:04:19 2026 +0200
CAMEL-25761: camel-jbang - the AI validator finds the parameters of an
endpoint wherever they stand in the step (#28057)
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
---
.../dsl/jbang/core/commands/ai/EndpointChecks.java | 29 ++++++++++---
.../ai/SourceValidatorPlaceholderTest.java | 48 ++++++++++++++++++++++
2 files changed, 72 insertions(+), 5 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
index ef0ddd26f006..801e9e50addf 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
@@ -137,11 +137,13 @@ final class EndpointChecks {
boolean consumerOnly = eipName != null &&
CONSUMER_EIPS.contains(eipName);
boolean producerOnly = eipName != null &&
PRODUCER_EIPS.contains(eipName);
- // look ahead for a parameters: block at the same indent level as
uri
+ // the parameters: block is a key of the same mapping as uri:,
after it or before it, and other keys of the
+ // step (id:, variableReceive:) may stand in between (CAMEL-25761)
StringBuilder uriBuilder = new StringBuilder(uri);
boolean hasParams = uri.contains("?");
Map<String, Integer> optionLineMap = new LinkedHashMap<>();
- for (int j = i + 1; j < lines.length; j++) {
+ int paramsBefore = keyBefore(lines, i, lineIndent, "parameters:");
+ for (int j = paramsBefore >= 0 ? paramsBefore : i + 1; j <
lines.length; j++) {
String next = lines[j];
if (next.isBlank()) {
continue;
@@ -214,9 +216,6 @@ final class EndpointChecks {
}
break;
}
- if (nextIndent == lineIndent) {
- break;
- }
}
checkUri(errors, catalog, uriBuilder.toString(), line, i,
optionLineMap, eipName, consumerOnly, producerOnly,
@@ -225,6 +224,26 @@ final class EndpointChecks {
return errors;
}
+ /**
+ * The line of the key (such as parameters:) of the same mapping as the
line at idx that comes before it: the same
+ * indent, up to the line that starts the mapping, or -1.
+ */
+ static int keyBefore(String[] lines, int idx, int indent, String key) {
+ for (int j = idx - 1; j >= 0; j--) {
+ if (lines[j].isBlank()) {
+ continue;
+ }
+ int ind = countLeadingSpaces(lines[j]);
+ if (ind < indent) {
+ return -1;
+ }
+ if (ind == indent && lines[j].trim().startsWith(key)) {
+ return j;
+ }
+ }
+ return -1;
+ }
+
/**
* The checks of one endpoint uri, whatever the DSL it is written in: the
options against the catalog, then the
* mistakes the catalog does not see.
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorPlaceholderTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorPlaceholderTest.java
index 4019b2a2dcfe..b13621e9297e 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorPlaceholderTest.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorPlaceholderTest.java
@@ -118,6 +118,54 @@ class SourceValidatorPlaceholderTest {
.noneMatch(e -> e.contains("required option"));
}
+ /** CAMEL-25761: another key of the step between uri: and parameters:, or
parameters: above uri: */
+ @Test
+ void theParametersAreFoundWhereverTheyStandInTheStep() {
+ String keyBetween = """
+ - route:
+ from:
+ uri: timer
+ parameters:
+ timerName: tick
+ steps:
+ - to:
+ uri: jms
+ variableReceive: answer
+ parameters:
+ destinationType: queue
+ destinationName: stock
+ - to:
+ uri: jms
+ id: send-order
+ parameters:
+ destinationName: orders
+ destinationTyp: queue
+ """;
+ List<String> errors =
SourceValidator.validateYamlEndpoints(keyBetween, catalog);
+ assertThat(errors).noneMatch(e -> e.contains("required option"));
+ // the options behind the other key are checked as well: a misspelled
one is reported on its own line
+ assertThat(errors).anyMatch(e -> e.startsWith("Line 18:") &&
e.contains("destinationTyp"));
+
+ String paramsFirst = """
+ - route:
+ from:
+ uri: timer
+ parameters:
+ timerName: tick
+ steps:
+ - to:
+ parameters:
+ destinationName: stock
+ uri: jms
+ """;
+ assertThat(SourceValidator.validateYamlEndpoints(paramsFirst,
catalog)).noneMatch(e -> e.contains("required option"));
+
+ // without the option anywhere in the step, it is still reported
+
assertThat(SourceValidator.validateYamlEndpoints(keyBetween.replace("\n
destinationName: stock", ""),
+ catalog))
+ .anyMatch(e -> e.startsWith("Line 8: jms: the required option
'destinationName' is missing"));
+ }
+
@Test
void aSimplePlaceholderInABeanPropertySaysToWriteAPropertyPlaceholder() {
String yaml = """