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 c10d7d6314a4 CAMEL-26384: camel-jbang - AI tools: a resource: in both
values of a Simple ternary goes before the function, and the list item column
message quotes the lines (#28634)
c10d7d6314a4 is described below
commit c10d7d6314a436cb1a21716fba2f04b9115444c6
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Oct 29 07:10:27 2026 +0100
CAMEL-26384: camel-jbang - AI tools: a resource: in both values of a Simple
ternary goes before the function, and the list item column message quotes the
lines (#28634)
- A top-level ternary whose two values start with the same resource: and
scheme is rewritten with that prefix before the function.
- The list item column message quotes the item's line and the list's first
line as written (cut at 120 characters); the lenient repair reads the quoted
form.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../dsl/jbang/core/commands/ai/LenientRepairs.java | 5 ++--
.../dsl/jbang/core/commands/ai/SimpleChecks.java | 23 ++++++++++++--
.../commands/ai/SourceValidatorSimpleTest.java | 13 ++++++++
.../camel/dsl/yaml/validator/YamlValidator.java | 21 +++++++++++--
.../validator/YamlValidatorPropertyHintTest.java | 35 +++++++++++++++++-----
5 files changed, 81 insertions(+), 16 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/LenientRepairs.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/LenientRepairs.java
index 6d640fb0869a..631b162a175f 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/LenientRepairs.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/LenientRepairs.java
@@ -77,9 +77,10 @@ final class LenientRepairs {
"^line (\\d+): .* without quotes is read as a YAML map .*write the
line as (.+)$");
private static final Pattern BRACES = Pattern.compile(
"^Line (\\d+): .*\\((\\{[^}]*\\}) without quotes is a YAML map");
+ // the validator quotes each line after its number: line 11 (" -
log:"): ...
private static final Pattern ITEM_COLUMN = Pattern.compile(
- "^line (\\d+): this list item starts in column (\\d+), but the
list that starts at line \\d+ has its items in"
- + " column
(\\d+)");
+ "^line (\\d+)(?: \\(\".*?\"\\))?: this list item starts in column
(\\d+), but the list that starts at line"
+ + " \\d+(?:
\\(\".*?\"\\))? has its items in column (\\d+)");
private static final Pattern KEY_COLUMN = Pattern.compile(
"^line (\\d+): (\\S+) starts in column (\\d+), but the keys of the
mapping that starts at line \\d+ are in"
+ " column
(\\d+)");
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/SimpleChecks.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/SimpleChecks.java
index 0d40463c873c..57cd4a9fa52c 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/SimpleChecks.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/SimpleChecks.java
@@ -210,7 +210,9 @@ final class SimpleChecks {
* function the condition starts with is opened before the condition and
closed after the second value, and a value
* written as bare text is quoted.
<tt>resource:file:${exchangeProperty.CamelTimerCounter} == 1 ? order.json :
* order-bad-email.json</tt> is
<tt>resource:file:${exchangeProperty.CamelTimerCounter == 1 ? 'order.json' :
- * 'order-bad-email.json'}</tt>.
+ * 'order-bad-email.json'}</tt>, and so is
+ * <tt>${exchangeProperty.CamelTimerCounter} == 1 ?
resource:file:order.json :
+ * resource:file:order-bad-email.json</tt>.
*/
static String ternaryInsideOneFunction(String text, int question, int
colon) {
// the functions at the top level before the ?, as {start, end} with
end the index of the closing brace
@@ -238,10 +240,25 @@ final class SimpleChecks {
int start = functions.get(index)[0];
int end = functions.get(index)[1];
String condition = text.substring(start + 2, end) + text.substring(end
+ 1, question);
- return text.substring(0, start) + "${" + condition + " ? " +
quoted(text.substring(question + 3, colon).trim())
- + " : " + quoted(text.substring(colon + 3).trim()) + "}";
+ String prefix = text.substring(0, start);
+ String first = text.substring(question + 3, colon).trim();
+ String second = text.substring(colon + 3).trim();
+ // resource: is read only at the start of the expression: inside the
function, 'resource:file:order.json' is the
+ // text the body becomes, so a resource: both values start with goes
before the function (the local-model
+ // benchmark: the body was the text resource:file:order.json, and the
next step failed to parse it as JSON)
+ Matcher scheme = RESOURCE_SCHEME.matcher(first);
+ if (prefix.isEmpty() && scheme.lookingAt() &&
second.startsWith(scheme.group())
+ && first.length() > scheme.end() && second.length() >
scheme.end()) {
+ prefix = scheme.group();
+ first = first.substring(scheme.end());
+ second = second.substring(scheme.end());
+ }
+ return prefix + "${" + condition + " ? " + quoted(first) + " : " +
quoted(second) + "}";
}
+ /** The resource: and its scheme a value starts with, such as
<tt>resource:file:</tt>. */
+ private static final Pattern RESOURCE_SCHEME =
Pattern.compile("resource:[a-z]+:");
+
/** The index of the brace that closes the function opened at the index,
or -1. */
private static int closingBrace(String text, int open) {
char quote = 0;
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorSimpleTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorSimpleTest.java
index 593d5058f278..290b5f6cae01 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorSimpleTest.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorSimpleTest.java
@@ -501,6 +501,19 @@ class SourceValidatorSimpleTest {
.endsWith("resource:file:${exchangeProperty.CamelTimerCounter
== 1 ? 'order.json' : 'order-bad-email.json'}");
}
+ @Test
+ void aResourceInBothValuesOfATopLevelTernaryGoesBeforeTheFunction() {
+ // inside the function, 'resource:file:order.json' is only text: the
body would be that text, not the file
+ assertThat(rewritten(
+ "${exchangeProperty.CamelTimerCounter} == 1 ?
resource:file:order.json : resource:file:order-bad-email.json"))
+ .isEqualTo("resource:file:${exchangeProperty.CamelTimerCounter
== 1 ? 'order.json' : 'order-bad-email.json'}");
+ // a value that is not a resource of the same scheme stays as it is
+ assertThat(rewritten("${header.a} == 1 ? resource:file:order.json :
resource:classpath:order.json"))
+ .isEqualTo("${header.a == 1 ? 'resource:file:order.json' :
'resource:classpath:order.json'}");
+ assertThat(rewritten("${header.a} == 1 ? resource:file:order.json :
none"))
+ .isEqualTo("${header.a == 1 ? 'resource:file:order.json' :
'none'}");
+ }
+
@Test
void aResourceLocationWithoutATopLevelTernaryIsAccepted() {
List<String> msgs = SourceValidator.validateYamlSimple(
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
index 06455137980b..cd1d75848cc6 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
@@ -485,10 +485,25 @@ public class YamlValidator {
}
}
Mark list = deeper != null ? deeper : shallower;
+ // the two lines as written: with the columns alone, a local model
sent the same indentation again up to 18 times
String belongs = list == null
- ? "" : ", but the list that starts at line " + list.line() + "
has its items in column " + list.column();
- return hint("line " + problem.line() + ": this list item starts in
column " + problem.column() + belongs
- + "; every item of a list must start in the same column");
+ ? ""
+ : ", but the list that starts at line " + list.line() +
quotedLine(lines, list.line())
+ + " has its items in column " + list.column();
+ return hint("line " + problem.line() + quotedLine(lines,
problem.line()) + ": this list item starts in column "
+ + problem.column() + belongs + "; every item of a list
must start in the same column");
+ }
+
+ /**
+ * The line as written, quoted after its number, or nothing when the line
is not in the text. A long line (a JSON
+ * body, a long expression) is cut at 120 characters, as the indentation
the hint is about is at its start.
+ */
+ private static String quotedLine(String[] lines, int line) {
+ if (line < 1 || line > lines.length || lines[line - 1].isBlank()) {
+ return "";
+ }
+ String text = lines[line - 1].stripTrailing();
+ return " (\"" + (text.length() > 120 ? text.substring(0, 120) + "..."
: text) + "\")";
}
/**
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorPropertyHintTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorPropertyHintTest.java
index 68807cc68354..64540c5c9e82 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorPropertyHintTest.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlValidatorPropertyHintTest.java
@@ -1142,12 +1142,31 @@ public class YamlValidatorPropertyHintTest {
""");
assertThat(errors).hasSize(1);
assertThat(errors.get(0).getMessage())
- .startsWith("line 11: this list item starts in column 13")
- .contains("the list that starts at line 7 has its items in
column 15")
+ .startsWith("line 11 (\" - simple: \"${body} >
2\"\"): this list item starts in column 13")
+ .contains(
+ "the list that starts at line 7 (\" -
simple: \"${body} > 1\"\") has its items in column 15")
.contains("every item of a list must start in the same column")
.doesNotContain("block end");
}
+ /** CAMEL-26384: a long line is quoted only up to 120 characters, so the
hint does not grow with the value. */
+ @Test
+ void aLongListItemLineIsCutInTheHint() throws Exception {
+ List<Error> errors = new YamlValidator().validate("""
+ - route:
+ from:
+ uri: timer:tick
+ steps:
+ - log:
+ message: a
+ - log: "%s"
+ """.formatted("x".repeat(200)));
+ assertThat(errors).hasSize(1);
+ assertThat(errors.get(0).getMessage())
+ .startsWith("line 7 (\" - log:
\"xxx").contains("...\"): this list item starts in column 11")
+ .doesNotContain("x".repeat(120));
+ }
+
/** CAMEL-24837: the item is over-indented, so the list it belongs to is
the shallower one above it. */
@Test
void anOverIndentedListItemNamesTheListAboveIt() throws Exception {
@@ -1163,8 +1182,8 @@ public class YamlValidatorPropertyHintTest {
""");
assertThat(errors).hasSize(1);
assertThat(errors.get(0).getMessage())
- .startsWith("line 7: this list item starts in column 11")
- .contains("the list that starts at line 5 has its items in
column 9");
+ .startsWith("line 7 (\"").contains("\"): this list item starts
in column 11")
+ .contains("the list that starts at line 5 (\"").contains("\")
has its items in column 9");
}
/**
@@ -1293,8 +1312,8 @@ public class YamlValidatorPropertyHintTest {
""");
assertThat(errors).hasSize(1);
assertThat(errors.get(0).getMessage())
- .startsWith("line 12: this list item starts in column 13")
- .contains("the list that starts at line 7 has its items in
column 15");
+ .startsWith("line 12 (\"").contains("\"): this list item
starts in column 13")
+ .contains("the list that starts at line 7 (\"").contains("\")
has its items in column 15");
}
/**
@@ -1316,8 +1335,8 @@ public class YamlValidatorPropertyHintTest {
""");
assertThat(errors).hasSize(1);
assertThat(errors.get(0).getMessage())
- .startsWith("line 8: this list item starts in column 10")
- .contains("the list that starts at line 5 has its items in
column 9")
+ .startsWith("line 8 (\"").contains("\"): this list item starts
in column 10")
+ .contains("the list that starts at line 5 (\"").contains("\")
has its items in column 9")
.doesNotContain("block sequence start");
}