ammachado commented on code in PR #26617:
URL: https://github.com/apache/camel/pull/26617#discussion_r4055867997
##########
dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java:
##########
@@ -214,6 +220,208 @@ static Error parseError(Exception e, String content) {
.build();
}
+ private static final Pattern SNAKE_MARK = Pattern.compile("in 'reader',
line (\\d+), column (\\d+):");
+ private static final Pattern ESCAPE_CHAR = Pattern.compile("found unknown
escape character (.)\\(");
+ private static final Pattern KEY_LINE =
Pattern.compile("^\\s*[^-\\s#][^:]*:(\\s|$)");
+
+ /** A position the parser reported: the line and the column it points at,
both 1-based. */
+ private record Mark(int line, int column) {
+ }
+
+ /**
+ * CAMEL-24837: the snakeyaml messages that only say where the parser gave
up, said in YAML words. Returns null for
+ * the messages this does not know, so the raw one is still reported.
+ */
+ static Error indentationError(String msg, String[] lines) {
+ List<Mark> marks = marks(msg, lines);
+ if (marks.isEmpty()) {
+ return null;
+ }
+ Mark problem = marks.get(marks.size() - 1);
+ if (msg.contains("expected <block end>, but found '-'")) {
+ return listItemColumn(problem, lines);
+ }
+ if (msg.contains("expected <block end>, but found '<block mapping
start>'")) {
+ return marks.size() > 1 ? mappingKeyColumn(marks.get(0), problem,
lines) : null;
+ }
+ if (msg.contains("mapping values are not allowed here")) {
+ return mappingValue(problem, lines);
+ }
+ if (msg.contains("found unknown escape character")) {
+ return unknownEscape(msg, problem, lines);
+ }
+ return null;
+ }
+
+ /** {@code found character '\t(TAB)' that cannot start any token}: the
line is indented with a tab. */
+ static Error tabIndentation(String msg) {
+ if (!msg.contains("(TAB) for indentation")) {
+ return null;
+ }
+ Matcher m = SNAKE_MARK.matcher(msg);
+ int line = -1;
+ while (m.find()) {
+ line = Integer.parseInt(m.group(1));
+ }
+ return line < 1
+ ? null
+ : hint("line " + line + ": the indentation uses a tab; YAML
indents with spaces only, replace the"
+ + " tab with spaces");
+ }
+
+ /**
+ * A list item in a column of its own: the parser only says that it
expected the end of what it was reading. Name
+ * the list the item belongs to, which is the shallowest list still open
below the item's column, or the deepest one
+ * above it when the item is the over-indented one.
+ */
+ private static Error listItemColumn(Mark problem, String[] lines) {
+ Mark deeper = null;
+ Mark shallower = null;
+ for (Mark open : openLists(problem, lines)) {
+ if (open.column() > problem.column() && (deeper == null ||
open.column() < deeper.column())) {
+ deeper = open;
+ } else if (open.column() < problem.column() && (shallower == null
|| open.column() > shallower.column())) {
+ shallower = open;
+ }
+ }
+ Mark list = deeper != null ? deeper : shallower;
+ 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");
+ }
+
+ /**
+ * The lists still open above the problem, each as the line and column of
its first item. A list at column c is open
+ * while every line below it is indented to at least c.
+ */
+ private static List<Mark> openLists(Mark problem, String[] lines) {
+ Map<Integer, Integer> firstItem = new LinkedHashMap<>();
+ int deepest = Integer.MAX_VALUE;
+ for (int i = problem.line() - 2; i >= 0; i--) {
+ String stripped = lines[i].stripLeading();
+ if (stripped.isEmpty() || stripped.startsWith("#")) {
+ continue;
+ }
+ int indent = lines[i].length() - stripped.length();
+ if (stripped.startsWith("- ") && indent <= deepest) {
Review Comment:
Fixed in 0c8fe2e, though the verification came out differently from the
suggestion, so here is what I found.
The example in the comment does not reach `openLists` at all. It produces a
third message variant:
```
while parsing a block collection
in 'reader', line 5, column 9:
-
^
expected <block end>, but found '<block sequence start>'
in 'reader', line 8, column 10:
- log:
^
```
`'<block sequence start>'`, not `'-'`, because the list it broke uses bare
dashes. Nothing matched that, so the file still got the full raw
`MarkedYAMLException` dump rather than a fallback message.
`stripped.equals("-")` on its own would not have changed that example's output.
The underlying concern is real, but the consequence is worse than a missing
clause. When the message *is* `found '-'` and the target list starts with a
bare dash, the list is skipped and the nearest **nested** list is named instead:
```yaml
7| - # the when list, items in column 15
10| - log: # a nested list, column 19
12| - simple: "${body} > 2" # the stray item
```
before: `line 12: this list item starts in column 13, but the list that
starts at line 10 has its items in column 19`
That points the reader confidently at the wrong place, which is worse than
the raw parser message this PR replaces.
Both are fixed:
- a list indicator is now a `-` followed by whitespace **or by the end of
the line**. `stripped.equals("-")` would have missed `"- "`, since
`stripLeading()` keeps trailing spaces;
- `'<block sequence start>'` routes into the same `listItemColumn` message
as `'-'`.
after, for the two cases above:
```
line 8: this list item starts in column 10, but the list that starts at line
5 has its items in column 9; ...
line 12: this list item starts in column 13, but the list that starts at
line 7 has its items in column 15; ...
```
A test each, both watched to fail first.
_Claude Code on behalf of Adriano Machado (@ammachado)_
_This was generated by an AI agent and may contain inaccuracies. Please
verify before relying on it._
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]